Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  linux/fs/hfsplus/super.c
0004  *
0005  * Copyright (C) 2001
0006  * Brad Boyer (flar@allandria.com)
0007  * (C) 2003 Ardis Technologies <roman@ardistech.com>
0008  *
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/init.h>
0013 #include <linux/pagemap.h>
0014 #include <linux/blkdev.h>
0015 #include <linux/backing-dev.h>
0016 #include <linux/fs.h>
0017 #include <linux/slab.h>
0018 #include <linux/vfs.h>
0019 #include <linux/nls.h>
0020 
0021 static struct inode *hfsplus_alloc_inode(struct super_block *sb);
0022 static void hfsplus_free_inode(struct inode *inode);
0023 
0024 #include "hfsplus_fs.h"
0025 #include "xattr.h"
0026 
0027 static int hfsplus_system_read_inode(struct inode *inode)
0028 {
0029     struct hfsplus_vh *vhdr = HFSPLUS_SB(inode->i_sb)->s_vhdr;
0030 
0031     switch (inode->i_ino) {
0032     case HFSPLUS_EXT_CNID:
0033         hfsplus_inode_read_fork(inode, &vhdr->ext_file);
0034         inode->i_mapping->a_ops = &hfsplus_btree_aops;
0035         break;
0036     case HFSPLUS_CAT_CNID:
0037         hfsplus_inode_read_fork(inode, &vhdr->cat_file);
0038         inode->i_mapping->a_ops = &hfsplus_btree_aops;
0039         break;
0040     case HFSPLUS_ALLOC_CNID:
0041         hfsplus_inode_read_fork(inode, &vhdr->alloc_file);
0042         inode->i_mapping->a_ops = &hfsplus_aops;
0043         break;
0044     case HFSPLUS_START_CNID:
0045         hfsplus_inode_read_fork(inode, &vhdr->start_file);
0046         break;
0047     case HFSPLUS_ATTR_CNID:
0048         hfsplus_inode_read_fork(inode, &vhdr->attr_file);
0049         inode->i_mapping->a_ops = &hfsplus_btree_aops;
0050         break;
0051     default:
0052         return -EIO;
0053     }
0054 
0055     return 0;
0056 }
0057 
0058 struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
0059 {
0060     struct hfs_find_data fd;
0061     struct inode *inode;
0062     int err;
0063 
0064     inode = iget_locked(sb, ino);
0065     if (!inode)
0066         return ERR_PTR(-ENOMEM);
0067     if (!(inode->i_state & I_NEW))
0068         return inode;
0069 
0070     INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
0071     spin_lock_init(&HFSPLUS_I(inode)->open_dir_lock);
0072     mutex_init(&HFSPLUS_I(inode)->extents_lock);
0073     HFSPLUS_I(inode)->flags = 0;
0074     HFSPLUS_I(inode)->extent_state = 0;
0075     HFSPLUS_I(inode)->rsrc_inode = NULL;
0076     atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
0077 
0078     if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
0079         inode->i_ino == HFSPLUS_ROOT_CNID) {
0080         err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
0081         if (!err) {
0082             err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
0083             if (!err)
0084                 err = hfsplus_cat_read_inode(inode, &fd);
0085             hfs_find_exit(&fd);
0086         }
0087     } else {
0088         err = hfsplus_system_read_inode(inode);
0089     }
0090 
0091     if (err) {
0092         iget_failed(inode);
0093         return ERR_PTR(err);
0094     }
0095 
0096     unlock_new_inode(inode);
0097     return inode;
0098 }
0099 
0100 static int hfsplus_system_write_inode(struct inode *inode)
0101 {
0102     struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
0103     struct hfsplus_vh *vhdr = sbi->s_vhdr;
0104     struct hfsplus_fork_raw *fork;
0105     struct hfs_btree *tree = NULL;
0106 
0107     switch (inode->i_ino) {
0108     case HFSPLUS_EXT_CNID:
0109         fork = &vhdr->ext_file;
0110         tree = sbi->ext_tree;
0111         break;
0112     case HFSPLUS_CAT_CNID:
0113         fork = &vhdr->cat_file;
0114         tree = sbi->cat_tree;
0115         break;
0116     case HFSPLUS_ALLOC_CNID:
0117         fork = &vhdr->alloc_file;
0118         break;
0119     case HFSPLUS_START_CNID:
0120         fork = &vhdr->start_file;
0121         break;
0122     case HFSPLUS_ATTR_CNID:
0123         fork = &vhdr->attr_file;
0124         tree = sbi->attr_tree;
0125         break;
0126     default:
0127         return -EIO;
0128     }
0129 
0130     if (fork->total_size != cpu_to_be64(inode->i_size)) {
0131         set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
0132         hfsplus_mark_mdb_dirty(inode->i_sb);
0133     }
0134     hfsplus_inode_write_fork(inode, fork);
0135     if (tree) {
0136         int err = hfs_btree_write(tree);
0137 
0138         if (err) {
0139             pr_err("b-tree write err: %d, ino %lu\n",
0140                    err, inode->i_ino);
0141             return err;
0142         }
0143     }
0144     return 0;
0145 }
0146 
0147 static int hfsplus_write_inode(struct inode *inode,
0148         struct writeback_control *wbc)
0149 {
0150     int err;
0151 
0152     hfs_dbg(INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
0153 
0154     err = hfsplus_ext_write_extent(inode);
0155     if (err)
0156         return err;
0157 
0158     if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
0159         inode->i_ino == HFSPLUS_ROOT_CNID)
0160         return hfsplus_cat_write_inode(inode);
0161     else
0162         return hfsplus_system_write_inode(inode);
0163 }
0164 
0165 static void hfsplus_evict_inode(struct inode *inode)
0166 {
0167     hfs_dbg(INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino);
0168     truncate_inode_pages_final(&inode->i_data);
0169     clear_inode(inode);
0170     if (HFSPLUS_IS_RSRC(inode)) {
0171         HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
0172         iput(HFSPLUS_I(inode)->rsrc_inode);
0173     }
0174 }
0175 
0176 static int hfsplus_sync_fs(struct super_block *sb, int wait)
0177 {
0178     struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
0179     struct hfsplus_vh *vhdr = sbi->s_vhdr;
0180     int write_backup = 0;
0181     int error, error2;
0182 
0183     if (!wait)
0184         return 0;
0185 
0186     hfs_dbg(SUPER, "hfsplus_sync_fs\n");
0187 
0188     /*
0189      * Explicitly write out the special metadata inodes.
0190      *
0191      * While these special inodes are marked as hashed and written
0192      * out peridocically by the flusher threads we redirty them
0193      * during writeout of normal inodes, and thus the life lock
0194      * prevents us from getting the latest state to disk.
0195      */
0196     error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
0197     error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
0198     if (!error)
0199         error = error2;
0200     if (sbi->attr_tree) {
0201         error2 =
0202             filemap_write_and_wait(sbi->attr_tree->inode->i_mapping);
0203         if (!error)
0204             error = error2;
0205     }
0206     error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
0207     if (!error)
0208         error = error2;
0209 
0210     mutex_lock(&sbi->vh_mutex);
0211     mutex_lock(&sbi->alloc_mutex);
0212     vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
0213     vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
0214     vhdr->folder_count = cpu_to_be32(sbi->folder_count);
0215     vhdr->file_count = cpu_to_be32(sbi->file_count);
0216 
0217     if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
0218         memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
0219         write_backup = 1;
0220     }
0221 
0222     error2 = hfsplus_submit_bio(sb,
0223                    sbi->part_start + HFSPLUS_VOLHEAD_SECTOR,
0224                    sbi->s_vhdr_buf, NULL, REQ_OP_WRITE |
0225                    REQ_SYNC);
0226     if (!error)
0227         error = error2;
0228     if (!write_backup)
0229         goto out;
0230 
0231     error2 = hfsplus_submit_bio(sb,
0232                   sbi->part_start + sbi->sect_count - 2,
0233                   sbi->s_backup_vhdr_buf, NULL, REQ_OP_WRITE |
0234                   REQ_SYNC);
0235     if (!error)
0236         error2 = error;
0237 out:
0238     mutex_unlock(&sbi->alloc_mutex);
0239     mutex_unlock(&sbi->vh_mutex);
0240 
0241     if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
0242         blkdev_issue_flush(sb->s_bdev);
0243 
0244     return error;
0245 }
0246 
0247 static void delayed_sync_fs(struct work_struct *work)
0248 {
0249     int err;
0250     struct hfsplus_sb_info *sbi;
0251 
0252     sbi = container_of(work, struct hfsplus_sb_info, sync_work.work);
0253 
0254     spin_lock(&sbi->work_lock);
0255     sbi->work_queued = 0;
0256     spin_unlock(&sbi->work_lock);
0257 
0258     err = hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
0259     if (err)
0260         pr_err("delayed sync fs err %d\n", err);
0261 }
0262 
0263 void hfsplus_mark_mdb_dirty(struct super_block *sb)
0264 {
0265     struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
0266     unsigned long delay;
0267 
0268     if (sb_rdonly(sb))
0269         return;
0270 
0271     spin_lock(&sbi->work_lock);
0272     if (!sbi->work_queued) {
0273         delay = msecs_to_jiffies(dirty_writeback_interval * 10);
0274         queue_delayed_work(system_long_wq, &sbi->sync_work, delay);
0275         sbi->work_queued = 1;
0276     }
0277     spin_unlock(&sbi->work_lock);
0278 }
0279 
0280 static void hfsplus_put_super(struct super_block *sb)
0281 {
0282     struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
0283 
0284     hfs_dbg(SUPER, "hfsplus_put_super\n");
0285 
0286     cancel_delayed_work_sync(&sbi->sync_work);
0287 
0288     if (!sb_rdonly(sb) && sbi->s_vhdr) {
0289         struct hfsplus_vh *vhdr = sbi->s_vhdr;
0290 
0291         vhdr->modify_date = hfsp_now2mt();
0292         vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
0293         vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
0294 
0295         hfsplus_sync_fs(sb, 1);
0296     }
0297 
0298     hfs_btree_close(sbi->attr_tree);
0299     hfs_btree_close(sbi->cat_tree);
0300     hfs_btree_close(sbi->ext_tree);
0301     iput(sbi->alloc_file);
0302     iput(sbi->hidden_dir);
0303     kfree(sbi->s_vhdr_buf);
0304     kfree(sbi->s_backup_vhdr_buf);
0305     unload_nls(sbi->nls);
0306     kfree(sb->s_fs_info);
0307     sb->s_fs_info = NULL;
0308 }
0309 
0310 static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
0311 {
0312     struct super_block *sb = dentry->d_sb;
0313     struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
0314     u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
0315 
0316     buf->f_type = HFSPLUS_SUPER_MAGIC;
0317     buf->f_bsize = sb->s_blocksize;
0318     buf->f_blocks = sbi->total_blocks << sbi->fs_shift;
0319     buf->f_bfree = sbi->free_blocks << sbi->fs_shift;
0320     buf->f_bavail = buf->f_bfree;
0321     buf->f_files = 0xFFFFFFFF;
0322     buf->f_ffree = 0xFFFFFFFF - sbi->next_cnid;
0323     buf->f_fsid = u64_to_fsid(id);
0324     buf->f_namelen = HFSPLUS_MAX_STRLEN;
0325 
0326     return 0;
0327 }
0328 
0329 static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
0330 {
0331     sync_filesystem(sb);
0332     if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
0333         return 0;
0334     if (!(*flags & SB_RDONLY)) {
0335         struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
0336         int force = 0;
0337 
0338         if (!hfsplus_parse_options_remount(data, &force))
0339             return -EINVAL;
0340 
0341         if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
0342             pr_warn("filesystem was not cleanly unmounted, running fsck.hfsplus is recommended.  leaving read-only.\n");
0343             sb->s_flags |= SB_RDONLY;
0344             *flags |= SB_RDONLY;
0345         } else if (force) {
0346             /* nothing */
0347         } else if (vhdr->attributes &
0348                 cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
0349             pr_warn("filesystem is marked locked, leaving read-only.\n");
0350             sb->s_flags |= SB_RDONLY;
0351             *flags |= SB_RDONLY;
0352         } else if (vhdr->attributes &
0353                 cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
0354             pr_warn("filesystem is marked journaled, leaving read-only.\n");
0355             sb->s_flags |= SB_RDONLY;
0356             *flags |= SB_RDONLY;
0357         }
0358     }
0359     return 0;
0360 }
0361 
0362 static const struct super_operations hfsplus_sops = {
0363     .alloc_inode    = hfsplus_alloc_inode,
0364     .free_inode = hfsplus_free_inode,
0365     .write_inode    = hfsplus_write_inode,
0366     .evict_inode    = hfsplus_evict_inode,
0367     .put_super  = hfsplus_put_super,
0368     .sync_fs    = hfsplus_sync_fs,
0369     .statfs     = hfsplus_statfs,
0370     .remount_fs = hfsplus_remount,
0371     .show_options   = hfsplus_show_options,
0372 };
0373 
0374 static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
0375 {
0376     struct hfsplus_vh *vhdr;
0377     struct hfsplus_sb_info *sbi;
0378     hfsplus_cat_entry entry;
0379     struct hfs_find_data fd;
0380     struct inode *root, *inode;
0381     struct qstr str;
0382     struct nls_table *nls = NULL;
0383     u64 last_fs_block, last_fs_page;
0384     int err;
0385 
0386     err = -ENOMEM;
0387     sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
0388     if (!sbi)
0389         goto out;
0390 
0391     sb->s_fs_info = sbi;
0392     mutex_init(&sbi->alloc_mutex);
0393     mutex_init(&sbi->vh_mutex);
0394     spin_lock_init(&sbi->work_lock);
0395     INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);
0396     hfsplus_fill_defaults(sbi);
0397 
0398     err = -EINVAL;
0399     if (!hfsplus_parse_options(data, sbi)) {
0400         pr_err("unable to parse mount options\n");
0401         goto out_unload_nls;
0402     }
0403 
0404     /* temporarily use utf8 to correctly find the hidden dir below */
0405     nls = sbi->nls;
0406     sbi->nls = load_nls("utf8");
0407     if (!sbi->nls) {
0408         pr_err("unable to load nls for utf8\n");
0409         goto out_unload_nls;
0410     }
0411 
0412     /* Grab the volume header */
0413     if (hfsplus_read_wrapper(sb)) {
0414         if (!silent)
0415             pr_warn("unable to find HFS+ superblock\n");
0416         goto out_unload_nls;
0417     }
0418     vhdr = sbi->s_vhdr;
0419 
0420     /* Copy parts of the volume header into the superblock */
0421     sb->s_magic = HFSPLUS_VOLHEAD_SIG;
0422     if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION ||
0423         be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) {
0424         pr_err("wrong filesystem version\n");
0425         goto out_free_vhdr;
0426     }
0427     sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
0428     sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
0429     sbi->next_cnid = be32_to_cpu(vhdr->next_cnid);
0430     sbi->file_count = be32_to_cpu(vhdr->file_count);
0431     sbi->folder_count = be32_to_cpu(vhdr->folder_count);
0432     sbi->data_clump_blocks =
0433         be32_to_cpu(vhdr->data_clump_sz) >> sbi->alloc_blksz_shift;
0434     if (!sbi->data_clump_blocks)
0435         sbi->data_clump_blocks = 1;
0436     sbi->rsrc_clump_blocks =
0437         be32_to_cpu(vhdr->rsrc_clump_sz) >> sbi->alloc_blksz_shift;
0438     if (!sbi->rsrc_clump_blocks)
0439         sbi->rsrc_clump_blocks = 1;
0440 
0441     err = -EFBIG;
0442     last_fs_block = sbi->total_blocks - 1;
0443     last_fs_page = (last_fs_block << sbi->alloc_blksz_shift) >>
0444             PAGE_SHIFT;
0445 
0446     if ((last_fs_block > (sector_t)(~0ULL) >> (sbi->alloc_blksz_shift - 9)) ||
0447         (last_fs_page > (pgoff_t)(~0ULL))) {
0448         pr_err("filesystem size too large\n");
0449         goto out_free_vhdr;
0450     }
0451 
0452     /* Set up operations so we can load metadata */
0453     sb->s_op = &hfsplus_sops;
0454     sb->s_maxbytes = MAX_LFS_FILESIZE;
0455 
0456     if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
0457         pr_warn("Filesystem was not cleanly unmounted, running fsck.hfsplus is recommended.  mounting read-only.\n");
0458         sb->s_flags |= SB_RDONLY;
0459     } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
0460         /* nothing */
0461     } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
0462         pr_warn("Filesystem is marked locked, mounting read-only.\n");
0463         sb->s_flags |= SB_RDONLY;
0464     } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
0465             !sb_rdonly(sb)) {
0466         pr_warn("write access to a journaled filesystem is not supported, use the force option at your own risk, mounting read-only.\n");
0467         sb->s_flags |= SB_RDONLY;
0468     }
0469 
0470     err = -EINVAL;
0471 
0472     /* Load metadata objects (B*Trees) */
0473     sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
0474     if (!sbi->ext_tree) {
0475         pr_err("failed to load extents file\n");
0476         goto out_free_vhdr;
0477     }
0478     sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
0479     if (!sbi->cat_tree) {
0480         pr_err("failed to load catalog file\n");
0481         goto out_close_ext_tree;
0482     }
0483     atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE);
0484     if (vhdr->attr_file.total_blocks != 0) {
0485         sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
0486         if (!sbi->attr_tree) {
0487             pr_err("failed to load attributes file\n");
0488             goto out_close_cat_tree;
0489         }
0490         atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE);
0491     }
0492     sb->s_xattr = hfsplus_xattr_handlers;
0493 
0494     inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
0495     if (IS_ERR(inode)) {
0496         pr_err("failed to load allocation file\n");
0497         err = PTR_ERR(inode);
0498         goto out_close_attr_tree;
0499     }
0500     sbi->alloc_file = inode;
0501 
0502     /* Load the root directory */
0503     root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
0504     if (IS_ERR(root)) {
0505         pr_err("failed to load root directory\n");
0506         err = PTR_ERR(root);
0507         goto out_put_alloc_file;
0508     }
0509 
0510     sb->s_d_op = &hfsplus_dentry_operations;
0511     sb->s_root = d_make_root(root);
0512     if (!sb->s_root) {
0513         err = -ENOMEM;
0514         goto out_put_alloc_file;
0515     }
0516 
0517     str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
0518     str.name = HFSP_HIDDENDIR_NAME;
0519     err = hfs_find_init(sbi->cat_tree, &fd);
0520     if (err)
0521         goto out_put_root;
0522     err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
0523     if (unlikely(err < 0))
0524         goto out_put_root;
0525     if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
0526         hfs_find_exit(&fd);
0527         if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) {
0528             err = -EINVAL;
0529             goto out_put_root;
0530         }
0531         inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
0532         if (IS_ERR(inode)) {
0533             err = PTR_ERR(inode);
0534             goto out_put_root;
0535         }
0536         sbi->hidden_dir = inode;
0537     } else
0538         hfs_find_exit(&fd);
0539 
0540     if (!sb_rdonly(sb)) {
0541         /*
0542          * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
0543          * all three are registered with Apple for our use
0544          */
0545         vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
0546         vhdr->modify_date = hfsp_now2mt();
0547         be32_add_cpu(&vhdr->write_count, 1);
0548         vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
0549         vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
0550         hfsplus_sync_fs(sb, 1);
0551 
0552         if (!sbi->hidden_dir) {
0553             mutex_lock(&sbi->vh_mutex);
0554             sbi->hidden_dir = hfsplus_new_inode(sb, root, S_IFDIR);
0555             if (!sbi->hidden_dir) {
0556                 mutex_unlock(&sbi->vh_mutex);
0557                 err = -ENOMEM;
0558                 goto out_put_root;
0559             }
0560             err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root,
0561                          &str, sbi->hidden_dir);
0562             if (err) {
0563                 mutex_unlock(&sbi->vh_mutex);
0564                 goto out_put_hidden_dir;
0565             }
0566 
0567             err = hfsplus_init_security(sbi->hidden_dir,
0568                             root, &str);
0569             if (err == -EOPNOTSUPP)
0570                 err = 0; /* Operation is not supported. */
0571             else if (err) {
0572                 /*
0573                  * Try to delete anyway without
0574                  * error analysis.
0575                  */
0576                 hfsplus_delete_cat(sbi->hidden_dir->i_ino,
0577                             root, &str);
0578                 mutex_unlock(&sbi->vh_mutex);
0579                 goto out_put_hidden_dir;
0580             }
0581 
0582             mutex_unlock(&sbi->vh_mutex);
0583             hfsplus_mark_inode_dirty(sbi->hidden_dir,
0584                          HFSPLUS_I_CAT_DIRTY);
0585         }
0586     }
0587 
0588     unload_nls(sbi->nls);
0589     sbi->nls = nls;
0590     return 0;
0591 
0592 out_put_hidden_dir:
0593     cancel_delayed_work_sync(&sbi->sync_work);
0594     iput(sbi->hidden_dir);
0595 out_put_root:
0596     dput(sb->s_root);
0597     sb->s_root = NULL;
0598 out_put_alloc_file:
0599     iput(sbi->alloc_file);
0600 out_close_attr_tree:
0601     hfs_btree_close(sbi->attr_tree);
0602 out_close_cat_tree:
0603     hfs_btree_close(sbi->cat_tree);
0604 out_close_ext_tree:
0605     hfs_btree_close(sbi->ext_tree);
0606 out_free_vhdr:
0607     kfree(sbi->s_vhdr_buf);
0608     kfree(sbi->s_backup_vhdr_buf);
0609 out_unload_nls:
0610     unload_nls(sbi->nls);
0611     unload_nls(nls);
0612     kfree(sbi);
0613 out:
0614     return err;
0615 }
0616 
0617 MODULE_AUTHOR("Brad Boyer");
0618 MODULE_DESCRIPTION("Extended Macintosh Filesystem");
0619 MODULE_LICENSE("GPL");
0620 
0621 static struct kmem_cache *hfsplus_inode_cachep;
0622 
0623 static struct inode *hfsplus_alloc_inode(struct super_block *sb)
0624 {
0625     struct hfsplus_inode_info *i;
0626 
0627     i = alloc_inode_sb(sb, hfsplus_inode_cachep, GFP_KERNEL);
0628     return i ? &i->vfs_inode : NULL;
0629 }
0630 
0631 static void hfsplus_free_inode(struct inode *inode)
0632 {
0633     kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode));
0634 }
0635 
0636 #define HFSPLUS_INODE_SIZE  sizeof(struct hfsplus_inode_info)
0637 
0638 static struct dentry *hfsplus_mount(struct file_system_type *fs_type,
0639               int flags, const char *dev_name, void *data)
0640 {
0641     return mount_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super);
0642 }
0643 
0644 static struct file_system_type hfsplus_fs_type = {
0645     .owner      = THIS_MODULE,
0646     .name       = "hfsplus",
0647     .mount      = hfsplus_mount,
0648     .kill_sb    = kill_block_super,
0649     .fs_flags   = FS_REQUIRES_DEV,
0650 };
0651 MODULE_ALIAS_FS("hfsplus");
0652 
0653 static void hfsplus_init_once(void *p)
0654 {
0655     struct hfsplus_inode_info *i = p;
0656 
0657     inode_init_once(&i->vfs_inode);
0658 }
0659 
0660 static int __init init_hfsplus_fs(void)
0661 {
0662     int err;
0663 
0664     hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache",
0665         HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT,
0666         hfsplus_init_once);
0667     if (!hfsplus_inode_cachep)
0668         return -ENOMEM;
0669     err = hfsplus_create_attr_tree_cache();
0670     if (err)
0671         goto destroy_inode_cache;
0672     err = register_filesystem(&hfsplus_fs_type);
0673     if (err)
0674         goto destroy_attr_tree_cache;
0675     return 0;
0676 
0677 destroy_attr_tree_cache:
0678     hfsplus_destroy_attr_tree_cache();
0679 
0680 destroy_inode_cache:
0681     kmem_cache_destroy(hfsplus_inode_cachep);
0682 
0683     return err;
0684 }
0685 
0686 static void __exit exit_hfsplus_fs(void)
0687 {
0688     unregister_filesystem(&hfsplus_fs_type);
0689 
0690     /*
0691      * Make sure all delayed rcu free inodes are flushed before we
0692      * destroy cache.
0693      */
0694     rcu_barrier();
0695     hfsplus_destroy_attr_tree_cache();
0696     kmem_cache_destroy(hfsplus_inode_cachep);
0697 }
0698 
0699 module_init(init_hfsplus_fs)
0700 module_exit(exit_hfsplus_fs)