linux/fs/cramfs/inode.c
<<
>>
Prefs
   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/blkdev.h>
  20#include <linux/cramfs_fs.h>
  21#include <linux/slab.h>
  22#include <linux/cramfs_fs_sb.h>
  23#include <linux/vfs.h>
  24#include <linux/mutex.h>
  25
  26#include <asm/uaccess.h>
  27
  28static const struct super_operations cramfs_ops;
  29static const struct inode_operations cramfs_dir_inode_operations;
  30static const struct file_operations cramfs_directory_operations;
  31static const struct address_space_operations cramfs_aops;
  32
  33static DEFINE_MUTEX(read_mutex);
  34
  35
  36/* These macros may change in future, to provide better st_ino semantics. */
  37#define OFFSET(x)       ((x)->i_ino)
  38
  39static unsigned long cramino(const struct cramfs_inode *cino, unsigned int offset)
  40{
  41        if (!cino->offset)
  42                return offset + 1;
  43        if (!cino->size)
  44                return offset + 1;
  45
  46        /*
  47         * The file mode test fixes buggy mkcramfs implementations where
  48         * cramfs_inode->offset is set to a non zero value for entries
  49         * which did not contain data, like devices node and fifos.
  50         */
  51        switch (cino->mode & S_IFMT) {
  52        case S_IFREG:
  53        case S_IFDIR:
  54        case S_IFLNK:
  55                return cino->offset << 2;
  56        default:
  57                break;
  58        }
  59        return offset + 1;
  60}
  61
  62static struct inode *get_cramfs_inode(struct super_block *sb,
  63        const struct cramfs_inode *cramfs_inode, unsigned int offset)
  64{
  65        struct inode *inode;
  66        static struct timespec zerotime;
  67
  68        inode = iget_locked(sb, cramino(cramfs_inode, offset));
  69        if (!inode)
  70                return ERR_PTR(-ENOMEM);
  71        if (!(inode->i_state & I_NEW))
  72                return inode;
  73
  74        switch (cramfs_inode->mode & S_IFMT) {
  75        case S_IFREG:
  76                inode->i_fop = &generic_ro_fops;
  77                inode->i_data.a_ops = &cramfs_aops;
  78                break;
  79        case S_IFDIR:
  80                inode->i_op = &cramfs_dir_inode_operations;
  81                inode->i_fop = &cramfs_directory_operations;
  82                break;
  83        case S_IFLNK:
  84                inode->i_op = &page_symlink_inode_operations;
  85                inode->i_data.a_ops = &cramfs_aops;
  86                break;
  87        default:
  88                init_special_inode(inode, cramfs_inode->mode,
  89                                old_decode_dev(cramfs_inode->size));
  90        }
  91
  92        inode->i_mode = cramfs_inode->mode;
  93        i_uid_write(inode, cramfs_inode->uid);
  94        i_gid_write(inode, cramfs_inode->gid);
  95
  96        /* if the lower 2 bits are zero, the inode contains data */
  97        if (!(inode->i_ino & 3)) {
  98                inode->i_size = cramfs_inode->size;
  99                inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
 100        }
 101
 102        /* Struct copy intentional */
 103        inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
 104        /* inode->i_nlink is left 1 - arguably wrong for directories,
 105           but it's the best we can do without reading the directory
 106           contents.  1 yields the right result in GNU find, even
 107           without -noleaf option. */
 108
 109        unlock_new_inode(inode);
 110
 111        return inode;
 112}
 113
 114/*
 115 * We have our own block cache: don't fill up the buffer cache
 116 * with the rom-image, because the way the filesystem is set
 117 * up the accesses should be fairly regular and cached in the
 118 * page cache and dentry tree anyway..
 119 *
 120 * This also acts as a way to guarantee contiguous areas of up to
 121 * BLKS_PER_BUF*PAGE_CACHE_SIZE, so that the caller doesn't need to
 122 * worry about end-of-buffer issues even when decompressing a full
 123 * page cache.
 124 */
 125#define READ_BUFFERS (2)
 126/* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */
 127#define NEXT_BUFFER(_ix) ((_ix) ^ 1)
 128
 129/*
 130 * BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed"
 131 * data that takes up more space than the original and with unlucky
 132 * alignment.
 133 */
 134#define BLKS_PER_BUF_SHIFT      (2)
 135#define BLKS_PER_BUF            (1 << BLKS_PER_BUF_SHIFT)
 136#define BUFFER_SIZE             (BLKS_PER_BUF*PAGE_CACHE_SIZE)
 137
 138static unsigned char read_buffers[READ_BUFFERS][BUFFER_SIZE];
 139static unsigned buffer_blocknr[READ_BUFFERS];
 140static struct super_block * buffer_dev[READ_BUFFERS];
 141static int next_buffer;
 142
 143/*
 144 * Returns a pointer to a buffer containing at least LEN bytes of
 145 * filesystem starting at byte offset OFFSET into the filesystem.
 146 */
 147static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
 148{
 149        struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
 150        struct page *pages[BLKS_PER_BUF];
 151        unsigned i, blocknr, buffer;
 152        unsigned long devsize;
 153        char *data;
 154
 155        if (!len)
 156                return NULL;
 157        blocknr = offset >> PAGE_CACHE_SHIFT;
 158        offset &= PAGE_CACHE_SIZE - 1;
 159
 160        /* Check if an existing buffer already has the data.. */
 161        for (i = 0; i < READ_BUFFERS; i++) {
 162                unsigned int blk_offset;
 163
 164                if (buffer_dev[i] != sb)
 165                        continue;
 166                if (blocknr < buffer_blocknr[i])
 167                        continue;
 168                blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;
 169                blk_offset += offset;
 170                if (blk_offset + len > BUFFER_SIZE)
 171                        continue;
 172                return read_buffers[i] + blk_offset;
 173        }
 174
 175        devsize = mapping->host->i_size >> PAGE_CACHE_SHIFT;
 176
 177        /* Ok, read in BLKS_PER_BUF pages completely first. */
 178        for (i = 0; i < BLKS_PER_BUF; i++) {
 179                struct page *page = NULL;
 180
 181                if (blocknr + i < devsize) {
 182                        page = read_mapping_page_async(mapping, blocknr + i,
 183                                                                        NULL);
 184                        /* synchronous error? */
 185                        if (IS_ERR(page))
 186                                page = NULL;
 187                }
 188                pages[i] = page;
 189        }
 190
 191        for (i = 0; i < BLKS_PER_BUF; i++) {
 192                struct page *page = pages[i];
 193                if (page) {
 194                        wait_on_page_locked(page);
 195                        if (!PageUptodate(page)) {
 196                                /* asynchronous error */
 197                                page_cache_release(page);
 198                                pages[i] = NULL;
 199                        }
 200                }
 201        }
 202
 203        buffer = next_buffer;
 204        next_buffer = NEXT_BUFFER(buffer);
 205        buffer_blocknr[buffer] = blocknr;
 206        buffer_dev[buffer] = sb;
 207
 208        data = read_buffers[buffer];
 209        for (i = 0; i < BLKS_PER_BUF; i++) {
 210                struct page *page = pages[i];
 211                if (page) {
 212                        memcpy(data, kmap(page), PAGE_CACHE_SIZE);
 213                        kunmap(page);
 214                        page_cache_release(page);
 215                } else
 216                        memset(data, 0, PAGE_CACHE_SIZE);
 217                data += PAGE_CACHE_SIZE;
 218        }
 219        return read_buffers[buffer] + offset;
 220}
 221
 222static void cramfs_put_super(struct super_block *sb)
 223{
 224        kfree(sb->s_fs_info);
 225        sb->s_fs_info = NULL;
 226}
 227
 228static int cramfs_remount(struct super_block *sb, int *flags, char *data)
 229{
 230        *flags |= MS_RDONLY;
 231        return 0;
 232}
 233
 234static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
 235{
 236        int i;
 237        struct cramfs_super super;
 238        unsigned long root_offset;
 239        struct cramfs_sb_info *sbi;
 240        struct inode *root;
 241
 242        sb->s_flags |= MS_RDONLY;
 243
 244        sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
 245        if (!sbi)
 246                return -ENOMEM;
 247        sb->s_fs_info = sbi;
 248
 249        /* Invalidate the read buffers on mount: think disk change.. */
 250        mutex_lock(&read_mutex);
 251        for (i = 0; i < READ_BUFFERS; i++)
 252                buffer_blocknr[i] = -1;
 253
 254        /* Read the first block and get the superblock from it */
 255        memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
 256        mutex_unlock(&read_mutex);
 257
 258        /* Do sanity checks on the superblock */
 259        if (super.magic != CRAMFS_MAGIC) {
 260                /* check for wrong endianness */
 261                if (super.magic == CRAMFS_MAGIC_WEND) {
 262                        if (!silent)
 263                                printk(KERN_ERR "cramfs: wrong endianness\n");
 264                        goto out;
 265                }
 266
 267                /* check at 512 byte offset */
 268                mutex_lock(&read_mutex);
 269                memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));
 270                mutex_unlock(&read_mutex);
 271                if (super.magic != CRAMFS_MAGIC) {
 272                        if (super.magic == CRAMFS_MAGIC_WEND && !silent)
 273                                printk(KERN_ERR "cramfs: wrong endianness\n");
 274                        else if (!silent)
 275                                printk(KERN_ERR "cramfs: wrong magic\n");
 276                        goto out;
 277                }
 278        }
 279
 280        /* get feature flags first */
 281        if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
 282                printk(KERN_ERR "cramfs: unsupported filesystem features\n");
 283                goto out;
 284        }
 285
 286        /* Check that the root inode is in a sane state */
 287        if (!S_ISDIR(super.root.mode)) {
 288                printk(KERN_ERR "cramfs: root is not a directory\n");
 289                goto out;
 290        }
 291        /* correct strange, hard-coded permissions of mkcramfs */
 292        super.root.mode |= (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
 293
 294        root_offset = super.root.offset << 2;
 295        if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {
 296                sbi->size=super.size;
 297                sbi->blocks=super.fsid.blocks;
 298                sbi->files=super.fsid.files;
 299        } else {
 300                sbi->size=1<<28;
 301                sbi->blocks=0;
 302                sbi->files=0;
 303        }
 304        sbi->magic=super.magic;
 305        sbi->flags=super.flags;
 306        if (root_offset == 0)
 307                printk(KERN_INFO "cramfs: empty filesystem");
 308        else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
 309                 ((root_offset != sizeof(struct cramfs_super)) &&
 310                  (root_offset != 512 + sizeof(struct cramfs_super))))
 311        {
 312                printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset);
 313                goto out;
 314        }
 315
 316        /* Set it all up.. */
 317        sb->s_op = &cramfs_ops;
 318        root = get_cramfs_inode(sb, &super.root, 0);
 319        if (IS_ERR(root))
 320                goto out;
 321        sb->s_root = d_make_root(root);
 322        if (!sb->s_root)
 323                goto out;
 324        return 0;
 325out:
 326        kfree(sbi);
 327        sb->s_fs_info = NULL;
 328        return -EINVAL;
 329}
 330
 331static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 332{
 333        struct super_block *sb = dentry->d_sb;
 334        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 335
 336        buf->f_type = CRAMFS_MAGIC;
 337        buf->f_bsize = PAGE_CACHE_SIZE;
 338        buf->f_blocks = CRAMFS_SB(sb)->blocks;
 339        buf->f_bfree = 0;
 340        buf->f_bavail = 0;
 341        buf->f_files = CRAMFS_SB(sb)->files;
 342        buf->f_ffree = 0;
 343        buf->f_fsid.val[0] = (u32)id;
 344        buf->f_fsid.val[1] = (u32)(id >> 32);
 345        buf->f_namelen = CRAMFS_MAXPATHLEN;
 346        return 0;
 347}
 348
 349/*
 350 * Read a cramfs directory entry.
 351 */
 352static int cramfs_readdir(struct file *file, struct dir_context *ctx)
 353{
 354        struct inode *inode = file_inode(file);
 355        struct super_block *sb = inode->i_sb;
 356        char *buf;
 357        unsigned int offset;
 358
 359        /* Offset within the thing. */
 360        if (ctx->pos >= inode->i_size)
 361                return 0;
 362        offset = ctx->pos;
 363        /* Directory entries are always 4-byte aligned */
 364        if (offset & 3)
 365                return -EINVAL;
 366
 367        buf = kmalloc(CRAMFS_MAXPATHLEN, GFP_KERNEL);
 368        if (!buf)
 369                return -ENOMEM;
 370
 371        while (offset < inode->i_size) {
 372                struct cramfs_inode *de;
 373                unsigned long nextoffset;
 374                char *name;
 375                ino_t ino;
 376                umode_t mode;
 377                int namelen;
 378
 379                mutex_lock(&read_mutex);
 380                de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);
 381                name = (char *)(de+1);
 382
 383                /*
 384                 * Namelengths on disk are shifted by two
 385                 * and the name padded out to 4-byte boundaries
 386                 * with zeroes.
 387                 */
 388                namelen = de->namelen << 2;
 389                memcpy(buf, name, namelen);
 390                ino = cramino(de, OFFSET(inode) + offset);
 391                mode = de->mode;
 392                mutex_unlock(&read_mutex);
 393                nextoffset = offset + sizeof(*de) + namelen;
 394                for (;;) {
 395                        if (!namelen) {
 396                                kfree(buf);
 397                                return -EIO;
 398                        }
 399                        if (buf[namelen-1])
 400                                break;
 401                        namelen--;
 402                }
 403                if (!dir_emit(ctx, buf, namelen, ino, mode >> 12))
 404                        break;
 405
 406                ctx->pos = offset = nextoffset;
 407        }
 408        kfree(buf);
 409        return 0;
 410}
 411
 412/*
 413 * Lookup and fill in the inode data..
 414 */
 415static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 416{
 417        unsigned int offset = 0;
 418        struct inode *inode = NULL;
 419        int sorted;
 420
 421        mutex_lock(&read_mutex);
 422        sorted = CRAMFS_SB(dir->i_sb)->flags & CRAMFS_FLAG_SORTED_DIRS;
 423        while (offset < dir->i_size) {
 424                struct cramfs_inode *de;
 425                char *name;
 426                int namelen, retval;
 427                int dir_off = OFFSET(dir) + offset;
 428
 429                de = cramfs_read(dir->i_sb, dir_off, sizeof(*de)+CRAMFS_MAXPATHLEN);
 430                name = (char *)(de+1);
 431
 432                /* Try to take advantage of sorted directories */
 433                if (sorted && (dentry->d_name.name[0] < name[0]))
 434                        break;
 435
 436                namelen = de->namelen << 2;
 437                offset += sizeof(*de) + namelen;
 438
 439                /* Quick check that the name is roughly the right length */
 440                if (((dentry->d_name.len + 3) & ~3) != namelen)
 441                        continue;
 442
 443                for (;;) {
 444                        if (!namelen) {
 445                                inode = ERR_PTR(-EIO);
 446                                goto out;
 447                        }
 448                        if (name[namelen-1])
 449                                break;
 450                        namelen--;
 451                }
 452                if (namelen != dentry->d_name.len)
 453                        continue;
 454                retval = memcmp(dentry->d_name.name, name, namelen);
 455                if (retval > 0)
 456                        continue;
 457                if (!retval) {
 458                        inode = get_cramfs_inode(dir->i_sb, de, dir_off);
 459                        break;
 460                }
 461                /* else (retval < 0) */
 462                if (sorted)
 463                        break;
 464        }
 465out:
 466        mutex_unlock(&read_mutex);
 467        if (IS_ERR(inode))
 468                return ERR_CAST(inode);
 469        d_add(dentry, inode);
 470        return NULL;
 471}
 472
 473static int cramfs_readpage(struct file *file, struct page * page)
 474{
 475        struct inode *inode = page->mapping->host;
 476        u32 maxblock;
 477        int bytes_filled;
 478        void *pgdata;
 479
 480        maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 481        bytes_filled = 0;
 482        pgdata = kmap(page);
 483
 484        if (page->index < maxblock) {
 485                struct super_block *sb = inode->i_sb;
 486                u32 blkptr_offset = OFFSET(inode) + page->index*4;
 487                u32 start_offset, compr_len;
 488
 489                start_offset = OFFSET(inode) + maxblock*4;
 490                mutex_lock(&read_mutex);
 491                if (page->index)
 492                        start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4,
 493                                4);
 494                compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) -
 495                        start_offset);
 496                mutex_unlock(&read_mutex);
 497
 498                if (compr_len == 0)
 499                        ; /* hole */
 500                else if (unlikely(compr_len > (PAGE_CACHE_SIZE << 1))) {
 501                        pr_err("cramfs: bad compressed blocksize %u\n",
 502                                compr_len);
 503                        goto err;
 504                } else {
 505                        mutex_lock(&read_mutex);
 506                        bytes_filled = cramfs_uncompress_block(pgdata,
 507                                 PAGE_CACHE_SIZE,
 508                                 cramfs_read(sb, start_offset, compr_len),
 509                                 compr_len);
 510                        mutex_unlock(&read_mutex);
 511                        if (unlikely(bytes_filled < 0))
 512                                goto err;
 513                }
 514        }
 515
 516        memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
 517        flush_dcache_page(page);
 518        kunmap(page);
 519        SetPageUptodate(page);
 520        unlock_page(page);
 521        return 0;
 522
 523err:
 524        kunmap(page);
 525        ClearPageUptodate(page);
 526        SetPageError(page);
 527        unlock_page(page);
 528        return 0;
 529}
 530
 531static const struct address_space_operations cramfs_aops = {
 532        .readpage = cramfs_readpage
 533};
 534
 535/*
 536 * Our operations:
 537 */
 538
 539/*
 540 * A directory can only readdir
 541 */
 542static const struct file_operations cramfs_directory_operations = {
 543        .llseek         = generic_file_llseek,
 544        .read           = generic_read_dir,
 545        .iterate        = cramfs_readdir,
 546};
 547
 548static const struct inode_operations cramfs_dir_inode_operations = {
 549        .lookup         = cramfs_lookup,
 550};
 551
 552static const struct super_operations cramfs_ops = {
 553        .put_super      = cramfs_put_super,
 554        .remount_fs     = cramfs_remount,
 555        .statfs         = cramfs_statfs,
 556};
 557
 558static struct dentry *cramfs_mount(struct file_system_type *fs_type,
 559        int flags, const char *dev_name, void *data)
 560{
 561        return mount_bdev(fs_type, flags, dev_name, data, cramfs_fill_super);
 562}
 563
 564static struct file_system_type cramfs_fs_type = {
 565        .owner          = THIS_MODULE,
 566        .name           = "cramfs",
 567        .mount          = cramfs_mount,
 568        .kill_sb        = kill_block_super,
 569        .fs_flags       = FS_REQUIRES_DEV,
 570};
 571MODULE_ALIAS_FS("cramfs");
 572
 573static int __init init_cramfs_fs(void)
 574{
 575        int rv;
 576
 577        rv = cramfs_uncompress_init();
 578        if (rv < 0)
 579                return rv;
 580        rv = register_filesystem(&cramfs_fs_type);
 581        if (rv < 0)
 582                cramfs_uncompress_exit();
 583        return rv;
 584}
 585
 586static void __exit exit_cramfs_fs(void)
 587{
 588        cramfs_uncompress_exit();
 589        unregister_filesystem(&cramfs_fs_type);
 590}
 591
 592module_init(init_cramfs_fs)
 593module_exit(exit_cramfs_fs)
 594MODULE_LICENSE("GPL");
 595
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.