On Thu, Oct 24, 2019 at 03:52:04PM +0800, Ian Kent wrote: > Define the struct fs_parameter_spec table that's used by the new mount > api for options parsing. > > Create the various fs context operations methods and define the > fs_context_operations struct. > > Create the fs context initialization method and update the struct > file_system_type to utilize it. The initialization function is > responsible for working storage initialization, allocation and > initialization of file system private information storage and for > setting the operations in the fs context. > > With the new mount api the options parsing and the filling of the super > block are done seperately. Becuase of this it's sometimes necessary to > communicate intermediate values between the options parsing and the > fill super functions. > > Define struct xfs_fc_context that holds intermediate values set from the > passed options. The fields dsunit and dswidth depend on one another so > the checks and setting of struct xfs_mount fields drom them need to be > done after options parsing. The iosizelog field could be set in the > options parsing function but the check used before setting the struct > xfs_mount field is a little more than trivial and would reduce the > readabiliy of the options parsing function so it's also added to the > struct xfs_fc_context. > > I could have moved the xfs_fs_remount() function up to be with the > other mount related code to try and highlight what actually changed > when converting it to xfs_fc_reconfigure(). But the function is fairly > short and the gain in patch readability didn't appear to be worth the > extra code churn. > > Finally remove unused code. > > And rename xfs_fs_fill_super() to xfs_fc_fill_super() for consistency. > > Signed-off-by: Ian Kent <raven@xxxxxxxxxx> Dunno what's up with this particular patch, but I see regressions on generic/361 (and similar asserts on a few others). The patches leading up to this patch do not generate this error. --D [ 430.789299] XFS (loop0): ino 83 data fork has delalloc extent at [0x1f7f0:0x1010] [ 430.790206] XFS: Assertion failed: 0, file: fs/xfs/xfs_super.c, line: 1390 [ 430.791010] ------------[ cut here ]------------ [ 430.791612] WARNING: CPU: 1 PID: 10107 at fs/xfs/xfs_message.c:104 assfail+0x32/0x50 [xfs] [ 430.792542] Modules linked in: xfs libcrc32c ip6t_REJECT nf_reject_ipv6 ipt_REJECT nf_reject_ipv4 ip_set_hash_ip ip_set_hash_net xt_tcpudp xt_set ip_set_hash_mac ip_set nfnetlink bfq ip6table_filter ip6_tables iptable_filter sch_fq_codel ip_tables x_tables nfsv4 af_packet [last unloaded: xfs] [ 430.795317] CPU: 1 PID: 10107 Comm: umount Not tainted 5.4.0-rc3-djw #rc3 [ 430.796081] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.10.2-1ubuntu1 04/01/2014 [ 430.797080] RIP: 0010:assfail+0x32/0x50 [xfs] [ 430.797597] Code: f1 41 89 d0 48 c7 c6 00 65 3a a0 48 89 fa 31 ff e8 13 f8 ff ff 0f b6 1d 88 65 11 00 80 fb 01 0f 87 a4 32 06 00 83 e3 01 75 04 <0f> 0b 5b c3 0f 0b 48 c7 c7 c0 a3 43 a0 e8 4c c1 09 e1 66 90 66 2e [ 430.799610] RSP: 0018:ffffc90002ddbd90 EFLAGS: 00010246 [ 430.800204] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 [ 430.801003] RDX: 00000000ffffffc0 RSI: 000000000000000a RDI: ffffffffa0395dcf [ 430.801804] RBP: ffffe8ffc0405d00 R08: 0000000000000000 R09: 0000000000000000 [ 430.802601] R10: 000000000000000a R11: f000000000000000 R12: ffff88803bc2b480 [ 430.803393] R13: ffff88803bc2b718 R14: 0000000000000001 R15: 0000000000000001 [ 430.804194] FS: 00007f8f354f9080(0000) GS:ffff88803ea00000(0000) knlGS:0000000000000000 [ 430.805097] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 430.805753] CR2: 0000561606b9bbd0 CR3: 000000002f1ce003 CR4: 00000000001606a0 [ 430.806551] Call Trace: [ 430.806901] xfs_fs_destroy_inode+0x2a3/0x4e0 [xfs] [ 430.807478] destroy_inode+0x3b/0x80 [ 430.807911] dispose_list+0x51/0x80 [ 430.808332] evict_inodes+0x15b/0x1b0 [ 430.808778] generic_shutdown_super+0x3a/0x100 [ 430.809293] kill_block_super+0x21/0x50 [ 430.809752] deactivate_locked_super+0x2f/0x70 [ 430.810274] cleanup_mnt+0xb4/0x140 [ 430.810698] task_work_run+0x9e/0xd0 [ 430.811124] exit_to_usermode_loop+0x83/0x90 [ 430.811627] do_syscall_64+0x16d/0x180 [ 430.812077] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 430.812662] RIP: 0033:0x7f8f34dbb8c7 [ 430.813089] Code: 95 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 31 f6 e9 09 00 00 00 66 0f 1f 84 00 00 00 00 00 b8 a6 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 91 95 2c 00 f7 d8 64 89 01 48 [ 430.815104] RSP: 002b:00007fff01ee9f98 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6 [ 430.815947] RAX: 0000000000000000 RBX: 000055bd5869f970 RCX: 00007f8f34dbb8c7 [ 430.816743] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 000055bd5869fb50 [ 430.817537] RBP: 0000000000000000 R08: 000055bd586a0900 R09: 0000000000000003 [ 430.818331] R10: 000000000000000b R11: 0000000000000246 R12: 000055bd5869fb50 [ 430.819131] R13: 00007f8f352dd8a4 R14: 0000000000000000 R15: 0000000000000000 [ 430.819943] irq event stamp: 51598 [ 430.820351] hardirqs last enabled at (51597): [<ffffffff810d6087>] console_unlock+0x437/0x590 [ 430.821300] hardirqs last disabled at (51598): [<ffffffff81001d8a>] trace_hardirqs_off_thunk+0x1a/0x20 [ 430.822331] softirqs last enabled at (51586): [<ffffffff81a003af>] __do_softirq+0x3af/0x4a4 [ 430.823269] softirqs last disabled at (51579): [<ffffffff8106528c>] irq_exit+0xbc/0xe0 [ 430.824152] ---[ end trace 27f9fee2eb75762a ]--- [ 430.824737] XFS (loop0): Unmounting Filesystem [ 430.854250] XFS: Assertion failed: XFS_FORCED_SHUTDOWN(mp) || percpu_counter_sum(&mp->m_delalloc_blks) == 0, file: fs/xfs/xfs_super.c, line: 1803 [ 430.855789] ------------[ cut here ]------------ [ 430.856507] WARNING: CPU: 1 PID: 10107 at fs/xfs/xfs_message.c:104 assfail+0x32/0x50 [xfs] [ 430.857782] Modules linked in: xfs libcrc32c ip6t_REJECT nf_reject_ipv6 ipt_REJECT nf_reject_ipv4 ip_set_hash_ip ip_set_hash_net xt_tcpudp xt_set ip_set_hash_mac ip_set nfnetlink bfq ip6table_filter ip6_tables iptable_filter sch_fq_codel ip_tables x_tables nfsv4 af_packet [last unloaded: xfs] [ 430.860781] CPU: 1 PID: 10107 Comm: umount Tainted: G W 5.4.0-rc3-djw #rc3 [ 430.861758] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.10.2-1ubuntu1 04/01/2014 [ 430.862832] RIP: 0010:assfail+0x32/0x50 [xfs] [ 430.863384] Code: f1 41 89 d0 48 c7 c6 00 65 3a a0 48 89 fa 31 ff e8 13 f8 ff ff 0f b6 1d 88 65 11 00 80 fb 01 0f 87 a4 32 06 00 83 e3 01 75 04 <0f> 0b 5b c3 0f 0b 48 c7 c7 c0 a3 43 a0 e8 4c c1 09 e1 66 90 66 2e [ 430.865561] RSP: 0018:ffffc90002ddbe30 EFLAGS: 00010246 [ 430.866201] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 [ 430.867074] RDX: 00000000ffffffc0 RSI: 000000000000000a RDI: ffffffffa0395dcf [ 430.867877] RBP: ffff88807faa42a0 R08: 0000000000000000 R09: 0000000000000000 [ 430.868671] R10: 000000000000000a R11: f000000000000000 R12: ffff88802f28d400 [ 430.869465] R13: ffffffff81db7286 R14: ffffffff826d3560 R15: 0000000000000000 [ 430.870269] FS: 00007f8f354f9080(0000) GS:ffff88803ea00000(0000) knlGS:0000000000000000 [ 430.871169] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 430.871833] CR2: 0000561606b9bbd0 CR3: 000000002f1ce003 CR4: 00000000001606a0 [ 430.872644] Call Trace: [ 430.872994] xfs_destroy_percpu_counters+0x6d/0x70 [xfs] [ 430.873650] xfs_fs_put_super+0x51/0x80 [xfs] [ 430.874163] generic_shutdown_super+0x67/0x100 [ 430.874690] kill_block_super+0x21/0x50 [ 430.875146] deactivate_locked_super+0x2f/0x70 [ 430.875666] cleanup_mnt+0xb4/0x140 [ 430.876093] task_work_run+0x9e/0xd0 [ 430.876531] exit_to_usermode_loop+0x83/0x90 [ 430.877030] do_syscall_64+0x16d/0x180 [ 430.877479] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 430.878065] RIP: 0033:0x7f8f34dbb8c7 [ 430.878495] Code: 95 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 31 f6 e9 09 00 00 00 66 0f 1f 84 00 00 00 00 00 b8 a6 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 91 95 2c 00 f7 d8 64 89 01 48 [ 430.880503] RSP: 002b:00007fff01ee9f98 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6 [ 430.881347] RAX: 0000000000000000 RBX: 000055bd5869f970 RCX: 00007f8f34dbb8c7 [ 430.882147] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 000055bd5869fb50 [ 430.882949] RBP: 0000000000000000 R08: 000055bd586a0900 R09: 0000000000000003 [ 430.883753] R10: 000000000000000b R11: 0000000000000246 R12: 000055bd5869fb50 [ 430.884559] R13: 00007f8f352dd8a4 R14: 0000000000000000 R15: 0000000000000000 [ 430.885361] irq event stamp: 52232 [ 430.885773] hardirqs last enabled at (52231): [<ffffffff810d6087>] console_unlock+0x437/0x590 [ 430.886738] hardirqs last disabled at (52232): [<ffffffff81001d8a>] trace_hardirqs_off_thunk+0x1a/0x20 [ 430.887763] softirqs last enabled at (51614): [<ffffffff81a003af>] __do_softirq+0x3af/0x4a4 [ 430.888701] softirqs last disabled at (51601): [<ffffffff8106528c>] irq_exit+0xbc/0xe0 [ 430.889591] ---[ end trace 27f9fee2eb75762b ]--- > --- > fs/xfs/xfs_super.c | 530 +++++++++++++++++++++++----------------------------- > 1 file changed, 237 insertions(+), 293 deletions(-) > > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c > index dd019be3fa72..3046aba9b058 100644 > --- a/fs/xfs/xfs_super.c > +++ b/fs/xfs/xfs_super.c > @@ -38,6 +38,8 @@ > > #include <linux/magic.h> > #include <linux/parser.h> > +#include <linux/fs_context.h> > +#include <linux/fs_parser.h> > > static const struct super_operations xfs_super_operations; > struct bio_set xfs_ioend_bioset; > @@ -71,55 +73,57 @@ enum { > Opt_filestreams, Opt_quota, Opt_noquota, Opt_usrquota, Opt_grpquota, > Opt_prjquota, Opt_uquota, Opt_gquota, Opt_pquota, > Opt_uqnoenforce, Opt_gqnoenforce, Opt_pqnoenforce, Opt_qnoenforce, > - Opt_discard, Opt_nodiscard, Opt_dax, Opt_err, > + Opt_discard, Opt_nodiscard, Opt_dax, > }; > > -static const match_table_t tokens = { > - {Opt_logbufs, "logbufs=%u"}, /* number of XFS log buffers */ > - {Opt_logbsize, "logbsize=%s"}, /* size of XFS log buffers */ > - {Opt_logdev, "logdev=%s"}, /* log device */ > - {Opt_rtdev, "rtdev=%s"}, /* realtime I/O device */ > - {Opt_wsync, "wsync"}, /* safe-mode nfs compatible mount */ > - {Opt_noalign, "noalign"}, /* turn off stripe alignment */ > - {Opt_swalloc, "swalloc"}, /* turn on stripe width allocation */ > - {Opt_sunit, "sunit=%u"}, /* data volume stripe unit */ > - {Opt_swidth, "swidth=%u"}, /* data volume stripe width */ > - {Opt_nouuid, "nouuid"}, /* ignore filesystem UUID */ > - {Opt_grpid, "grpid"}, /* group-ID from parent directory */ > - {Opt_nogrpid, "nogrpid"}, /* group-ID from current process */ > - {Opt_bsdgroups, "bsdgroups"}, /* group-ID from parent directory */ > - {Opt_sysvgroups,"sysvgroups"}, /* group-ID from current process */ > - {Opt_allocsize, "allocsize=%s"},/* preferred allocation size */ > - {Opt_norecovery,"norecovery"}, /* don't run XFS recovery */ > - {Opt_inode64, "inode64"}, /* inodes can be allocated anywhere */ > - {Opt_inode32, "inode32"}, /* inode allocation limited to > - * XFS_MAXINUMBER_32 */ > - {Opt_ikeep, "ikeep"}, /* do not free empty inode clusters */ > - {Opt_noikeep, "noikeep"}, /* free empty inode clusters */ > - {Opt_largeio, "largeio"}, /* report large I/O sizes in stat() */ > - {Opt_nolargeio, "nolargeio"}, /* do not report large I/O sizes > - * in stat(). */ > - {Opt_attr2, "attr2"}, /* do use attr2 attribute format */ > - {Opt_noattr2, "noattr2"}, /* do not use attr2 attribute format */ > - {Opt_filestreams,"filestreams"},/* use filestreams allocator */ > - {Opt_quota, "quota"}, /* disk quotas (user) */ > - {Opt_noquota, "noquota"}, /* no quotas */ > - {Opt_usrquota, "usrquota"}, /* user quota enabled */ > - {Opt_grpquota, "grpquota"}, /* group quota enabled */ > - {Opt_prjquota, "prjquota"}, /* project quota enabled */ > - {Opt_uquota, "uquota"}, /* user quota (IRIX variant) */ > - {Opt_gquota, "gquota"}, /* group quota (IRIX variant) */ > - {Opt_pquota, "pquota"}, /* project quota (IRIX variant) */ > - {Opt_uqnoenforce,"uqnoenforce"},/* user quota limit enforcement */ > - {Opt_gqnoenforce,"gqnoenforce"},/* group quota limit enforcement */ > - {Opt_pqnoenforce,"pqnoenforce"},/* project quota limit enforcement */ > - {Opt_qnoenforce, "qnoenforce"}, /* same as uqnoenforce */ > - {Opt_discard, "discard"}, /* Discard unused blocks */ > - {Opt_nodiscard, "nodiscard"}, /* Do not discard unused blocks */ > - {Opt_dax, "dax"}, /* Enable direct access to bdev pages */ > - {Opt_err, NULL}, > +static const struct fs_parameter_spec xfs_fc_param_specs[] = { > + fsparam_u32("logbufs", Opt_logbufs), > + fsparam_string("logbsize", Opt_logbsize), > + fsparam_string("logdev", Opt_logdev), > + fsparam_string("rtdev", Opt_rtdev), > + fsparam_flag("wsync", Opt_wsync), > + fsparam_flag("noalign", Opt_noalign), > + fsparam_flag("swalloc", Opt_swalloc), > + fsparam_u32("sunit", Opt_sunit), > + fsparam_u32("swidth", Opt_swidth), > + fsparam_flag("nouuid", Opt_nouuid), > + fsparam_flag("grpid", Opt_grpid), > + fsparam_flag("nogrpid", Opt_nogrpid), > + fsparam_flag("bsdgroups", Opt_bsdgroups), > + fsparam_flag("sysvgroups", Opt_sysvgroups), > + fsparam_string("allocsize", Opt_allocsize), > + fsparam_flag("norecovery", Opt_norecovery), > + fsparam_flag("inode64", Opt_inode64), > + fsparam_flag("inode32", Opt_inode32), > + fsparam_flag("ikeep", Opt_ikeep), > + fsparam_flag("noikeep", Opt_noikeep), > + fsparam_flag("largeio", Opt_largeio), > + fsparam_flag("nolargeio", Opt_nolargeio), > + fsparam_flag("attr2", Opt_attr2), > + fsparam_flag("noattr2", Opt_noattr2), > + fsparam_flag("filestreams", Opt_filestreams), > + fsparam_flag("quota", Opt_quota), > + fsparam_flag("noquota", Opt_noquota), > + fsparam_flag("usrquota", Opt_usrquota), > + fsparam_flag("grpquota", Opt_grpquota), > + fsparam_flag("prjquota", Opt_prjquota), > + fsparam_flag("uquota", Opt_uquota), > + fsparam_flag("gquota", Opt_gquota), > + fsparam_flag("pquota", Opt_pquota), > + fsparam_flag("uqnoenforce", Opt_uqnoenforce), > + fsparam_flag("gqnoenforce", Opt_gqnoenforce), > + fsparam_flag("pqnoenforce", Opt_pqnoenforce), > + fsparam_flag("qnoenforce", Opt_qnoenforce), > + fsparam_flag("discard", Opt_discard), > + fsparam_flag("nodiscard", Opt_nodiscard), > + fsparam_flag("dax", Opt_dax), > + {} > }; > > +static const struct fs_parameter_description xfs_fc_parameters = { > + .name = "xfs", > + .specs = xfs_fc_param_specs, > +}; > > static int > suffix_kstrtoint( > @@ -156,60 +160,51 @@ suffix_kstrtoint( > return ret; > } > > -static int > -match_kstrtoint( > - const substring_t *s, > - unsigned int base, > - int *res) > -{ > - const char *value; > - int ret; > - > - value = match_strdup(s); > - if (!value) > - return -ENOMEM; > - ret = suffix_kstrtoint(value, base, res); > - kfree(value); > - return ret; > -} > +struct xfs_fc_context { > + int dsunit; > + int dswidth; > + uint8_t iosizelog; > +}; > > static int > xfs_fc_parse_param( > - int token, > - char *p, > - substring_t *args, > - struct xfs_mount *mp, > - int *dsunit, > - int *dswidth, > - uint8_t *iosizelog) > + struct fs_context *fc, > + struct fs_parameter *param) > { > + struct xfs_fc_context *ctx = fc->fs_private; > + struct xfs_mount *mp = fc->s_fs_info; > + struct fs_parse_result result; > int iosize = 0; > + int opt; > + > + opt = fs_parse(fc, &xfs_fc_parameters, param, &result); > + if (opt < 0) > + return opt; > > - switch (token) { > + switch (opt) { > case Opt_logbufs: > - if (match_int(args, &mp->m_logbufs)) > - return -EINVAL; > + mp->m_logbufs = result.uint_32; > return 0; > case Opt_logbsize: > - if (match_kstrtoint(args, 10, &mp->m_logbsize)) > + if (suffix_kstrtoint(param->string, 10, &mp->m_logbsize)) > return -EINVAL; > return 0; > case Opt_logdev: > kfree(mp->m_logname); > - mp->m_logname = match_strdup(args); > + mp->m_logname = kstrdup(param->string, GFP_KERNEL); > if (!mp->m_logname) > return -ENOMEM; > return 0; > case Opt_rtdev: > kfree(mp->m_rtname); > - mp->m_rtname = match_strdup(args); > + mp->m_rtname = kstrdup(param->string, GFP_KERNEL); > if (!mp->m_rtname) > return -ENOMEM; > return 0; > case Opt_allocsize: > - if (match_kstrtoint(args, 10, &iosize)) > + if (suffix_kstrtoint(param->string, 10, &iosize)) > return -EINVAL; > - *iosizelog = ffs(iosize) - 1; > + ctx->iosizelog = ffs(iosize) - 1; > return 0; > case Opt_grpid: > case Opt_bsdgroups: > @@ -232,13 +227,11 @@ xfs_fc_parse_param( > mp->m_flags |= XFS_MOUNT_SWALLOC; > return 0; > case Opt_sunit: > - if (match_int(args, dsunit)) > - return -EINVAL; > + ctx->dsunit = result.uint_32; > return 0; > case Opt_swidth: > - if (match_int(args, dswidth)) > - return -EINVAL; > - return 0; > + ctx->dswidth = result.uint_32; > + return 0;; > case Opt_inode32: > mp->m_flags |= XFS_MOUNT_SMALL_INUMS; > return 0; > @@ -316,7 +309,7 @@ xfs_fc_parse_param( > return 0; > #endif > default: > - xfs_warn(mp, "unknown mount option [%s].", p); > + xfs_warn(mp, "unknown mount option [%s].", param->key); > return -EINVAL; > } > > @@ -326,9 +319,7 @@ xfs_fc_parse_param( > static int > xfs_fc_validate_params( > struct xfs_mount *mp, > - int dsunit, > - int dswidth, > - uint8_t iosizelog) > + struct xfs_fc_context *ctx) > { > /* > * no recovery flag requires a read-only mount > @@ -339,7 +330,8 @@ xfs_fc_validate_params( > return -EINVAL; > } > > - if ((mp->m_flags & XFS_MOUNT_NOALIGN) && (dsunit || dswidth)) { > + if ((mp->m_flags & XFS_MOUNT_NOALIGN) && > + (ctx->dsunit || ctx->dswidth)) { > xfs_warn(mp, > "sunit and swidth options incompatible with the noalign option"); > return -EINVAL; > @@ -352,27 +344,27 @@ xfs_fc_validate_params( > } > #endif > > - if ((dsunit && !dswidth) || (!dsunit && dswidth)) { > + if ((ctx->dsunit && !ctx->dswidth) || (!ctx->dsunit && ctx->dswidth)) { > xfs_warn(mp, "sunit and swidth must be specified together"); > return -EINVAL; > } > > - if (dsunit && (dswidth % dsunit != 0)) { > + if (ctx->dsunit && (ctx->dswidth % ctx->dsunit != 0)) { > xfs_warn(mp, > "stripe width (%d) must be a multiple of the stripe unit (%d)", > - dswidth, dsunit); > + ctx->dswidth, ctx->dsunit); > return -EINVAL; > } > > - if (dsunit && !(mp->m_flags & XFS_MOUNT_NOALIGN)) { > + if (ctx->dsunit && !(mp->m_flags & XFS_MOUNT_NOALIGN)) { > /* > * At this point the superblock has not been read > * in, therefore we do not know the block size. > * Before the mount call ends we will convert > * these to FSBs. > */ > - mp->m_dalign = dsunit; > - mp->m_swidth = dswidth; > + mp->m_dalign = ctx->dsunit; > + mp->m_swidth = ctx->dswidth; > } > > if (mp->m_logbufs != -1 && > @@ -394,18 +386,18 @@ xfs_fc_validate_params( > return -EINVAL; > } > > - if (iosizelog) { > - if (iosizelog > XFS_MAX_IO_LOG || > - iosizelog < XFS_MIN_IO_LOG) { > + if (ctx->iosizelog) { > + if (ctx->iosizelog > XFS_MAX_IO_LOG || > + ctx->iosizelog < XFS_MIN_IO_LOG) { > xfs_warn(mp, "invalid log iosize: %d [not %d-%d]", > - iosizelog, XFS_MIN_IO_LOG, > + ctx->iosizelog, XFS_MIN_IO_LOG, > XFS_MAX_IO_LOG); > return -EINVAL; > } > > mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE; > - mp->m_readio_log = iosizelog; > - mp->m_writeio_log = iosizelog; > + mp->m_readio_log = ctx->iosizelog; > + mp->m_writeio_log = ctx->iosizelog; > } > > return 0; > @@ -552,92 +544,19 @@ xfs_remount_ro( > return 0; > } > > -/* > - * This function fills in xfs_mount_t fields based on mount args. > - * Note: the superblock has _not_ yet been read in. > - * > - * Note that this function leaks the various device name allocations on > - * failure. The caller takes care of them. > - * > - * *sb is const because this is also used to test options on the remount > - * path, and we don't want this to have any side effects at remount time. > - * Today this function does not change *sb, but just to future-proof... > - */ > static int > -xfs_parseargs( > - struct xfs_mount *mp, > - char *options) > -{ > - const struct super_block *sb = mp->m_super; > - char *p; > - substring_t args[MAX_OPT_ARGS]; > - int dsunit = 0; > - int dswidth = 0; > - uint8_t iosizelog = 0; > - > - /* > - * Copy binary VFS mount flags we are interested in. > - */ > - if (sb_rdonly(sb)) > - mp->m_flags |= XFS_MOUNT_RDONLY; > - if (sb->s_flags & SB_DIRSYNC) > - mp->m_flags |= XFS_MOUNT_DIRSYNC; > - if (sb->s_flags & SB_SYNCHRONOUS) > - mp->m_flags |= XFS_MOUNT_WSYNC; > - > - /* > - * Set some default flags that could be cleared by the mount option > - * parsing. > - */ > - mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; > - > - /* > - * These can be overridden by the mount option parsing. > - */ > - mp->m_logbufs = -1; > - mp->m_logbsize = -1; > - > - if (!options) > - return 0; > - > - while ((p = strsep(&options, ",")) != NULL) { > - int token; > - int ret; > - > - if (!*p) > - continue; > - > - token = match_token(p, tokens, args); > - ret = xfs_fc_parse_param(token, p, args, mp, &dsunit, &dswidth, > - &iosizelog); > - if (ret) > - return ret; > - } > - > - return xfs_fc_validate_params(mp, dsunit, dswidth, iosizelog); > -} > - > -static int > -xfs_fs_fill_super( > +xfs_fc_fill_super( > struct super_block *sb, > - void *data, > - int silent) > + struct fs_context *fc) > { > + struct xfs_fc_context *ctx = fc->fs_private; > + struct xfs_mount *mp = sb->s_fs_info; > struct inode *root; > - struct xfs_mount *mp = NULL; > int flags = 0, error = -ENOMEM; > > - /* > - * allocate mp and do all low-level struct initializations before we > - * attach it to the super > - */ > - mp = xfs_mount_alloc(); > - if (!mp) > - goto out; > mp->m_super = sb; > - sb->s_fs_info = mp; > > - error = xfs_parseargs(mp, (char *)data); > + error = xfs_fc_validate_params(mp, ctx); > if (error) > goto out_free_names; > > @@ -661,7 +580,7 @@ xfs_fs_fill_super( > msleep(xfs_globals.mount_delay * 1000); > } > > - if (silent) > + if (fc->sb_flags & SB_SILENT) > flags |= XFS_MFSI_QUIET; > > error = xfs_open_devices(mp); > @@ -806,7 +725,6 @@ xfs_fs_fill_super( > out_free_names: > sb->s_fs_info = NULL; > xfs_mount_free(mp); > - out: > return error; > > out_unmount: > @@ -815,6 +733,147 @@ xfs_fs_fill_super( > goto out_free_sb; > } > > +static int > +xfs_fc_get_tree( > + struct fs_context *fc) > +{ > + return get_tree_bdev(fc, xfs_fc_fill_super); > +} > + > +/* > + * Logically we would return an error here to prevent users from believing > + * they might have changed mount options using remount which can't be changed. > + * > + * But unfortunately mount(8) adds all options from mtab and fstab to the mount > + * arguments in some cases so we can't blindly reject options, but have to > + * check for each specified option if it actually differs from the currently > + * set option and only reject it if that's the case. > + * > + * Until that is implemented we return success for every remount request, and > + * silently ignore all options that we can't actually change. > + */ > +static int > +xfs_fc_reconfigure( > + struct fs_context *fc) > +{ > + struct xfs_fc_context *ctx = fc->fs_private; > + struct xfs_mount *mp = XFS_M(fc->root->d_sb); > + struct xfs_mount *new_mp = fc->s_fs_info; > + xfs_sb_t *sbp = &mp->m_sb; > + int flags = fc->sb_flags; > + int error; > + > + error = xfs_fc_validate_params(new_mp, ctx); > + if (error) > + return error; > + > + /* inode32 -> inode64 */ > + if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && > + !(new_mp->m_flags & XFS_MOUNT_SMALL_INUMS)) { > + mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; > + mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount); > + } > + > + /* inode64 -> inode32 */ > + if (!(mp->m_flags & XFS_MOUNT_SMALL_INUMS) && > + (new_mp->m_flags & XFS_MOUNT_SMALL_INUMS)) { > + mp->m_flags |= XFS_MOUNT_SMALL_INUMS; > + mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount); > + } > + > + /* ro -> rw */ > + if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(flags & SB_RDONLY)) { > + error = xfs_remount_rw(mp); > + if (error) > + return error; > + } > + > + /* rw -> ro */ > + if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (flags & SB_RDONLY)) { > + error = xfs_remount_ro(mp); > + if (error) > + return error; > + } > + > + return 0; > +} > + > +static void xfs_fc_free(struct fs_context *fc) > +{ > + struct xfs_fc_context *ctx = fc->fs_private; > + struct xfs_mount *mp = fc->s_fs_info; > + > + /* > + * mp and ctx are stored in the fs_context when it is > + * initialized. mp is transferred to the superblock on > + * a successful mount, but if an error occurs before the > + * transfer we have to free it here. > + */ > + if (mp) > + xfs_mount_free(mp); > + kfree(ctx); > +} > + > +static const struct fs_context_operations xfs_context_ops = { > + .parse_param = xfs_fc_parse_param, > + .get_tree = xfs_fc_get_tree, > + .reconfigure = xfs_fc_reconfigure, > + .free = xfs_fc_free, > +}; > + > +static int xfs_fc_init_context(struct fs_context *fc) > +{ > + struct xfs_fc_context *ctx; > + struct xfs_mount *mp; > + > + ctx = kzalloc(sizeof(struct xfs_fc_context), GFP_KERNEL); > + if (!ctx) > + return -ENOMEM; > + > + mp = xfs_mount_alloc(); > + if (!mp) { > + kfree(ctx); > + return -ENOMEM; > + } > + > + /* > + * Set some default flags that could be cleared by the mount option > + * parsing. > + */ > + mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; > + > + /* > + * These can be overridden by the mount option parsing. > + */ > + mp->m_logbufs = -1; > + mp->m_logbsize = -1; > + > + /* > + * Copy binary VFS mount flags we are interested in. > + */ > + if (fc->sb_flags & SB_RDONLY) > + mp->m_flags |= XFS_MOUNT_RDONLY; > + if (fc->sb_flags & SB_DIRSYNC) > + mp->m_flags |= XFS_MOUNT_DIRSYNC; > + if (fc->sb_flags & SB_SYNCHRONOUS) > + mp->m_flags |= XFS_MOUNT_WSYNC; > + > + fc->fs_private = ctx; > + fc->s_fs_info = mp; > + fc->ops = &xfs_context_ops; > + > + return 0; > +} > + > +static struct file_system_type xfs_fs_type = { > + .owner = THIS_MODULE, > + .name = "xfs", > + .init_fs_context = xfs_fc_init_context, > + .parameters = &xfs_fc_parameters, > + .kill_sb = kill_block_super, > + .fs_flags = FS_REQUIRES_DEV, > +}; > + > struct proc_xfs_info { > uint64_t flag; > char *str; > @@ -1585,103 +1644,6 @@ xfs_quiesce_attr( > xfs_log_quiesce(mp); > } > > -STATIC int > -xfs_test_remount_options( > - struct super_block *sb, > - char *options) > -{ > - int error = 0; > - struct xfs_mount *tmp_mp; > - > - tmp_mp = kmem_zalloc(sizeof(*tmp_mp), KM_MAYFAIL); > - if (!tmp_mp) > - return -ENOMEM; > - > - tmp_mp->m_super = sb; > - error = xfs_parseargs(tmp_mp, options); > - xfs_mount_free(tmp_mp); > - > - return error; > -} > - > -STATIC int > -xfs_fs_remount( > - struct super_block *sb, > - int *flags, > - char *options) > -{ > - struct xfs_mount *mp = XFS_M(sb); > - xfs_sb_t *sbp = &mp->m_sb; > - substring_t args[MAX_OPT_ARGS]; > - char *p; > - int error; > - > - /* First, check for complete junk; i.e. invalid options */ > - error = xfs_test_remount_options(sb, options); > - if (error) > - return error; > - > - sync_filesystem(sb); > - while ((p = strsep(&options, ",")) != NULL) { > - int token; > - > - if (!*p) > - continue; > - > - token = match_token(p, tokens, args); > - switch (token) { > - case Opt_inode64: > - mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; > - mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount); > - break; > - case Opt_inode32: > - mp->m_flags |= XFS_MOUNT_SMALL_INUMS; > - mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount); > - break; > - default: > - /* > - * Logically we would return an error here to prevent > - * users from believing they might have changed > - * mount options using remount which can't be changed. > - * > - * But unfortunately mount(8) adds all options from > - * mtab and fstab to the mount arguments in some cases > - * so we can't blindly reject options, but have to > - * check for each specified option if it actually > - * differs from the currently set option and only > - * reject it if that's the case. > - * > - * Until that is implemented we return success for > - * every remount request, and silently ignore all > - * options that we can't actually change. > - */ > -#if 0 > - xfs_info(mp, > - "mount option \"%s\" not supported for remount", p); > - return -EINVAL; > -#else > - break; > -#endif > - } > - } > - > - /* ro -> rw */ > - if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & SB_RDONLY)) { > - error = xfs_remount_rw(mp); > - if (error) > - return error; > - } > - > - /* rw -> ro */ > - if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & SB_RDONLY)) { > - error = xfs_remount_ro(mp); > - if (error) > - return error; > - } > - > - return 0; > -} > - > /* > * Second stage of a freeze. The data is already frozen so we only > * need to take care of the metadata. Once that's done sync the superblock > @@ -1867,16 +1829,6 @@ xfs_fs_put_super( > xfs_mount_free(mp); > } > > -STATIC struct dentry * > -xfs_fs_mount( > - struct file_system_type *fs_type, > - int flags, > - const char *dev_name, > - void *data) > -{ > - return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); > -} > - > static long > xfs_fs_nr_cached_objects( > struct super_block *sb, > @@ -1906,19 +1858,11 @@ static const struct super_operations xfs_super_operations = { > .freeze_fs = xfs_fs_freeze, > .unfreeze_fs = xfs_fs_unfreeze, > .statfs = xfs_fs_statfs, > - .remount_fs = xfs_fs_remount, > .show_options = xfs_fs_show_options, > .nr_cached_objects = xfs_fs_nr_cached_objects, > .free_cached_objects = xfs_fs_free_cached_objects, > }; > > -static struct file_system_type xfs_fs_type = { > - .owner = THIS_MODULE, > - .name = "xfs", > - .mount = xfs_fs_mount, > - .kill_sb = kill_block_super, > - .fs_flags = FS_REQUIRES_DEV, > -}; > MODULE_ALIAS_FS("xfs"); > > STATIC int __init >