0001
0002
0003
0004
0005
0006
0007
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
0190
0191
0192
0193
0194
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
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
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
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
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
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
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
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
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
0543
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;
0571 else if (err) {
0572
0573
0574
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
0692
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)