162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/fs/hfs/super.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1995-1997 Paul H. Hargrove 562306a36Sopenharmony_ci * (C) 2003 Ardis Technologies <roman@ardistech.com> 662306a36Sopenharmony_ci * This file may be distributed under the terms of the GNU General Public License. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file contains hfs_read_super(), some of the super_ops and 962306a36Sopenharmony_ci * init_hfs_fs() and exit_hfs_fs(). The remaining super_ops are in 1062306a36Sopenharmony_ci * inode.c since they deal with inodes. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/blkdev.h> 1762306a36Sopenharmony_ci#include <linux/backing-dev.h> 1862306a36Sopenharmony_ci#include <linux/mount.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/nls.h> 2162306a36Sopenharmony_ci#include <linux/parser.h> 2262306a36Sopenharmony_ci#include <linux/seq_file.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/vfs.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "hfs_fs.h" 2762306a36Sopenharmony_ci#include "btree.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic struct kmem_cache *hfs_inode_cachep; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int hfs_sync_fs(struct super_block *sb, int wait) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci hfs_mdb_commit(sb); 3662306a36Sopenharmony_ci return 0; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * hfs_put_super() 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * This is the put_super() entry in the super_operations structure for 4362306a36Sopenharmony_ci * HFS filesystems. The purpose is to release the resources 4462306a36Sopenharmony_ci * associated with the superblock sb. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistatic void hfs_put_super(struct super_block *sb) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci cancel_delayed_work_sync(&HFS_SB(sb)->mdb_work); 4962306a36Sopenharmony_ci hfs_mdb_close(sb); 5062306a36Sopenharmony_ci /* release the MDB's resources */ 5162306a36Sopenharmony_ci hfs_mdb_put(sb); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void flush_mdb(struct work_struct *work) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct hfs_sb_info *sbi; 5762306a36Sopenharmony_ci struct super_block *sb; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci sbi = container_of(work, struct hfs_sb_info, mdb_work.work); 6062306a36Sopenharmony_ci sb = sbi->sb; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci spin_lock(&sbi->work_lock); 6362306a36Sopenharmony_ci sbi->work_queued = 0; 6462306a36Sopenharmony_ci spin_unlock(&sbi->work_lock); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci hfs_mdb_commit(sb); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_civoid hfs_mark_mdb_dirty(struct super_block *sb) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct hfs_sb_info *sbi = HFS_SB(sb); 7262306a36Sopenharmony_ci unsigned long delay; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (sb_rdonly(sb)) 7562306a36Sopenharmony_ci return; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci spin_lock(&sbi->work_lock); 7862306a36Sopenharmony_ci if (!sbi->work_queued) { 7962306a36Sopenharmony_ci delay = msecs_to_jiffies(dirty_writeback_interval * 10); 8062306a36Sopenharmony_ci queue_delayed_work(system_long_wq, &sbi->mdb_work, delay); 8162306a36Sopenharmony_ci sbi->work_queued = 1; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci spin_unlock(&sbi->work_lock); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * hfs_statfs() 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * This is the statfs() entry in the super_operations structure for 9062306a36Sopenharmony_ci * HFS filesystems. The purpose is to return various data about the 9162306a36Sopenharmony_ci * filesystem. 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_cistatic int hfs_statfs(struct dentry *dentry, struct kstatfs *buf) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 9862306a36Sopenharmony_ci u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci buf->f_type = HFS_SUPER_MAGIC; 10162306a36Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 10262306a36Sopenharmony_ci buf->f_blocks = (u32)HFS_SB(sb)->fs_ablocks * HFS_SB(sb)->fs_div; 10362306a36Sopenharmony_ci buf->f_bfree = (u32)HFS_SB(sb)->free_ablocks * HFS_SB(sb)->fs_div; 10462306a36Sopenharmony_ci buf->f_bavail = buf->f_bfree; 10562306a36Sopenharmony_ci buf->f_files = HFS_SB(sb)->fs_ablocks; 10662306a36Sopenharmony_ci buf->f_ffree = HFS_SB(sb)->free_ablocks; 10762306a36Sopenharmony_ci buf->f_fsid = u64_to_fsid(id); 10862306a36Sopenharmony_ci buf->f_namelen = HFS_NAMELEN; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int hfs_remount(struct super_block *sb, int *flags, char *data) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci sync_filesystem(sb); 11662306a36Sopenharmony_ci *flags |= SB_NODIRATIME; 11762306a36Sopenharmony_ci if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci if (!(*flags & SB_RDONLY)) { 12062306a36Sopenharmony_ci if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { 12162306a36Sopenharmony_ci pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended. leaving read-only.\n"); 12262306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 12362306a36Sopenharmony_ci *flags |= SB_RDONLY; 12462306a36Sopenharmony_ci } else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) { 12562306a36Sopenharmony_ci pr_warn("filesystem is marked locked, leaving read-only.\n"); 12662306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 12762306a36Sopenharmony_ci *flags |= SB_RDONLY; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int hfs_show_options(struct seq_file *seq, struct dentry *root) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct hfs_sb_info *sbi = HFS_SB(root->d_sb); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (sbi->s_creator != cpu_to_be32(0x3f3f3f3f)) 13862306a36Sopenharmony_ci seq_show_option_n(seq, "creator", (char *)&sbi->s_creator, 4); 13962306a36Sopenharmony_ci if (sbi->s_type != cpu_to_be32(0x3f3f3f3f)) 14062306a36Sopenharmony_ci seq_show_option_n(seq, "type", (char *)&sbi->s_type, 4); 14162306a36Sopenharmony_ci seq_printf(seq, ",uid=%u,gid=%u", 14262306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, sbi->s_uid), 14362306a36Sopenharmony_ci from_kgid_munged(&init_user_ns, sbi->s_gid)); 14462306a36Sopenharmony_ci if (sbi->s_file_umask != 0133) 14562306a36Sopenharmony_ci seq_printf(seq, ",file_umask=%o", sbi->s_file_umask); 14662306a36Sopenharmony_ci if (sbi->s_dir_umask != 0022) 14762306a36Sopenharmony_ci seq_printf(seq, ",dir_umask=%o", sbi->s_dir_umask); 14862306a36Sopenharmony_ci if (sbi->part >= 0) 14962306a36Sopenharmony_ci seq_printf(seq, ",part=%u", sbi->part); 15062306a36Sopenharmony_ci if (sbi->session >= 0) 15162306a36Sopenharmony_ci seq_printf(seq, ",session=%u", sbi->session); 15262306a36Sopenharmony_ci if (sbi->nls_disk) 15362306a36Sopenharmony_ci seq_printf(seq, ",codepage=%s", sbi->nls_disk->charset); 15462306a36Sopenharmony_ci if (sbi->nls_io) 15562306a36Sopenharmony_ci seq_printf(seq, ",iocharset=%s", sbi->nls_io->charset); 15662306a36Sopenharmony_ci if (sbi->s_quiet) 15762306a36Sopenharmony_ci seq_printf(seq, ",quiet"); 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic struct inode *hfs_alloc_inode(struct super_block *sb) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct hfs_inode_info *i; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci i = alloc_inode_sb(sb, hfs_inode_cachep, GFP_KERNEL); 16662306a36Sopenharmony_ci return i ? &i->vfs_inode : NULL; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void hfs_free_inode(struct inode *inode) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci kmem_cache_free(hfs_inode_cachep, HFS_I(inode)); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic const struct super_operations hfs_super_operations = { 17562306a36Sopenharmony_ci .alloc_inode = hfs_alloc_inode, 17662306a36Sopenharmony_ci .free_inode = hfs_free_inode, 17762306a36Sopenharmony_ci .write_inode = hfs_write_inode, 17862306a36Sopenharmony_ci .evict_inode = hfs_evict_inode, 17962306a36Sopenharmony_ci .put_super = hfs_put_super, 18062306a36Sopenharmony_ci .sync_fs = hfs_sync_fs, 18162306a36Sopenharmony_ci .statfs = hfs_statfs, 18262306a36Sopenharmony_ci .remount_fs = hfs_remount, 18362306a36Sopenharmony_ci .show_options = hfs_show_options, 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cienum { 18762306a36Sopenharmony_ci opt_uid, opt_gid, opt_umask, opt_file_umask, opt_dir_umask, 18862306a36Sopenharmony_ci opt_part, opt_session, opt_type, opt_creator, opt_quiet, 18962306a36Sopenharmony_ci opt_codepage, opt_iocharset, 19062306a36Sopenharmony_ci opt_err 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic const match_table_t tokens = { 19462306a36Sopenharmony_ci { opt_uid, "uid=%u" }, 19562306a36Sopenharmony_ci { opt_gid, "gid=%u" }, 19662306a36Sopenharmony_ci { opt_umask, "umask=%o" }, 19762306a36Sopenharmony_ci { opt_file_umask, "file_umask=%o" }, 19862306a36Sopenharmony_ci { opt_dir_umask, "dir_umask=%o" }, 19962306a36Sopenharmony_ci { opt_part, "part=%u" }, 20062306a36Sopenharmony_ci { opt_session, "session=%u" }, 20162306a36Sopenharmony_ci { opt_type, "type=%s" }, 20262306a36Sopenharmony_ci { opt_creator, "creator=%s" }, 20362306a36Sopenharmony_ci { opt_quiet, "quiet" }, 20462306a36Sopenharmony_ci { opt_codepage, "codepage=%s" }, 20562306a36Sopenharmony_ci { opt_iocharset, "iocharset=%s" }, 20662306a36Sopenharmony_ci { opt_err, NULL } 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline int match_fourchar(substring_t *arg, u32 *result) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci if (arg->to - arg->from != 4) 21262306a36Sopenharmony_ci return -EINVAL; 21362306a36Sopenharmony_ci memcpy(result, arg->from, 4); 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* 21862306a36Sopenharmony_ci * parse_options() 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * adapted from linux/fs/msdos/inode.c written 1992,93 by Werner Almesberger 22162306a36Sopenharmony_ci * This function is called by hfs_read_super() to parse the mount options. 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_cistatic int parse_options(char *options, struct hfs_sb_info *hsb) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci char *p; 22662306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 22762306a36Sopenharmony_ci int tmp, token; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* initialize the sb with defaults */ 23062306a36Sopenharmony_ci hsb->s_uid = current_uid(); 23162306a36Sopenharmony_ci hsb->s_gid = current_gid(); 23262306a36Sopenharmony_ci hsb->s_file_umask = 0133; 23362306a36Sopenharmony_ci hsb->s_dir_umask = 0022; 23462306a36Sopenharmony_ci hsb->s_type = hsb->s_creator = cpu_to_be32(0x3f3f3f3f); /* == '????' */ 23562306a36Sopenharmony_ci hsb->s_quiet = 0; 23662306a36Sopenharmony_ci hsb->part = -1; 23762306a36Sopenharmony_ci hsb->session = -1; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (!options) 24062306a36Sopenharmony_ci return 1; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 24362306a36Sopenharmony_ci if (!*p) 24462306a36Sopenharmony_ci continue; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci token = match_token(p, tokens, args); 24762306a36Sopenharmony_ci switch (token) { 24862306a36Sopenharmony_ci case opt_uid: 24962306a36Sopenharmony_ci if (match_int(&args[0], &tmp)) { 25062306a36Sopenharmony_ci pr_err("uid requires an argument\n"); 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci hsb->s_uid = make_kuid(current_user_ns(), (uid_t)tmp); 25462306a36Sopenharmony_ci if (!uid_valid(hsb->s_uid)) { 25562306a36Sopenharmony_ci pr_err("invalid uid %d\n", tmp); 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case opt_gid: 26062306a36Sopenharmony_ci if (match_int(&args[0], &tmp)) { 26162306a36Sopenharmony_ci pr_err("gid requires an argument\n"); 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci hsb->s_gid = make_kgid(current_user_ns(), (gid_t)tmp); 26562306a36Sopenharmony_ci if (!gid_valid(hsb->s_gid)) { 26662306a36Sopenharmony_ci pr_err("invalid gid %d\n", tmp); 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci break; 27062306a36Sopenharmony_ci case opt_umask: 27162306a36Sopenharmony_ci if (match_octal(&args[0], &tmp)) { 27262306a36Sopenharmony_ci pr_err("umask requires a value\n"); 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci hsb->s_file_umask = (umode_t)tmp; 27662306a36Sopenharmony_ci hsb->s_dir_umask = (umode_t)tmp; 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci case opt_file_umask: 27962306a36Sopenharmony_ci if (match_octal(&args[0], &tmp)) { 28062306a36Sopenharmony_ci pr_err("file_umask requires a value\n"); 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci hsb->s_file_umask = (umode_t)tmp; 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case opt_dir_umask: 28662306a36Sopenharmony_ci if (match_octal(&args[0], &tmp)) { 28762306a36Sopenharmony_ci pr_err("dir_umask requires a value\n"); 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci hsb->s_dir_umask = (umode_t)tmp; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case opt_part: 29362306a36Sopenharmony_ci if (match_int(&args[0], &hsb->part)) { 29462306a36Sopenharmony_ci pr_err("part requires an argument\n"); 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci case opt_session: 29962306a36Sopenharmony_ci if (match_int(&args[0], &hsb->session)) { 30062306a36Sopenharmony_ci pr_err("session requires an argument\n"); 30162306a36Sopenharmony_ci return 0; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci case opt_type: 30562306a36Sopenharmony_ci if (match_fourchar(&args[0], &hsb->s_type)) { 30662306a36Sopenharmony_ci pr_err("type requires a 4 character value\n"); 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci case opt_creator: 31162306a36Sopenharmony_ci if (match_fourchar(&args[0], &hsb->s_creator)) { 31262306a36Sopenharmony_ci pr_err("creator requires a 4 character value\n"); 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci case opt_quiet: 31762306a36Sopenharmony_ci hsb->s_quiet = 1; 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci case opt_codepage: 32062306a36Sopenharmony_ci if (hsb->nls_disk) { 32162306a36Sopenharmony_ci pr_err("unable to change codepage\n"); 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci p = match_strdup(&args[0]); 32562306a36Sopenharmony_ci if (p) 32662306a36Sopenharmony_ci hsb->nls_disk = load_nls(p); 32762306a36Sopenharmony_ci if (!hsb->nls_disk) { 32862306a36Sopenharmony_ci pr_err("unable to load codepage \"%s\"\n", p); 32962306a36Sopenharmony_ci kfree(p); 33062306a36Sopenharmony_ci return 0; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci kfree(p); 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci case opt_iocharset: 33562306a36Sopenharmony_ci if (hsb->nls_io) { 33662306a36Sopenharmony_ci pr_err("unable to change iocharset\n"); 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci p = match_strdup(&args[0]); 34062306a36Sopenharmony_ci if (p) 34162306a36Sopenharmony_ci hsb->nls_io = load_nls(p); 34262306a36Sopenharmony_ci if (!hsb->nls_io) { 34362306a36Sopenharmony_ci pr_err("unable to load iocharset \"%s\"\n", p); 34462306a36Sopenharmony_ci kfree(p); 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci kfree(p); 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci default: 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (hsb->nls_disk && !hsb->nls_io) { 35562306a36Sopenharmony_ci hsb->nls_io = load_nls_default(); 35662306a36Sopenharmony_ci if (!hsb->nls_io) { 35762306a36Sopenharmony_ci pr_err("unable to load default iocharset\n"); 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci hsb->s_dir_umask &= 0777; 36262306a36Sopenharmony_ci hsb->s_file_umask &= 0577; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return 1; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* 36862306a36Sopenharmony_ci * hfs_read_super() 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci * This is the function that is responsible for mounting an HFS 37162306a36Sopenharmony_ci * filesystem. It performs all the tasks necessary to get enough data 37262306a36Sopenharmony_ci * from the disk to read the root inode. This includes parsing the 37362306a36Sopenharmony_ci * mount options, dealing with Macintosh partitions, reading the 37462306a36Sopenharmony_ci * superblock and the allocation bitmap blocks, calling 37562306a36Sopenharmony_ci * hfs_btree_init() to get the necessary data about the extents and 37662306a36Sopenharmony_ci * catalog B-trees and, finally, reading the root inode into memory. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_cistatic int hfs_fill_super(struct super_block *sb, void *data, int silent) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct hfs_sb_info *sbi; 38162306a36Sopenharmony_ci struct hfs_find_data fd; 38262306a36Sopenharmony_ci hfs_cat_rec rec; 38362306a36Sopenharmony_ci struct inode *root_inode; 38462306a36Sopenharmony_ci int res; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci sbi = kzalloc(sizeof(struct hfs_sb_info), GFP_KERNEL); 38762306a36Sopenharmony_ci if (!sbi) 38862306a36Sopenharmony_ci return -ENOMEM; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci sbi->sb = sb; 39162306a36Sopenharmony_ci sb->s_fs_info = sbi; 39262306a36Sopenharmony_ci spin_lock_init(&sbi->work_lock); 39362306a36Sopenharmony_ci INIT_DELAYED_WORK(&sbi->mdb_work, flush_mdb); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci res = -EINVAL; 39662306a36Sopenharmony_ci if (!parse_options((char *)data, sbi)) { 39762306a36Sopenharmony_ci pr_err("unable to parse mount options\n"); 39862306a36Sopenharmony_ci goto bail; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci sb->s_op = &hfs_super_operations; 40262306a36Sopenharmony_ci sb->s_xattr = hfs_xattr_handlers; 40362306a36Sopenharmony_ci sb->s_flags |= SB_NODIRATIME; 40462306a36Sopenharmony_ci mutex_init(&sbi->bitmap_lock); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci res = hfs_mdb_get(sb); 40762306a36Sopenharmony_ci if (res) { 40862306a36Sopenharmony_ci if (!silent) 40962306a36Sopenharmony_ci pr_warn("can't find a HFS filesystem on dev %s\n", 41062306a36Sopenharmony_ci hfs_mdb_name(sb)); 41162306a36Sopenharmony_ci res = -EINVAL; 41262306a36Sopenharmony_ci goto bail; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* try to get the root inode */ 41662306a36Sopenharmony_ci res = hfs_find_init(HFS_SB(sb)->cat_tree, &fd); 41762306a36Sopenharmony_ci if (res) 41862306a36Sopenharmony_ci goto bail_no_root; 41962306a36Sopenharmony_ci res = hfs_cat_find_brec(sb, HFS_ROOT_CNID, &fd); 42062306a36Sopenharmony_ci if (!res) { 42162306a36Sopenharmony_ci if (fd.entrylength > sizeof(rec) || fd.entrylength < 0) { 42262306a36Sopenharmony_ci res = -EIO; 42362306a36Sopenharmony_ci goto bail_hfs_find; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, fd.entrylength); 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci if (res) 42862306a36Sopenharmony_ci goto bail_hfs_find; 42962306a36Sopenharmony_ci res = -EINVAL; 43062306a36Sopenharmony_ci root_inode = hfs_iget(sb, &fd.search_key->cat, &rec); 43162306a36Sopenharmony_ci hfs_find_exit(&fd); 43262306a36Sopenharmony_ci if (!root_inode) 43362306a36Sopenharmony_ci goto bail_no_root; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci sb->s_d_op = &hfs_dentry_operations; 43662306a36Sopenharmony_ci res = -ENOMEM; 43762306a36Sopenharmony_ci sb->s_root = d_make_root(root_inode); 43862306a36Sopenharmony_ci if (!sb->s_root) 43962306a36Sopenharmony_ci goto bail_no_root; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* everything's okay */ 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cibail_hfs_find: 44562306a36Sopenharmony_ci hfs_find_exit(&fd); 44662306a36Sopenharmony_cibail_no_root: 44762306a36Sopenharmony_ci pr_err("get root inode failed\n"); 44862306a36Sopenharmony_cibail: 44962306a36Sopenharmony_ci hfs_mdb_put(sb); 45062306a36Sopenharmony_ci return res; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic struct dentry *hfs_mount(struct file_system_type *fs_type, 45462306a36Sopenharmony_ci int flags, const char *dev_name, void *data) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, hfs_fill_super); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic struct file_system_type hfs_fs_type = { 46062306a36Sopenharmony_ci .owner = THIS_MODULE, 46162306a36Sopenharmony_ci .name = "hfs", 46262306a36Sopenharmony_ci .mount = hfs_mount, 46362306a36Sopenharmony_ci .kill_sb = kill_block_super, 46462306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ciMODULE_ALIAS_FS("hfs"); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic void hfs_init_once(void *p) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci struct hfs_inode_info *i = p; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci inode_init_once(&i->vfs_inode); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int __init init_hfs_fs(void) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci int err; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci hfs_inode_cachep = kmem_cache_create("hfs_inode_cache", 48062306a36Sopenharmony_ci sizeof(struct hfs_inode_info), 0, 48162306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, hfs_init_once); 48262306a36Sopenharmony_ci if (!hfs_inode_cachep) 48362306a36Sopenharmony_ci return -ENOMEM; 48462306a36Sopenharmony_ci err = register_filesystem(&hfs_fs_type); 48562306a36Sopenharmony_ci if (err) 48662306a36Sopenharmony_ci kmem_cache_destroy(hfs_inode_cachep); 48762306a36Sopenharmony_ci return err; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic void __exit exit_hfs_fs(void) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci unregister_filesystem(&hfs_fs_type); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* 49562306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 49662306a36Sopenharmony_ci * destroy cache. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci rcu_barrier(); 49962306a36Sopenharmony_ci kmem_cache_destroy(hfs_inode_cachep); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cimodule_init(init_hfs_fs) 50362306a36Sopenharmony_cimodule_exit(exit_hfs_fs) 504