udf: convert to new mount API

Convert the UDF filesystem to the new mount API.

UDF is slightly unique in that it always preserves prior mount
options across a remount, so that's handled by udf_init_options().

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Message-Id: <fcb3faf3-e2df-450c-b37a-11000c274585@redhat.com>
This commit is contained in:
Eric Sandeen 2024-02-20 15:44:52 -06:00 committed by Jan Kara
parent 7a8e72c16e
commit c4e89cc674

View File

@ -40,20 +40,20 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/parser.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/nls.h> #include <linux/nls.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mount.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/crc-itu-t.h> #include <linux/crc-itu-t.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/iversion.h> #include <linux/iversion.h>
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
#include "udf_sb.h" #include "udf_sb.h"
#include "udf_i.h" #include "udf_i.h"
@ -91,16 +91,20 @@ enum { UDF_MAX_LINKS = 0xffff };
#define UDF_MAX_FILESIZE (1ULL << 42) #define UDF_MAX_FILESIZE (1ULL << 42)
/* These are the "meat" - everything else is stuffing */ /* These are the "meat" - everything else is stuffing */
static int udf_fill_super(struct super_block *, void *, int); static int udf_fill_super(struct super_block *sb, struct fs_context *fc);
static void udf_put_super(struct super_block *); static void udf_put_super(struct super_block *);
static int udf_sync_fs(struct super_block *, int); static int udf_sync_fs(struct super_block *, int);
static int udf_remount_fs(struct super_block *, int *, char *);
static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad); static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad);
static void udf_open_lvid(struct super_block *); static void udf_open_lvid(struct super_block *);
static void udf_close_lvid(struct super_block *); static void udf_close_lvid(struct super_block *);
static unsigned int udf_count_free(struct super_block *); static unsigned int udf_count_free(struct super_block *);
static int udf_statfs(struct dentry *, struct kstatfs *); static int udf_statfs(struct dentry *, struct kstatfs *);
static int udf_show_options(struct seq_file *, struct dentry *); static int udf_show_options(struct seq_file *, struct dentry *);
static int udf_init_fs_context(struct fs_context *fc);
static int udf_parse_param(struct fs_context *fc, struct fs_parameter *param);
static int udf_reconfigure(struct fs_context *fc);
static void udf_free_fc(struct fs_context *fc);
static const struct fs_parameter_spec udf_param_spec[];
struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb) struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)
{ {
@ -119,18 +123,25 @@ struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)
} }
/* UDF filesystem type */ /* UDF filesystem type */
static struct dentry *udf_mount(struct file_system_type *fs_type, static int udf_get_tree(struct fs_context *fc)
int flags, const char *dev_name, void *data)
{ {
return mount_bdev(fs_type, flags, dev_name, data, udf_fill_super); return get_tree_bdev(fc, udf_fill_super);
} }
static const struct fs_context_operations udf_context_ops = {
.parse_param = udf_parse_param,
.get_tree = udf_get_tree,
.reconfigure = udf_reconfigure,
.free = udf_free_fc,
};
static struct file_system_type udf_fstype = { static struct file_system_type udf_fstype = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "udf", .name = "udf",
.mount = udf_mount,
.kill_sb = kill_block_super, .kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV, .fs_flags = FS_REQUIRES_DEV,
.init_fs_context = udf_init_fs_context,
.parameters = udf_param_spec,
}; };
MODULE_ALIAS_FS("udf"); MODULE_ALIAS_FS("udf");
@ -204,7 +215,6 @@ static const struct super_operations udf_sb_ops = {
.put_super = udf_put_super, .put_super = udf_put_super,
.sync_fs = udf_sync_fs, .sync_fs = udf_sync_fs,
.statfs = udf_statfs, .statfs = udf_statfs,
.remount_fs = udf_remount_fs,
.show_options = udf_show_options, .show_options = udf_show_options,
}; };
@ -222,6 +232,65 @@ struct udf_options {
struct nls_table *nls_map; struct nls_table *nls_map;
}; };
/*
* UDF has historically preserved prior mount options across
* a remount, so copy those here if remounting, otherwise set
* initial mount defaults.
*/
static void udf_init_options(struct fs_context *fc, struct udf_options *uopt)
{
if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
struct super_block *sb = fc->root->d_sb;
struct udf_sb_info *sbi = UDF_SB(sb);
uopt->flags = sbi->s_flags;
uopt->uid = sbi->s_uid;
uopt->gid = sbi->s_gid;
uopt->umask = sbi->s_umask;
uopt->fmode = sbi->s_fmode;
uopt->dmode = sbi->s_dmode;
uopt->nls_map = NULL;
} else {
uopt->flags = (1 << UDF_FLAG_USE_AD_IN_ICB) |
(1 << UDF_FLAG_STRICT);
/*
* By default we'll use overflow[ug]id when UDF
* inode [ug]id == -1
*/
uopt->uid = make_kuid(current_user_ns(), overflowuid);
uopt->gid = make_kgid(current_user_ns(), overflowgid);
uopt->umask = 0;
uopt->fmode = UDF_INVALID_MODE;
uopt->dmode = UDF_INVALID_MODE;
uopt->nls_map = NULL;
uopt->session = 0xFFFFFFFF;
}
}
static int udf_init_fs_context(struct fs_context *fc)
{
struct udf_options *uopt;
uopt = kzalloc(sizeof(*uopt), GFP_KERNEL);
if (!uopt)
return -ENOMEM;
udf_init_options(fc, uopt);
fc->fs_private = uopt;
fc->ops = &udf_context_ops;
return 0;
}
static void udf_free_fc(struct fs_context *fc)
{
struct udf_options *uopt = fc->fs_private;
unload_nls(uopt->nls_map);
kfree(fc->fs_private);
}
static int __init init_udf_fs(void) static int __init init_udf_fs(void)
{ {
int err; int err;
@ -357,7 +426,7 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root)
} }
/* /*
* udf_parse_options * udf_parse_param
* *
* PURPOSE * PURPOSE
* Parse mount options. * Parse mount options.
@ -400,12 +469,12 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root)
* yield highly unpredictable results. * yield highly unpredictable results.
* *
* PRE-CONDITIONS * PRE-CONDITIONS
* options Pointer to mount options string. * fc fs_context with pointer to mount options variable.
* uopts Pointer to mount options variable. * param Pointer to fs_parameter being parsed.
* *
* POST-CONDITIONS * POST-CONDITIONS
* <return> 1 Mount options parsed okay. * <return> 0 Mount options parsed okay.
* <return> 0 Error parsing mount options. * <return> errno Error parsing mount options.
* *
* HISTORY * HISTORY
* July 1, 1997 - Andrew E. Mileski * July 1, 1997 - Andrew E. Mileski
@ -417,74 +486,56 @@ enum {
Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad, Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad,
Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock, Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock,
Opt_anchor, Opt_volume, Opt_partition, Opt_fileset, Opt_anchor, Opt_volume, Opt_partition, Opt_fileset,
Opt_rootdir, Opt_utf8, Opt_iocharset, Opt_rootdir, Opt_utf8, Opt_iocharset, Opt_err, Opt_fmode, Opt_dmode
Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore,
Opt_fmode, Opt_dmode
}; };
static const match_table_t tokens = { static const struct fs_parameter_spec udf_param_spec[] = {
{Opt_novrs, "novrs"}, fsparam_flag ("novrs", Opt_novrs),
{Opt_nostrict, "nostrict"}, fsparam_flag ("nostrict", Opt_nostrict),
{Opt_bs, "bs=%u"}, fsparam_u32 ("bs", Opt_bs),
{Opt_unhide, "unhide"}, fsparam_flag ("unhide", Opt_unhide),
{Opt_undelete, "undelete"}, fsparam_flag ("undelete", Opt_undelete),
{Opt_noadinicb, "noadinicb"}, fsparam_flag_no ("adinicb", Opt_adinicb),
{Opt_adinicb, "adinicb"}, fsparam_flag ("shortad", Opt_shortad),
{Opt_shortad, "shortad"}, fsparam_flag ("longad", Opt_longad),
{Opt_longad, "longad"}, fsparam_string ("gid", Opt_gid),
{Opt_uforget, "uid=forget"}, fsparam_string ("uid", Opt_uid),
{Opt_uignore, "uid=ignore"}, fsparam_u32 ("umask", Opt_umask),
{Opt_gforget, "gid=forget"}, fsparam_u32 ("session", Opt_session),
{Opt_gignore, "gid=ignore"}, fsparam_u32 ("lastblock", Opt_lastblock),
{Opt_gid, "gid=%u"}, fsparam_u32 ("anchor", Opt_anchor),
{Opt_uid, "uid=%u"}, fsparam_u32 ("volume", Opt_volume),
{Opt_umask, "umask=%o"}, fsparam_u32 ("partition", Opt_partition),
{Opt_session, "session=%u"}, fsparam_u32 ("fileset", Opt_fileset),
{Opt_lastblock, "lastblock=%u"}, fsparam_u32 ("rootdir", Opt_rootdir),
{Opt_anchor, "anchor=%u"}, fsparam_flag ("utf8", Opt_utf8),
{Opt_volume, "volume=%u"}, fsparam_string ("iocharset", Opt_iocharset),
{Opt_partition, "partition=%u"}, fsparam_u32 ("mode", Opt_fmode),
{Opt_fileset, "fileset=%u"}, fsparam_u32 ("dmode", Opt_dmode),
{Opt_rootdir, "rootdir=%u"}, {}
{Opt_utf8, "utf8"},
{Opt_iocharset, "iocharset=%s"},
{Opt_fmode, "mode=%o"},
{Opt_dmode, "dmode=%o"},
{Opt_err, NULL}
}; };
static int udf_parse_options(char *options, struct udf_options *uopt, static int udf_parse_param(struct fs_context *fc, struct fs_parameter *param)
bool remount)
{ {
char *p;
int option;
unsigned int uv; unsigned int uv;
unsigned int n;
uopt->session = 0xFFFFFFFF; struct udf_options *uopt = fc->fs_private;
uopt->lastblock = 0; struct fs_parse_result result;
uopt->anchor = 0;
if (!options)
return 1;
while ((p = strsep(&options, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
int token; int token;
unsigned n; bool remount = (fc->purpose & FS_CONTEXT_FOR_RECONFIGURE);
if (!*p)
continue; token = fs_parse(fc, udf_param_spec, param, &result);
if (token < 0)
return token;
token = match_token(p, tokens, args);
switch (token) { switch (token) {
case Opt_novrs: case Opt_novrs:
uopt->flags |= (1 << UDF_FLAG_NOVRS); uopt->flags |= (1 << UDF_FLAG_NOVRS);
break; break;
case Opt_bs: case Opt_bs:
if (match_int(&args[0], &option)) n = result.uint_32;
return 0;
n = option;
if (n != 512 && n != 1024 && n != 2048 && n != 4096) if (n != 512 && n != 1024 && n != 2048 && n != 4096)
return 0; return -EINVAL;
uopt->blocksize = n; uopt->blocksize = n;
uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET); uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET);
break; break;
@ -494,10 +545,10 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
case Opt_undelete: case Opt_undelete:
uopt->flags |= (1 << UDF_FLAG_UNDELETE); uopt->flags |= (1 << UDF_FLAG_UNDELETE);
break; break;
case Opt_noadinicb:
uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
break;
case Opt_adinicb: case Opt_adinicb:
if (result.negated)
uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
else
uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB); uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
break; break;
case Opt_shortad: case Opt_shortad:
@ -507,47 +558,55 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD); uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
break; break;
case Opt_gid: case Opt_gid:
if (match_uint(args, &uv)) if (kstrtoint(param->string, 10, &uv) == 0) {
return 0; kgid_t gid = make_kgid(current_user_ns(), uv);
uopt->gid = make_kgid(current_user_ns(), uv); if (!gid_valid(gid))
if (!gid_valid(uopt->gid)) return -EINVAL;
return 0; uopt->gid = gid;
uopt->flags |= (1 << UDF_FLAG_GID_SET); uopt->flags |= (1 << UDF_FLAG_GID_SET);
} else if (!strcmp(param->string, "forget")) {
uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
} else if (!strcmp(param->string, "ignore")) {
/* this option is superseded by gid=<number> */
;
} else {
return -EINVAL;
}
break; break;
case Opt_uid: case Opt_uid:
if (match_uint(args, &uv)) if (kstrtoint(param->string, 10, &uv) == 0) {
return 0; kuid_t uid = make_kuid(current_user_ns(), uv);
uopt->uid = make_kuid(current_user_ns(), uv); if (!uid_valid(uid))
if (!uid_valid(uopt->uid)) return -EINVAL;
return 0; uopt->uid = uid;
uopt->flags |= (1 << UDF_FLAG_UID_SET); uopt->flags |= (1 << UDF_FLAG_UID_SET);
} else if (!strcmp(param->string, "forget")) {
uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
} else if (!strcmp(param->string, "ignore")) {
/* this option is superseded by uid=<number> */
;
} else {
return -EINVAL;
}
break; break;
case Opt_umask: case Opt_umask:
if (match_octal(args, &option)) uopt->umask = result.uint_32;
return 0;
uopt->umask = option;
break; break;
case Opt_nostrict: case Opt_nostrict:
uopt->flags &= ~(1 << UDF_FLAG_STRICT); uopt->flags &= ~(1 << UDF_FLAG_STRICT);
break; break;
case Opt_session: case Opt_session:
if (match_int(args, &option)) uopt->session = result.uint_32;
return 0;
uopt->session = option;
if (!remount) if (!remount)
uopt->flags |= (1 << UDF_FLAG_SESSION_SET); uopt->flags |= (1 << UDF_FLAG_SESSION_SET);
break; break;
case Opt_lastblock: case Opt_lastblock:
if (match_int(args, &option)) uopt->lastblock = result.uint_32;
return 0;
uopt->lastblock = option;
if (!remount) if (!remount)
uopt->flags |= (1 << UDF_FLAG_LASTBLOCK_SET); uopt->flags |= (1 << UDF_FLAG_LASTBLOCK_SET);
break; break;
case Opt_anchor: case Opt_anchor:
if (match_int(args, &option)) uopt->anchor = result.uint_32;
return 0;
uopt->anchor = option;
break; break;
case Opt_volume: case Opt_volume:
case Opt_partition: case Opt_partition:
@ -567,78 +626,53 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
uopt->nls_map = NULL; uopt->nls_map = NULL;
} }
/* When nls_map is not loaded then UTF-8 is used */ /* When nls_map is not loaded then UTF-8 is used */
if (!remount && strcmp(args[0].from, "utf8") != 0) { if (!remount && strcmp(param->string, "utf8") != 0) {
uopt->nls_map = load_nls(args[0].from); uopt->nls_map = load_nls(param->string);
if (!uopt->nls_map) { if (!uopt->nls_map) {
pr_err("iocharset %s not found\n", errorf(fc, "iocharset %s not found",
args[0].from); param->string);
return 0; return -EINVAL;;
} }
} }
break; break;
case Opt_uforget:
uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
break;
case Opt_uignore:
case Opt_gignore:
/* These options are superseeded by uid=<number> */
break;
case Opt_gforget:
uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
break;
case Opt_fmode: case Opt_fmode:
if (match_octal(args, &option)) uopt->fmode = result.uint_32 & 0777;
return 0;
uopt->fmode = option & 0777;
break; break;
case Opt_dmode: case Opt_dmode:
if (match_octal(args, &option)) uopt->dmode = result.uint_32 & 0777;
return 0;
uopt->dmode = option & 0777;
break; break;
default: default:
pr_err("bad mount option \"%s\" or missing value\n", p); return -EINVAL;
}
return 0; return 0;
} }
}
return 1;
}
static int udf_remount_fs(struct super_block *sb, int *flags, char *options) static int udf_reconfigure(struct fs_context *fc)
{ {
struct udf_options uopt; struct udf_options *uopt = fc->fs_private;
struct super_block *sb = fc->root->d_sb;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
int readonly = fc->sb_flags & SB_RDONLY;
int error = 0; int error = 0;
if (!(*flags & SB_RDONLY) && UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT)) if (!readonly && UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT))
return -EACCES; return -EACCES;
sync_filesystem(sb); sync_filesystem(sb);
uopt.flags = sbi->s_flags;
uopt.uid = sbi->s_uid;
uopt.gid = sbi->s_gid;
uopt.umask = sbi->s_umask;
uopt.fmode = sbi->s_fmode;
uopt.dmode = sbi->s_dmode;
uopt.nls_map = NULL;
if (!udf_parse_options(options, &uopt, true))
return -EINVAL;
write_lock(&sbi->s_cred_lock); write_lock(&sbi->s_cred_lock);
sbi->s_flags = uopt.flags; sbi->s_flags = uopt->flags;
sbi->s_uid = uopt.uid; sbi->s_uid = uopt->uid;
sbi->s_gid = uopt.gid; sbi->s_gid = uopt->gid;
sbi->s_umask = uopt.umask; sbi->s_umask = uopt->umask;
sbi->s_fmode = uopt.fmode; sbi->s_fmode = uopt->fmode;
sbi->s_dmode = uopt.dmode; sbi->s_dmode = uopt->dmode;
write_unlock(&sbi->s_cred_lock); write_unlock(&sbi->s_cred_lock);
if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) if (readonly == sb_rdonly(sb))
goto out_unlock; goto out_unlock;
if (*flags & SB_RDONLY) if (readonly)
udf_close_lvid(sb); udf_close_lvid(sb);
else else
udf_open_lvid(sb); udf_open_lvid(sb);
@ -2090,23 +2124,15 @@ u64 lvid_get_unique_id(struct super_block *sb)
return ret; return ret;
} }
static int udf_fill_super(struct super_block *sb, void *options, int silent) static int udf_fill_super(struct super_block *sb, struct fs_context *fc)
{ {
int ret = -EINVAL; int ret = -EINVAL;
struct inode *inode = NULL; struct inode *inode = NULL;
struct udf_options uopt; struct udf_options *uopt = fc->fs_private;
struct kernel_lb_addr rootdir, fileset; struct kernel_lb_addr rootdir, fileset;
struct udf_sb_info *sbi; struct udf_sb_info *sbi;
bool lvid_open = false; bool lvid_open = false;
int silent = fc->sb_flags & SB_SILENT;
uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
/* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */
uopt.uid = make_kuid(current_user_ns(), overflowuid);
uopt.gid = make_kgid(current_user_ns(), overflowgid);
uopt.umask = 0;
uopt.fmode = UDF_INVALID_MODE;
uopt.dmode = UDF_INVALID_MODE;
uopt.nls_map = NULL;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi) if (!sbi)
@ -2116,25 +2142,23 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
mutex_init(&sbi->s_alloc_mutex); mutex_init(&sbi->s_alloc_mutex);
if (!udf_parse_options((char *)options, &uopt, false))
goto parse_options_failure;
fileset.logicalBlockNum = 0xFFFFFFFF; fileset.logicalBlockNum = 0xFFFFFFFF;
fileset.partitionReferenceNum = 0xFFFF; fileset.partitionReferenceNum = 0xFFFF;
sbi->s_flags = uopt.flags; sbi->s_flags = uopt->flags;
sbi->s_uid = uopt.uid; sbi->s_uid = uopt->uid;
sbi->s_gid = uopt.gid; sbi->s_gid = uopt->gid;
sbi->s_umask = uopt.umask; sbi->s_umask = uopt->umask;
sbi->s_fmode = uopt.fmode; sbi->s_fmode = uopt->fmode;
sbi->s_dmode = uopt.dmode; sbi->s_dmode = uopt->dmode;
sbi->s_nls_map = uopt.nls_map; sbi->s_nls_map = uopt->nls_map;
uopt->nls_map = NULL;
rwlock_init(&sbi->s_cred_lock); rwlock_init(&sbi->s_cred_lock);
if (uopt.session == 0xFFFFFFFF) if (uopt->session == 0xFFFFFFFF)
sbi->s_session = udf_get_last_session(sb); sbi->s_session = udf_get_last_session(sb);
else else
sbi->s_session = uopt.session; sbi->s_session = uopt->session;
udf_debug("Multi-session=%d\n", sbi->s_session); udf_debug("Multi-session=%d\n", sbi->s_session);
@ -2145,16 +2169,16 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sb->s_magic = UDF_SUPER_MAGIC; sb->s_magic = UDF_SUPER_MAGIC;
sb->s_time_gran = 1000; sb->s_time_gran = 1000;
if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) { if (uopt->flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) {
ret = udf_load_vrs(sb, &uopt, silent, &fileset); ret = udf_load_vrs(sb, uopt, silent, &fileset);
} else { } else {
uopt.blocksize = bdev_logical_block_size(sb->s_bdev); uopt->blocksize = bdev_logical_block_size(sb->s_bdev);
while (uopt.blocksize <= 4096) { while (uopt->blocksize <= 4096) {
ret = udf_load_vrs(sb, &uopt, silent, &fileset); ret = udf_load_vrs(sb, uopt, silent, &fileset);
if (ret < 0) { if (ret < 0) {
if (!silent && ret != -EACCES) { if (!silent && ret != -EACCES) {
pr_notice("Scanning with blocksize %u failed\n", pr_notice("Scanning with blocksize %u failed\n",
uopt.blocksize); uopt->blocksize);
} }
brelse(sbi->s_lvid_bh); brelse(sbi->s_lvid_bh);
sbi->s_lvid_bh = NULL; sbi->s_lvid_bh = NULL;
@ -2167,7 +2191,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
} else } else
break; break;
uopt.blocksize <<= 1; uopt->blocksize <<= 1;
} }
} }
if (ret < 0) { if (ret < 0) {
@ -2272,8 +2296,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
error_out: error_out:
iput(sbi->s_vat_inode); iput(sbi->s_vat_inode);
parse_options_failure: unload_nls(uopt->nls_map);
unload_nls(uopt.nls_map);
if (lvid_open) if (lvid_open)
udf_close_lvid(sb); udf_close_lvid(sb);
brelse(sbi->s_lvid_bh); brelse(sbi->s_lvid_bh);