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