The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/efs/inode.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * inode.c
    3  *
    4  * Copyright (c) 1999 Al Smith
    5  *
    6  * Portions derived from work (c) 1995,1996 Christian Vogelgsang,
    7  *              and from work (c) 1998 Mike Shaver.
    8  */
    9 
   10 #include <linux/efs_fs.h>
   11 #include <linux/efs_fs_sb.h>
   12 #include <linux/module.h>
   13 
   14 
   15 extern int efs_get_block(struct inode *, long, struct buffer_head *, int);
   16 static int efs_readpage(struct file *file, struct page *page)
   17 {
   18         return block_read_full_page(page,efs_get_block);
   19 }
   20 static int _efs_bmap(struct address_space *mapping, long block)
   21 {
   22         return generic_block_bmap(mapping,block,efs_get_block);
   23 }
   24 struct address_space_operations efs_aops = {
   25         readpage: efs_readpage,
   26         sync_page: block_sync_page,
   27         bmap: _efs_bmap
   28 };
   29 
   30 static inline void extent_copy(efs_extent *src, efs_extent *dst) {
   31         /*
   32          * this is slightly evil. it doesn't just copy
   33          * efs_extent from src to dst, it also mangles
   34          * the bits so that dst ends up in cpu byte-order.
   35          */
   36 
   37         dst->cooked.ex_magic  =  (unsigned int) src->raw[0];
   38         dst->cooked.ex_bn     = ((unsigned int) src->raw[1] << 16) |
   39                                 ((unsigned int) src->raw[2] <<  8) |
   40                                 ((unsigned int) src->raw[3] <<  0);
   41         dst->cooked.ex_length =  (unsigned int) src->raw[4];
   42         dst->cooked.ex_offset = ((unsigned int) src->raw[5] << 16) |
   43                                 ((unsigned int) src->raw[6] <<  8) |
   44                                 ((unsigned int) src->raw[7] <<  0);
   45         return;
   46 }
   47 
   48 void efs_read_inode(struct inode *inode) {
   49         int i, inode_index;
   50         dev_t device;
   51         struct buffer_head *bh;
   52         struct efs_sb_info    *sb = SUPER_INFO(inode->i_sb);
   53         struct efs_inode_info *in = INODE_INFO(inode);
   54         efs_block_t block, offset;
   55         struct efs_dinode *efs_inode;
   56   
   57         /*
   58         ** EFS layout:
   59         **
   60         ** |   cylinder group    |   cylinder group    |   cylinder group ..etc
   61         ** |inodes|data          |inodes|data          |inodes|data       ..etc
   62         **
   63         ** work out the inode block index, (considering initially that the
   64         ** inodes are stored as consecutive blocks). then work out the block
   65         ** number of that inode given the above layout, and finally the
   66         ** offset of the inode within that block.
   67         */
   68 
   69         inode_index = inode->i_ino /
   70                 (EFS_BLOCKSIZE / sizeof(struct efs_dinode));
   71 
   72         block = sb->fs_start + sb->first_block + 
   73                 (sb->group_size * (inode_index / sb->inode_blocks)) +
   74                 (inode_index % sb->inode_blocks);
   75 
   76         offset = (inode->i_ino %
   77                         (EFS_BLOCKSIZE / sizeof(struct efs_dinode))) *
   78                 sizeof(struct efs_dinode);
   79 
   80         bh = sb_bread(inode->i_sb, block);
   81         if (!bh) {
   82                 printk(KERN_WARNING "EFS: bread() failed at block %d\n", block);
   83                 goto read_inode_error;
   84         }
   85 
   86         efs_inode = (struct efs_dinode *) (bh->b_data + offset);
   87     
   88         inode->i_mode  = be16_to_cpu(efs_inode->di_mode);
   89         inode->i_nlink = be16_to_cpu(efs_inode->di_nlink);
   90         inode->i_uid   = (uid_t)be16_to_cpu(efs_inode->di_uid);
   91         inode->i_gid   = (gid_t)be16_to_cpu(efs_inode->di_gid);
   92         inode->i_size  = be32_to_cpu(efs_inode->di_size);
   93         inode->i_atime = be32_to_cpu(efs_inode->di_atime);
   94         inode->i_mtime = be32_to_cpu(efs_inode->di_mtime);
   95         inode->i_ctime = be32_to_cpu(efs_inode->di_ctime);
   96 
   97         /* this is the number of blocks in the file */
   98         if (inode->i_size == 0) {
   99                 inode->i_blocks = 0;
  100         } else {
  101                 inode->i_blocks = ((inode->i_size - 1) >> EFS_BLOCKSIZE_BITS) + 1;
  102         }
  103 
  104         /*
  105          * BUG: irix dev_t is 32-bits. linux dev_t is only 16-bits.
  106          *
  107          * apparently linux will change to 32-bit dev_t sometime during
  108          * linux 2.3.
  109          *
  110          * as is, this code maps devices that can't be represented in
  111          * 16-bits (ie major > 255 or minor > 255) to major = minor = 255.
  112          *
  113          * during 2.3 when 32-bit dev_t become available, we should test
  114          * to see whether odev contains 65535. if this is the case then we
  115          * should then do device = be32_to_cpu(efs_inode->di_u.di_dev.ndev).
  116          */
  117         device = be16_to_cpu(efs_inode->di_u.di_dev.odev);
  118 
  119         /* get the number of extents for this object */
  120         in->numextents = be16_to_cpu(efs_inode->di_numextents);
  121         in->lastextent = 0;
  122 
  123         /* copy the extents contained within the inode to memory */
  124         for(i = 0; i < EFS_DIRECTEXTENTS; i++) {
  125                 extent_copy(&(efs_inode->di_u.di_extents[i]), &(in->extents[i]));
  126                 if (i < in->numextents && in->extents[i].cooked.ex_magic != 0) {
  127                         printk(KERN_WARNING "EFS: extent %d has bad magic number in inode %lu\n", i, inode->i_ino);
  128                         brelse(bh);
  129                         goto read_inode_error;
  130                 }
  131         }
  132 
  133         brelse(bh);
  134    
  135 #ifdef DEBUG
  136         printk(KERN_DEBUG "EFS: read_inode(): inode %lu, extents %d, mode %o\n",
  137                 inode->i_ino, in->numextents, inode->i_mode);
  138 #endif
  139 
  140         switch (inode->i_mode & S_IFMT) {
  141                 case S_IFDIR: 
  142                         inode->i_op = &efs_dir_inode_operations; 
  143                         inode->i_fop = &efs_dir_operations; 
  144                         break;
  145                 case S_IFREG:
  146                         inode->i_fop = &generic_ro_fops;
  147                         inode->i_data.a_ops = &efs_aops;
  148                         break;
  149                 case S_IFLNK:
  150                         inode->i_op = &page_symlink_inode_operations;
  151                         inode->i_data.a_ops = &efs_symlink_aops;
  152                         break;
  153                 case S_IFCHR:
  154                 case S_IFBLK:
  155                 case S_IFIFO:
  156                         init_special_inode(inode, inode->i_mode, device);
  157                         break;
  158                 default:
  159                         printk(KERN_WARNING "EFS: unsupported inode mode %o\n", inode->i_mode);
  160                         goto read_inode_error;
  161                         break;
  162         }
  163 
  164         return;
  165         
  166 read_inode_error:
  167         printk(KERN_WARNING "EFS: failed to read inode %lu\n", inode->i_ino);
  168         make_bad_inode(inode);
  169 
  170         return;
  171 }
  172 
  173 static inline efs_block_t
  174 efs_extent_check(efs_extent *ptr, efs_block_t block, struct efs_sb_info *sb) {
  175         efs_block_t start;
  176         efs_block_t length;
  177         efs_block_t offset;
  178 
  179         /*
  180          * given an extent and a logical block within a file,
  181          * can this block be found within this extent ?
  182          */
  183         start  = ptr->cooked.ex_bn;
  184         length = ptr->cooked.ex_length;
  185         offset = ptr->cooked.ex_offset;
  186 
  187         if ((block >= offset) && (block < offset+length)) {
  188                 return(sb->fs_start + start + block - offset);
  189         } else {
  190                 return 0;
  191         }
  192 }
  193 
  194 efs_block_t efs_map_block(struct inode *inode, efs_block_t block) {
  195         struct efs_sb_info    *sb = SUPER_INFO(inode->i_sb);
  196         struct efs_inode_info *in = INODE_INFO(inode);
  197         struct buffer_head    *bh = NULL;
  198 
  199         int cur, last, first = 1;
  200         int ibase, ioffset, dirext, direxts, indext, indexts;
  201         efs_block_t iblock, result = 0, lastblock = 0;
  202         efs_extent ext, *exts;
  203 
  204         last = in->lastextent;
  205 
  206         if (in->numextents <= EFS_DIRECTEXTENTS) {
  207                 /* first check the last extent we returned */
  208                 if ((result = efs_extent_check(&in->extents[last], block, sb)))
  209                         return result;
  210     
  211                 /* if we only have one extent then nothing can be found */
  212                 if (in->numextents == 1) {
  213                         printk(KERN_ERR "EFS: map_block() failed to map (1 extent)\n");
  214                         return 0;
  215                 }
  216 
  217                 direxts = in->numextents;
  218 
  219                 /*
  220                  * check the stored extents in the inode
  221                  * start with next extent and check forwards
  222                  */
  223                 for(dirext = 1; dirext < direxts; dirext++) {
  224                         cur = (last + dirext) % in->numextents;
  225                         if ((result = efs_extent_check(&in->extents[cur], block, sb))) {
  226                                 in->lastextent = cur;
  227                                 return result;
  228                         }
  229                 }
  230 
  231                 printk(KERN_ERR "EFS: map_block() failed to map block %u (dir)\n", block);
  232                 return 0;
  233         }
  234 
  235 #ifdef DEBUG
  236         printk(KERN_DEBUG "EFS: map_block(): indirect search for logical block %u\n", block);
  237 #endif
  238         direxts = in->extents[0].cooked.ex_offset;
  239         indexts = in->numextents;
  240 
  241         for(indext = 0; indext < indexts; indext++) {
  242                 cur = (last + indext) % indexts;
  243 
  244                 /*
  245                  * work out which direct extent contains `cur'.
  246                  *
  247                  * also compute ibase: i.e. the number of the first
  248                  * indirect extent contained within direct extent `cur'.
  249                  *
  250                  */
  251                 ibase = 0;
  252                 for(dirext = 0; cur < ibase && dirext < direxts; dirext++) {
  253                         ibase += in->extents[dirext].cooked.ex_length *
  254                                 (EFS_BLOCKSIZE / sizeof(efs_extent));
  255                 }
  256 
  257                 if (dirext == direxts) {
  258                         /* should never happen */
  259                         printk(KERN_ERR "EFS: couldn't find direct extent for indirect extent %d (block %u)\n", cur, block);
  260                         if (bh) brelse(bh);
  261                         return 0;
  262                 }
  263                 
  264                 /* work out block number and offset of this indirect extent */
  265                 iblock = sb->fs_start + in->extents[dirext].cooked.ex_bn +
  266                         (cur - ibase) /
  267                         (EFS_BLOCKSIZE / sizeof(efs_extent));
  268                 ioffset = (cur - ibase) %
  269                         (EFS_BLOCKSIZE / sizeof(efs_extent));
  270 
  271                 if (first || lastblock != iblock) {
  272                         if (bh) brelse(bh);
  273 
  274                         bh = sb_bread(inode->i_sb, iblock);
  275                         if (!bh) {
  276                                 printk(KERN_ERR "EFS: bread() failed at block %d\n", iblock);
  277                                 return 0;
  278                         }
  279 #ifdef DEBUG
  280                         printk(KERN_DEBUG "EFS: map_block(): read indirect extent block %d\n", iblock);
  281 #endif
  282                         first = 0;
  283                         lastblock = iblock;
  284                 }
  285 
  286                 exts = (efs_extent *) bh->b_data;
  287 
  288                 extent_copy(&(exts[ioffset]), &ext);
  289 
  290                 if (ext.cooked.ex_magic != 0) {
  291                         printk(KERN_ERR "EFS: extent %d has bad magic number in block %d\n", cur, iblock);
  292                         if (bh) brelse(bh);
  293                         return 0;
  294                 }
  295 
  296                 if ((result = efs_extent_check(&ext, block, sb))) {
  297                         if (bh) brelse(bh);
  298                         in->lastextent = cur;
  299                         return result;
  300                 }
  301         }
  302         if (bh) brelse(bh);
  303         printk(KERN_ERR "EFS: map_block() failed to map block %u (indir)\n", block);
  304         return 0;
  305 }  
  306 
  307 MODULE_LICENSE("GPL");

Cache object: 30f8d96270d079a42634e3da24684f0e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.