This is the complement to the corresponding kernel patch that
adds support for permanent options.

NOTE: Like the corresponding kernel patch, this is a WIP with the
goal o gathering feedback.

Signed-off-by: Filipe David Borba Manana <[email protected]>
---
 btrfstune.c  |  105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 ctree.h      |    8 +++++
 print-tree.c |    9 +++++
 3 files changed, 120 insertions(+), 2 deletions(-)

diff --git a/btrfstune.c b/btrfstune.c
index 4db1767..b3d3e57 100644
--- a/btrfstune.c
+++ b/btrfstune.c
@@ -97,12 +97,100 @@ int enable_skinny_metadata(struct btrfs_root *root)
        return 0;
 }
 
+static int set_persistent_mount_options(struct btrfs_root *root,
+                                       const char *options)
+{
+       int ret;
+       struct btrfs_trans_handle *trans = NULL;
+       struct btrfs_path *path;
+       struct btrfs_key key, location;
+       struct extent_buffer *leaf;
+       struct btrfs_dir_item *dir_item;
+       struct btrfs_disk_key disk_key;
+       struct btrfs_root *tree_root = root->fs_info->tree_root;
+       unsigned long data_ptr;
+       u32 data_size, data_len;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       trans = btrfs_start_transaction(root, 1);
+       if (!trans) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       key.objectid = BTRFS_PERSISTENT_OPTIONS_OBJECTID;
+       key.type = 0;
+       key.offset = 0;
+
+       ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
+       if (ret < 0)
+               goto out;
+       if (!ret) {
+               char *buf;
+
+               leaf = path->nodes[0];
+               dir_item = btrfs_item_ptr(leaf, path->slots[0],
+                                         struct btrfs_dir_item);
+               buf = (char *) malloc(btrfs_dir_data_len(leaf, dir_item));
+               if (!buf) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               read_extent_buffer(leaf, buf,
+                                  (unsigned long)((char *)(dir_item + 1)),
+                                  btrfs_dir_data_len(leaf, dir_item));
+               printf("Current persistent options:  %.*s\n",
+                      btrfs_dir_data_len(leaf, dir_item), buf);
+               free(buf);
+               ret = btrfs_del_item(trans, tree_root, path);
+               if (ret)
+                       goto out;
+       }
+
+       btrfs_release_path(root, path);
+
+       data_len = strlen(options);
+       data_size = sizeof(*dir_item) + data_len;
+       ret = btrfs_insert_empty_item(trans, tree_root, path, &key, data_size);
+       if (ret)
+               goto out;
+
+       leaf = path->nodes[0];
+       dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
+
+       memset(&location, 0, sizeof(location));
+       btrfs_cpu_key_to_disk(&disk_key, &location);
+       btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
+       btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_UNKNOWN);
+       btrfs_set_dir_name_len(leaf, dir_item, 0);
+       btrfs_set_dir_data_len(leaf, dir_item, data_len);
+       data_ptr = (unsigned long)((char *)(dir_item + 1));
+
+       write_extent_buffer(leaf, options, data_ptr, data_len);
+       btrfs_mark_buffer_dirty(leaf);
+
+out:
+       if (!ret && trans)
+               ret = btrfs_commit_transaction(trans, root);
+       else if (trans)
+               btrfs_free_transaction(root, trans);
+       btrfs_free_path(path);
+       if (!ret)
+               printf("New persistent options:      %s\n", options);
+
+       return ret;
+}
+
 static void print_usage(void)
 {
        fprintf(stderr, "usage: btrfstune [options] device\n");
        fprintf(stderr, "\t-S value\tenable/disable seeding\n");
        fprintf(stderr, "\t-r \t\tenable extended inode refs\n");
-       fprintf(stderr, "\t-x enable skinny metadata extent refs\n");
+       fprintf(stderr, "\t-x \t\tenable skinny metadata extent refs\n");
+       fprintf(stderr, "\t-o options\tset persistent mount options\n");
 }
 
 int main(int argc, char *argv[])
@@ -114,9 +202,10 @@ int main(int argc, char *argv[])
        int seeding_value = 0;
        int skinny_flag = 0;
        int ret;
+       char *options = NULL;
 
        while(1) {
-               int c = getopt(argc, argv, "S:rx");
+               int c = getopt(argc, argv, "S:rxo:");
                if (c < 0)
                        break;
                switch(c) {
@@ -130,6 +219,9 @@ int main(int argc, char *argv[])
                case 'x':
                        skinny_flag = 1;
                        break;
+               case 'o':
+                       options = optarg;
+                       break;
                default:
                        print_usage();
                        return 1;
@@ -171,6 +263,15 @@ int main(int argc, char *argv[])
                success++;
        }
 
+       if (options) {
+               ret = set_persistent_mount_options(root, options);
+               if (ret)
+                       fprintf(stderr,
+                               "Error setting persistent options: %d\n", ret);
+               else
+                       success++;
+       }
+
        if (success > 0) {
                ret = 0;
        } else {
diff --git a/ctree.h b/ctree.h
index 0b0d701..8255661 100644
--- a/ctree.h
+++ b/ctree.h
@@ -102,6 +102,14 @@ struct btrfs_free_space_ctl;
  */
 #define BTRFS_FREE_INO_OBJECTID -12ULL
 
+/*
+ * Item that stores permanent mount options. These options
+ * have effect if they are not specified as well at mount
+ * time (that is, if a permanent option is also specified at
+ * mount time, the later wins).
+ */
+#define BTRFS_PERSISTENT_OPTIONS_OBJECTID -13ULL
+
 /* dummy objectid represents multiple objectids */
 #define BTRFS_MULTIPLE_OBJECTIDS -255ULL
 
diff --git a/print-tree.c b/print-tree.c
index aae47a9..4cb7af6 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -585,6 +585,9 @@ static void print_objectid(u64 objectid, u8 type)
        case BTRFS_MULTIPLE_OBJECTIDS:
                printf("MULTIPLE");
                break;
+       case BTRFS_PERSISTENT_OPTIONS_OBJECTID:
+               printf("PERSISTENT_OPTIONS");
+               break;
        case (u64)-1:
                printf("-1");
                break;
@@ -849,6 +852,12 @@ void btrfs_print_leaf(struct btrfs_root *root, struct 
extent_buffer *l)
                case BTRFS_DEV_STATS_KEY:
                        printf("\t\tdevice stats\n");
                        break;
+               case 0:
+                       if (objectid == BTRFS_PERSISTENT_OPTIONS_OBJECTID) {
+                               di = btrfs_item_ptr(l, i, struct 
btrfs_dir_item);
+                               print_dir_item(l, item, di);
+                       }
+                       break;
                };
                fflush(stdout);
        }
-- 
1.7.9.5

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

Reply via email to