Btrfs: deal with all 'subvol=xxx' options once
diff mbox

Message ID 1416900194-17495-1-git-send-email-wangshilong1991@gmail.com
State New, archived
Headers show

Commit Message

Wang Shilong Nov. 25, 2014, 7:23 a.m. UTC
Steps to reproduce:
 # mkfs.btrfs -f /dev/sdb
 # mount -t btrfs /dev/sdb /mnt
 # btrfs sub create /mnt/dir
 # mount -t btrfs /dev/sdb /mnt -o subvol=dir,subvol=dir

It fails with:
 mount: mount(2) failed: No such file or directory

Btrfs deal with subvolume mounting in a recursive way,
to avoid looping, it will stripe out 'subvol=xxxx' string,
then next loop will stop.Problem here is it only deal one
string once, if users specify mount option multiple times.
It will loop several times which is not good, and above
reproducing steps will also return confusing results.

Fix this problem by striping out all 'subvol=xxx' options,
only last is valid.

Signed-off-by: Wang Shilong <wangshilong1991@gmail.com>
---
 fs/btrfs/super.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

Comments

Wang Shilong Nov. 25, 2014, 7:42 a.m. UTC | #1
> 
> Steps to reproduce:
> # mkfs.btrfs -f /dev/sdb
> # mount -t btrfs /dev/sdb /mnt
> # btrfs sub create /mnt/dir
> # mount -t btrfs /dev/sdb /mnt -o subvol=dir,subvol=dir
> 
> It fails with:
> mount: mount(2) failed: No such file or directory
> 
> Btrfs deal with subvolume mounting in a recursive way,
> to avoid looping, it will stripe out 'subvol=xxxx' string,
> then next loop will stop.Problem here is it only deal one
> string once, if users specify mount option multiple times.
> It will loop several times which is not good, and above
> reproducing steps will also return confusing results.
> 
> Fix this problem by striping out all 'subvol=xxx' options,
> only last is valid.
> 
> Signed-off-by: Wang Shilong <wangshilong1991@gmail.com>
> ---
> fs/btrfs/super.c | 20 +++++++++++++++++++-
> 1 file changed, 19 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index 54bd91e..2b2fa4b 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -1115,7 +1115,7 @@ static inline int is_subvolume_inode(struct inode *inode)
>  * subvolid=0 to make sure we get the actual tree root for path walking to the
>  * subvol we want.
>  */
> -static char *setup_root_args(char *args)
> +static char *__setup_root_args(char *args)
> {
> 	unsigned len = strlen(args) + 2 + 1;
> 	char *src, *dst, *buf;
> @@ -1161,6 +1161,24 @@ static char *setup_root_args(char *args)
> 	return buf;
> }
> 
> +static char *setup_root_args(char *args)
> +{
> +	char *p, *new_args;
> +
> +	p = new_args = __setup_root_args(args);
> +	/* in case users specify subvol=xxx option multiple times */
> +	while (p) {
> +		p = __setup_root_args(new_args);

Oh, i missed error handling here, will update it..



> +		if (p) {
> +			kfree(new_args);
> +			new_args = p;
> +		} else {
> +			break;
> +		}
> +	}
> +	return new_args;
> +}
> +
> static struct dentry *mount_subvol(const char *subvol_name, int flags,
> 				   const char *device_name, char *data)
> {
> -- 
> 1.7.12.4
> 

Best Regards,
Wang Shilong

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 54bd91e..2b2fa4b 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1115,7 +1115,7 @@  static inline int is_subvolume_inode(struct inode *inode)
  * subvolid=0 to make sure we get the actual tree root for path walking to the
  * subvol we want.
  */
-static char *setup_root_args(char *args)
+static char *__setup_root_args(char *args)
 {
 	unsigned len = strlen(args) + 2 + 1;
 	char *src, *dst, *buf;
@@ -1161,6 +1161,24 @@  static char *setup_root_args(char *args)
 	return buf;
 }
 
+static char *setup_root_args(char *args)
+{
+	char *p, *new_args;
+
+	p = new_args = __setup_root_args(args);
+	/* in case users specify subvol=xxx option multiple times */
+	while (p) {
+		p = __setup_root_args(new_args);
+		if (p) {
+			kfree(new_args);
+			new_args = p;
+		} else {
+			break;
+		}
+	}
+	return new_args;
+}
+
 static struct dentry *mount_subvol(const char *subvol_name, int flags,
 				   const char *device_name, char *data)
 {