From nobody Fri Dec 19 15:34:17 2025 Received: from mail-pf1-f179.google.com (mail-pf1-f179.google.com [209.85.210.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 37D4639FCF; Thu, 25 Apr 2024 19:06:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714071964; cv=none; b=gAu0krlLrawIUvB4NdntN1LreiQjZ2yIpoXcdTHZEqoBYMnmdmVp4ORQUcF4jKXdDuec2GPNjT7+n+FQVKaeg9TuBdfHm4UbticYJmq+7/2G/6DPlILYvdToGz9qUIdCpCdD1qFN6O6k0euKPatWpp0G9tqwLRpMIspSLa7JuWE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714071964; c=relaxed/simple; bh=ZEmZGRl1rm/iHfnBBtlNElEh12bpHVKFN0H8fnxPGCA=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=PtQJzAE197UsrI2QBG3J1QNQvjSs1H3mpgbJNieZPmAXo7yuVo7apSwDfZLoc6xu1jdQBUsZoYoV2pcGSrq7zBzjHpFPvbx3mZa2npBW+wjUrQLDzzUsFfTIuBoGNm+kHwhYMnqvUGwarKC9submERsbLvvJvN/D9kkuHnvwSa4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=S1IIRItH; arc=none smtp.client-ip=209.85.210.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="S1IIRItH" Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-6ed3cafd766so1331780b3a.0; Thu, 25 Apr 2024 12:06:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1714071961; x=1714676761; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=SX8tGEcFT5/jFu3pdWpkn+5vdsSuK+OxzBcQI05MfR0=; b=S1IIRItHCXKiKLNseh1pRfmX6IxP52m7/QHqcJFl7E4HOUvRLJLhNf5U8ZUj9OP6qR HPn6MJlbsjRtioC7ty24ukAW+ztZ75X3jK6xjBh9Z4C+1d6/Ig2ca5lgql5nArKF+UA+ hrHFp4x9aPlFfXPlyWRzZiaD0IwSCZFYW8srhJ3Tow51YFYR162s6BYeH82f3eCo30/C g6s9YLvtU380zEGWCskgC3Rqc38JrYyPxN4f/pMwBV53SaqbbtW7pDKZx+cF2Bnnb0GR eCgvzrpbkTlBChVp196M0PjCvGwsEUDjLZY8LVfcluBQtBz1piebrKf2iXZuPifgVQdp n/nQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1714071961; x=1714676761; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=SX8tGEcFT5/jFu3pdWpkn+5vdsSuK+OxzBcQI05MfR0=; b=MtBgR7a2p2dTKuIvERL9uCRNnQ54Q5w3lgnaePRmfw/Ht6pfXOLok5K5x5TqTYf7Nw tS3MZm0zclshkLr93i7vmlAX7L8ImSKOKLaZafzqwRE8hIYfWXe9rXapY2kahdOF4ScG Hne8SRoOxT0edvbqTId4YO3zoAk5XIlsebVAHb8+BwRuPInnGACot5wNjeHBu+bfdgcj aCnEks6clNfZIdcdK/4iG4KPXw0sv0b/MjvZ49ajb/+hiEkSNiCZ1BeOOit47zfDN9nA XbKmC3gVo+ouHW3rSisFKzZU2Sy8S4bPIk4FrcpivSJ8/zzHMPij4wbd9ZcvCL71ABjv jRng== X-Forwarded-Encrypted: i=1; AJvYcCV+ZdD8n3deXaSQo6o7hq8aKtgaBlFJ50hi/ze5EAHj3IMD/uQC/tUsg5EDcWXO7VOpANuaKoXUBk2XdoJcHoHFt7wn6GqMCQzNt8hWAwtvVeDVuiC7UgXkEYQFxoMRI0PhpO4t+mi+p0NXVw== X-Gm-Message-State: AOJu0YxiFL3VIiqUlHIYM4o7avI3aHj1K+jK0L5R+MYE00G+jftHGRQC vc7RRSv1/5c7aMxpR0ciSQLjkl226fiF7fVQK50h9hQwqLM+1zT39YSP0Q== X-Google-Smtp-Source: AGHT+IH/7PZ1Ec0+lG3sulNmNZKT9oHefX51Btp/WXF2ghMJ8O1JnMUNxidWuGjGA+8fdjfHiw00EA== X-Received: by 2002:a05:6a20:975b:b0:1ac:de56:eed4 with SMTP id hs27-20020a056a20975b00b001acde56eed4mr640082pzc.53.1714071961157; Thu, 25 Apr 2024 12:06:01 -0700 (PDT) Received: from carrot.. (i223-218-108-246.s42.a014.ap.plala.or.jp. [223.218.108.246]) by smtp.gmail.com with ESMTPSA id z1-20020aa79901000000b006ed3509ecd0sm13481458pff.56.2024.04.25.12.05.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Apr 2024 12:06:00 -0700 (PDT) From: Ryusuke Konishi To: Andrew Morton Cc: linux-nilfs@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, Eric Sandeen Subject: [PATCH -mm v2] nilfs2: convert to use the new mount API Date: Fri, 26 Apr 2024 04:05:26 +0900 Message-Id: <20240425190526.10905-1-konishi.ryusuke@gmail.com> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Eric Sandeen Convert nilfs2 to use the new mount API. [konishi.ryusuke: fixed missing SB_RDONLY flag repair, UAF read for fc->root on error, reference to uninitialized variable, duplicate header inclusion, and missing update of kernel-doc comments] Link: https://lkml.kernel.org/r/33d078a7-9072-4d8e-a3a9-dec23d4191da@redhat= .com Signed-off-by: Eric Sandeen Signed-off-by: Ryusuke Konishi --- Hi Andrew, please use this to replace the new mount API support patch queued for the next merge window. v2 (to -mm): - fix UAF read for fc->root in put_fs_context() when call to nilfs_reconfigure() from nilfs_get_tree() fails. - fix reference to uninitialized variable 's' in nilfs_get_tree(). - fix duplicate inclusion of fs_context.h. - reflect function argument changes to kernel-doc comments. Thanks, Ryusuke Konishi fs/nilfs2/nilfs.h | 4 +- fs/nilfs2/super.c | 388 ++++++++++++++++++------------------------ fs/nilfs2/the_nilfs.c | 5 +- fs/nilfs2/the_nilfs.h | 6 +- 4 files changed, 174 insertions(+), 229 deletions(-) diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 2e29b98ba8ba..728e90be3570 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -335,8 +335,8 @@ void __nilfs_error(struct super_block *sb, const char *= function, =20 extern struct nilfs_super_block * nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head = **); -extern int nilfs_store_magic_and_option(struct super_block *, - struct nilfs_super_block *, char *); +extern int nilfs_store_magic(struct super_block *sb, + struct nilfs_super_block *sbp); extern int nilfs_check_feature_compatibility(struct super_block *, struct nilfs_super_block *); extern void nilfs_set_log_cursor(struct nilfs_super_block *, diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index ac24ed109ce9..e835e1f5a712 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -29,13 +29,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include "nilfs.h" #include "export.h" #include "mdt.h" @@ -61,7 +61,6 @@ struct kmem_cache *nilfs_segbuf_cachep; struct kmem_cache *nilfs_btree_path_cache; =20 static int nilfs_setup_super(struct super_block *sb, int is_mount); -static int nilfs_remount(struct super_block *sb, int *flags, char *data); =20 void __nilfs_msg(struct super_block *sb, const char *fmt, ...) { @@ -702,105 +701,98 @@ static const struct super_operations nilfs_sops =3D { .freeze_fs =3D nilfs_freeze, .unfreeze_fs =3D nilfs_unfreeze, .statfs =3D nilfs_statfs, - .remount_fs =3D nilfs_remount, .show_options =3D nilfs_show_options }; =20 enum { - Opt_err_cont, Opt_err_panic, Opt_err_ro, - Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, - Opt_discard, Opt_nodiscard, Opt_err, + Opt_err, Opt_barrier, Opt_snapshot, Opt_order, Opt_norecovery, + Opt_discard, }; =20 -static match_table_t tokens =3D { - {Opt_err_cont, "errors=3Dcontinue"}, - {Opt_err_panic, "errors=3Dpanic"}, - {Opt_err_ro, "errors=3Dremount-ro"}, - {Opt_barrier, "barrier"}, - {Opt_nobarrier, "nobarrier"}, - {Opt_snapshot, "cp=3D%u"}, - {Opt_order, "order=3D%s"}, - {Opt_norecovery, "norecovery"}, - {Opt_discard, "discard"}, - {Opt_nodiscard, "nodiscard"}, - {Opt_err, NULL} +static const struct constant_table nilfs_param_err[] =3D { + {"continue", NILFS_MOUNT_ERRORS_CONT}, + {"panic", NILFS_MOUNT_ERRORS_PANIC}, + {"remount-ro", NILFS_MOUNT_ERRORS_RO}, + {} }; =20 -static int parse_options(char *options, struct super_block *sb, int is_rem= ount) -{ - struct the_nilfs *nilfs =3D sb->s_fs_info; - char *p; - substring_t args[MAX_OPT_ARGS]; - - if (!options) - return 1; - - while ((p =3D strsep(&options, ",")) !=3D NULL) { - int token; +static const struct fs_parameter_spec nilfs_param_spec[] =3D { + fsparam_enum ("errors", Opt_err, nilfs_param_err), + fsparam_flag_no ("barrier", Opt_barrier), + fsparam_u64 ("cp", Opt_snapshot), + fsparam_string ("order", Opt_order), + fsparam_flag ("norecovery", Opt_norecovery), + fsparam_flag_no ("discard", Opt_discard), + {} +}; =20 - if (!*p) - continue; +struct nilfs_fs_context { + unsigned long ns_mount_opt; + __u64 cno; +}; =20 - token =3D match_token(p, tokens, args); - switch (token) { - case Opt_barrier: - nilfs_set_opt(nilfs, BARRIER); - break; - case Opt_nobarrier: +static int nilfs_parse_param(struct fs_context *fc, struct fs_parameter *p= aram) +{ + struct nilfs_fs_context *nilfs =3D fc->fs_private; + int is_remount =3D fc->purpose =3D=3D FS_CONTEXT_FOR_RECONFIGURE; + struct fs_parse_result result; + int opt; + + opt =3D fs_parse(fc, nilfs_param_spec, param, &result); + if (opt < 0) + return opt; + + switch (opt) { + case Opt_barrier: + if (result.negated) nilfs_clear_opt(nilfs, BARRIER); - break; - case Opt_order: - if (strcmp(args[0].from, "relaxed") =3D=3D 0) - /* Ordered data semantics */ - nilfs_clear_opt(nilfs, STRICT_ORDER); - else if (strcmp(args[0].from, "strict") =3D=3D 0) - /* Strict in-order semantics */ - nilfs_set_opt(nilfs, STRICT_ORDER); - else - return 0; - break; - case Opt_err_panic: - nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_PANIC); - break; - case Opt_err_ro: - nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_RO); - break; - case Opt_err_cont: - nilfs_write_opt(nilfs, ERROR_MODE, ERRORS_CONT); - break; - case Opt_snapshot: - if (is_remount) { - nilfs_err(sb, - "\"%s\" option is invalid for remount", - p); - return 0; - } - break; - case Opt_norecovery: - nilfs_set_opt(nilfs, NORECOVERY); - break; - case Opt_discard: - nilfs_set_opt(nilfs, DISCARD); - break; - case Opt_nodiscard: - nilfs_clear_opt(nilfs, DISCARD); - break; - default: - nilfs_err(sb, "unrecognized mount option \"%s\"", p); - return 0; + else + nilfs_set_opt(nilfs, BARRIER); + break; + case Opt_order: + if (strcmp(param->string, "relaxed") =3D=3D 0) + /* Ordered data semantics */ + nilfs_clear_opt(nilfs, STRICT_ORDER); + else if (strcmp(param->string, "strict") =3D=3D 0) + /* Strict in-order semantics */ + nilfs_set_opt(nilfs, STRICT_ORDER); + else + return -EINVAL; + break; + case Opt_err: + nilfs->ns_mount_opt &=3D ~NILFS_MOUNT_ERROR_MODE; + nilfs->ns_mount_opt |=3D result.uint_32; + break; + case Opt_snapshot: + if (is_remount) { + struct super_block *sb =3D fc->root->d_sb; + + nilfs_err(sb, + "\"%s\" option is invalid for remount", + param->key); + return -EINVAL; + } + if (result.uint_64 =3D=3D 0) { + nilfs_err(NULL, + "invalid option \"cp=3D0\": invalid checkpoint number 0"); + return -EINVAL; } + nilfs->cno =3D result.uint_64; + break; + case Opt_norecovery: + nilfs_set_opt(nilfs, NORECOVERY); + break; + case Opt_discard: + if (result.negated) + nilfs_clear_opt(nilfs, DISCARD); + else + nilfs_set_opt(nilfs, DISCARD); + break; + default: + return -EINVAL; } - return 1; -} - -static inline void -nilfs_set_default_options(struct super_block *sb, - struct nilfs_super_block *sbp) -{ - struct the_nilfs *nilfs =3D sb->s_fs_info; =20 - nilfs->ns_mount_opt =3D - NILFS_MOUNT_ERRORS_RO | NILFS_MOUNT_BARRIER; + return 0; } =20 static int nilfs_setup_super(struct super_block *sb, int is_mount) @@ -857,9 +849,8 @@ struct nilfs_super_block *nilfs_read_super_block(struct= super_block *sb, return (struct nilfs_super_block *)((char *)(*pbh)->b_data + offset); } =20 -int nilfs_store_magic_and_option(struct super_block *sb, - struct nilfs_super_block *sbp, - char *data) +int nilfs_store_magic(struct super_block *sb, + struct nilfs_super_block *sbp) { struct the_nilfs *nilfs =3D sb->s_fs_info; =20 @@ -870,14 +861,12 @@ int nilfs_store_magic_and_option(struct super_block *= sb, sb->s_flags |=3D SB_NOATIME; #endif =20 - nilfs_set_default_options(sb, sbp); - nilfs->ns_resuid =3D le16_to_cpu(sbp->s_def_resuid); nilfs->ns_resgid =3D le16_to_cpu(sbp->s_def_resgid); nilfs->ns_interval =3D le32_to_cpu(sbp->s_c_interval); nilfs->ns_watermark =3D le32_to_cpu(sbp->s_c_block_max); =20 - return !parse_options(data, sb, 0) ? -EINVAL : 0; + return 0; } =20 int nilfs_check_feature_compatibility(struct super_block *sb, @@ -1035,17 +1024,17 @@ int nilfs_checkpoint_is_mounted(struct super_block = *sb, __u64 cno) /** * nilfs_fill_super() - initialize a super block instance * @sb: super_block - * @data: mount options - * @silent: silent mode flag + * @fc: filesystem context * * This function is called exclusively by nilfs->ns_mount_mutex. * So, the recovery process is protected from other simultaneous mounts. */ static int -nilfs_fill_super(struct super_block *sb, void *data, int silent) +nilfs_fill_super(struct super_block *sb, struct fs_context *fc) { struct the_nilfs *nilfs; struct nilfs_root *fsroot; + struct nilfs_fs_context *ctx =3D fc->fs_private; __u64 cno; int err; =20 @@ -1055,10 +1044,13 @@ nilfs_fill_super(struct super_block *sb, void *data= , int silent) =20 sb->s_fs_info =3D nilfs; =20 - err =3D init_nilfs(nilfs, sb, (char *)data); + err =3D init_nilfs(nilfs, sb); if (err) goto failed_nilfs; =20 + /* Copy in parsed mount options */ + nilfs->ns_mount_opt =3D ctx->ns_mount_opt; + sb->s_op =3D &nilfs_sops; sb->s_export_op =3D &nilfs_export_ops; sb->s_root =3D NULL; @@ -1117,34 +1109,25 @@ nilfs_fill_super(struct super_block *sb, void *data= , int silent) return err; } =20 -static int nilfs_remount(struct super_block *sb, int *flags, char *data) +static int nilfs_reconfigure(struct fs_context *fc) { + struct nilfs_fs_context *ctx =3D fc->fs_private; + struct super_block *sb =3D fc->root->d_sb; struct the_nilfs *nilfs =3D sb->s_fs_info; - unsigned long old_sb_flags; - unsigned long old_mount_opt; int err; =20 sync_filesystem(sb); - old_sb_flags =3D sb->s_flags; - old_mount_opt =3D nilfs->ns_mount_opt; - - if (!parse_options(data, sb, 1)) { - err =3D -EINVAL; - goto restore_opts; - } - sb->s_flags =3D (sb->s_flags & ~SB_POSIXACL); =20 err =3D -EINVAL; =20 if (!nilfs_valid_fs(nilfs)) { nilfs_warn(sb, "couldn't remount because the filesystem is in an incomplete recover= y state"); - goto restore_opts; + goto ignore_opts; } - - if ((bool)(*flags & SB_RDONLY) =3D=3D sb_rdonly(sb)) + if ((bool)(fc->sb_flags & SB_RDONLY) =3D=3D sb_rdonly(sb)) goto out; - if (*flags & SB_RDONLY) { + if (fc->sb_flags & SB_RDONLY) { sb->s_flags |=3D SB_RDONLY; =20 /* @@ -1172,138 +1155,67 @@ static int nilfs_remount(struct super_block *sb, i= nt *flags, char *data) "couldn't remount RDWR because of unsupported optional features (%l= lx)", (unsigned long long)features); err =3D -EROFS; - goto restore_opts; + goto ignore_opts; } =20 sb->s_flags &=3D ~SB_RDONLY; =20 root =3D NILFS_I(d_inode(sb->s_root))->i_root; err =3D nilfs_attach_log_writer(sb, root); - if (err) - goto restore_opts; + if (err) { + sb->s_flags |=3D SB_RDONLY; + goto ignore_opts; + } =20 down_write(&nilfs->ns_sem); nilfs_setup_super(sb, true); up_write(&nilfs->ns_sem); } out: - return 0; - - restore_opts: - sb->s_flags =3D old_sb_flags; - nilfs->ns_mount_opt =3D old_mount_opt; - return err; -} - -struct nilfs_super_data { - __u64 cno; - int flags; -}; - -static int nilfs_parse_snapshot_option(const char *option, - const substring_t *arg, - struct nilfs_super_data *sd) -{ - unsigned long long val; - const char *msg =3D NULL; - int err; - - if (!(sd->flags & SB_RDONLY)) { - msg =3D "read-only option is not specified"; - goto parse_error; - } - - err =3D kstrtoull(arg->from, 0, &val); - if (err) { - if (err =3D=3D -ERANGE) - msg =3D "too large checkpoint number"; - else - msg =3D "malformed argument"; - goto parse_error; - } else if (val =3D=3D 0) { - msg =3D "invalid checkpoint number 0"; - goto parse_error; - } - sd->cno =3D val; - return 0; - -parse_error: - nilfs_err(NULL, "invalid option \"%s\": %s", option, msg); - return 1; -} - -/** - * nilfs_identify - pre-read mount options needed to identify mount instan= ce - * @data: mount options - * @sd: nilfs_super_data - */ -static int nilfs_identify(char *data, struct nilfs_super_data *sd) -{ - char *p, *options =3D data; - substring_t args[MAX_OPT_ARGS]; - int token; - int ret =3D 0; - - do { - p =3D strsep(&options, ","); - if (p !=3D NULL && *p) { - token =3D match_token(p, tokens, args); - if (token =3D=3D Opt_snapshot) - ret =3D nilfs_parse_snapshot_option(p, &args[0], - sd); - } - if (!options) - break; - BUG_ON(options =3D=3D data); - *(options - 1) =3D ','; - } while (!ret); - return ret; -} + sb->s_flags =3D (sb->s_flags & ~SB_POSIXACL); + /* Copy over parsed remount options */ + nilfs->ns_mount_opt =3D ctx->ns_mount_opt; =20 -static int nilfs_set_bdev_super(struct super_block *s, void *data) -{ - s->s_dev =3D *(dev_t *)data; return 0; -} =20 -static int nilfs_test_bdev_super(struct super_block *s, void *data) -{ - return !(s->s_iflags & SB_I_RETIRED) && s->s_dev =3D=3D *(dev_t *)data; + ignore_opts: + return err; } =20 -static struct dentry * -nilfs_mount(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static int +nilfs_get_tree(struct fs_context *fc) { - struct nilfs_super_data sd =3D { .flags =3D flags }; + struct nilfs_fs_context *ctx =3D fc->fs_private; struct super_block *s; dev_t dev; int err; =20 - if (nilfs_identify(data, &sd)) - return ERR_PTR(-EINVAL); + if (ctx->cno && !(fc->sb_flags & SB_RDONLY)) { + nilfs_err(NULL, + "invalid option \"cp=3D%llu\": read-only option is not specified", + ctx->cno); + return -EINVAL; + } =20 - err =3D lookup_bdev(dev_name, &dev); + err =3D lookup_bdev(fc->source, &dev); if (err) - return ERR_PTR(err); + return err; =20 - s =3D sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, flags, - &dev); + s =3D sget_dev(fc, dev); if (IS_ERR(s)) - return ERR_CAST(s); + return PTR_ERR(s); =20 if (!s->s_root) { - err =3D setup_bdev_super(s, flags, NULL); + err =3D setup_bdev_super(s, fc->sb_flags, fc); if (!err) - err =3D nilfs_fill_super(s, data, - flags & SB_SILENT ? 1 : 0); + err =3D nilfs_fill_super(s, fc); if (err) goto failed_super; =20 s->s_flags |=3D SB_ACTIVE; - } else if (!sd.cno) { + } else if (!ctx->cno) { if (nilfs_tree_is_busy(s->s_root)) { - if ((flags ^ s->s_flags) & SB_RDONLY) { + if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY) { nilfs_err(s, "the device already has a %s mount.", sb_rdonly(s) ? "read-only" : "read/write"); @@ -1312,37 +1224,75 @@ nilfs_mount(struct file_system_type *fs_type, int f= lags, } } else { /* - * Try remount to setup mount states if the current + * Try reconfigure to setup mount states if the current * tree is not mounted and only snapshots use this sb. + * + * Since nilfs_reconfigure() requires fc->root to be + * set, set it first and release it on failure. */ - err =3D nilfs_remount(s, &flags, data); - if (err) + fc->root =3D dget(s->s_root); + err =3D nilfs_reconfigure(fc); + if (err) { + dput(fc->root); + fc->root =3D NULL; /* prevent double release */ goto failed_super; + } + return 0; } } =20 - if (sd.cno) { + if (ctx->cno) { struct dentry *root_dentry; =20 - err =3D nilfs_attach_snapshot(s, sd.cno, &root_dentry); + err =3D nilfs_attach_snapshot(s, ctx->cno, &root_dentry); if (err) goto failed_super; - return root_dentry; + fc->root =3D root_dentry; + return 0; } =20 - return dget(s->s_root); + fc->root =3D dget(s->s_root); + return 0; =20 failed_super: deactivate_locked_super(s); - return ERR_PTR(err); + return err; +} + +static void nilfs_free_fc(struct fs_context *fc) +{ + kfree(fc->fs_private); +} + +static const struct fs_context_operations nilfs_context_ops =3D { + .parse_param =3D nilfs_parse_param, + .get_tree =3D nilfs_get_tree, + .reconfigure =3D nilfs_reconfigure, + .free =3D nilfs_free_fc, +}; + +static int nilfs_init_fs_context(struct fs_context *fc) +{ + struct nilfs_fs_context *ctx; + + ctx =3D kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->ns_mount_opt =3D NILFS_MOUNT_ERRORS_RO | NILFS_MOUNT_BARRIER; + fc->fs_private =3D ctx; + fc->ops =3D &nilfs_context_ops; + + return 0; } =20 struct file_system_type nilfs_fs_type =3D { .owner =3D THIS_MODULE, .name =3D "nilfs2", - .mount =3D nilfs_mount, .kill_sb =3D kill_block_super, .fs_flags =3D FS_REQUIRES_DEV, + .init_fs_context =3D nilfs_init_fs_context, + .parameters =3D nilfs_param_spec, }; MODULE_ALIAS_FS("nilfs2"); =20 diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 2ae2c1bbf6d1..db322068678f 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -659,7 +659,6 @@ static int nilfs_load_super_block(struct the_nilfs *nil= fs, * init_nilfs - initialize a NILFS instance. * @nilfs: the_nilfs structure * @sb: super block - * @data: mount options * * init_nilfs() performs common initialization per block device (e.g. * reading the super block, getting disk layout information, initializing @@ -668,7 +667,7 @@ static int nilfs_load_super_block(struct the_nilfs *nil= fs, * Return Value: On success, 0 is returned. On error, a negative error * code is returned. */ -int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data) +int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb) { struct nilfs_super_block *sbp; int blocksize; @@ -686,7 +685,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct super_bl= ock *sb, char *data) if (err) goto out; =20 - err =3D nilfs_store_magic_and_option(sb, sbp, data); + err =3D nilfs_store_magic(sb, sbp); if (err) goto failed_sbh; =20 diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index cd4ae1b8ae16..85da0629415d 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -219,10 +219,6 @@ THE_NILFS_FNS(PURGING, purging) #define nilfs_set_opt(nilfs, opt) \ ((nilfs)->ns_mount_opt |=3D NILFS_MOUNT_##opt) #define nilfs_test_opt(nilfs, opt) ((nilfs)->ns_mount_opt & NILFS_MOUNT_##= opt) -#define nilfs_write_opt(nilfs, mask, opt) \ - ((nilfs)->ns_mount_opt =3D \ - (((nilfs)->ns_mount_opt & ~NILFS_MOUNT_##mask) | \ - NILFS_MOUNT_##opt)) \ =20 /** * struct nilfs_root - nilfs root object @@ -276,7 +272,7 @@ static inline int nilfs_sb_will_flip(struct the_nilfs *= nilfs) void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); struct the_nilfs *alloc_nilfs(struct super_block *sb); void destroy_nilfs(struct the_nilfs *nilfs); -int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data= ); +int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb); int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb); unsigned long nilfs_nrsvsegs(struct the_nilfs *nilfs, unsigned long nsegs); void nilfs_set_nsegments(struct the_nilfs *nilfs, unsigned long nsegs); --=20 2.34.1