linux/fs/hfsplus/super.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/hfsplus/super.c
   3 *
   4 * Copyright (C) 2001
   5 * Brad Boyer (flar@allandria.com)
   6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
   7 *
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/init.h>
  12#include <linux/pagemap.h>
  13#include <linux/blkdev.h>
  14#include <linux/fs.h>
  15#include <linux/slab.h>
  16#include <linux/vfs.h>
  17#include <linux/nls.h>
  18
  19static struct inode *hfsplus_alloc_inode(struct super_block *sb);
  20static void hfsplus_destroy_inode(struct inode *inode);
  21
  22#include "hfsplus_fs.h"
  23#include "xattr.h"
  24
  25static int hfsplus_system_read_inode(struct inode *inode)
  26{
  27        struct hfsplus_vh *vhdr = HFSPLUS_SB(inode->i_sb)->s_vhdr;
  28
  29        switch (inode->i_ino) {
  30        case HFSPLUS_EXT_CNID:
  31                hfsplus_inode_read_fork(inode, &vhdr->ext_file);
  32                inode->i_mapping->a_ops = &hfsplus_btree_aops;
  33                break;
  34        case HFSPLUS_CAT_CNID:
  35                hfsplus_inode_read_fork(inode, &vhdr->cat_file);
  36                inode->i_mapping->a_ops = &hfsplus_btree_aops;
  37                break;
  38        case HFSPLUS_ALLOC_CNID:
  39                hfsplus_inode_read_fork(inode, &vhdr->alloc_file);
  40                inode->i_mapping->a_ops = &hfsplus_aops;
  41                break;
  42        case HFSPLUS_START_CNID:
  43                hfsplus_inode_read_fork(inode, &vhdr->start_file);
  44                break;
  45        case HFSPLUS_ATTR_CNID:
  46                hfsplus_inode_read_fork(inode, &vhdr->attr_file);
  47                inode->i_mapping->a_ops = &hfsplus_btree_aops;
  48                break;
  49        default:
  50                return -EIO;
  51        }
  52
  53        return 0;
  54}
  55
  56struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
  57{
  58        struct hfs_find_data fd;
  59        struct inode *inode;
  60        int err;
  61
  62        inode = iget_locked(sb, ino);
  63        if (!inode)
  64                return ERR_PTR(-ENOMEM);
  65        if (!(inode->i_state & I_NEW))
  66                return inode;
  67
  68        INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
  69        mutex_init(&HFSPLUS_I(inode)->extents_lock);
  70        HFSPLUS_I(inode)->flags = 0;
  71        HFSPLUS_I(inode)->extent_state = 0;
  72        HFSPLUS_I(inode)->rsrc_inode = NULL;
  73        atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
  74
  75        if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
  76            inode->i_ino == HFSPLUS_ROOT_CNID) {
  77                err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
  78                if (!err) {
  79                        err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
  80                        if (!err)
  81                                err = hfsplus_cat_read_inode(inode, &fd);
  82                        hfs_find_exit(&fd);
  83                }
  84        } else {
  85                err = hfsplus_system_read_inode(inode);
  86        }
  87
  88        if (err) {
  89                iget_failed(inode);
  90                return ERR_PTR(err);
  91        }
  92
  93        unlock_new_inode(inode);
  94        return inode;
  95}
  96
  97static int hfsplus_system_write_inode(struct inode *inode)
  98{
  99        struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
 100        struct hfsplus_vh *vhdr = sbi->s_vhdr;
 101        struct hfsplus_fork_raw *fork;
 102        struct hfs_btree *tree = NULL;
 103
 104        switch (inode->i_ino) {
 105        case HFSPLUS_EXT_CNID:
 106                fork = &vhdr->ext_file;
 107                tree = sbi->ext_tree;
 108                break;
 109        case HFSPLUS_CAT_CNID:
 110                fork = &vhdr->cat_file;
 111                tree = sbi->cat_tree;
 112                break;
 113        case HFSPLUS_ALLOC_CNID:
 114                fork = &vhdr->alloc_file;
 115                break;
 116        case HFSPLUS_START_CNID:
 117                fork = &vhdr->start_file;
 118                break;
 119        case HFSPLUS_ATTR_CNID:
 120                fork = &vhdr->attr_file;
 121                tree = sbi->attr_tree;
 122                break;
 123        default:
 124                return -EIO;
 125        }
 126
 127        if (fork->total_size != cpu_to_be64(inode->i_size)) {
 128                set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
 129                hfsplus_mark_mdb_dirty(inode->i_sb);
 130        }
 131        hfsplus_inode_write_fork(inode, fork);
 132        if (tree) {
 133                int err = hfs_btree_write(tree);
 134                if (err) {
 135                        pr_err("b-tree write err: %d, ino %lu\n",
 136                                        err, inode->i_ino);
 137                        return err;
 138                }
 139        }
 140        return 0;
 141}
 142
 143static int hfsplus_write_inode(struct inode *inode,
 144                struct writeback_control *wbc)
 145{
 146        int err;
 147
 148        hfs_dbg(INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
 149
 150        err = hfsplus_ext_write_extent(inode);
 151        if (err)
 152                return err;
 153
 154        if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
 155            inode->i_ino == HFSPLUS_ROOT_CNID)
 156                return hfsplus_cat_write_inode(inode);
 157        else
 158                return hfsplus_system_write_inode(inode);
 159}
 160
 161static void hfsplus_evict_inode(struct inode *inode)
 162{
 163        hfs_dbg(INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino);
 164        truncate_inode_pages(&inode->i_data, 0);
 165        clear_inode(inode);
 166        if (HFSPLUS_IS_RSRC(inode)) {
 167                HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
 168                iput(HFSPLUS_I(inode)->rsrc_inode);
 169        }
 170}
 171
 172static int hfsplus_sync_fs(struct super_block *sb, int wait)
 173{
 174        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
 175        struct hfsplus_vh *vhdr = sbi->s_vhdr;
 176        int write_backup = 0;
 177        int error, error2;
 178
 179        if (!wait)
 180                return 0;
 181
 182        hfs_dbg(SUPER, "hfsplus_sync_fs\n");
 183
 184        /*
 185         * Explicitly write out the special metadata inodes.
 186         *
 187         * While these special inodes are marked as hashed and written
 188         * out peridocically by the flusher threads we redirty them
 189         * during writeout of normal inodes, and thus the life lock
 190         * prevents us from getting the latest state to disk.
 191         */
 192        error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
 193        error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
 194        if (!error)
 195                error = error2;
 196        if (sbi->attr_tree) {
 197                error2 =
 198                    filemap_write_and_wait(sbi->attr_tree->inode->i_mapping);
 199                if (!error)
 200                        error = error2;
 201        }
 202        error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
 203        if (!error)
 204                error = error2;
 205
 206        mutex_lock(&sbi->vh_mutex);
 207        mutex_lock(&sbi->alloc_mutex);
 208        vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
 209        vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
 210        vhdr->folder_count = cpu_to_be32(sbi->folder_count);
 211        vhdr->file_count = cpu_to_be32(sbi->file_count);
 212
 213        if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
 214                memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
 215                write_backup = 1;
 216        }
 217
 218        error2 = hfsplus_submit_bio(sb,
 219                                   sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
 220                                   sbi->s_vhdr_buf, NULL, WRITE_SYNC);
 221        if (!error)
 222                error = error2;
 223        if (!write_backup)
 224                goto out;
 225
 226        error2 = hfsplus_submit_bio(sb,
 227                                  sbi->part_start + sbi->sect_count - 2,
 228                                  sbi->s_backup_vhdr_buf, NULL, WRITE_SYNC);
 229        if (!error)
 230                error2 = error;
 231out:
 232        mutex_unlock(&sbi->alloc_mutex);
 233        mutex_unlock(&sbi->vh_mutex);
 234
 235        if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
 236                blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL);
 237
 238        return error;
 239}
 240
 241static void delayed_sync_fs(struct work_struct *work)
 242{
 243        int err;
 244        struct hfsplus_sb_info *sbi;
 245
 246        sbi = container_of(work, struct hfsplus_sb_info, sync_work.work);
 247
 248        spin_lock(&sbi->work_lock);
 249        sbi->work_queued = 0;
 250        spin_unlock(&sbi->work_lock);
 251
 252        err = hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
 253        if (err)
 254                pr_err("delayed sync fs err %d\n", err);
 255}
 256
 257void hfsplus_mark_mdb_dirty(struct super_block *sb)
 258{
 259        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
 260        unsigned long delay;
 261
 262        if (sb->s_flags & MS_RDONLY)
 263                return;
 264
 265        spin_lock(&sbi->work_lock);
 266        if (!sbi->work_queued) {
 267                delay = msecs_to_jiffies(dirty_writeback_interval * 10);
 268                queue_delayed_work(system_long_wq, &sbi->sync_work, delay);
 269                sbi->work_queued = 1;
 270        }
 271        spin_unlock(&sbi->work_lock);
 272}
 273
 274static void hfsplus_put_super(struct super_block *sb)
 275{
 276        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
 277
 278        hfs_dbg(SUPER, "hfsplus_put_super\n");
 279
 280        cancel_delayed_work_sync(&sbi->sync_work);
 281
 282        if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
 283                struct hfsplus_vh *vhdr = sbi->s_vhdr;
 284
 285                vhdr->modify_date = hfsp_now2mt();
 286                vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
 287                vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
 288
 289                hfsplus_sync_fs(sb, 1);
 290        }
 291
 292        hfs_btree_close(sbi->attr_tree);
 293        hfs_btree_close(sbi->cat_tree);
 294        hfs_btree_close(sbi->ext_tree);
 295        iput(sbi->alloc_file);
 296        iput(sbi->hidden_dir);
 297        kfree(sbi->s_vhdr_buf);
 298        kfree(sbi->s_backup_vhdr_buf);
 299        unload_nls(sbi->nls);
 300        kfree(sb->s_fs_info);
 301        sb->s_fs_info = NULL;
 302}
 303
 304static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
 305{
 306        struct super_block *sb = dentry->d_sb;
 307        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
 308        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 309
 310        buf->f_type = HFSPLUS_SUPER_MAGIC;
 311        buf->f_bsize = sb->s_blocksize;
 312        buf->f_blocks = sbi->total_blocks << sbi->fs_shift;
 313        buf->f_bfree = sbi->free_blocks << sbi->fs_shift;
 314        buf->f_bavail = buf->f_bfree;
 315        buf->f_files = 0xFFFFFFFF;
 316        buf->f_ffree = 0xFFFFFFFF - sbi->next_cnid;
 317        buf->f_fsid.val[0] = (u32)id;
 318        buf->f_fsid.val[1] = (u32)(id >> 32);
 319        buf->f_namelen = HFSPLUS_MAX_STRLEN;
 320
 321        return 0;
 322}
 323
 324static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
 325{
 326        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
 327                return 0;
 328        if (!(*flags & MS_RDONLY)) {
 329                struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
 330                int force = 0;
 331
 332                if (!hfsplus_parse_options_remount(data, &force))
 333                        return -EINVAL;
 334
 335                if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
 336                        pr_warn("filesystem was not cleanly unmounted, running fsck.hfsplus is recommended.  leaving read-only.\n");
 337                        sb->s_flags |= MS_RDONLY;
 338                        *flags |= MS_RDONLY;
 339                } else if (force) {
 340                        /* nothing */
 341                } else if (vhdr->attributes &
 342                                cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
 343                        pr_warn("filesystem is marked locked, leaving read-only.\n");
 344                        sb->s_flags |= MS_RDONLY;
 345                        *flags |= MS_RDONLY;
 346                } else if (vhdr->attributes &
 347                                cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
 348                        pr_warn("filesystem is marked journaled, leaving read-only.\n");
 349                        sb->s_flags |= MS_RDONLY;
 350                        *flags |= MS_RDONLY;
 351                }
 352        }
 353        return 0;
 354}
 355
 356static const struct super_operations hfsplus_sops = {
 357        .alloc_inode    = hfsplus_alloc_inode,
 358        .destroy_inode  = hfsplus_destroy_inode,
 359        .write_inode    = hfsplus_write_inode,
 360        .evict_inode    = hfsplus_evict_inode,
 361        .put_super      = hfsplus_put_super,
 362        .sync_fs        = hfsplus_sync_fs,
 363        .statfs         = hfsplus_statfs,
 364        .remount_fs     = hfsplus_remount,
 365        .show_options   = hfsplus_show_options,
 366};
 367
 368static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
 369{
 370        struct hfsplus_vh *vhdr;
 371        struct hfsplus_sb_info *sbi;
 372        hfsplus_cat_entry entry;
 373        struct hfs_find_data fd;
 374        struct inode *root, *inode;
 375        struct qstr str;
 376        struct nls_table *nls = NULL;
 377        u64 last_fs_block, last_fs_page;
 378        int err;
 379
 380        err = -ENOMEM;
 381        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
 382        if (!sbi)
 383                goto out;
 384
 385        sb->s_fs_info = sbi;
 386        mutex_init(&sbi->alloc_mutex);
 387        mutex_init(&sbi->vh_mutex);
 388        spin_lock_init(&sbi->work_lock);
 389        INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);
 390        hfsplus_fill_defaults(sbi);
 391
 392        err = -EINVAL;
 393        if (!hfsplus_parse_options(data, sbi)) {
 394                pr_err("unable to parse mount options\n");
 395                goto out_unload_nls;
 396        }
 397
 398        /* temporarily use utf8 to correctly find the hidden dir below */
 399        nls = sbi->nls;
 400        sbi->nls = load_nls("utf8");
 401        if (!sbi->nls) {
 402                pr_err("unable to load nls for utf8\n");
 403                goto out_unload_nls;
 404        }
 405
 406        /* Grab the volume header */
 407        if (hfsplus_read_wrapper(sb)) {
 408                if (!silent)
 409                        pr_warn("unable to find HFS+ superblock\n");
 410                goto out_unload_nls;
 411        }
 412        vhdr = sbi->s_vhdr;
 413
 414        /* Copy parts of the volume header into the superblock */
 415        sb->s_magic = HFSPLUS_VOLHEAD_SIG;
 416        if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION ||
 417            be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) {
 418                pr_err("wrong filesystem version\n");
 419                goto out_free_vhdr;
 420        }
 421        sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
 422        sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
 423        sbi->next_cnid = be32_to_cpu(vhdr->next_cnid);
 424        sbi->file_count = be32_to_cpu(vhdr->file_count);
 425        sbi->folder_count = be32_to_cpu(vhdr->folder_count);
 426        sbi->data_clump_blocks =
 427                be32_to_cpu(vhdr->data_clump_sz) >> sbi->alloc_blksz_shift;
 428        if (!sbi->data_clump_blocks)
 429                sbi->data_clump_blocks = 1;
 430        sbi->rsrc_clump_blocks =
 431                be32_to_cpu(vhdr->rsrc_clump_sz) >> sbi->alloc_blksz_shift;
 432        if (!sbi->rsrc_clump_blocks)
 433                sbi->rsrc_clump_blocks = 1;
 434
 435        err = -EFBIG;
 436        last_fs_block = sbi->total_blocks - 1;
 437        last_fs_page = (last_fs_block << sbi->alloc_blksz_shift) >>
 438                        PAGE_CACHE_SHIFT;
 439
 440        if ((last_fs_block > (sector_t)(~0ULL) >> (sbi->alloc_blksz_shift - 9)) ||
 441            (last_fs_page > (pgoff_t)(~0ULL))) {
 442                pr_err("filesystem size too large\n");
 443                goto out_free_vhdr;
 444        }
 445
 446        /* Set up operations so we can load metadata */
 447        sb->s_op = &hfsplus_sops;
 448        sb->s_maxbytes = MAX_LFS_FILESIZE;
 449
 450        if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
 451                pr_warn("Filesystem was not cleanly unmounted, running fsck.hfsplus is recommended.  mounting read-only.\n");
 452                sb->s_flags |= MS_RDONLY;
 453        } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
 454                /* nothing */
 455        } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
 456                pr_warn("Filesystem is marked locked, mounting read-only.\n");
 457                sb->s_flags |= MS_RDONLY;
 458        } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
 459                        !(sb->s_flags & MS_RDONLY)) {
 460                pr_warn("write access to a journaled filesystem is not supported, use the force option at your own risk, mounting read-only.\n");
 461                sb->s_flags |= MS_RDONLY;
 462        }
 463
 464        err = -EINVAL;
 465
 466        /* Load metadata objects (B*Trees) */
 467        sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
 468        if (!sbi->ext_tree) {
 469                pr_err("failed to load extents file\n");
 470                goto out_free_vhdr;
 471        }
 472        sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
 473        if (!sbi->cat_tree) {
 474                pr_err("failed to load catalog file\n");
 475                goto out_close_ext_tree;
 476        }
 477        if (vhdr->attr_file.total_blocks != 0) {
 478                sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
 479                if (!sbi->attr_tree) {
 480                        pr_err("failed to load attributes file\n");
 481                        goto out_close_cat_tree;
 482                }
 483        }
 484        sb->s_xattr = hfsplus_xattr_handlers;
 485
 486        inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
 487        if (IS_ERR(inode)) {
 488                pr_err("failed to load allocation file\n");
 489                err = PTR_ERR(inode);
 490                goto out_close_attr_tree;
 491        }
 492        sbi->alloc_file = inode;
 493
 494        /* Load the root directory */
 495        root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
 496        if (IS_ERR(root)) {
 497                pr_err("failed to load root directory\n");
 498                err = PTR_ERR(root);
 499                goto out_put_alloc_file;
 500        }
 501
 502        sb->s_d_op = &hfsplus_dentry_operations;
 503        sb->s_root = d_make_root(root);
 504        if (!sb->s_root) {
 505                err = -ENOMEM;
 506                goto out_put_alloc_file;
 507        }
 508
 509        str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
 510        str.name = HFSP_HIDDENDIR_NAME;
 511        err = hfs_find_init(sbi->cat_tree, &fd);
 512        if (err)
 513                goto out_put_root;
 514        hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
 515        if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
 516                hfs_find_exit(&fd);
 517                if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
 518                        goto out_put_root;
 519                inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
 520                if (IS_ERR(inode)) {
 521                        err = PTR_ERR(inode);
 522                        goto out_put_root;
 523                }
 524                sbi->hidden_dir = inode;
 525        } else
 526                hfs_find_exit(&fd);
 527
 528        if (!(sb->s_flags & MS_RDONLY)) {
 529                /*
 530                 * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
 531                 * all three are registered with Apple for our use
 532                 */
 533                vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
 534                vhdr->modify_date = hfsp_now2mt();
 535                be32_add_cpu(&vhdr->write_count, 1);
 536                vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
 537                vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
 538                hfsplus_sync_fs(sb, 1);
 539
 540                if (!sbi->hidden_dir) {
 541                        mutex_lock(&sbi->vh_mutex);
 542                        sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
 543                        if (!sbi->hidden_dir) {
 544                                mutex_unlock(&sbi->vh_mutex);
 545                                err = -ENOMEM;
 546                                goto out_put_root;
 547                        }
 548                        err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root,
 549                                                 &str, sbi->hidden_dir);
 550                        if (err) {
 551                                mutex_unlock(&sbi->vh_mutex);
 552                                goto out_put_hidden_dir;
 553                        }
 554
 555                        err = hfsplus_init_inode_security(sbi->hidden_dir,
 556                                                                root, &str);
 557                        if (err == -EOPNOTSUPP)
 558                                err = 0; /* Operation is not supported. */
 559                        else if (err) {
 560                                /*
 561                                 * Try to delete anyway without
 562                                 * error analysis.
 563                                 */
 564                                hfsplus_delete_cat(sbi->hidden_dir->i_ino,
 565                                                        root, &str);
 566                                mutex_unlock(&sbi->vh_mutex);
 567                                goto out_put_hidden_dir;
 568                        }
 569
 570                        mutex_unlock(&sbi->vh_mutex);
 571                        hfsplus_mark_inode_dirty(sbi->hidden_dir,
 572                                                 HFSPLUS_I_CAT_DIRTY);
 573                }
 574        }
 575
 576        unload_nls(sbi->nls);
 577        sbi->nls = nls;
 578        return 0;
 579
 580out_put_hidden_dir:
 581        iput(sbi->hidden_dir);
 582out_put_root:
 583        dput(sb->s_root);
 584        sb->s_root = NULL;
 585out_put_alloc_file:
 586        iput(sbi->alloc_file);
 587out_close_attr_tree:
 588        hfs_btree_close(sbi->attr_tree);
 589out_close_cat_tree:
 590        hfs_btree_close(sbi->cat_tree);
 591out_close_ext_tree:
 592        hfs_btree_close(sbi->ext_tree);
 593out_free_vhdr:
 594        kfree(sbi->s_vhdr_buf);
 595        kfree(sbi->s_backup_vhdr_buf);
 596out_unload_nls:
 597        unload_nls(sbi->nls);
 598        unload_nls(nls);
 599        kfree(sbi);
 600out:
 601        return err;
 602}
 603
 604MODULE_AUTHOR("Brad Boyer");
 605MODULE_DESCRIPTION("Extended Macintosh Filesystem");
 606MODULE_LICENSE("GPL");
 607
 608static struct kmem_cache *hfsplus_inode_cachep;
 609
 610static struct inode *hfsplus_alloc_inode(struct super_block *sb)
 611{
 612        struct hfsplus_inode_info *i;
 613
 614        i = kmem_cache_alloc(hfsplus_inode_cachep, GFP_KERNEL);
 615        return i ? &i->vfs_inode : NULL;
 616}
 617
 618static void hfsplus_i_callback(struct rcu_head *head)
 619{
 620        struct inode *inode = container_of(head, struct inode, i_rcu);
 621
 622        kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode));
 623}
 624
 625static void hfsplus_destroy_inode(struct inode *inode)
 626{
 627        call_rcu(&inode->i_rcu, hfsplus_i_callback);
 628}
 629
 630#define HFSPLUS_INODE_SIZE      sizeof(struct hfsplus_inode_info)
 631
 632static struct dentry *hfsplus_mount(struct file_system_type *fs_type,
 633                          int flags, const char *dev_name, void *data)
 634{
 635        return mount_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super);
 636}
 637
 638static struct file_system_type hfsplus_fs_type = {
 639        .owner          = THIS_MODULE,
 640        .name           = "hfsplus",
 641        .mount          = hfsplus_mount,
 642        .kill_sb        = kill_block_super,
 643        .fs_flags       = FS_REQUIRES_DEV,
 644};
 645MODULE_ALIAS_FS("hfsplus");
 646
 647static void hfsplus_init_once(void *p)
 648{
 649        struct hfsplus_inode_info *i = p;
 650
 651        inode_init_once(&i->vfs_inode);
 652}
 653
 654static int __init init_hfsplus_fs(void)
 655{
 656        int err;
 657
 658        hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache",
 659                HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN,
 660                hfsplus_init_once);
 661        if (!hfsplus_inode_cachep)
 662                return -ENOMEM;
 663        err = hfsplus_create_attr_tree_cache();
 664        if (err)
 665                goto destroy_inode_cache;
 666        err = register_filesystem(&hfsplus_fs_type);
 667        if (err)
 668                goto destroy_attr_tree_cache;
 669        return 0;
 670
 671destroy_attr_tree_cache:
 672        hfsplus_destroy_attr_tree_cache();
 673
 674destroy_inode_cache:
 675        kmem_cache_destroy(hfsplus_inode_cachep);
 676
 677        return err;
 678}
 679
 680static void __exit exit_hfsplus_fs(void)
 681{
 682        unregister_filesystem(&hfsplus_fs_type);
 683
 684        /*
 685         * Make sure all delayed rcu free inodes are flushed before we
 686         * destroy cache.
 687         */
 688        rcu_barrier();
 689        hfsplus_destroy_attr_tree_cache();
 690        kmem_cache_destroy(hfsplus_inode_cachep);
 691}
 692
 693module_init(init_hfsplus_fs)
 694module_exit(exit_hfsplus_fs)
 695
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.