@@ -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 {
@@ -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
@@ -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);
}
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 <fdmanana@gmail.com> --- btrfstune.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- ctree.h | 8 +++++ print-tree.c | 9 +++++ 3 files changed, 120 insertions(+), 2 deletions(-)