linux/fs/omfs/inode.c
<<
>>
Prefs
   1/*
   2 * Optimized MPEG FS - inode and super operations.
   3 * Copyright (C) 2006 Bob Copeland <me@bobcopeland.com>
   4 * Released under GPL v2.
   5 */
   6#include <linux/version.h>
   7#include <linux/module.h>
   8#include <linux/sched.h>
   9#include <linux/fs.h>
  10#include <linux/vfs.h>
  11#include <linux/parser.h>
  12#include <linux/buffer_head.h>
  13#include <linux/vmalloc.h>
  14#include <linux/crc-itu-t.h>
  15#include "omfs.h"
  16
  17MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>");
  18MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux");
  19MODULE_LICENSE("GPL");
  20
  21struct inode *omfs_new_inode(struct inode *dir, int mode)
  22{
  23        struct inode *inode;
  24        u64 new_block;
  25        int err;
  26        int len;
  27        struct omfs_sb_info *sbi = OMFS_SB(dir->i_sb);
  28
  29        inode = new_inode(dir->i_sb);
  30        if (!inode)
  31                return ERR_PTR(-ENOMEM);
  32
  33        err = omfs_allocate_range(dir->i_sb, sbi->s_mirrors, sbi->s_mirrors,
  34                        &new_block, &len);
  35        if (err)
  36                goto fail;
  37
  38        inode->i_ino = new_block;
  39        inode->i_mode = mode;
  40        inode->i_uid = current_fsuid();
  41        inode->i_gid = current_fsgid();
  42        inode->i_mapping->a_ops = &omfs_aops;
  43
  44        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  45        switch (mode & S_IFMT) {
  46        case S_IFDIR:
  47                inode->i_op = &omfs_dir_inops;
  48                inode->i_fop = &omfs_dir_operations;
  49                inode->i_size = sbi->s_sys_blocksize;
  50                inc_nlink(inode);
  51                break;
  52        case S_IFREG:
  53                inode->i_op = &omfs_file_inops;
  54                inode->i_fop = &omfs_file_operations;
  55                inode->i_size = 0;
  56                break;
  57        }
  58
  59        insert_inode_hash(inode);
  60        mark_inode_dirty(inode);
  61        return inode;
  62fail:
  63        make_bad_inode(inode);
  64        iput(inode);
  65        return ERR_PTR(err);
  66}
  67
  68/*
  69 * Update the header checksums for a dirty inode based on its contents.
  70 * Caller is expected to hold the buffer head underlying oi and mark it
  71 * dirty.
  72 */
  73static void omfs_update_checksums(struct omfs_inode *oi)
  74{
  75        int xor, i, ofs = 0, count;
  76        u16 crc = 0;
  77        unsigned char *ptr = (unsigned char *) oi;
  78
  79        count = be32_to_cpu(oi->i_head.h_body_size);
  80        ofs = sizeof(struct omfs_header);
  81
  82        crc = crc_itu_t(crc, ptr + ofs, count);
  83        oi->i_head.h_crc = cpu_to_be16(crc);
  84
  85        xor = ptr[0];
  86        for (i = 1; i < OMFS_XOR_COUNT; i++)
  87                xor ^= ptr[i];
  88
  89        oi->i_head.h_check_xor = xor;
  90}
  91
  92static int omfs_write_inode(struct inode *inode, int wait)
  93{
  94        struct omfs_inode *oi;
  95        struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb);
  96        struct buffer_head *bh, *bh2;
  97        unsigned int block;
  98        u64 ctime;
  99        int i;
 100        int ret = -EIO;
 101        int sync_failed = 0;
 102
 103        /* get current inode since we may have written sibling ptrs etc. */
 104        block = clus_to_blk(sbi, inode->i_ino);
 105        bh = sb_bread(inode->i_sb, block);
 106        if (!bh)
 107                goto out;
 108
 109        oi = (struct omfs_inode *) bh->b_data;
 110
 111        oi->i_head.h_self = cpu_to_be64(inode->i_ino);
 112        if (S_ISDIR(inode->i_mode))
 113                oi->i_type = OMFS_DIR;
 114        else if (S_ISREG(inode->i_mode))
 115                oi->i_type = OMFS_FILE;
 116        else {
 117                printk(KERN_WARNING "omfs: unknown file type: %d\n",
 118                        inode->i_mode);
 119                goto out_brelse;
 120        }
 121
 122        oi->i_head.h_body_size = cpu_to_be32(sbi->s_sys_blocksize -
 123                sizeof(struct omfs_header));
 124        oi->i_head.h_version = 1;
 125        oi->i_head.h_type = OMFS_INODE_NORMAL;
 126        oi->i_head.h_magic = OMFS_IMAGIC;
 127        oi->i_size = cpu_to_be64(inode->i_size);
 128
 129        ctime = inode->i_ctime.tv_sec * 1000LL +
 130                ((inode->i_ctime.tv_nsec + 999)/1000);
 131        oi->i_ctime = cpu_to_be64(ctime);
 132
 133        omfs_update_checksums(oi);
 134
 135        mark_buffer_dirty(bh);
 136        if (wait) {
 137                sync_dirty_buffer(bh);
 138                if (buffer_req(bh) && !buffer_uptodate(bh))
 139                        sync_failed = 1;
 140        }
 141
 142        /* if mirroring writes, copy to next fsblock */
 143        for (i = 1; i < sbi->s_mirrors; i++) {
 144                bh2 = sb_bread(inode->i_sb, block + i *
 145                        (sbi->s_blocksize / sbi->s_sys_blocksize));
 146                if (!bh2)
 147                        goto out_brelse;
 148
 149                memcpy(bh2->b_data, bh->b_data, bh->b_size);
 150                mark_buffer_dirty(bh2);
 151                if (wait) {
 152                        sync_dirty_buffer(bh2);
 153                        if (buffer_req(bh2) && !buffer_uptodate(bh2))
 154                                sync_failed = 1;
 155                }
 156                brelse(bh2);
 157        }
 158        ret = (sync_failed) ? -EIO : 0;
 159out_brelse:
 160        brelse(bh);
 161out:
 162        return ret;
 163}
 164
 165int omfs_sync_inode(struct inode *inode)
 166{
 167        return omfs_write_inode(inode, 1);
 168}
 169
 170/*
 171 * called when an entry is deleted, need to clear the bits in the
 172 * bitmaps.
 173 */
 174static void omfs_delete_inode(struct inode *inode)
 175{
 176        truncate_inode_pages(&inode->i_data, 0);
 177
 178        if (S_ISREG(inode->i_mode)) {
 179                inode->i_size = 0;
 180                omfs_shrink_inode(inode);
 181        }
 182
 183        omfs_clear_range(inode->i_sb, inode->i_ino, 2);
 184        clear_inode(inode);
 185}
 186
 187struct inode *omfs_iget(struct super_block *sb, ino_t ino)
 188{
 189        struct omfs_sb_info *sbi = OMFS_SB(sb);
 190        struct omfs_inode *oi;
 191        struct buffer_head *bh;
 192        unsigned int block;
 193        u64 ctime;
 194        unsigned long nsecs;
 195        struct inode *inode;
 196
 197        inode = iget_locked(sb, ino);
 198        if (!inode)
 199                return ERR_PTR(-ENOMEM);
 200        if (!(inode->i_state & I_NEW))
 201                return inode;
 202
 203        block = clus_to_blk(sbi, ino);
 204        bh = sb_bread(inode->i_sb, block);
 205        if (!bh)
 206                goto iget_failed;
 207
 208        oi = (struct omfs_inode *)bh->b_data;
 209
 210        /* check self */
 211        if (ino != be64_to_cpu(oi->i_head.h_self))
 212                goto fail_bh;
 213
 214        inode->i_uid = sbi->s_uid;
 215        inode->i_gid = sbi->s_gid;
 216
 217        ctime = be64_to_cpu(oi->i_ctime);
 218        nsecs = do_div(ctime, 1000) * 1000L;
 219
 220        inode->i_atime.tv_sec = ctime;
 221        inode->i_mtime.tv_sec = ctime;
 222        inode->i_ctime.tv_sec = ctime;
 223        inode->i_atime.tv_nsec = nsecs;
 224        inode->i_mtime.tv_nsec = nsecs;
 225        inode->i_ctime.tv_nsec = nsecs;
 226
 227        inode->i_mapping->a_ops = &omfs_aops;
 228
 229        switch (oi->i_type) {
 230        case OMFS_DIR:
 231                inode->i_mode = S_IFDIR | (S_IRWXUGO & ~sbi->s_dmask);
 232                inode->i_op = &omfs_dir_inops;
 233                inode->i_fop = &omfs_dir_operations;
 234                inode->i_size = sbi->s_sys_blocksize;
 235                inc_nlink(inode);
 236                break;
 237        case OMFS_FILE:
 238                inode->i_mode = S_IFREG | (S_IRWXUGO & ~sbi->s_fmask);
 239                inode->i_fop = &omfs_file_operations;
 240                inode->i_size = be64_to_cpu(oi->i_size);
 241                break;
 242        }
 243        brelse(bh);
 244        unlock_new_inode(inode);
 245        return inode;
 246fail_bh:
 247        brelse(bh);
 248iget_failed:
 249        iget_failed(inode);
 250        return ERR_PTR(-EIO);
 251}
 252
 253static void omfs_put_super(struct super_block *sb)
 254{
 255        struct omfs_sb_info *sbi = OMFS_SB(sb);
 256        kfree(sbi->s_imap);
 257        kfree(sbi);
 258        sb->s_fs_info = NULL;
 259}
 260
 261static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 262{
 263        struct super_block *s = dentry->d_sb;
 264        struct omfs_sb_info *sbi = OMFS_SB(s);
 265        u64 id = huge_encode_dev(s->s_bdev->bd_dev);
 266
 267        buf->f_type = OMFS_MAGIC;
 268        buf->f_bsize = sbi->s_blocksize;
 269        buf->f_blocks = sbi->s_num_blocks;
 270        buf->f_files = sbi->s_num_blocks;
 271        buf->f_namelen = OMFS_NAMELEN;
 272        buf->f_fsid.val[0] = (u32)id;
 273        buf->f_fsid.val[1] = (u32)(id >> 32);
 274
 275        buf->f_bfree = buf->f_bavail = buf->f_ffree =
 276                omfs_count_free(s);
 277
 278        return 0;
 279}
 280
 281static const struct super_operations omfs_sops = {
 282        .write_inode    = omfs_write_inode,
 283        .delete_inode   = omfs_delete_inode,
 284        .put_super      = omfs_put_super,
 285        .statfs         = omfs_statfs,
 286        .show_options   = generic_show_options,
 287};
 288
 289/*
 290 * For Rio Karma, there is an on-disk free bitmap whose location is
 291 * stored in the root block.  For ReplayTV, there is no such free bitmap
 292 * so we have to walk the tree.  Both inodes and file data are allocated
 293 * from the same map.  This array can be big (300k) so we allocate
 294 * in units of the blocksize.
 295 */
 296static int omfs_get_imap(struct super_block *sb)
 297{
 298        int bitmap_size;
 299        int array_size;
 300        int count;
 301        struct omfs_sb_info *sbi = OMFS_SB(sb);
 302        struct buffer_head *bh;
 303        unsigned long **ptr;
 304        sector_t block;
 305
 306        bitmap_size = DIV_ROUND_UP(sbi->s_num_blocks, 8);
 307        array_size = DIV_ROUND_UP(bitmap_size, sb->s_blocksize);
 308
 309        if (sbi->s_bitmap_ino == ~0ULL)
 310                goto out;
 311
 312        sbi->s_imap_size = array_size;
 313        sbi->s_imap = kzalloc(array_size * sizeof(unsigned long *), GFP_KERNEL);
 314        if (!sbi->s_imap)
 315                goto nomem;
 316
 317        block = clus_to_blk(sbi, sbi->s_bitmap_ino);
 318        ptr = sbi->s_imap;
 319        for (count = bitmap_size; count > 0; count -= sb->s_blocksize) {
 320                bh = sb_bread(sb, block++);
 321                if (!bh)
 322                        goto nomem_free;
 323                *ptr = kmalloc(sb->s_blocksize, GFP_KERNEL);
 324                if (!*ptr) {
 325                        brelse(bh);
 326                        goto nomem_free;
 327                }
 328                memcpy(*ptr, bh->b_data, sb->s_blocksize);
 329                if (count < sb->s_blocksize)
 330                        memset((void *)*ptr + count, 0xff,
 331                                sb->s_blocksize - count);
 332                brelse(bh);
 333                ptr++;
 334        }
 335out:
 336        return 0;
 337
 338nomem_free:
 339        for (count = 0; count < array_size; count++)
 340                kfree(sbi->s_imap[count]);
 341
 342        kfree(sbi->s_imap);
 343nomem:
 344        sbi->s_imap = NULL;
 345        sbi->s_imap_size = 0;
 346        return -ENOMEM;
 347}
 348
 349enum {
 350        Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask
 351};
 352
 353static const match_table_t tokens = {
 354        {Opt_uid, "uid=%u"},
 355        {Opt_gid, "gid=%u"},
 356        {Opt_umask, "umask=%o"},
 357        {Opt_dmask, "dmask=%o"},
 358        {Opt_fmask, "fmask=%o"},
 359};
 360
 361static int parse_options(char *options, struct omfs_sb_info *sbi)
 362{
 363        char *p;
 364        substring_t args[MAX_OPT_ARGS];
 365        int option;
 366
 367        if (!options)
 368                return 1;
 369
 370        while ((p = strsep(&options, ",")) != NULL) {
 371                int token;
 372                if (!*p)
 373                        continue;
 374
 375                token = match_token(p, tokens, args);
 376                switch (token) {
 377                case Opt_uid:
 378                        if (match_int(&args[0], &option))
 379                                return 0;
 380                        sbi->s_uid = option;
 381                        break;
 382                case Opt_gid:
 383                        if (match_int(&args[0], &option))
 384                                return 0;
 385                        sbi->s_gid = option;
 386                        break;
 387                case Opt_umask:
 388                        if (match_octal(&args[0], &option))
 389                                return 0;
 390                        sbi->s_fmask = sbi->s_dmask = option;
 391                        break;
 392                case Opt_dmask:
 393                        if (match_octal(&args[0], &option))
 394                                return 0;
 395                        sbi->s_dmask = option;
 396                        break;
 397                case Opt_fmask:
 398                        if (match_octal(&args[0], &option))
 399                                return 0;
 400                        sbi->s_fmask = option;
 401                        break;
 402                default:
 403                        return 0;
 404                }
 405        }
 406        return 1;
 407}
 408
 409static int omfs_fill_super(struct super_block *sb, void *data, int silent)
 410{
 411        struct buffer_head *bh, *bh2;
 412        struct omfs_super_block *omfs_sb;
 413        struct omfs_root_block *omfs_rb;
 414        struct omfs_sb_info *sbi;
 415        struct inode *root;
 416        sector_t start;
 417        int ret = -EINVAL;
 418
 419        save_mount_options(sb, (char *) data);
 420
 421        sbi = kzalloc(sizeof(struct omfs_sb_info), GFP_KERNEL);
 422        if (!sbi)
 423                return -ENOMEM;
 424
 425        sb->s_fs_info = sbi;
 426
 427        sbi->s_uid = current_uid();
 428        sbi->s_gid = current_gid();
 429        sbi->s_dmask = sbi->s_fmask = current_umask();
 430
 431        if (!parse_options((char *) data, sbi))
 432                goto end;
 433
 434        sb->s_maxbytes = 0xffffffff;
 435
 436        sb_set_blocksize(sb, 0x200);
 437
 438        bh = sb_bread(sb, 0);
 439        if (!bh)
 440                goto end;
 441
 442        omfs_sb = (struct omfs_super_block *)bh->b_data;
 443
 444        if (omfs_sb->s_magic != cpu_to_be32(OMFS_MAGIC)) {
 445                if (!silent)
 446                        printk(KERN_ERR "omfs: Invalid superblock (%x)\n",
 447                                   omfs_sb->s_magic);
 448                goto out_brelse_bh;
 449        }
 450        sb->s_magic = OMFS_MAGIC;
 451
 452        sbi->s_num_blocks = be64_to_cpu(omfs_sb->s_num_blocks);
 453        sbi->s_blocksize = be32_to_cpu(omfs_sb->s_blocksize);
 454        sbi->s_mirrors = be32_to_cpu(omfs_sb->s_mirrors);
 455        sbi->s_root_ino = be64_to_cpu(omfs_sb->s_root_block);
 456        sbi->s_sys_blocksize = be32_to_cpu(omfs_sb->s_sys_blocksize);
 457        mutex_init(&sbi->s_bitmap_lock);
 458
 459        if (sbi->s_sys_blocksize > PAGE_SIZE) {
 460                printk(KERN_ERR "omfs: sysblock size (%d) is out of range\n",
 461                        sbi->s_sys_blocksize);
 462                goto out_brelse_bh;
 463        }
 464
 465        if (sbi->s_blocksize < sbi->s_sys_blocksize ||
 466            sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) {
 467                printk(KERN_ERR "omfs: block size (%d) is out of range\n",
 468                        sbi->s_blocksize);
 469                goto out_brelse_bh;
 470        }
 471
 472        /*
 473         * Use sys_blocksize as the fs block since it is smaller than a
 474         * page while the fs blocksize can be larger.
 475         */
 476        sb_set_blocksize(sb, sbi->s_sys_blocksize);
 477
 478        /*
 479         * ...and the difference goes into a shift.  sys_blocksize is always
 480         * a power of two factor of blocksize.
 481         */
 482        sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) -
 483                get_bitmask_order(sbi->s_sys_blocksize);
 484
 485        start = clus_to_blk(sbi, be64_to_cpu(omfs_sb->s_root_block));
 486        bh2 = sb_bread(sb, start);
 487        if (!bh2)
 488                goto out_brelse_bh;
 489
 490        omfs_rb = (struct omfs_root_block *)bh2->b_data;
 491
 492        sbi->s_bitmap_ino = be64_to_cpu(omfs_rb->r_bitmap);
 493        sbi->s_clustersize = be32_to_cpu(omfs_rb->r_clustersize);
 494
 495        if (sbi->s_num_blocks != be64_to_cpu(omfs_rb->r_num_blocks)) {
 496                printk(KERN_ERR "omfs: block count discrepancy between "
 497                        "super and root blocks (%llx, %llx)\n",
 498                        (unsigned long long)sbi->s_num_blocks,
 499                        (unsigned long long)be64_to_cpu(omfs_rb->r_num_blocks));
 500                goto out_brelse_bh2;
 501        }
 502
 503        ret = omfs_get_imap(sb);
 504        if (ret)
 505                goto out_brelse_bh2;
 506
 507        sb->s_op = &omfs_sops;
 508
 509        root = omfs_iget(sb, be64_to_cpu(omfs_rb->r_root_dir));
 510        if (IS_ERR(root)) {
 511                ret = PTR_ERR(root);
 512                goto out_brelse_bh2;
 513        }
 514
 515        sb->s_root = d_alloc_root(root);
 516        if (!sb->s_root) {
 517                iput(root);
 518                goto out_brelse_bh2;
 519        }
 520        printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name);
 521
 522        ret = 0;
 523out_brelse_bh2:
 524        brelse(bh2);
 525out_brelse_bh:
 526        brelse(bh);
 527end:
 528        return ret;
 529}
 530
 531static int omfs_get_sb(struct file_system_type *fs_type,
 532                        int flags, const char *dev_name,
 533                        void *data, struct vfsmount *m)
 534{
 535        return get_sb_bdev(fs_type, flags, dev_name, data, omfs_fill_super, m);
 536}
 537
 538static struct file_system_type omfs_fs_type = {
 539        .owner = THIS_MODULE,
 540        .name = "omfs",
 541        .get_sb = omfs_get_sb,
 542        .kill_sb = kill_block_super,
 543        .fs_flags = FS_REQUIRES_DEV,
 544};
 545
 546static int __init init_omfs_fs(void)
 547{
 548        return register_filesystem(&omfs_fs_type);
 549}
 550
 551static void __exit exit_omfs_fs(void)
 552{
 553        unregister_filesystem(&omfs_fs_type);
 554}
 555
 556module_init(init_omfs_fs);
 557module_exit(exit_omfs_fs);
 558