Btrfs: Use mount -o subvol to select the subvol directory instead of dev:

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index ffeee54..cd75c90 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1064,6 +1064,12 @@
 	((type *)(btrfs_leaf_data(leaf) + \
 	btrfs_item_offset((leaf)->items + (slot))))
 
+/* mount option defines and helpers */
+#define BTRFS_MOUNT_SUBVOL		0x000001
+#define btrfs_clear_opt(o, opt)		o &= ~BTRFS_MOUNT_##opt
+#define btrfs_set_opt(o, opt)		o |= BTRFS_MOUNT_##opt
+#define btrfs_test_opt(sb, opt)		(BTRFS_SB(sb)->s_mount_opt & \
+					 BTRFS_MOUNT_##opt)
 /* extent-tree.c */
 int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
 			 struct btrfs_root *root);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 8a94be1..66a01cb 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -33,6 +33,7 @@
 #include <linux/writeback.h>
 #include <linux/statfs.h>
 #include <linux/compat.h>
+#include <linux/parser.h>
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -58,6 +59,41 @@
 	sb->s_fs_info = NULL;
 }
 
+enum {
+	Opt_subvol, Opt_err,
+};
+
+static match_table_t tokens = {
+	{Opt_subvol, "subvol=%s"},
+	{Opt_err, NULL}
+};
+
+static int parse_options (char * options,
+			  struct btrfs_root *root,
+			  char **subvol_name)
+{
+	char * p;
+	substring_t args[MAX_OPT_ARGS];
+	if (!options)
+		return 1;
+
+	while ((p = strsep (&options, ",")) != NULL) {
+		int token;
+		if (!*p)
+			continue;
+
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case Opt_subvol:
+			*subvol_name = match_strdup(&args[0]);
+			break;
+		default:
+			return 0;
+		}
+	}
+	return 1;
+}
+
 static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
 {
 	struct inode * inode;
@@ -250,22 +286,15 @@
 /* end copy & paste */
 
 static int btrfs_get_sb(struct file_system_type *fs_type,
-	int flags, const char *identifier, void *data, struct vfsmount *mnt)
+	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
 	int ret;
-	char *_identifier = kstrdup(identifier, GFP_KERNEL);
-	char *subvol_name;
-	const char *dev_name;
+	char *subvol_name = NULL;
 
-	subvol_name = _identifier;
-	dev_name = strsep(&subvol_name, ":");
-	if (!dev_name)
-		return -ENOMEM;
-
+	parse_options((char *)data, NULL, &subvol_name);
 	ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data,
 			btrfs_fill_super, mnt,
 			subvol_name ? subvol_name : "default");
-	kfree(_identifier);
 	return ret;
 }