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/cramfs/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  * Compressed rom filesystem for Linux.
    3  *
    4  * Copyright (C) 1999 Linus Torvalds.
    5  *
    6  * This file is released under the GPL.
    7  */
    8 
    9 /*
   10  * These are the VFS interfaces to the compressed rom filesystem.
   11  * The actual compression is based on zlib, see the other files.
   12  */
   13 
   14 #include <linux/module.h>
   15 #include <linux/fs.h>
   16 #include <linux/pagemap.h>
   17 #include <linux/init.h>
   18 #include <linux/string.h>
   19 #include <linux/locks.h>
   20 #include <linux/blkdev.h>
   21 #include <linux/cramfs_fs.h>
   22 #include <asm/semaphore.h>
   23 
   24 #include <asm/uaccess.h>
   25 
   26 #define CRAMFS_SB_MAGIC u.cramfs_sb.magic
   27 #define CRAMFS_SB_SIZE u.cramfs_sb.size
   28 #define CRAMFS_SB_BLOCKS u.cramfs_sb.blocks
   29 #define CRAMFS_SB_FILES u.cramfs_sb.files
   30 #define CRAMFS_SB_FLAGS u.cramfs_sb.flags
   31 
   32 static struct super_operations cramfs_ops;
   33 static struct inode_operations cramfs_dir_inode_operations;
   34 static struct file_operations cramfs_directory_operations;
   35 static struct address_space_operations cramfs_aops;
   36 
   37 static DECLARE_MUTEX(read_mutex);
   38 
   39 
   40 /* These two macros may change in future, to provide better st_ino
   41    semantics. */
   42 #define CRAMINO(x)      ((x)->offset?(x)->offset<<2:1)
   43 #define OFFSET(x)       ((x)->i_ino)
   44 
   45 static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
   46 {
   47         struct inode * inode = new_inode(sb);
   48 
   49         if (inode) {
   50                 inode->i_mode = cramfs_inode->mode;
   51                 inode->i_uid = cramfs_inode->uid;
   52                 inode->i_size = cramfs_inode->size;
   53                 inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
   54                 inode->i_blksize = PAGE_CACHE_SIZE;
   55                 inode->i_gid = cramfs_inode->gid;
   56                 inode->i_ino = CRAMINO(cramfs_inode);
   57                 /* inode->i_nlink is left 1 - arguably wrong for directories,
   58                    but it's the best we can do without reading the directory
   59                    contents.  1 yields the right result in GNU find, even
   60                    without -noleaf option. */
   61                 insert_inode_hash(inode);
   62                 if (S_ISREG(inode->i_mode)) {
   63                         inode->i_fop = &generic_ro_fops;
   64                         inode->i_data.a_ops = &cramfs_aops;
   65                 } else if (S_ISDIR(inode->i_mode)) {
   66                         inode->i_op = &cramfs_dir_inode_operations;
   67                         inode->i_fop = &cramfs_directory_operations;
   68                 } else if (S_ISLNK(inode->i_mode)) {
   69                         inode->i_op = &page_symlink_inode_operations;
   70                         inode->i_data.a_ops = &cramfs_aops;
   71                 } else {
   72                         inode->i_size = 0;
   73                         init_special_inode(inode, inode->i_mode, cramfs_inode->size);
   74                 }
   75         }
   76         return inode;
   77 }
   78 
   79 /*
   80  * We have our own block cache: don't fill up the buffer cache
   81  * with the rom-image, because the way the filesystem is set
   82  * up the accesses should be fairly regular and cached in the
   83  * page cache and dentry tree anyway..
   84  *
   85  * This also acts as a way to guarantee contiguous areas of up to
   86  * BLKS_PER_BUF*PAGE_CACHE_SIZE, so that the caller doesn't need to
   87  * worry about end-of-buffer issues even when decompressing a full
   88  * page cache.
   89  */
   90 #define READ_BUFFERS (2)
   91 /* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */
   92 #define NEXT_BUFFER(_ix) ((_ix) ^ 1)
   93 
   94 /*
   95  * BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed"
   96  * data that takes up more space than the original and with unlucky
   97  * alignment.
   98  */
   99 #define BLKS_PER_BUF_SHIFT      (2)
  100 #define BLKS_PER_BUF            (1 << BLKS_PER_BUF_SHIFT)
  101 #define BUFFER_SIZE             (BLKS_PER_BUF*PAGE_CACHE_SIZE)
  102 
  103 static unsigned char read_buffers[READ_BUFFERS][BUFFER_SIZE];
  104 static unsigned buffer_blocknr[READ_BUFFERS];
  105 static struct super_block * buffer_dev[READ_BUFFERS];
  106 static int next_buffer;
  107 
  108 /*
  109  * Returns a pointer to a buffer containing at least LEN bytes of
  110  * filesystem starting at byte offset OFFSET into the filesystem.
  111  */
  112 static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
  113 {
  114         struct buffer_head * bh_array[BLKS_PER_BUF];
  115         struct buffer_head * read_array[BLKS_PER_BUF];
  116         unsigned i, blocknr, buffer, unread;
  117         unsigned long devsize;
  118         int major, minor;
  119 
  120         char *data;
  121 
  122         if (!len)
  123                 return NULL;
  124         blocknr = offset >> PAGE_CACHE_SHIFT;
  125         offset &= PAGE_CACHE_SIZE - 1;
  126 
  127         /* Check if an existing buffer already has the data.. */
  128         for (i = 0; i < READ_BUFFERS; i++) {
  129                 unsigned int blk_offset;
  130 
  131                 if (buffer_dev[i] != sb)
  132                         continue;
  133                 if (blocknr < buffer_blocknr[i])
  134                         continue;
  135                 blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;
  136                 blk_offset += offset;
  137                 if (blk_offset + len > BUFFER_SIZE)
  138                         continue;
  139                 return read_buffers[i] + blk_offset;
  140         }
  141 
  142         devsize = ~0UL;
  143         major = MAJOR(sb->s_dev);
  144         minor = MINOR(sb->s_dev);
  145 
  146         if (blk_size[major])
  147                 devsize = blk_size[major][minor] >> 2;
  148 
  149         /* Ok, read in BLKS_PER_BUF pages completely first. */
  150         unread = 0;
  151         for (i = 0; i < BLKS_PER_BUF; i++) {
  152                 struct buffer_head *bh;
  153 
  154                 bh = NULL;
  155                 if (blocknr + i < devsize) {
  156                         bh = sb_getblk(sb, blocknr + i);
  157                         if (!buffer_uptodate(bh))
  158                                 read_array[unread++] = bh;
  159                 }
  160                 bh_array[i] = bh;
  161         }
  162 
  163         if (unread) {
  164                 ll_rw_block(READ, unread, read_array);
  165                 do {
  166                         unread--;
  167                         wait_on_buffer(read_array[unread]);
  168                 } while (unread);
  169         }
  170 
  171         /* Ok, copy them to the staging area without sleeping. */
  172         buffer = next_buffer;
  173         next_buffer = NEXT_BUFFER(buffer);
  174         buffer_blocknr[buffer] = blocknr;
  175         buffer_dev[buffer] = sb;
  176 
  177         data = read_buffers[buffer];
  178         for (i = 0; i < BLKS_PER_BUF; i++) {
  179                 struct buffer_head * bh = bh_array[i];
  180                 if (bh) {
  181                         memcpy(data, bh->b_data, PAGE_CACHE_SIZE);
  182                         brelse(bh);
  183                 } else
  184                         memset(data, 0, PAGE_CACHE_SIZE);
  185                 data += PAGE_CACHE_SIZE;
  186         }
  187         return read_buffers[buffer] + offset;
  188 }
  189 
  190 
  191 static struct super_block * cramfs_read_super(struct super_block *sb, void *data, int silent)
  192 {
  193         int i;
  194         struct cramfs_super super;
  195         unsigned long root_offset;
  196         struct super_block * retval = NULL;
  197 
  198         set_blocksize(sb->s_dev, PAGE_CACHE_SIZE);
  199         sb->s_blocksize = PAGE_CACHE_SIZE;
  200         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
  201 
  202         /* Invalidate the read buffers on mount: think disk change.. */
  203         for (i = 0; i < READ_BUFFERS; i++)
  204                 buffer_blocknr[i] = -1;
  205 
  206         down(&read_mutex);
  207         /* Read the first block and get the superblock from it */
  208         memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
  209         up(&read_mutex);
  210 
  211         /* Do sanity checks on the superblock */
  212         if (super.magic != CRAMFS_MAGIC) {
  213                 /* check at 512 byte offset */
  214                 memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));
  215                 if (super.magic != CRAMFS_MAGIC) {
  216                         printk(KERN_ERR "cramfs: wrong magic\n");
  217                         goto out;
  218                 }
  219         }
  220 
  221         /* get feature flags first */
  222         if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
  223                 printk(KERN_ERR "cramfs: unsupported filesystem features\n");
  224                 goto out;
  225         }
  226 
  227         /* Check that the root inode is in a sane state */
  228         if (!S_ISDIR(super.root.mode)) {
  229                 printk(KERN_ERR "cramfs: root is not a directory\n");
  230                 goto out;
  231         }
  232         root_offset = super.root.offset << 2;
  233         if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {
  234                 sb->CRAMFS_SB_SIZE=super.size;
  235                 sb->CRAMFS_SB_BLOCKS=super.fsid.blocks;
  236                 sb->CRAMFS_SB_FILES=super.fsid.files;
  237         } else {
  238                 sb->CRAMFS_SB_SIZE=1<<28;
  239                 sb->CRAMFS_SB_BLOCKS=0;
  240                 sb->CRAMFS_SB_FILES=0;
  241         }
  242         sb->CRAMFS_SB_MAGIC=super.magic;
  243         sb->CRAMFS_SB_FLAGS=super.flags;
  244         if (root_offset == 0)
  245                 printk(KERN_INFO "cramfs: empty filesystem");
  246         else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
  247                  ((root_offset != sizeof(struct cramfs_super)) &&
  248                   (root_offset != 512 + sizeof(struct cramfs_super))))
  249         {
  250                 printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset);
  251                 goto out;
  252         }
  253 
  254         /* Set it all up.. */
  255         sb->s_op = &cramfs_ops;
  256         sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root));
  257         retval = sb;
  258 out:
  259         return retval;
  260 }
  261 
  262 static int cramfs_statfs(struct super_block *sb, struct statfs *buf)
  263 {
  264         buf->f_type = CRAMFS_MAGIC;
  265         buf->f_bsize = PAGE_CACHE_SIZE;
  266         buf->f_blocks = sb->CRAMFS_SB_BLOCKS;
  267         buf->f_bfree = 0;
  268         buf->f_bavail = 0;
  269         buf->f_files = sb->CRAMFS_SB_FILES;
  270         buf->f_ffree = 0;
  271         buf->f_namelen = CRAMFS_MAXPATHLEN;
  272         return 0;
  273 }
  274 
  275 /*
  276  * Read a cramfs directory entry.
  277  */
  278 static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
  279 {
  280         struct inode *inode = filp->f_dentry->d_inode;
  281         struct super_block *sb = inode->i_sb;
  282         unsigned int offset;
  283         int copied;
  284 
  285         /* Offset within the thing. */
  286         offset = filp->f_pos;
  287         if (offset >= inode->i_size)
  288                 return 0;
  289         /* Directory entries are always 4-byte aligned */
  290         if (offset & 3)
  291                 return -EINVAL;
  292 
  293         copied = 0;
  294         while (offset < inode->i_size) {
  295                 struct cramfs_inode *de;
  296                 unsigned long nextoffset;
  297                 char *name;
  298                 int namelen, error;
  299 
  300                 down(&read_mutex);
  301                 de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+256);
  302                 up(&read_mutex);
  303                 name = (char *)(de+1);
  304 
  305                 /*
  306                  * Namelengths on disk are shifted by two
  307                  * and the name padded out to 4-byte boundaries
  308                  * with zeroes.
  309                  */
  310                 namelen = de->namelen << 2;
  311                 nextoffset = offset + sizeof(*de) + namelen;
  312                 for (;;) {
  313                         if (!namelen)
  314                                 return -EIO;
  315                         if (name[namelen-1])
  316                                 break;
  317                         namelen--;
  318                 }
  319                 error = filldir(dirent, name, namelen, offset, CRAMINO(de), de->mode >> 12);
  320                 if (error)
  321                         break;
  322 
  323                 offset = nextoffset;
  324                 filp->f_pos = offset;
  325                 copied++;
  326         }
  327         return 0;
  328 }
  329 
  330 /*
  331  * Lookup and fill in the inode data..
  332  */
  333 static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry)
  334 {
  335         unsigned int offset = 0;
  336         int sorted = dir->i_sb->CRAMFS_SB_FLAGS & CRAMFS_FLAG_SORTED_DIRS;
  337 
  338         while (offset < dir->i_size) {
  339                 struct cramfs_inode *de;
  340                 char *name;
  341                 int namelen, retval;
  342 
  343                 down(&read_mutex);
  344                 de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+256);
  345                 up(&read_mutex);
  346                 name = (char *)(de+1);
  347 
  348                 /* Try to take advantage of sorted directories */
  349                 if (sorted && (dentry->d_name.name[0] < name[0]))
  350                         break;
  351 
  352                 namelen = de->namelen << 2;
  353                 offset += sizeof(*de) + namelen;
  354 
  355                 /* Quick check that the name is roughly the right length */
  356                 if (((dentry->d_name.len + 3) & ~3) != namelen)
  357                         continue;
  358 
  359                 for (;;) {
  360                         if (!namelen)
  361                                 return ERR_PTR(-EIO);
  362                         if (name[namelen-1])
  363                                 break;
  364                         namelen--;
  365                 }
  366                 if (namelen != dentry->d_name.len)
  367                         continue;
  368                 retval = memcmp(dentry->d_name.name, name, namelen);
  369                 if (retval > 0)
  370                         continue;
  371                 if (!retval) {
  372                         d_add(dentry, get_cramfs_inode(dir->i_sb, de));
  373                         return NULL;
  374                 }
  375                 /* else (retval < 0) */
  376                 if (sorted)
  377                         break;
  378         }
  379         d_add(dentry, NULL);
  380         return NULL;
  381 }
  382 
  383 static int cramfs_readpage(struct file *file, struct page * page)
  384 {
  385         struct inode *inode = page->mapping->host;
  386         u32 maxblock, bytes_filled;
  387         void *pgdata;
  388 
  389         maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  390         bytes_filled = 0;
  391         if (page->index < maxblock) {
  392                 struct super_block *sb = inode->i_sb;
  393                 u32 blkptr_offset = OFFSET(inode) + page->index*4;
  394                 u32 start_offset, compr_len;
  395 
  396                 start_offset = OFFSET(inode) + maxblock*4;
  397                 down(&read_mutex);
  398                 if (page->index)
  399                         start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
  400                 compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - start_offset);
  401                 up(&read_mutex);
  402                 pgdata = kmap(page);
  403                 if (compr_len == 0)
  404                         ; /* hole */
  405                 else {
  406                         down(&read_mutex);
  407                         bytes_filled = cramfs_uncompress_block(pgdata,
  408                                  PAGE_CACHE_SIZE,
  409                                  cramfs_read(sb, start_offset, compr_len),
  410                                  compr_len);
  411                         up(&read_mutex);
  412                 }
  413         } else
  414                 pgdata = kmap(page);
  415         memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
  416         kunmap(page);
  417         flush_dcache_page(page);
  418         SetPageUptodate(page);
  419         UnlockPage(page);
  420         return 0;
  421 }
  422 
  423 static struct address_space_operations cramfs_aops = {
  424         readpage: cramfs_readpage
  425 };
  426 
  427 /*
  428  * Our operations:
  429  */
  430 
  431 /*
  432  * A directory can only readdir
  433  */
  434 static struct file_operations cramfs_directory_operations = {
  435         read:           generic_read_dir,
  436         readdir:        cramfs_readdir,
  437 };
  438 
  439 static struct inode_operations cramfs_dir_inode_operations = {
  440         lookup:         cramfs_lookup,
  441 };
  442 
  443 static struct super_operations cramfs_ops = {
  444         statfs:         cramfs_statfs,
  445 };
  446 
  447 static DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super);
  448 
  449 static int __init init_cramfs_fs(void)
  450 {
  451         cramfs_uncompress_init();
  452         return register_filesystem(&cramfs_fs_type);
  453 }
  454 
  455 static void __exit exit_cramfs_fs(void)
  456 {
  457         cramfs_uncompress_exit();
  458         unregister_filesystem(&cramfs_fs_type);
  459 }
  460 
  461 module_init(init_cramfs_fs)
  462 module_exit(exit_cramfs_fs)
  463 MODULE_LICENSE("GPL");

Cache object: dd2952061aaac82ddd2678a32b43cf12


[ 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.