Btrfs: Add mount option to turn off data cow

A number of workloads do not require copy on write data or checksumming.
mount -o nodatasum to disable checksums and -o nodatacow to disable
both copy on write and checksumming.

In nodatacow mode, copy on write is still performed when a given extent
is under snapshot.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index ad4f280..2116728 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -61,12 +61,13 @@
 }
 
 enum {
-	Opt_subvol, Opt_nodatasum, Opt_err,
+	Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_err,
 };
 
 static match_table_t tokens = {
 	{Opt_subvol, "subvol=%s"},
 	{Opt_nodatasum, "nodatasum"},
+	{Opt_nodatacow, "nodatacow"},
 	{Opt_err, NULL}
 };
 
@@ -78,12 +79,20 @@
 	struct btrfs_fs_info *info = NULL;
 	substring_t args[MAX_OPT_ARGS];
 
-	if (root)
-		info = root->fs_info;
-
 	if (!options)
 		return 1;
 
+	/*
+	 * strsep changes the string, duplicate it because parse_options
+	 * gets called twice
+	 */
+	options = kstrdup(options, GFP_NOFS);
+	if (!options)
+		return -ENOMEM;
+
+	if (root)
+		info = root->fs_info;
+
 	while ((p = strsep (&options, ",")) != NULL) {
 		int token;
 		if (!*p)
@@ -92,17 +101,28 @@
 		token = match_token(p, tokens, args);
 		switch (token) {
 		case Opt_subvol:
-			if (subvol_name)
+			if (subvol_name) {
 				*subvol_name = match_strdup(&args[0]);
+			}
 			break;
 		case Opt_nodatasum:
-			if (root)
+			if (info) {
+				printk("btrfs: setting nodatacsum\n");
 				btrfs_set_opt(info->mount_opt, NODATASUM);
+			}
+			break;
+		case Opt_nodatacow:
+			if (info) {
+				printk("btrfs: setting nodatacow\n");
+				btrfs_set_opt(info->mount_opt, NODATACOW);
+				btrfs_set_opt(info->mount_opt, NODATASUM);
+			}
 			break;
 		default:
-			return 0;
+			break;
 		}
 	}
+	kfree(options);
 	return 1;
 }