diff mbox series

[V2] isofs: convert isofs to use the new mount API

Message ID 409e28da-9c19-427a-acfb-78788f0a23b8@redhat.com (mailing list archive)
State New
Headers show
Series [V2] isofs: convert isofs to use the new mount API | expand

Commit Message

Eric Sandeen March 7, 2024, 6:56 p.m. UTC
This also renames iso9660_options to isofs_options, for
consistency.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
cc: Jan Kara <jack@suse.cz>
---

V2: fix iso9660_ naming and thinko/paste-o in _reconfigure readonly check

 fs/isofs/inode.c | 473 ++++++++++++++++++++++++-----------------------
 1 file changed, 240 insertions(+), 233 deletions(-)

Comments

Jan Kara March 13, 2024, 6:03 p.m. UTC | #1
On Thu 07-03-24 12:56:33, Eric Sandeen wrote:
> This also renames iso9660_options to isofs_options, for
> consistency.
> 
> Signed-off-by: Eric Sandeen <sandeen@redhat.com>
> cc: Jan Kara <jack@suse.cz>
> ---

The patch looks good to me. I'll merge this patch once Linus tags rc1 and
my tree gets a in sync with Linus again.

								Honza


> 
> V2: fix iso9660_ naming and thinko/paste-o in _reconfigure readonly check
> 
>  fs/isofs/inode.c | 473 ++++++++++++++++++++++++-----------------------
>  1 file changed, 240 insertions(+), 233 deletions(-)
> 
> diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
> index 3e4d53e26f94..a52b4465627d 100644
> --- a/fs/isofs/inode.c
> +++ b/fs/isofs/inode.c
> @@ -21,11 +21,12 @@
>  #include <linux/ctype.h>
>  #include <linux/statfs.h>
>  #include <linux/cdrom.h>
> -#include <linux/parser.h>
>  #include <linux/mpage.h>
>  #include <linux/user_namespace.h>
>  #include <linux/seq_file.h>
>  #include <linux/blkdev.h>
> +#include <linux/fs_context.h>
> +#include <linux/fs_parser.h>
>  
>  #include "isofs.h"
>  #include "zisofs.h"
> @@ -110,10 +111,10 @@ static void destroy_inodecache(void)
>  	kmem_cache_destroy(isofs_inode_cachep);
>  }
>  
> -static int isofs_remount(struct super_block *sb, int *flags, char *data)
> +static int isofs_reconfigure(struct fs_context *fc)
>  {
> -	sync_filesystem(sb);
> -	if (!(*flags & SB_RDONLY))
> +	sync_filesystem(fc->root->d_sb);
> +	if (!(fc->sb_flags & SB_RDONLY))
>  		return -EROFS;
>  	return 0;
>  }
> @@ -123,7 +124,6 @@ static const struct super_operations isofs_sops = {
>  	.free_inode	= isofs_free_inode,
>  	.put_super	= isofs_put_super,
>  	.statfs		= isofs_statfs,
> -	.remount_fs	= isofs_remount,
>  	.show_options	= isofs_show_options,
>  };
>  
> @@ -145,7 +145,7 @@ static const struct dentry_operations isofs_dentry_ops[] = {
>  #endif
>  };
>  
> -struct iso9660_options{
> +struct isofs_options{
>  	unsigned int rock:1;
>  	unsigned int joliet:1;
>  	unsigned int cruft:1;
> @@ -289,197 +289,161 @@ isofs_dentry_cmpi_ms(const struct dentry *dentry,
>  #endif
>  
>  enum {
> -	Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore,
> -	Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet,
> -	Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err,
> -	Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, Opt_overriderockperm,
> +	Opt_block, Opt_check, Opt_cruft, Opt_gid, Opt_ignore, Opt_iocharset,
> +	Opt_map, Opt_mode, Opt_nojoliet, Opt_norock, Opt_sb, Opt_session,
> +	Opt_uid, Opt_unhide, Opt_utf8, Opt_err, Opt_nocompress, Opt_hide,
> +	Opt_showassoc, Opt_dmode, Opt_overriderockperm,
>  };
>  
> -static const match_table_t tokens = {
> -	{Opt_norock, "norock"},
> -	{Opt_nojoliet, "nojoliet"},
> -	{Opt_unhide, "unhide"},
> -	{Opt_hide, "hide"},
> -	{Opt_showassoc, "showassoc"},
> -	{Opt_cruft, "cruft"},
> -	{Opt_utf8, "utf8"},
> -	{Opt_iocharset, "iocharset=%s"},
> -	{Opt_map_a, "map=acorn"},
> -	{Opt_map_a, "map=a"},
> -	{Opt_map_n, "map=normal"},
> -	{Opt_map_n, "map=n"},
> -	{Opt_map_o, "map=off"},
> -	{Opt_map_o, "map=o"},
> -	{Opt_session, "session=%u"},
> -	{Opt_sb, "sbsector=%u"},
> -	{Opt_check_r, "check=relaxed"},
> -	{Opt_check_r, "check=r"},
> -	{Opt_check_s, "check=strict"},
> -	{Opt_check_s, "check=s"},
> -	{Opt_uid, "uid=%u"},
> -	{Opt_gid, "gid=%u"},
> -	{Opt_mode, "mode=%u"},
> -	{Opt_dmode, "dmode=%u"},
> -	{Opt_overriderockperm, "overriderockperm"},
> -	{Opt_block, "block=%u"},
> -	{Opt_ignore, "conv=binary"},
> -	{Opt_ignore, "conv=b"},
> -	{Opt_ignore, "conv=text"},
> -	{Opt_ignore, "conv=t"},
> -	{Opt_ignore, "conv=mtext"},
> -	{Opt_ignore, "conv=m"},
> -	{Opt_ignore, "conv=auto"},
> -	{Opt_ignore, "conv=a"},
> -	{Opt_nocompress, "nocompress"},
> -	{Opt_err, NULL}
> +static const struct constant_table isofs_param_map[] = {
> +	{"acorn",	'a'},
> +	{"a",		'a'},
> +	{"normal",	'n'},
> +	{"n",		'n'},
> +	{"off",		'o'},
> +	{"o",		'o'},
> +	{}
>  };
>  
> -static int parse_options(char *options, struct iso9660_options *popt)
> -{
> -	char *p;
> -	int option;
> -	unsigned int uv;
> -
> -	popt->map = 'n';
> -	popt->rock = 1;
> -	popt->joliet = 1;
> -	popt->cruft = 0;
> -	popt->hide = 0;
> -	popt->showassoc = 0;
> -	popt->check = 'u';		/* unset */
> -	popt->nocompress = 0;
> -	popt->blocksize = 1024;
> -	popt->fmode = popt->dmode = ISOFS_INVALID_MODE;
> -	popt->uid_set = 0;
> -	popt->gid_set = 0;
> -	popt->gid = GLOBAL_ROOT_GID;
> -	popt->uid = GLOBAL_ROOT_UID;
> -	popt->iocharset = NULL;
> -	popt->overriderockperm = 0;
> -	popt->session=-1;
> -	popt->sbsector=-1;
> -	if (!options)
> -		return 1;
> -
> -	while ((p = strsep(&options, ",")) != NULL) {
> -		int token;
> -		substring_t args[MAX_OPT_ARGS];
> -		unsigned n;
> -
> -		if (!*p)
> -			continue;
> +static const struct constant_table isofs_param_check[] = {
> +	{"relaxed",	'r'},
> +	{"r",		'r'},
> +	{"strict",	's'},
> +	{"s",		's'},
> +	{}
> +};
>  
> -		token = match_token(p, tokens, args);
> -		switch (token) {
> -		case Opt_norock:
> -			popt->rock = 0;
> -			break;
> -		case Opt_nojoliet:
> -			popt->joliet = 0;
> -			break;
> -		case Opt_hide:
> -			popt->hide = 1;
> -			break;
> -		case Opt_unhide:
> -		case Opt_showassoc:
> -			popt->showassoc = 1;
> -			break;
> -		case Opt_cruft:
> -			popt->cruft = 1;
> -			break;
> +static const struct fs_parameter_spec isofs_param_spec[] = {
> +	fsparam_flag	("norock",		Opt_norock),
> +	fsparam_flag	("nojoliet",		Opt_nojoliet),
> +	fsparam_flag	("unhide",		Opt_unhide),
> +	fsparam_flag	("hide",		Opt_hide),
> +	fsparam_flag	("showassoc",		Opt_showassoc),
> +	fsparam_flag	("cruft",		Opt_cruft),
> +	fsparam_flag	("utf8",		Opt_utf8),
> +	fsparam_string	("iocharset",		Opt_iocharset),
> +	fsparam_enum	("map",			Opt_map, isofs_param_map),
> +	fsparam_u32	("session",		Opt_session),
> +	fsparam_u32	("sbsector",		Opt_sb),
> +	fsparam_enum	("check",		Opt_check, isofs_param_check),
> +	fsparam_u32	("uid",			Opt_uid),
> +	fsparam_u32	("gid",			Opt_gid),
> +	/* Note: mode/dmode historically accepted %u not strictly %o */
> +	fsparam_u32	("mode",		Opt_mode),
> +	fsparam_u32	("dmode",		Opt_dmode),
> +	fsparam_flag	("overriderockperm",	Opt_overriderockperm),
> +	fsparam_u32	("block",		Opt_block),
> +	fsparam_string	("conv",		Opt_ignore),
> +	fsparam_flag	("nocompress",		Opt_nocompress),
> +	{}
> +};
> +
> +static int isofs_parse_param(struct fs_context *fc,
> +			       struct fs_parameter *param)
> +{
> +	struct isofs_options *popt = fc->fs_private;
> +	struct fs_parse_result result;
> +	int opt;
> +	kuid_t uid;
> +	kgid_t gid;
> +	unsigned int n;
> +
> +	/* There are no remountable options */
> +	if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE)
> +		return 0;
> +
> +	opt = fs_parse(fc, isofs_param_spec, param, &result);
> +	if (opt < 0)
> +		return opt;
> +
> +	switch (opt) {
> +	case Opt_norock:
> +		popt->rock = 0;
> +		break;
> +	case Opt_nojoliet:
> +		popt->joliet = 0;
> +		break;
> +	case Opt_hide:
> +		popt->hide = 1;
> +		break;
> +	case Opt_unhide:
> +	case Opt_showassoc:
> +		popt->showassoc = 1;
> +		break;
> +	case Opt_cruft:
> +		popt->cruft = 1;
> +		break;
>  #ifdef CONFIG_JOLIET
> -		case Opt_utf8:
> -			kfree(popt->iocharset);
> -			popt->iocharset = kstrdup("utf8", GFP_KERNEL);
> -			if (!popt->iocharset)
> -				return 0;
> -			break;
> -		case Opt_iocharset:
> -			kfree(popt->iocharset);
> -			popt->iocharset = match_strdup(&args[0]);
> -			if (!popt->iocharset)
> -				return 0;
> -			break;
> +	case Opt_utf8:
> +		kfree(popt->iocharset);
> +		popt->iocharset = kstrdup("utf8", GFP_KERNEL);
> +		if (!popt->iocharset)
> +			return -ENOMEM;
> +		break;
> +	case Opt_iocharset:
> +		kfree(popt->iocharset);
> +		popt->iocharset = kstrdup(param->string, GFP_KERNEL);
> +		if (!popt->iocharset)
> +			return -ENOMEM;
> +		break;
>  #endif
> -		case Opt_map_a:
> -			popt->map = 'a';
> -			break;
> -		case Opt_map_o:
> -			popt->map = 'o';
> -			break;
> -		case Opt_map_n:
> -			popt->map = 'n';
> -			break;
> -		case Opt_session:
> -			if (match_int(&args[0], &option))
> -				return 0;
> -			n = option;
> -			/*
> -			 * Track numbers are supposed to be in range 1-99, the
> -			 * mount option starts indexing at 0.
> -			 */
> -			if (n >= 99)
> -				return 0;
> -			popt->session = n + 1;
> -			break;
> -		case Opt_sb:
> -			if (match_int(&args[0], &option))
> -				return 0;
> -			popt->sbsector = option;
> -			break;
> -		case Opt_check_r:
> -			popt->check = 'r';
> -			break;
> -		case Opt_check_s:
> -			popt->check = 's';
> -			break;
> -		case Opt_ignore:
> -			break;
> -		case Opt_uid:
> -			if (match_uint(&args[0], &uv))
> -				return 0;
> -			popt->uid = make_kuid(current_user_ns(), uv);
> -			if (!uid_valid(popt->uid))
> -				return 0;
> -			popt->uid_set = 1;
> -			break;
> -		case Opt_gid:
> -			if (match_uint(&args[0], &uv))
> -				return 0;
> -			popt->gid = make_kgid(current_user_ns(), uv);
> -			if (!gid_valid(popt->gid))
> -				return 0;
> -			popt->gid_set = 1;
> -			break;
> -		case Opt_mode:
> -			if (match_int(&args[0], &option))
> -				return 0;
> -			popt->fmode = option;
> -			break;
> -		case Opt_dmode:
> -			if (match_int(&args[0], &option))
> -				return 0;
> -			popt->dmode = option;
> -			break;
> -		case Opt_overriderockperm:
> -			popt->overriderockperm = 1;
> -			break;
> -		case Opt_block:
> -			if (match_int(&args[0], &option))
> -				return 0;
> -			n = option;
> -			if (n != 512 && n != 1024 && n != 2048)
> -				return 0;
> -			popt->blocksize = n;
> -			break;
> -		case Opt_nocompress:
> -			popt->nocompress = 1;
> -			break;
> -		default:
> -			return 0;
> -		}
> +	case Opt_map:
> +		popt->map = result.uint_32;
> +		break;
> +	case Opt_session:
> +		n = result.uint_32;
> +		/*
> +		 * Track numbers are supposed to be in range 1-99, the
> +		 * mount option starts indexing at 0.
> +		 */
> +		if (n >= 99)
> +			return -EINVAL;
> +		popt->session = n + 1;
> +		break;
> +	case Opt_sb:
> +		popt->sbsector = result.uint_32;
> +		break;
> +	case Opt_check:
> +		popt->check = result.uint_32;
> +		break;
> +	case Opt_ignore:
> +		break;
> +	case Opt_uid:
> +		uid = make_kuid(current_user_ns(), result.uint_32);
> +		if (!uid_valid(uid))
> +			return -EINVAL;
> +		popt->uid = uid;
> +		popt->uid_set = 1;
> +		break;
> +	case Opt_gid:
> +		gid = make_kgid(current_user_ns(), result.uint_32);
> +		if (!gid_valid(gid))
> +			return -EINVAL;
> +		popt->gid = gid;
> +		popt->gid_set = 1;
> +		break;
> +	case Opt_mode:
> +		popt->fmode = result.uint_32;
> +		break;
> +	case Opt_dmode:
> +		popt->dmode = result.uint_32;
> +		break;
> +	case Opt_overriderockperm:
> +		popt->overriderockperm = 1;
> +		break;
> +	case Opt_block:
> +		n = result.uint_32;
> +		if (n != 512 && n != 1024 && n != 2048)
> +			return -EINVAL;
> +		popt->blocksize = n;
> +		break;
> +	case Opt_nocompress:
> +		popt->nocompress = 1;
> +		break;
> +	default:
> +		return -EINVAL;
>  	}
> -	return 1;
> +	return 0;
>  }
>  
>  /*
> @@ -615,7 +579,7 @@ static bool rootdir_empty(struct super_block *sb, unsigned long block)
>  /*
>   * Initialize the superblock and read the root inode.
>   */
> -static int isofs_fill_super(struct super_block *s, void *data, int silent)
> +static int isofs_fill_super(struct super_block *s, struct fs_context *fc)
>  {
>  	struct buffer_head *bh = NULL, *pri_bh = NULL;
>  	struct hs_primary_descriptor *h_pri = NULL;
> @@ -623,7 +587,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  	struct iso_supplementary_descriptor *sec = NULL;
>  	struct iso_directory_record *rootp;
>  	struct inode *inode;
> -	struct iso9660_options opt;
> +	struct isofs_options *opt = fc->fs_private;
>  	struct isofs_sb_info *sbi;
>  	unsigned long first_data_zone;
>  	int joliet_level = 0;
> @@ -631,15 +595,13 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  	int orig_zonesize;
>  	int table, error = -EINVAL;
>  	unsigned int vol_desc_start;
> +	int silent = fc->sb_flags & SB_SILENT;
>  
>  	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
>  	if (!sbi)
>  		return -ENOMEM;
>  	s->s_fs_info = sbi;
>  
> -	if (!parse_options((char *)data, &opt))
> -		goto out_freesbi;
> -
>  	/*
>  	 * First of all, get the hardware blocksize for this device.
>  	 * If we don't know what it is, or the hardware blocksize is
> @@ -655,14 +617,14 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  			bdev_logical_block_size(s->s_bdev));
>  		goto out_freesbi;
>  	}
> -	opt.blocksize = sb_min_blocksize(s, opt.blocksize);
> +	opt->blocksize = sb_min_blocksize(s, opt->blocksize);
>  
>  	sbi->s_high_sierra = 0; /* default is iso9660 */
> -	sbi->s_session = opt.session;
> -	sbi->s_sbsector = opt.sbsector;
> +	sbi->s_session = opt->session;
> +	sbi->s_sbsector = opt->sbsector;
>  
> -	vol_desc_start = (opt.sbsector != -1) ?
> -		opt.sbsector : isofs_get_last_session(s,opt.session);
> +	vol_desc_start = (opt->sbsector != -1) ?
> +		opt->sbsector : isofs_get_last_session(s, opt->session);
>  
>  	for (iso_blknum = vol_desc_start+16;
>  		iso_blknum < vol_desc_start+100; iso_blknum++) {
> @@ -696,7 +658,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  			else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) {
>  				sec = (struct iso_supplementary_descriptor *)vdp;
>  				if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
> -					if (opt.joliet) {
> +					if (opt->joliet) {
>  						if (sec->escape[2] == 0x40)
>  							joliet_level = 1;
>  						else if (sec->escape[2] == 0x43)
> @@ -721,7 +683,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  					goto out_freebh;
>  
>  				sbi->s_high_sierra = 1;
> -				opt.rock = 0;
> +				opt->rock = 0;
>  				h_pri = (struct hs_primary_descriptor *)vdp;
>  				goto root_found;
>  			}
> @@ -749,7 +711,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  		goto out_freebh;
>  	}
>  
> -	if (joliet_level && (!pri || !opt.rock)) {
> +	if (joliet_level && (!pri || !opt->rock)) {
>  		/* This is the case of Joliet with the norock mount flag.
>  		 * A disc with both Joliet and Rock Ridge is handled later
>  		 */
> @@ -780,7 +742,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  	 * blocks that were 512 bytes (which should only very rarely
>  	 * happen.)
>  	 */
> -	if (orig_zonesize < opt.blocksize)
> +	if (orig_zonesize < opt->blocksize)
>  		goto out_bad_size;
>  
>  	/* RDE: convert log zone size to bit shift */
> @@ -865,10 +827,10 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  
>  #ifdef CONFIG_JOLIET
>  	if (joliet_level) {
> -		char *p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
> +		char *p = opt->iocharset ? opt->iocharset : CONFIG_NLS_DEFAULT;
>  		if (strcmp(p, "utf8") != 0) {
> -			sbi->s_nls_iocharset = opt.iocharset ?
> -				load_nls(opt.iocharset) : load_nls_default();
> +			sbi->s_nls_iocharset = opt->iocharset ?
> +				load_nls(opt->iocharset) : load_nls_default();
>  			if (!sbi->s_nls_iocharset)
>  				goto out_freesbi;
>  		}
> @@ -876,29 +838,29 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  #endif
>  	s->s_op = &isofs_sops;
>  	s->s_export_op = &isofs_export_ops;
> -	sbi->s_mapping = opt.map;
> -	sbi->s_rock = (opt.rock ? 2 : 0);
> +	sbi->s_mapping = opt->map;
> +	sbi->s_rock = (opt->rock ? 2 : 0);
>  	sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/
> -	sbi->s_cruft = opt.cruft;
> -	sbi->s_hide = opt.hide;
> -	sbi->s_showassoc = opt.showassoc;
> -	sbi->s_uid = opt.uid;
> -	sbi->s_gid = opt.gid;
> -	sbi->s_uid_set = opt.uid_set;
> -	sbi->s_gid_set = opt.gid_set;
> -	sbi->s_nocompress = opt.nocompress;
> -	sbi->s_overriderockperm = opt.overriderockperm;
> +	sbi->s_cruft = opt->cruft;
> +	sbi->s_hide = opt->hide;
> +	sbi->s_showassoc = opt->showassoc;
> +	sbi->s_uid = opt->uid;
> +	sbi->s_gid = opt->gid;
> +	sbi->s_uid_set = opt->uid_set;
> +	sbi->s_gid_set = opt->gid_set;
> +	sbi->s_nocompress = opt->nocompress;
> +	sbi->s_overriderockperm = opt->overriderockperm;
>  	/*
>  	 * It would be incredibly stupid to allow people to mark every file
>  	 * on the disk as suid, so we merely allow them to set the default
>  	 * permissions.
>  	 */
> -	if (opt.fmode != ISOFS_INVALID_MODE)
> -		sbi->s_fmode = opt.fmode & 0777;
> +	if (opt->fmode != ISOFS_INVALID_MODE)
> +		sbi->s_fmode = opt->fmode & 0777;
>  	else
>  		sbi->s_fmode = ISOFS_INVALID_MODE;
> -	if (opt.dmode != ISOFS_INVALID_MODE)
> -		sbi->s_dmode = opt.dmode & 0777;
> +	if (opt->dmode != ISOFS_INVALID_MODE)
> +		sbi->s_dmode = opt->dmode & 0777;
>  	else
>  		sbi->s_dmode = ISOFS_INVALID_MODE;
>  
> @@ -946,12 +908,12 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  		}
>  	}
>  
> -	if (opt.check == 'u') {
> +	if (opt->check == 'u') {
>  		/* Only Joliet is case insensitive by default */
>  		if (joliet_level)
> -			opt.check = 'r';
> +			opt->check = 'r';
>  		else
> -			opt.check = 's';
> +			opt->check = 's';
>  	}
>  	sbi->s_joliet_level = joliet_level;
>  
> @@ -966,9 +928,9 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  	table = 0;
>  	if (joliet_level)
>  		table += 2;
> -	if (opt.check == 'r')
> +	if (opt->check == 'r')
>  		table++;
> -	sbi->s_check = opt.check;
> +	sbi->s_check = opt->check;
>  
>  	if (table)
>  		s->s_d_op = &isofs_dentry_ops[table - 1];
> @@ -980,7 +942,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  		goto out_no_inode;
>  	}
>  
> -	kfree(opt.iocharset);
> +	kfree(opt->iocharset);
>  
>  	return 0;
>  
> @@ -1009,7 +971,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  	goto out_freebh;
>  out_bad_size:
>  	printk(KERN_WARNING "ISOFS: Logical zone size(%d) < hardware blocksize(%u)\n",
> -		orig_zonesize, opt.blocksize);
> +		orig_zonesize, opt->blocksize);
>  	goto out_freebh;
>  out_unknown_format:
>  	if (!silent)
> @@ -1019,7 +981,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
>  	brelse(bh);
>  	brelse(pri_bh);
>  out_freesbi:
> -	kfree(opt.iocharset);
> +	kfree(opt->iocharset);
>  	kfree(sbi);
>  	s->s_fs_info = NULL;
>  	return error;
> @@ -1553,18 +1515,63 @@ struct inode *__isofs_iget(struct super_block *sb,
>  	return inode;
>  }
>  
> -static struct dentry *isofs_mount(struct file_system_type *fs_type,
> -	int flags, const char *dev_name, void *data)
> +static int isofs_get_tree(struct fs_context *fc)
>  {
> -	return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
> +	return get_tree_bdev(fc, isofs_fill_super);
> +}
> +
> +static void isofs_free_fc(struct fs_context *fc)
> +{
> +	kfree(fc->fs_private);
> +}
> +
> +static const struct fs_context_operations isofs_context_ops = {
> +	.parse_param	= isofs_parse_param,
> +	.get_tree	= isofs_get_tree,
> +	.reconfigure	= isofs_reconfigure,
> +	.free		= isofs_free_fc,
> +};
> +
> +static int isofs_init_fs_context(struct fs_context *fc)
> +{
> +	struct isofs_options *opt;
> +
> +	opt = kzalloc(sizeof(*opt), GFP_KERNEL);
> +	if (!opt)
> +		return -ENOMEM;
> +
> +	opt->map = 'n';
> +	opt->rock = 1;
> +	opt->joliet = 1;
> +	opt->cruft = 0;
> +	opt->hide = 0;
> +	opt->showassoc = 0;
> +	opt->check = 'u';		/* unset */
> +	opt->nocompress = 0;
> +	opt->blocksize = 1024;
> +	opt->fmode = opt->dmode = ISOFS_INVALID_MODE;
> +	opt->uid_set = 0;
> +	opt->gid_set = 0;
> +	opt->gid = GLOBAL_ROOT_GID;
> +	opt->uid = GLOBAL_ROOT_UID;
> +	opt->iocharset = NULL;
> +	opt->overriderockperm = 0;
> +	opt->session = -1;
> +	opt->sbsector = -1;
> +
> +	fc->fs_private = opt;
> +	fc->ops = &isofs_context_ops;
> +
> +	return 0;
>  }
>  
>  static struct file_system_type iso9660_fs_type = {
>  	.owner		= THIS_MODULE,
>  	.name		= "iso9660",
> -	.mount		= isofs_mount,
>  	.kill_sb	= kill_block_super,
>  	.fs_flags	= FS_REQUIRES_DEV,
> +	.init_fs_context = isofs_init_fs_context,
> +	.parameters	= isofs_param_spec,
>  };
>  MODULE_ALIAS_FS("iso9660");
>  MODULE_ALIAS("iso9660");
> -- 
> 2.43.0
>
diff mbox series

Patch

diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 3e4d53e26f94..a52b4465627d 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -21,11 +21,12 @@ 
 #include <linux/ctype.h>
 #include <linux/statfs.h>
 #include <linux/cdrom.h>
-#include <linux/parser.h>
 #include <linux/mpage.h>
 #include <linux/user_namespace.h>
 #include <linux/seq_file.h>
 #include <linux/blkdev.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 
 #include "isofs.h"
 #include "zisofs.h"
@@ -110,10 +111,10 @@  static void destroy_inodecache(void)
 	kmem_cache_destroy(isofs_inode_cachep);
 }
 
-static int isofs_remount(struct super_block *sb, int *flags, char *data)
+static int isofs_reconfigure(struct fs_context *fc)
 {
-	sync_filesystem(sb);
-	if (!(*flags & SB_RDONLY))
+	sync_filesystem(fc->root->d_sb);
+	if (!(fc->sb_flags & SB_RDONLY))
 		return -EROFS;
 	return 0;
 }
@@ -123,7 +124,6 @@  static const struct super_operations isofs_sops = {
 	.free_inode	= isofs_free_inode,
 	.put_super	= isofs_put_super,
 	.statfs		= isofs_statfs,
-	.remount_fs	= isofs_remount,
 	.show_options	= isofs_show_options,
 };
 
@@ -145,7 +145,7 @@  static const struct dentry_operations isofs_dentry_ops[] = {
 #endif
 };
 
-struct iso9660_options{
+struct isofs_options{
 	unsigned int rock:1;
 	unsigned int joliet:1;
 	unsigned int cruft:1;
@@ -289,197 +289,161 @@  isofs_dentry_cmpi_ms(const struct dentry *dentry,
 #endif
 
 enum {
-	Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore,
-	Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet,
-	Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err,
-	Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, Opt_overriderockperm,
+	Opt_block, Opt_check, Opt_cruft, Opt_gid, Opt_ignore, Opt_iocharset,
+	Opt_map, Opt_mode, Opt_nojoliet, Opt_norock, Opt_sb, Opt_session,
+	Opt_uid, Opt_unhide, Opt_utf8, Opt_err, Opt_nocompress, Opt_hide,
+	Opt_showassoc, Opt_dmode, Opt_overriderockperm,
 };
 
-static const match_table_t tokens = {
-	{Opt_norock, "norock"},
-	{Opt_nojoliet, "nojoliet"},
-	{Opt_unhide, "unhide"},
-	{Opt_hide, "hide"},
-	{Opt_showassoc, "showassoc"},
-	{Opt_cruft, "cruft"},
-	{Opt_utf8, "utf8"},
-	{Opt_iocharset, "iocharset=%s"},
-	{Opt_map_a, "map=acorn"},
-	{Opt_map_a, "map=a"},
-	{Opt_map_n, "map=normal"},
-	{Opt_map_n, "map=n"},
-	{Opt_map_o, "map=off"},
-	{Opt_map_o, "map=o"},
-	{Opt_session, "session=%u"},
-	{Opt_sb, "sbsector=%u"},
-	{Opt_check_r, "check=relaxed"},
-	{Opt_check_r, "check=r"},
-	{Opt_check_s, "check=strict"},
-	{Opt_check_s, "check=s"},
-	{Opt_uid, "uid=%u"},
-	{Opt_gid, "gid=%u"},
-	{Opt_mode, "mode=%u"},
-	{Opt_dmode, "dmode=%u"},
-	{Opt_overriderockperm, "overriderockperm"},
-	{Opt_block, "block=%u"},
-	{Opt_ignore, "conv=binary"},
-	{Opt_ignore, "conv=b"},
-	{Opt_ignore, "conv=text"},
-	{Opt_ignore, "conv=t"},
-	{Opt_ignore, "conv=mtext"},
-	{Opt_ignore, "conv=m"},
-	{Opt_ignore, "conv=auto"},
-	{Opt_ignore, "conv=a"},
-	{Opt_nocompress, "nocompress"},
-	{Opt_err, NULL}
+static const struct constant_table isofs_param_map[] = {
+	{"acorn",	'a'},
+	{"a",		'a'},
+	{"normal",	'n'},
+	{"n",		'n'},
+	{"off",		'o'},
+	{"o",		'o'},
+	{}
 };
 
-static int parse_options(char *options, struct iso9660_options *popt)
-{
-	char *p;
-	int option;
-	unsigned int uv;
-
-	popt->map = 'n';
-	popt->rock = 1;
-	popt->joliet = 1;
-	popt->cruft = 0;
-	popt->hide = 0;
-	popt->showassoc = 0;
-	popt->check = 'u';		/* unset */
-	popt->nocompress = 0;
-	popt->blocksize = 1024;
-	popt->fmode = popt->dmode = ISOFS_INVALID_MODE;
-	popt->uid_set = 0;
-	popt->gid_set = 0;
-	popt->gid = GLOBAL_ROOT_GID;
-	popt->uid = GLOBAL_ROOT_UID;
-	popt->iocharset = NULL;
-	popt->overriderockperm = 0;
-	popt->session=-1;
-	popt->sbsector=-1;
-	if (!options)
-		return 1;
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		int token;
-		substring_t args[MAX_OPT_ARGS];
-		unsigned n;
-
-		if (!*p)
-			continue;
+static const struct constant_table isofs_param_check[] = {
+	{"relaxed",	'r'},
+	{"r",		'r'},
+	{"strict",	's'},
+	{"s",		's'},
+	{}
+};
 
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_norock:
-			popt->rock = 0;
-			break;
-		case Opt_nojoliet:
-			popt->joliet = 0;
-			break;
-		case Opt_hide:
-			popt->hide = 1;
-			break;
-		case Opt_unhide:
-		case Opt_showassoc:
-			popt->showassoc = 1;
-			break;
-		case Opt_cruft:
-			popt->cruft = 1;
-			break;
+static const struct fs_parameter_spec isofs_param_spec[] = {
+	fsparam_flag	("norock",		Opt_norock),
+	fsparam_flag	("nojoliet",		Opt_nojoliet),
+	fsparam_flag	("unhide",		Opt_unhide),
+	fsparam_flag	("hide",		Opt_hide),
+	fsparam_flag	("showassoc",		Opt_showassoc),
+	fsparam_flag	("cruft",		Opt_cruft),
+	fsparam_flag	("utf8",		Opt_utf8),
+	fsparam_string	("iocharset",		Opt_iocharset),
+	fsparam_enum	("map",			Opt_map, isofs_param_map),
+	fsparam_u32	("session",		Opt_session),
+	fsparam_u32	("sbsector",		Opt_sb),
+	fsparam_enum	("check",		Opt_check, isofs_param_check),
+	fsparam_u32	("uid",			Opt_uid),
+	fsparam_u32	("gid",			Opt_gid),
+	/* Note: mode/dmode historically accepted %u not strictly %o */
+	fsparam_u32	("mode",		Opt_mode),
+	fsparam_u32	("dmode",		Opt_dmode),
+	fsparam_flag	("overriderockperm",	Opt_overriderockperm),
+	fsparam_u32	("block",		Opt_block),
+	fsparam_string	("conv",		Opt_ignore),
+	fsparam_flag	("nocompress",		Opt_nocompress),
+	{}
+};
+
+static int isofs_parse_param(struct fs_context *fc,
+			       struct fs_parameter *param)
+{
+	struct isofs_options *popt = fc->fs_private;
+	struct fs_parse_result result;
+	int opt;
+	kuid_t uid;
+	kgid_t gid;
+	unsigned int n;
+
+	/* There are no remountable options */
+	if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE)
+		return 0;
+
+	opt = fs_parse(fc, isofs_param_spec, param, &result);
+	if (opt < 0)
+		return opt;
+
+	switch (opt) {
+	case Opt_norock:
+		popt->rock = 0;
+		break;
+	case Opt_nojoliet:
+		popt->joliet = 0;
+		break;
+	case Opt_hide:
+		popt->hide = 1;
+		break;
+	case Opt_unhide:
+	case Opt_showassoc:
+		popt->showassoc = 1;
+		break;
+	case Opt_cruft:
+		popt->cruft = 1;
+		break;
 #ifdef CONFIG_JOLIET
-		case Opt_utf8:
-			kfree(popt->iocharset);
-			popt->iocharset = kstrdup("utf8", GFP_KERNEL);
-			if (!popt->iocharset)
-				return 0;
-			break;
-		case Opt_iocharset:
-			kfree(popt->iocharset);
-			popt->iocharset = match_strdup(&args[0]);
-			if (!popt->iocharset)
-				return 0;
-			break;
+	case Opt_utf8:
+		kfree(popt->iocharset);
+		popt->iocharset = kstrdup("utf8", GFP_KERNEL);
+		if (!popt->iocharset)
+			return -ENOMEM;
+		break;
+	case Opt_iocharset:
+		kfree(popt->iocharset);
+		popt->iocharset = kstrdup(param->string, GFP_KERNEL);
+		if (!popt->iocharset)
+			return -ENOMEM;
+		break;
 #endif
-		case Opt_map_a:
-			popt->map = 'a';
-			break;
-		case Opt_map_o:
-			popt->map = 'o';
-			break;
-		case Opt_map_n:
-			popt->map = 'n';
-			break;
-		case Opt_session:
-			if (match_int(&args[0], &option))
-				return 0;
-			n = option;
-			/*
-			 * Track numbers are supposed to be in range 1-99, the
-			 * mount option starts indexing at 0.
-			 */
-			if (n >= 99)
-				return 0;
-			popt->session = n + 1;
-			break;
-		case Opt_sb:
-			if (match_int(&args[0], &option))
-				return 0;
-			popt->sbsector = option;
-			break;
-		case Opt_check_r:
-			popt->check = 'r';
-			break;
-		case Opt_check_s:
-			popt->check = 's';
-			break;
-		case Opt_ignore:
-			break;
-		case Opt_uid:
-			if (match_uint(&args[0], &uv))
-				return 0;
-			popt->uid = make_kuid(current_user_ns(), uv);
-			if (!uid_valid(popt->uid))
-				return 0;
-			popt->uid_set = 1;
-			break;
-		case Opt_gid:
-			if (match_uint(&args[0], &uv))
-				return 0;
-			popt->gid = make_kgid(current_user_ns(), uv);
-			if (!gid_valid(popt->gid))
-				return 0;
-			popt->gid_set = 1;
-			break;
-		case Opt_mode:
-			if (match_int(&args[0], &option))
-				return 0;
-			popt->fmode = option;
-			break;
-		case Opt_dmode:
-			if (match_int(&args[0], &option))
-				return 0;
-			popt->dmode = option;
-			break;
-		case Opt_overriderockperm:
-			popt->overriderockperm = 1;
-			break;
-		case Opt_block:
-			if (match_int(&args[0], &option))
-				return 0;
-			n = option;
-			if (n != 512 && n != 1024 && n != 2048)
-				return 0;
-			popt->blocksize = n;
-			break;
-		case Opt_nocompress:
-			popt->nocompress = 1;
-			break;
-		default:
-			return 0;
-		}
+	case Opt_map:
+		popt->map = result.uint_32;
+		break;
+	case Opt_session:
+		n = result.uint_32;
+		/*
+		 * Track numbers are supposed to be in range 1-99, the
+		 * mount option starts indexing at 0.
+		 */
+		if (n >= 99)
+			return -EINVAL;
+		popt->session = n + 1;
+		break;
+	case Opt_sb:
+		popt->sbsector = result.uint_32;
+		break;
+	case Opt_check:
+		popt->check = result.uint_32;
+		break;
+	case Opt_ignore:
+		break;
+	case Opt_uid:
+		uid = make_kuid(current_user_ns(), result.uint_32);
+		if (!uid_valid(uid))
+			return -EINVAL;
+		popt->uid = uid;
+		popt->uid_set = 1;
+		break;
+	case Opt_gid:
+		gid = make_kgid(current_user_ns(), result.uint_32);
+		if (!gid_valid(gid))
+			return -EINVAL;
+		popt->gid = gid;
+		popt->gid_set = 1;
+		break;
+	case Opt_mode:
+		popt->fmode = result.uint_32;
+		break;
+	case Opt_dmode:
+		popt->dmode = result.uint_32;
+		break;
+	case Opt_overriderockperm:
+		popt->overriderockperm = 1;
+		break;
+	case Opt_block:
+		n = result.uint_32;
+		if (n != 512 && n != 1024 && n != 2048)
+			return -EINVAL;
+		popt->blocksize = n;
+		break;
+	case Opt_nocompress:
+		popt->nocompress = 1;
+		break;
+	default:
+		return -EINVAL;
 	}
-	return 1;
+	return 0;
 }
 
 /*
@@ -615,7 +579,7 @@  static bool rootdir_empty(struct super_block *sb, unsigned long block)
 /*
  * Initialize the superblock and read the root inode.
  */
-static int isofs_fill_super(struct super_block *s, void *data, int silent)
+static int isofs_fill_super(struct super_block *s, struct fs_context *fc)
 {
 	struct buffer_head *bh = NULL, *pri_bh = NULL;
 	struct hs_primary_descriptor *h_pri = NULL;
@@ -623,7 +587,7 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 	struct iso_supplementary_descriptor *sec = NULL;
 	struct iso_directory_record *rootp;
 	struct inode *inode;
-	struct iso9660_options opt;
+	struct isofs_options *opt = fc->fs_private;
 	struct isofs_sb_info *sbi;
 	unsigned long first_data_zone;
 	int joliet_level = 0;
@@ -631,15 +595,13 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 	int orig_zonesize;
 	int table, error = -EINVAL;
 	unsigned int vol_desc_start;
+	int silent = fc->sb_flags & SB_SILENT;
 
 	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
 	s->s_fs_info = sbi;
 
-	if (!parse_options((char *)data, &opt))
-		goto out_freesbi;
-
 	/*
 	 * First of all, get the hardware blocksize for this device.
 	 * If we don't know what it is, or the hardware blocksize is
@@ -655,14 +617,14 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 			bdev_logical_block_size(s->s_bdev));
 		goto out_freesbi;
 	}
-	opt.blocksize = sb_min_blocksize(s, opt.blocksize);
+	opt->blocksize = sb_min_blocksize(s, opt->blocksize);
 
 	sbi->s_high_sierra = 0; /* default is iso9660 */
-	sbi->s_session = opt.session;
-	sbi->s_sbsector = opt.sbsector;
+	sbi->s_session = opt->session;
+	sbi->s_sbsector = opt->sbsector;
 
-	vol_desc_start = (opt.sbsector != -1) ?
-		opt.sbsector : isofs_get_last_session(s,opt.session);
+	vol_desc_start = (opt->sbsector != -1) ?
+		opt->sbsector : isofs_get_last_session(s, opt->session);
 
 	for (iso_blknum = vol_desc_start+16;
 		iso_blknum < vol_desc_start+100; iso_blknum++) {
@@ -696,7 +658,7 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 			else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) {
 				sec = (struct iso_supplementary_descriptor *)vdp;
 				if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
-					if (opt.joliet) {
+					if (opt->joliet) {
 						if (sec->escape[2] == 0x40)
 							joliet_level = 1;
 						else if (sec->escape[2] == 0x43)
@@ -721,7 +683,7 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 					goto out_freebh;
 
 				sbi->s_high_sierra = 1;
-				opt.rock = 0;
+				opt->rock = 0;
 				h_pri = (struct hs_primary_descriptor *)vdp;
 				goto root_found;
 			}
@@ -749,7 +711,7 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 		goto out_freebh;
 	}
 
-	if (joliet_level && (!pri || !opt.rock)) {
+	if (joliet_level && (!pri || !opt->rock)) {
 		/* This is the case of Joliet with the norock mount flag.
 		 * A disc with both Joliet and Rock Ridge is handled later
 		 */
@@ -780,7 +742,7 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 	 * blocks that were 512 bytes (which should only very rarely
 	 * happen.)
 	 */
-	if (orig_zonesize < opt.blocksize)
+	if (orig_zonesize < opt->blocksize)
 		goto out_bad_size;
 
 	/* RDE: convert log zone size to bit shift */
@@ -865,10 +827,10 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 
 #ifdef CONFIG_JOLIET
 	if (joliet_level) {
-		char *p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
+		char *p = opt->iocharset ? opt->iocharset : CONFIG_NLS_DEFAULT;
 		if (strcmp(p, "utf8") != 0) {
-			sbi->s_nls_iocharset = opt.iocharset ?
-				load_nls(opt.iocharset) : load_nls_default();
+			sbi->s_nls_iocharset = opt->iocharset ?
+				load_nls(opt->iocharset) : load_nls_default();
 			if (!sbi->s_nls_iocharset)
 				goto out_freesbi;
 		}
@@ -876,29 +838,29 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 #endif
 	s->s_op = &isofs_sops;
 	s->s_export_op = &isofs_export_ops;
-	sbi->s_mapping = opt.map;
-	sbi->s_rock = (opt.rock ? 2 : 0);
+	sbi->s_mapping = opt->map;
+	sbi->s_rock = (opt->rock ? 2 : 0);
 	sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/
-	sbi->s_cruft = opt.cruft;
-	sbi->s_hide = opt.hide;
-	sbi->s_showassoc = opt.showassoc;
-	sbi->s_uid = opt.uid;
-	sbi->s_gid = opt.gid;
-	sbi->s_uid_set = opt.uid_set;
-	sbi->s_gid_set = opt.gid_set;
-	sbi->s_nocompress = opt.nocompress;
-	sbi->s_overriderockperm = opt.overriderockperm;
+	sbi->s_cruft = opt->cruft;
+	sbi->s_hide = opt->hide;
+	sbi->s_showassoc = opt->showassoc;
+	sbi->s_uid = opt->uid;
+	sbi->s_gid = opt->gid;
+	sbi->s_uid_set = opt->uid_set;
+	sbi->s_gid_set = opt->gid_set;
+	sbi->s_nocompress = opt->nocompress;
+	sbi->s_overriderockperm = opt->overriderockperm;
 	/*
 	 * It would be incredibly stupid to allow people to mark every file
 	 * on the disk as suid, so we merely allow them to set the default
 	 * permissions.
 	 */
-	if (opt.fmode != ISOFS_INVALID_MODE)
-		sbi->s_fmode = opt.fmode & 0777;
+	if (opt->fmode != ISOFS_INVALID_MODE)
+		sbi->s_fmode = opt->fmode & 0777;
 	else
 		sbi->s_fmode = ISOFS_INVALID_MODE;
-	if (opt.dmode != ISOFS_INVALID_MODE)
-		sbi->s_dmode = opt.dmode & 0777;
+	if (opt->dmode != ISOFS_INVALID_MODE)
+		sbi->s_dmode = opt->dmode & 0777;
 	else
 		sbi->s_dmode = ISOFS_INVALID_MODE;
 
@@ -946,12 +908,12 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 		}
 	}
 
-	if (opt.check == 'u') {
+	if (opt->check == 'u') {
 		/* Only Joliet is case insensitive by default */
 		if (joliet_level)
-			opt.check = 'r';
+			opt->check = 'r';
 		else
-			opt.check = 's';
+			opt->check = 's';
 	}
 	sbi->s_joliet_level = joliet_level;
 
@@ -966,9 +928,9 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 	table = 0;
 	if (joliet_level)
 		table += 2;
-	if (opt.check == 'r')
+	if (opt->check == 'r')
 		table++;
-	sbi->s_check = opt.check;
+	sbi->s_check = opt->check;
 
 	if (table)
 		s->s_d_op = &isofs_dentry_ops[table - 1];
@@ -980,7 +942,7 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 		goto out_no_inode;
 	}
 
-	kfree(opt.iocharset);
+	kfree(opt->iocharset);
 
 	return 0;
 
@@ -1009,7 +971,7 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 	goto out_freebh;
 out_bad_size:
 	printk(KERN_WARNING "ISOFS: Logical zone size(%d) < hardware blocksize(%u)\n",
-		orig_zonesize, opt.blocksize);
+		orig_zonesize, opt->blocksize);
 	goto out_freebh;
 out_unknown_format:
 	if (!silent)
@@ -1019,7 +981,7 @@  static int isofs_fill_super(struct super_block *s, void *data, int silent)
 	brelse(bh);
 	brelse(pri_bh);
 out_freesbi:
-	kfree(opt.iocharset);
+	kfree(opt->iocharset);
 	kfree(sbi);
 	s->s_fs_info = NULL;
 	return error;
@@ -1553,18 +1515,63 @@  struct inode *__isofs_iget(struct super_block *sb,
 	return inode;
 }
 
-static struct dentry *isofs_mount(struct file_system_type *fs_type,
-	int flags, const char *dev_name, void *data)
+static int isofs_get_tree(struct fs_context *fc)
 {
-	return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
+	return get_tree_bdev(fc, isofs_fill_super);
+}
+
+static void isofs_free_fc(struct fs_context *fc)
+{
+	kfree(fc->fs_private);
+}
+
+static const struct fs_context_operations isofs_context_ops = {
+	.parse_param	= isofs_parse_param,
+	.get_tree	= isofs_get_tree,
+	.reconfigure	= isofs_reconfigure,
+	.free		= isofs_free_fc,
+};
+
+static int isofs_init_fs_context(struct fs_context *fc)
+{
+	struct isofs_options *opt;
+
+	opt = kzalloc(sizeof(*opt), GFP_KERNEL);
+	if (!opt)
+		return -ENOMEM;
+
+	opt->map = 'n';
+	opt->rock = 1;
+	opt->joliet = 1;
+	opt->cruft = 0;
+	opt->hide = 0;
+	opt->showassoc = 0;
+	opt->check = 'u';		/* unset */
+	opt->nocompress = 0;
+	opt->blocksize = 1024;
+	opt->fmode = opt->dmode = ISOFS_INVALID_MODE;
+	opt->uid_set = 0;
+	opt->gid_set = 0;
+	opt->gid = GLOBAL_ROOT_GID;
+	opt->uid = GLOBAL_ROOT_UID;
+	opt->iocharset = NULL;
+	opt->overriderockperm = 0;
+	opt->session = -1;
+	opt->sbsector = -1;
+
+	fc->fs_private = opt;
+	fc->ops = &isofs_context_ops;
+
+	return 0;
 }
 
 static struct file_system_type iso9660_fs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "iso9660",
-	.mount		= isofs_mount,
 	.kill_sb	= kill_block_super,
 	.fs_flags	= FS_REQUIRES_DEV,
+	.init_fs_context = isofs_init_fs_context,
+	.parameters	= isofs_param_spec,
 };
 MODULE_ALIAS_FS("iso9660");
 MODULE_ALIAS("iso9660");