11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/hfsplus/super.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 51da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com) 61da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include <linux/module.h> 111da177e4SLinus Torvalds #include <linux/init.h> 121da177e4SLinus Torvalds #include <linux/pagemap.h> 1334a2d313SChristoph Hellwig #include <linux/blkdev.h> 1466114cadSTejun Heo #include <linux/backing-dev.h> 151da177e4SLinus Torvalds #include <linux/fs.h> 161da177e4SLinus Torvalds #include <linux/slab.h> 171da177e4SLinus Torvalds #include <linux/vfs.h> 181da177e4SLinus Torvalds #include <linux/nls.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds static struct inode *hfsplus_alloc_inode(struct super_block *sb); 211da177e4SLinus Torvalds static void hfsplus_destroy_inode(struct inode *inode); 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include "hfsplus_fs.h" 24324ef39aSVyacheslav Dubeyko #include "xattr.h" 251da177e4SLinus Torvalds 26fc4fff82SChristoph Hellwig static int hfsplus_system_read_inode(struct inode *inode) 271da177e4SLinus Torvalds { 28fc4fff82SChristoph Hellwig struct hfsplus_vh *vhdr = HFSPLUS_SB(inode->i_sb)->s_vhdr; 2963525391SDavid Howells 301da177e4SLinus Torvalds switch (inode->i_ino) { 311da177e4SLinus Torvalds case HFSPLUS_EXT_CNID: 321da177e4SLinus Torvalds hfsplus_inode_read_fork(inode, &vhdr->ext_file); 331da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_btree_aops; 341da177e4SLinus Torvalds break; 351da177e4SLinus Torvalds case HFSPLUS_CAT_CNID: 361da177e4SLinus Torvalds hfsplus_inode_read_fork(inode, &vhdr->cat_file); 371da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_btree_aops; 381da177e4SLinus Torvalds break; 391da177e4SLinus Torvalds case HFSPLUS_ALLOC_CNID: 401da177e4SLinus Torvalds hfsplus_inode_read_fork(inode, &vhdr->alloc_file); 411da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 421da177e4SLinus Torvalds break; 431da177e4SLinus Torvalds case HFSPLUS_START_CNID: 441da177e4SLinus Torvalds hfsplus_inode_read_fork(inode, &vhdr->start_file); 451da177e4SLinus Torvalds break; 461da177e4SLinus Torvalds case HFSPLUS_ATTR_CNID: 471da177e4SLinus Torvalds hfsplus_inode_read_fork(inode, &vhdr->attr_file); 481da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_btree_aops; 491da177e4SLinus Torvalds break; 501da177e4SLinus Torvalds default: 51fc4fff82SChristoph Hellwig return -EIO; 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 54fc4fff82SChristoph Hellwig return 0; 55fc4fff82SChristoph Hellwig } 56fc4fff82SChristoph Hellwig 57fc4fff82SChristoph Hellwig struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino) 58fc4fff82SChristoph Hellwig { 59fc4fff82SChristoph Hellwig struct hfs_find_data fd; 60fc4fff82SChristoph Hellwig struct inode *inode; 61fc4fff82SChristoph Hellwig int err; 62fc4fff82SChristoph Hellwig 63fc4fff82SChristoph Hellwig inode = iget_locked(sb, ino); 64fc4fff82SChristoph Hellwig if (!inode) 65fc4fff82SChristoph Hellwig return ERR_PTR(-ENOMEM); 66fc4fff82SChristoph Hellwig if (!(inode->i_state & I_NEW)) 6763525391SDavid Howells return inode; 681da177e4SLinus Torvalds 69fc4fff82SChristoph Hellwig INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list); 70fc4fff82SChristoph Hellwig mutex_init(&HFSPLUS_I(inode)->extents_lock); 71fc4fff82SChristoph Hellwig HFSPLUS_I(inode)->flags = 0; 72b33b7921SChristoph Hellwig HFSPLUS_I(inode)->extent_state = 0; 73fc4fff82SChristoph Hellwig HFSPLUS_I(inode)->rsrc_inode = NULL; 74fc4fff82SChristoph Hellwig atomic_set(&HFSPLUS_I(inode)->opencnt, 0); 75fc4fff82SChristoph Hellwig 76fc4fff82SChristoph Hellwig if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID || 77fc4fff82SChristoph Hellwig inode->i_ino == HFSPLUS_ROOT_CNID) { 785bd9d99dSAlexey Khoroshilov err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 795bd9d99dSAlexey Khoroshilov if (!err) { 80fc4fff82SChristoph Hellwig err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 81fc4fff82SChristoph Hellwig if (!err) 82fc4fff82SChristoph Hellwig err = hfsplus_cat_read_inode(inode, &fd); 83fc4fff82SChristoph Hellwig hfs_find_exit(&fd); 845bd9d99dSAlexey Khoroshilov } 85fc4fff82SChristoph Hellwig } else { 86fc4fff82SChristoph Hellwig err = hfsplus_system_read_inode(inode); 87fc4fff82SChristoph Hellwig } 88fc4fff82SChristoph Hellwig 89fc4fff82SChristoph Hellwig if (err) { 9063525391SDavid Howells iget_failed(inode); 9163525391SDavid Howells return ERR_PTR(err); 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 94fc4fff82SChristoph Hellwig unlock_new_inode(inode); 95fc4fff82SChristoph Hellwig return inode; 96fc4fff82SChristoph Hellwig } 97fc4fff82SChristoph Hellwig 98b5080f77SChristoph Hellwig static int hfsplus_system_write_inode(struct inode *inode) 99b5080f77SChristoph Hellwig { 100b5080f77SChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 101b5080f77SChristoph Hellwig struct hfsplus_vh *vhdr = sbi->s_vhdr; 102b5080f77SChristoph Hellwig struct hfsplus_fork_raw *fork; 103b5080f77SChristoph Hellwig struct hfs_btree *tree = NULL; 104b5080f77SChristoph Hellwig 105b5080f77SChristoph Hellwig switch (inode->i_ino) { 106b5080f77SChristoph Hellwig case HFSPLUS_EXT_CNID: 107b5080f77SChristoph Hellwig fork = &vhdr->ext_file; 108b5080f77SChristoph Hellwig tree = sbi->ext_tree; 109b5080f77SChristoph Hellwig break; 110b5080f77SChristoph Hellwig case HFSPLUS_CAT_CNID: 111b5080f77SChristoph Hellwig fork = &vhdr->cat_file; 112b5080f77SChristoph Hellwig tree = sbi->cat_tree; 113b5080f77SChristoph Hellwig break; 114b5080f77SChristoph Hellwig case HFSPLUS_ALLOC_CNID: 115b5080f77SChristoph Hellwig fork = &vhdr->alloc_file; 116b5080f77SChristoph Hellwig break; 117b5080f77SChristoph Hellwig case HFSPLUS_START_CNID: 118b5080f77SChristoph Hellwig fork = &vhdr->start_file; 119b5080f77SChristoph Hellwig break; 120b5080f77SChristoph Hellwig case HFSPLUS_ATTR_CNID: 121b5080f77SChristoph Hellwig fork = &vhdr->attr_file; 122b5080f77SChristoph Hellwig tree = sbi->attr_tree; 123324ef39aSVyacheslav Dubeyko break; 124b5080f77SChristoph Hellwig default: 125b5080f77SChristoph Hellwig return -EIO; 126b5080f77SChristoph Hellwig } 127b5080f77SChristoph Hellwig 128b5080f77SChristoph Hellwig if (fork->total_size != cpu_to_be64(inode->i_size)) { 12984adede3SChristoph Hellwig set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags); 1309e6c5829SArtem Bityutskiy hfsplus_mark_mdb_dirty(inode->i_sb); 131b5080f77SChristoph Hellwig } 132b5080f77SChristoph Hellwig hfsplus_inode_write_fork(inode, fork); 13381cc7fadSVyacheslav Dubeyko if (tree) { 13481cc7fadSVyacheslav Dubeyko int err = hfs_btree_write(tree); 135b73f3d0eSFabian Frederick 13681cc7fadSVyacheslav Dubeyko if (err) { 137d6142673SJoe Perches pr_err("b-tree write err: %d, ino %lu\n", 13881cc7fadSVyacheslav Dubeyko err, inode->i_ino); 13981cc7fadSVyacheslav Dubeyko return err; 14081cc7fadSVyacheslav Dubeyko } 14181cc7fadSVyacheslav Dubeyko } 142b5080f77SChristoph Hellwig return 0; 143b5080f77SChristoph Hellwig } 144b5080f77SChristoph Hellwig 145a9185b41SChristoph Hellwig static int hfsplus_write_inode(struct inode *inode, 146a9185b41SChristoph Hellwig struct writeback_control *wbc) 1471da177e4SLinus Torvalds { 148dd7f3d54SAlexey Khoroshilov int err; 149dd7f3d54SAlexey Khoroshilov 150c2b3e1f7SJoe Perches hfs_dbg(INODE, "hfsplus_write_inode: %lu\n", inode->i_ino); 151b5080f77SChristoph Hellwig 152dd7f3d54SAlexey Khoroshilov err = hfsplus_ext_write_extent(inode); 153dd7f3d54SAlexey Khoroshilov if (err) 154dd7f3d54SAlexey Khoroshilov return err; 155b5080f77SChristoph Hellwig 156b5080f77SChristoph Hellwig if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID || 157b5080f77SChristoph Hellwig inode->i_ino == HFSPLUS_ROOT_CNID) 1581da177e4SLinus Torvalds return hfsplus_cat_write_inode(inode); 159b5080f77SChristoph Hellwig else 160b5080f77SChristoph Hellwig return hfsplus_system_write_inode(inode); 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds 163b57922d9SAl Viro static void hfsplus_evict_inode(struct inode *inode) 1641da177e4SLinus Torvalds { 165c2b3e1f7SJoe Perches hfs_dbg(INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino); 16691b0abe3SJohannes Weiner truncate_inode_pages_final(&inode->i_data); 167dbd5768fSJan Kara clear_inode(inode); 1681da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) { 1696af502deSChristoph Hellwig HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL; 1706af502deSChristoph Hellwig iput(HFSPLUS_I(inode)->rsrc_inode); 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 1740a818619SArtem Bityutskiy static int hfsplus_sync_fs(struct super_block *sb, int wait) 1751da177e4SLinus Torvalds { 176dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 177dd73a01aSChristoph Hellwig struct hfsplus_vh *vhdr = sbi->s_vhdr; 17852399b17SChristoph Hellwig int write_backup = 0; 17952399b17SChristoph Hellwig int error, error2; 1801da177e4SLinus Torvalds 181f02e26f8SChristoph Hellwig if (!wait) 182f02e26f8SChristoph Hellwig return 0; 1831da177e4SLinus Torvalds 184c2b3e1f7SJoe Perches hfs_dbg(SUPER, "hfsplus_sync_fs\n"); 185ebc1ac16SChristoph Hellwig 1867dc4f001SChristoph Hellwig /* 1877dc4f001SChristoph Hellwig * Explicitly write out the special metadata inodes. 1887dc4f001SChristoph Hellwig * 1897dc4f001SChristoph Hellwig * While these special inodes are marked as hashed and written 1907dc4f001SChristoph Hellwig * out peridocically by the flusher threads we redirty them 1917dc4f001SChristoph Hellwig * during writeout of normal inodes, and thus the life lock 1927dc4f001SChristoph Hellwig * prevents us from getting the latest state to disk. 1937dc4f001SChristoph Hellwig */ 1947dc4f001SChristoph Hellwig error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); 1957dc4f001SChristoph Hellwig error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); 1967dc4f001SChristoph Hellwig if (!error) 1977dc4f001SChristoph Hellwig error = error2; 198324ef39aSVyacheslav Dubeyko if (sbi->attr_tree) { 199324ef39aSVyacheslav Dubeyko error2 = 200324ef39aSVyacheslav Dubeyko filemap_write_and_wait(sbi->attr_tree->inode->i_mapping); 201324ef39aSVyacheslav Dubeyko if (!error) 202324ef39aSVyacheslav Dubeyko error = error2; 203324ef39aSVyacheslav Dubeyko } 2047dc4f001SChristoph Hellwig error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); 2057dc4f001SChristoph Hellwig if (!error) 2067dc4f001SChristoph Hellwig error = error2; 2077dc4f001SChristoph Hellwig 20852399b17SChristoph Hellwig mutex_lock(&sbi->vh_mutex); 20952399b17SChristoph Hellwig mutex_lock(&sbi->alloc_mutex); 210dd73a01aSChristoph Hellwig vhdr->free_blocks = cpu_to_be32(sbi->free_blocks); 211dd73a01aSChristoph Hellwig vhdr->next_cnid = cpu_to_be32(sbi->next_cnid); 212dd73a01aSChristoph Hellwig vhdr->folder_count = cpu_to_be32(sbi->folder_count); 213dd73a01aSChristoph Hellwig vhdr->file_count = cpu_to_be32(sbi->file_count); 2141da177e4SLinus Torvalds 21584adede3SChristoph Hellwig if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) { 21652399b17SChristoph Hellwig memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr)); 21752399b17SChristoph Hellwig write_backup = 1; 21852399b17SChristoph Hellwig } 2191da177e4SLinus Torvalds 2206596528eSSeth Forshee error2 = hfsplus_submit_bio(sb, 22152399b17SChristoph Hellwig sbi->part_start + HFSPLUS_VOLHEAD_SECTOR, 2226596528eSSeth Forshee sbi->s_vhdr_buf, NULL, WRITE_SYNC); 2237dc4f001SChristoph Hellwig if (!error) 2247dc4f001SChristoph Hellwig error = error2; 22552399b17SChristoph Hellwig if (!write_backup) 22652399b17SChristoph Hellwig goto out; 22752399b17SChristoph Hellwig 2286596528eSSeth Forshee error2 = hfsplus_submit_bio(sb, 22952399b17SChristoph Hellwig sbi->part_start + sbi->sect_count - 2, 2306596528eSSeth Forshee sbi->s_backup_vhdr_buf, NULL, WRITE_SYNC); 23152399b17SChristoph Hellwig if (!error) 23252399b17SChristoph Hellwig error2 = error; 23352399b17SChristoph Hellwig out: 234dd73a01aSChristoph Hellwig mutex_unlock(&sbi->alloc_mutex); 2357ac9fb9cSChristoph Hellwig mutex_unlock(&sbi->vh_mutex); 23634a2d313SChristoph Hellwig 23734a2d313SChristoph Hellwig if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) 23834a2d313SChristoph Hellwig blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL); 23934a2d313SChristoph Hellwig 24052399b17SChristoph Hellwig return error; 2417fbc6df0SChristoph Hellwig } 2427fbc6df0SChristoph Hellwig 2439e6c5829SArtem Bityutskiy static void delayed_sync_fs(struct work_struct *work) 2447fbc6df0SChristoph Hellwig { 245bffdd661SVyacheslav Dubeyko int err; 2469e6c5829SArtem Bityutskiy struct hfsplus_sb_info *sbi; 2479e6c5829SArtem Bityutskiy 2489e6c5829SArtem Bityutskiy sbi = container_of(work, struct hfsplus_sb_info, sync_work.work); 2499e6c5829SArtem Bityutskiy 2509e6c5829SArtem Bityutskiy spin_lock(&sbi->work_lock); 2519e6c5829SArtem Bityutskiy sbi->work_queued = 0; 2529e6c5829SArtem Bityutskiy spin_unlock(&sbi->work_lock); 2539e6c5829SArtem Bityutskiy 254bffdd661SVyacheslav Dubeyko err = hfsplus_sync_fs(sbi->alloc_file->i_sb, 1); 255bffdd661SVyacheslav Dubeyko if (err) 256d6142673SJoe Perches pr_err("delayed sync fs err %d\n", err); 2579e6c5829SArtem Bityutskiy } 2589e6c5829SArtem Bityutskiy 2599e6c5829SArtem Bityutskiy void hfsplus_mark_mdb_dirty(struct super_block *sb) 2609e6c5829SArtem Bityutskiy { 2619e6c5829SArtem Bityutskiy struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 2629e6c5829SArtem Bityutskiy unsigned long delay; 2639e6c5829SArtem Bityutskiy 2649e6c5829SArtem Bityutskiy if (sb->s_flags & MS_RDONLY) 2659e6c5829SArtem Bityutskiy return; 2669e6c5829SArtem Bityutskiy 2679e6c5829SArtem Bityutskiy spin_lock(&sbi->work_lock); 2689e6c5829SArtem Bityutskiy if (!sbi->work_queued) { 2699e6c5829SArtem Bityutskiy delay = msecs_to_jiffies(dirty_writeback_interval * 10); 2709e6c5829SArtem Bityutskiy queue_delayed_work(system_long_wq, &sbi->sync_work, delay); 2719e6c5829SArtem Bityutskiy sbi->work_queued = 1; 2729e6c5829SArtem Bityutskiy } 2739e6c5829SArtem Bityutskiy spin_unlock(&sbi->work_lock); 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static void hfsplus_put_super(struct super_block *sb) 2771da177e4SLinus Torvalds { 278dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 279dd73a01aSChristoph Hellwig 280c2b3e1f7SJoe Perches hfs_dbg(SUPER, "hfsplus_put_super\n"); 281dd73a01aSChristoph Hellwig 2829e6c5829SArtem Bityutskiy cancel_delayed_work_sync(&sbi->sync_work); 2839e6c5829SArtem Bityutskiy 284dd73a01aSChristoph Hellwig if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) { 285dd73a01aSChristoph Hellwig struct hfsplus_vh *vhdr = sbi->s_vhdr; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds vhdr->modify_date = hfsp_now2mt(); 2881da177e4SLinus Torvalds vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT); 2891da177e4SLinus Torvalds vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT); 2903b5ce8aeSChristoph Hellwig 2913b5ce8aeSChristoph Hellwig hfsplus_sync_fs(sb, 1); 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds 294324ef39aSVyacheslav Dubeyko hfs_btree_close(sbi->attr_tree); 295dd73a01aSChristoph Hellwig hfs_btree_close(sbi->cat_tree); 296dd73a01aSChristoph Hellwig hfs_btree_close(sbi->ext_tree); 297dd73a01aSChristoph Hellwig iput(sbi->alloc_file); 298dd73a01aSChristoph Hellwig iput(sbi->hidden_dir); 2996596528eSSeth Forshee kfree(sbi->s_vhdr_buf); 3006596528eSSeth Forshee kfree(sbi->s_backup_vhdr_buf); 301dd73a01aSChristoph Hellwig unload_nls(sbi->nls); 302945b0920SColin Leroy kfree(sb->s_fs_info); 303945b0920SColin Leroy sb->s_fs_info = NULL; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 306726c3342SDavid Howells static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf) 3071da177e4SLinus Torvalds { 308726c3342SDavid Howells struct super_block *sb = dentry->d_sb; 309dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 31025564dd8SColy Li u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 311726c3342SDavid Howells 3121da177e4SLinus Torvalds buf->f_type = HFSPLUS_SUPER_MAGIC; 3131da177e4SLinus Torvalds buf->f_bsize = sb->s_blocksize; 314dd73a01aSChristoph Hellwig buf->f_blocks = sbi->total_blocks << sbi->fs_shift; 315dd73a01aSChristoph Hellwig buf->f_bfree = sbi->free_blocks << sbi->fs_shift; 3161da177e4SLinus Torvalds buf->f_bavail = buf->f_bfree; 3171da177e4SLinus Torvalds buf->f_files = 0xFFFFFFFF; 318dd73a01aSChristoph Hellwig buf->f_ffree = 0xFFFFFFFF - sbi->next_cnid; 31925564dd8SColy Li buf->f_fsid.val[0] = (u32)id; 32025564dd8SColy Li buf->f_fsid.val[1] = (u32)(id >> 32); 3211da177e4SLinus Torvalds buf->f_namelen = HFSPLUS_MAX_STRLEN; 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds return 0; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds static int hfsplus_remount(struct super_block *sb, int *flags, char *data) 3271da177e4SLinus Torvalds { 32802b9984dSTheodore Ts'o sync_filesystem(sb); 3291da177e4SLinus Torvalds if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) 3301da177e4SLinus Torvalds return 0; 3311da177e4SLinus Torvalds if (!(*flags & MS_RDONLY)) { 332dd73a01aSChristoph Hellwig struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr; 3336f80dfe5SChristoph Hellwig int force = 0; 334b0b623c3SRoman Zippel 3356f80dfe5SChristoph Hellwig if (!hfsplus_parse_options_remount(data, &force)) 336b0b623c3SRoman Zippel return -EINVAL; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 339d6142673SJoe Perches pr_warn("filesystem was not cleanly unmounted, running fsck.hfsplus is recommended. leaving read-only.\n"); 3401da177e4SLinus Torvalds sb->s_flags |= MS_RDONLY; 3411da177e4SLinus Torvalds *flags |= MS_RDONLY; 3426f80dfe5SChristoph Hellwig } else if (force) { 343b0b623c3SRoman Zippel /* nothing */ 3442753cc28SAnton Salikhmetov } else if (vhdr->attributes & 3452753cc28SAnton Salikhmetov cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 346d6142673SJoe Perches pr_warn("filesystem is marked locked, leaving read-only.\n"); 3471da177e4SLinus Torvalds sb->s_flags |= MS_RDONLY; 3481da177e4SLinus Torvalds *flags |= MS_RDONLY; 3492753cc28SAnton Salikhmetov } else if (vhdr->attributes & 3502753cc28SAnton Salikhmetov cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { 351d6142673SJoe Perches pr_warn("filesystem is marked journaled, leaving read-only.\n"); 352b0b623c3SRoman Zippel sb->s_flags |= MS_RDONLY; 353b0b623c3SRoman Zippel *flags |= MS_RDONLY; 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds return 0; 3571da177e4SLinus Torvalds } 3581da177e4SLinus Torvalds 359ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations hfsplus_sops = { 3601da177e4SLinus Torvalds .alloc_inode = hfsplus_alloc_inode, 3611da177e4SLinus Torvalds .destroy_inode = hfsplus_destroy_inode, 3621da177e4SLinus Torvalds .write_inode = hfsplus_write_inode, 363b57922d9SAl Viro .evict_inode = hfsplus_evict_inode, 3641da177e4SLinus Torvalds .put_super = hfsplus_put_super, 3657fbc6df0SChristoph Hellwig .sync_fs = hfsplus_sync_fs, 3661da177e4SLinus Torvalds .statfs = hfsplus_statfs, 3671da177e4SLinus Torvalds .remount_fs = hfsplus_remount, 368717dd80eSRoman Zippel .show_options = hfsplus_show_options, 3691da177e4SLinus Torvalds }; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) 3721da177e4SLinus Torvalds { 3731da177e4SLinus Torvalds struct hfsplus_vh *vhdr; 3741da177e4SLinus Torvalds struct hfsplus_sb_info *sbi; 3751da177e4SLinus Torvalds hfsplus_cat_entry entry; 3761da177e4SLinus Torvalds struct hfs_find_data fd; 37763525391SDavid Howells struct inode *root, *inode; 3781da177e4SLinus Torvalds struct qstr str; 3791da177e4SLinus Torvalds struct nls_table *nls = NULL; 380f1fcd9f0SChristoph Hellwig u64 last_fs_block, last_fs_page; 381c5b8d0bcSChristoph Hellwig int err; 3821da177e4SLinus Torvalds 383497d48bdSNamjae Jeon err = -ENOMEM; 384a5001a27SWyatt Banks sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 3851da177e4SLinus Torvalds if (!sbi) 386c5b8d0bcSChristoph Hellwig goto out; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds sb->s_fs_info = sbi; 38940bf48afSChristoph Hellwig mutex_init(&sbi->alloc_mutex); 3907ac9fb9cSChristoph Hellwig mutex_init(&sbi->vh_mutex); 3919e6c5829SArtem Bityutskiy spin_lock_init(&sbi->work_lock); 3929e6c5829SArtem Bityutskiy INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs); 393717dd80eSRoman Zippel hfsplus_fill_defaults(sbi); 394c5b8d0bcSChristoph Hellwig 395c5b8d0bcSChristoph Hellwig err = -EINVAL; 396717dd80eSRoman Zippel if (!hfsplus_parse_options(data, sbi)) { 397d6142673SJoe Perches pr_err("unable to parse mount options\n"); 398c5b8d0bcSChristoph Hellwig goto out_unload_nls; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* temporarily use utf8 to correctly find the hidden dir below */ 4021da177e4SLinus Torvalds nls = sbi->nls; 4031da177e4SLinus Torvalds sbi->nls = load_nls("utf8"); 404bd6a59b2SJoshua Kwan if (!sbi->nls) { 405d6142673SJoe Perches pr_err("unable to load nls for utf8\n"); 406c5b8d0bcSChristoph Hellwig goto out_unload_nls; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds /* Grab the volume header */ 4101da177e4SLinus Torvalds if (hfsplus_read_wrapper(sb)) { 4111da177e4SLinus Torvalds if (!silent) 412d6142673SJoe Perches pr_warn("unable to find HFS+ superblock\n"); 413c5b8d0bcSChristoph Hellwig goto out_unload_nls; 4141da177e4SLinus Torvalds } 415dd73a01aSChristoph Hellwig vhdr = sbi->s_vhdr; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds /* Copy parts of the volume header into the superblock */ 4182179d372SDavid Elliott sb->s_magic = HFSPLUS_VOLHEAD_SIG; 4192179d372SDavid Elliott if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || 4202179d372SDavid Elliott be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { 421d6142673SJoe Perches pr_err("wrong filesystem version\n"); 422c5b8d0bcSChristoph Hellwig goto out_free_vhdr; 4231da177e4SLinus Torvalds } 424dd73a01aSChristoph Hellwig sbi->total_blocks = be32_to_cpu(vhdr->total_blocks); 425dd73a01aSChristoph Hellwig sbi->free_blocks = be32_to_cpu(vhdr->free_blocks); 426dd73a01aSChristoph Hellwig sbi->next_cnid = be32_to_cpu(vhdr->next_cnid); 427dd73a01aSChristoph Hellwig sbi->file_count = be32_to_cpu(vhdr->file_count); 428dd73a01aSChristoph Hellwig sbi->folder_count = be32_to_cpu(vhdr->folder_count); 429dd73a01aSChristoph Hellwig sbi->data_clump_blocks = 430dd73a01aSChristoph Hellwig be32_to_cpu(vhdr->data_clump_sz) >> sbi->alloc_blksz_shift; 431dd73a01aSChristoph Hellwig if (!sbi->data_clump_blocks) 432dd73a01aSChristoph Hellwig sbi->data_clump_blocks = 1; 433dd73a01aSChristoph Hellwig sbi->rsrc_clump_blocks = 434dd73a01aSChristoph Hellwig be32_to_cpu(vhdr->rsrc_clump_sz) >> sbi->alloc_blksz_shift; 435dd73a01aSChristoph Hellwig if (!sbi->rsrc_clump_blocks) 436dd73a01aSChristoph Hellwig sbi->rsrc_clump_blocks = 1; 4371da177e4SLinus Torvalds 438f1fcd9f0SChristoph Hellwig err = -EFBIG; 439f1fcd9f0SChristoph Hellwig last_fs_block = sbi->total_blocks - 1; 440f1fcd9f0SChristoph Hellwig last_fs_page = (last_fs_block << sbi->alloc_blksz_shift) >> 441f1fcd9f0SChristoph Hellwig PAGE_CACHE_SHIFT; 442f1fcd9f0SChristoph Hellwig 443f1fcd9f0SChristoph Hellwig if ((last_fs_block > (sector_t)(~0ULL) >> (sbi->alloc_blksz_shift - 9)) || 444f1fcd9f0SChristoph Hellwig (last_fs_page > (pgoff_t)(~0ULL))) { 445d6142673SJoe Perches pr_err("filesystem size too large\n"); 446c6d5f5faSChristoph Hellwig goto out_free_vhdr; 447c6d5f5faSChristoph Hellwig } 448c6d5f5faSChristoph Hellwig 4491da177e4SLinus Torvalds /* Set up operations so we can load metadata */ 4501da177e4SLinus Torvalds sb->s_op = &hfsplus_sops; 4511da177e4SLinus Torvalds sb->s_maxbytes = MAX_LFS_FILESIZE; 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 454d6142673SJoe Perches pr_warn("Filesystem was not cleanly unmounted, running fsck.hfsplus is recommended. mounting read-only.\n"); 4551da177e4SLinus Torvalds sb->s_flags |= MS_RDONLY; 45684adede3SChristoph Hellwig } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) { 457b0b623c3SRoman Zippel /* nothing */ 4581da177e4SLinus Torvalds } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 459d6142673SJoe Perches pr_warn("Filesystem is marked locked, mounting read-only.\n"); 4601da177e4SLinus Torvalds sb->s_flags |= MS_RDONLY; 4612753cc28SAnton Salikhmetov } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && 4622753cc28SAnton Salikhmetov !(sb->s_flags & MS_RDONLY)) { 463d6142673SJoe Perches pr_warn("write access to a journaled filesystem is not supported, use the force option at your own risk, mounting read-only.\n"); 464b0b623c3SRoman Zippel sb->s_flags |= MS_RDONLY; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 467c6d5f5faSChristoph Hellwig err = -EINVAL; 468c6d5f5faSChristoph Hellwig 4691da177e4SLinus Torvalds /* Load metadata objects (B*Trees) */ 470dd73a01aSChristoph Hellwig sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); 471dd73a01aSChristoph Hellwig if (!sbi->ext_tree) { 472d6142673SJoe Perches pr_err("failed to load extents file\n"); 473c5b8d0bcSChristoph Hellwig goto out_free_vhdr; 4741da177e4SLinus Torvalds } 475dd73a01aSChristoph Hellwig sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); 476dd73a01aSChristoph Hellwig if (!sbi->cat_tree) { 477d6142673SJoe Perches pr_err("failed to load catalog file\n"); 478c5b8d0bcSChristoph Hellwig goto out_close_ext_tree; 4791da177e4SLinus Torvalds } 48095e0d7dbSVyacheslav Dubeyko atomic_set(&sbi->attr_tree_state, HFSPLUS_EMPTY_ATTR_TREE); 481324ef39aSVyacheslav Dubeyko if (vhdr->attr_file.total_blocks != 0) { 482324ef39aSVyacheslav Dubeyko sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); 483324ef39aSVyacheslav Dubeyko if (!sbi->attr_tree) { 484d6142673SJoe Perches pr_err("failed to load attributes file\n"); 485324ef39aSVyacheslav Dubeyko goto out_close_cat_tree; 486324ef39aSVyacheslav Dubeyko } 48795e0d7dbSVyacheslav Dubeyko atomic_set(&sbi->attr_tree_state, HFSPLUS_VALID_ATTR_TREE); 488324ef39aSVyacheslav Dubeyko } 489324ef39aSVyacheslav Dubeyko sb->s_xattr = hfsplus_xattr_handlers; 4901da177e4SLinus Torvalds 49163525391SDavid Howells inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID); 49263525391SDavid Howells if (IS_ERR(inode)) { 493d6142673SJoe Perches pr_err("failed to load allocation file\n"); 49463525391SDavid Howells err = PTR_ERR(inode); 495324ef39aSVyacheslav Dubeyko goto out_close_attr_tree; 4961da177e4SLinus Torvalds } 497dd73a01aSChristoph Hellwig sbi->alloc_file = inode; 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds /* Load the root directory */ 50063525391SDavid Howells root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID); 50163525391SDavid Howells if (IS_ERR(root)) { 502d6142673SJoe Perches pr_err("failed to load root directory\n"); 50363525391SDavid Howells err = PTR_ERR(root); 504c5b8d0bcSChristoph Hellwig goto out_put_alloc_file; 5051da177e4SLinus Torvalds } 5061da177e4SLinus Torvalds 50768acb8e6SAl Viro sb->s_d_op = &hfsplus_dentry_operations; 50868acb8e6SAl Viro sb->s_root = d_make_root(root); 50968acb8e6SAl Viro if (!sb->s_root) { 51068acb8e6SAl Viro err = -ENOMEM; 51168acb8e6SAl Viro goto out_put_alloc_file; 51268acb8e6SAl Viro } 51368acb8e6SAl Viro 5141da177e4SLinus Torvalds str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; 5151da177e4SLinus Torvalds str.name = HFSP_HIDDENDIR_NAME; 5165bd9d99dSAlexey Khoroshilov err = hfs_find_init(sbi->cat_tree, &fd); 5175bd9d99dSAlexey Khoroshilov if (err) 5185bd9d99dSAlexey Khoroshilov goto out_put_root; 51989ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); 52089ac9b4dSSougata Santra if (unlikely(err < 0)) 52189ac9b4dSSougata Santra goto out_put_root; 5221da177e4SLinus Torvalds if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { 5231da177e4SLinus Torvalds hfs_find_exit(&fd); 5241da177e4SLinus Torvalds if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) 525c5b8d0bcSChristoph Hellwig goto out_put_root; 52663525391SDavid Howells inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id)); 52763525391SDavid Howells if (IS_ERR(inode)) { 52863525391SDavid Howells err = PTR_ERR(inode); 529c5b8d0bcSChristoph Hellwig goto out_put_root; 53063525391SDavid Howells } 531dd73a01aSChristoph Hellwig sbi->hidden_dir = inode; 5321da177e4SLinus Torvalds } else 5331da177e4SLinus Torvalds hfs_find_exit(&fd); 5341da177e4SLinus Torvalds 535c5b8d0bcSChristoph Hellwig if (!(sb->s_flags & MS_RDONLY)) { 536c5b8d0bcSChristoph Hellwig /* 537c5b8d0bcSChristoph Hellwig * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused 5381da177e4SLinus Torvalds * all three are registered with Apple for our use 5391da177e4SLinus Torvalds */ 5401da177e4SLinus Torvalds vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION); 5411da177e4SLinus Torvalds vhdr->modify_date = hfsp_now2mt(); 54220c79e78SMarcin Slusarz be32_add_cpu(&vhdr->write_count, 1); 5431da177e4SLinus Torvalds vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); 5441da177e4SLinus Torvalds vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); 5453b5ce8aeSChristoph Hellwig hfsplus_sync_fs(sb, 1); 5461da177e4SLinus Torvalds 547dd73a01aSChristoph Hellwig if (!sbi->hidden_dir) { 5487ac9fb9cSChristoph Hellwig mutex_lock(&sbi->vh_mutex); 549dd73a01aSChristoph Hellwig sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR); 550b3f2a924SAl Viro if (!sbi->hidden_dir) { 5517ac9fb9cSChristoph Hellwig mutex_unlock(&sbi->vh_mutex); 552b3f2a924SAl Viro err = -ENOMEM; 553b3f2a924SAl Viro goto out_put_root; 554b3f2a924SAl Viro } 555b3f2a924SAl Viro err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root, 556b3f2a924SAl Viro &str, sbi->hidden_dir); 557324ef39aSVyacheslav Dubeyko if (err) { 558b3f2a924SAl Viro mutex_unlock(&sbi->vh_mutex); 559b3f2a924SAl Viro goto out_put_hidden_dir; 560324ef39aSVyacheslav Dubeyko } 5617ac9fb9cSChristoph Hellwig 562324ef39aSVyacheslav Dubeyko err = hfsplus_init_inode_security(sbi->hidden_dir, 563324ef39aSVyacheslav Dubeyko root, &str); 564324ef39aSVyacheslav Dubeyko if (err == -EOPNOTSUPP) 565324ef39aSVyacheslav Dubeyko err = 0; /* Operation is not supported. */ 566324ef39aSVyacheslav Dubeyko else if (err) { 567324ef39aSVyacheslav Dubeyko /* 568324ef39aSVyacheslav Dubeyko * Try to delete anyway without 569324ef39aSVyacheslav Dubeyko * error analysis. 570324ef39aSVyacheslav Dubeyko */ 571324ef39aSVyacheslav Dubeyko hfsplus_delete_cat(sbi->hidden_dir->i_ino, 572324ef39aSVyacheslav Dubeyko root, &str); 573324ef39aSVyacheslav Dubeyko mutex_unlock(&sbi->vh_mutex); 574324ef39aSVyacheslav Dubeyko goto out_put_hidden_dir; 575324ef39aSVyacheslav Dubeyko } 576324ef39aSVyacheslav Dubeyko 577324ef39aSVyacheslav Dubeyko mutex_unlock(&sbi->vh_mutex); 578c5b8d0bcSChristoph Hellwig hfsplus_mark_inode_dirty(sbi->hidden_dir, 579c5b8d0bcSChristoph Hellwig HFSPLUS_I_CAT_DIRTY); 5801da177e4SLinus Torvalds } 581c5b8d0bcSChristoph Hellwig } 582c5b8d0bcSChristoph Hellwig 5831da177e4SLinus Torvalds unload_nls(sbi->nls); 5841da177e4SLinus Torvalds sbi->nls = nls; 5851da177e4SLinus Torvalds return 0; 5861da177e4SLinus Torvalds 587c5b8d0bcSChristoph Hellwig out_put_hidden_dir: 588c5b8d0bcSChristoph Hellwig iput(sbi->hidden_dir); 589c5b8d0bcSChristoph Hellwig out_put_root: 59068acb8e6SAl Viro dput(sb->s_root); 59168acb8e6SAl Viro sb->s_root = NULL; 592c5b8d0bcSChristoph Hellwig out_put_alloc_file: 593c5b8d0bcSChristoph Hellwig iput(sbi->alloc_file); 594324ef39aSVyacheslav Dubeyko out_close_attr_tree: 595324ef39aSVyacheslav Dubeyko hfs_btree_close(sbi->attr_tree); 596c5b8d0bcSChristoph Hellwig out_close_cat_tree: 597c5b8d0bcSChristoph Hellwig hfs_btree_close(sbi->cat_tree); 598c5b8d0bcSChristoph Hellwig out_close_ext_tree: 599c5b8d0bcSChristoph Hellwig hfs_btree_close(sbi->ext_tree); 600c5b8d0bcSChristoph Hellwig out_free_vhdr: 601f588c960SSeth Forshee kfree(sbi->s_vhdr_buf); 602f588c960SSeth Forshee kfree(sbi->s_backup_vhdr_buf); 603c5b8d0bcSChristoph Hellwig out_unload_nls: 604c5b8d0bcSChristoph Hellwig unload_nls(sbi->nls); 6051da177e4SLinus Torvalds unload_nls(nls); 606c5b8d0bcSChristoph Hellwig kfree(sbi); 607c5b8d0bcSChristoph Hellwig out: 6081da177e4SLinus Torvalds return err; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds MODULE_AUTHOR("Brad Boyer"); 6121da177e4SLinus Torvalds MODULE_DESCRIPTION("Extended Macintosh Filesystem"); 6131da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 6141da177e4SLinus Torvalds 615e18b890bSChristoph Lameter static struct kmem_cache *hfsplus_inode_cachep; 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds static struct inode *hfsplus_alloc_inode(struct super_block *sb) 6181da177e4SLinus Torvalds { 6191da177e4SLinus Torvalds struct hfsplus_inode_info *i; 6201da177e4SLinus Torvalds 621e94b1766SChristoph Lameter i = kmem_cache_alloc(hfsplus_inode_cachep, GFP_KERNEL); 6221da177e4SLinus Torvalds return i ? &i->vfs_inode : NULL; 6231da177e4SLinus Torvalds } 6241da177e4SLinus Torvalds 625fa0d7e3dSNick Piggin static void hfsplus_i_callback(struct rcu_head *head) 626fa0d7e3dSNick Piggin { 627fa0d7e3dSNick Piggin struct inode *inode = container_of(head, struct inode, i_rcu); 628fa0d7e3dSNick Piggin 629fa0d7e3dSNick Piggin kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode)); 630fa0d7e3dSNick Piggin } 631fa0d7e3dSNick Piggin 6321da177e4SLinus Torvalds static void hfsplus_destroy_inode(struct inode *inode) 6331da177e4SLinus Torvalds { 634fa0d7e3dSNick Piggin call_rcu(&inode->i_rcu, hfsplus_i_callback); 6351da177e4SLinus Torvalds } 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds #define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info) 6381da177e4SLinus Torvalds 639152a0836SAl Viro static struct dentry *hfsplus_mount(struct file_system_type *fs_type, 640152a0836SAl Viro int flags, const char *dev_name, void *data) 6411da177e4SLinus Torvalds { 642152a0836SAl Viro return mount_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super); 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds static struct file_system_type hfsplus_fs_type = { 6461da177e4SLinus Torvalds .owner = THIS_MODULE, 6471da177e4SLinus Torvalds .name = "hfsplus", 648152a0836SAl Viro .mount = hfsplus_mount, 6491da177e4SLinus Torvalds .kill_sb = kill_block_super, 6501da177e4SLinus Torvalds .fs_flags = FS_REQUIRES_DEV, 6511da177e4SLinus Torvalds }; 6527f78e035SEric W. Biederman MODULE_ALIAS_FS("hfsplus"); 6531da177e4SLinus Torvalds 65451cc5068SAlexey Dobriyan static void hfsplus_init_once(void *p) 6551da177e4SLinus Torvalds { 6561da177e4SLinus Torvalds struct hfsplus_inode_info *i = p; 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds inode_init_once(&i->vfs_inode); 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds static int __init init_hfsplus_fs(void) 6621da177e4SLinus Torvalds { 6631da177e4SLinus Torvalds int err; 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache", 6661da177e4SLinus Torvalds HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN, 66720c2df83SPaul Mundt hfsplus_init_once); 6681da177e4SLinus Torvalds if (!hfsplus_inode_cachep) 6691da177e4SLinus Torvalds return -ENOMEM; 670324ef39aSVyacheslav Dubeyko err = hfsplus_create_attr_tree_cache(); 671324ef39aSVyacheslav Dubeyko if (err) 672324ef39aSVyacheslav Dubeyko goto destroy_inode_cache; 6731da177e4SLinus Torvalds err = register_filesystem(&hfsplus_fs_type); 6741da177e4SLinus Torvalds if (err) 675324ef39aSVyacheslav Dubeyko goto destroy_attr_tree_cache; 676324ef39aSVyacheslav Dubeyko return 0; 677324ef39aSVyacheslav Dubeyko 678324ef39aSVyacheslav Dubeyko destroy_attr_tree_cache: 679324ef39aSVyacheslav Dubeyko hfsplus_destroy_attr_tree_cache(); 680324ef39aSVyacheslav Dubeyko 681324ef39aSVyacheslav Dubeyko destroy_inode_cache: 6821da177e4SLinus Torvalds kmem_cache_destroy(hfsplus_inode_cachep); 683324ef39aSVyacheslav Dubeyko 6841da177e4SLinus Torvalds return err; 6851da177e4SLinus Torvalds } 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds static void __exit exit_hfsplus_fs(void) 6881da177e4SLinus Torvalds { 6891da177e4SLinus Torvalds unregister_filesystem(&hfsplus_fs_type); 6908c0a8537SKirill A. Shutemov 6918c0a8537SKirill A. Shutemov /* 6928c0a8537SKirill A. Shutemov * Make sure all delayed rcu free inodes are flushed before we 6938c0a8537SKirill A. Shutemov * destroy cache. 6948c0a8537SKirill A. Shutemov */ 6958c0a8537SKirill A. Shutemov rcu_barrier(); 696324ef39aSVyacheslav Dubeyko hfsplus_destroy_attr_tree_cache(); 6971a1d92c1SAlexey Dobriyan kmem_cache_destroy(hfsplus_inode_cachep); 6981da177e4SLinus Torvalds } 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds module_init(init_hfsplus_fs) 7011da177e4SLinus Torvalds module_exit(exit_hfsplus_fs) 702