New utility(btrfsrevert) added to swap subvolumes.
With this utility, a subvolume (Source Subvolume) takes place of
another subvolume (Target Subvolume), and target subvolume goes
under hidden directory(".old_trees") in filesystem root(fs tree,
tree id=5), and its name is expanded with random UUID.
This utility cannot operate mounted filesystem. This is only for
unmounted device.
And this utility also cannot operate filesystem root. For now,
if we want to swap filesystem root, we can use btrfsctl with
Josef Bacik''s patch. I wonder which is better, integrating
''root swap''
ioctl or not supporting ''root swap'' as for this utility...
A patch follows this mail.
man-page-like description and examples are as follows.
NAME
btrfsrevert - swap subvolumes.
SYNOPSIS
btrfsrevert -s source_subvolume -t target_subvolume device
OPTIONS
-s source subvolume
Specify subvolume number which replace target
subvolume.
-t target subvolume
Specify subvolume number which is replaced by
source subvolume.
device
Specify target device which is not mounted.
SAMPLES
Consider two subvolumes ''target''(id=256) and
''source''(id=300)
exist in filesystem root.
/ +
+- ''target'' (id=256)
+- ''source'' (id=300)
In this case, following command swaps subvolume,
# btrfsrevert -s 300 -t 256 /dev/hda1
like this.
/ +
+- ''target'' (id=300)
|
+- ''.old_tree''
+- ''target_[random uuid]'' (id=256)
A subvolume(id:256) is replaced with a subvolume(id:300),
and replaced subvolume(id:256) goes to .old_trees directory.
Regards,
taruisi
--
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
Add btrfsrevert utility to swap subvolumes.
Signed-off-by: TARUISI Hiroaki <taruishi.hiroak@jp.fujitsu.com>
---
Makefile | 5
btrfsrevert.c | 778 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 782 insertions(+), 1 deletion(-)
Index: b/Makefile
==================================================================--- a/Makefile
2009-12-24 10:45:24.000000000 +0900
+++ b/Makefile 2009-12-24 10:45:43.000000000 +0900
@@ -17,7 +17,7 @@ bindir = $(prefix)/bin
LIBS=-luuid
progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \
- btrfs-map-logical
+ btrfs-map-logical btrfsrevert
# make C=1 to enable sparse
ifdef C
@@ -63,6 +63,9 @@ btrfs-map-logical: $(objects) btrfs-map-
btrfs-image: $(objects) btrfs-image.o
gcc $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS)
$(LIBS)
+btrfsrevert: $(objects) btrfsrevert.o
+ gcc $(CFLAGS) -o btrfsrevert $(objects) btrfsrevert.o $(LDFLAGS) $(LIBS)
+
dir-test: $(objects) dir-test.o
gcc $(CFLAGS) -o dir-test $(objects) dir-test.o $(LDFLAGS) $(LIBS)
Index: b/btrfsrevert.c
==================================================================--- /dev/null
1970-01-01 00:00:00.000000000 +0000
+++ b/btrfsrevert.c 2009-12-24 10:45:43.000000000 +0900
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2008 Oracle. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#define _XOPEN_SOURCE 500
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <uuid/uuid.h>
+#include "kerncompat.h"
+#include "ctree.h"
+#include "disk-io.h"
+#include "transaction.h"
+#include "utils.h"
+#include "version.h"
+#include "ioctl.h"
+#include "hash.h"
+#include <mcheck.h>
+
+#define BTRFS_REVERTED_TREE_LOCATION ".old_trees"
+
+struct tree_info {
+ u64 id, parent_treeid;
+ u64 parent_dirid, index;
+ int name_len;
+ char *name;
+};
+
+struct revert_packet {
+ struct tree_info source, target, backup;
+};
+
+static void print_usage(void)
+{
+ fprintf(stderr, "usage: btrfsrevert [options] device\n");
+ fprintf(stderr, "\t-s source tree\n");
+ fprintf(stderr, "\t-t target tree\n");
+}
+
+static int find_file_tree(struct btrfs_root *root, struct tree_info *tinfo)
+{
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ struct btrfs_root_ref *ref;
+ int ret;
+
+ if (tinfo->id == BTRFS_FS_TREE_OBJECTID) {
+ tinfo->name = malloc(9);
+ strcpy(tinfo->name, "default");
+ tinfo->name_len = 8;
+ return 0;
+ }
+ if (tinfo->id < BTRFS_FIRST_FREE_OBJECTID ||
+ BTRFS_LAST_FREE_OBJECTID < tinfo->id)
+ return 2;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ key.objectid = tinfo->id;
+ key.type = BTRFS_ROOT_BACKREF_KEY;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key,
+ path, 0, 0);
+ if (ret < 0)
+ goto out;
+
+ BUG_ON(ret == 0);
+ if (path->slots[0] == 0) {
+ ret = btrfs_prev_leaf(root->fs_info->tree_root, path);
+
+ if (ret)
+ goto out;
+ } else
+ path->slots[0]--;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ if (key.objectid == tinfo->id && key.type ==
BTRFS_ROOT_BACKREF_KEY) {
+ ret = 0;
+ tinfo->parent_treeid = key.offset;
+ ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_root_ref);
+ tinfo->parent_dirid = btrfs_root_ref_dirid(path->nodes[0], ref);
+ tinfo->index = btrfs_root_ref_sequence(path->nodes[0], ref);
+ tinfo->name_len = btrfs_root_ref_name_len(path->nodes[0], ref);
+ tinfo->name = malloc(tinfo->name_len + 1);
+ if (tinfo->name) {
+ tinfo->name[tinfo->name_len] = ''\0'';
+ read_extent_buffer(path->nodes[0], tinfo->name,
+ (long)(ref + 1), tinfo->name_len);
+ } else
+ ret = -ENOMEM;
+ } else
+ ret = 1;
+
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
+static int btrfs_revert_root(struct btrfs_fs_info *fs_info,
+ struct revert_packet *rvp)
+{
+ printf("Root swap is not implemented yet.\n");
+ return 0;
+}
+
+static int btrfs_update_root_ref(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct btrfs_key *ref_key,
+ struct tree_info *f_tinfo, struct tree_info *t_tinfo,
+ char *new_name)
+{
+ struct btrfs_root *tree_root = root->fs_info->tree_root;
+ struct btrfs_root_ref *oldref;
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ int ret, name_len, new_name_len = strlen(new_name);
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+ if (f_tinfo->parent_treeid != t_tinfo->parent_treeid) {
+ if (ref_key->type == BTRFS_ROOT_REF_KEY) {
+ ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
+ t_tinfo->parent_treeid, BTRFS_ROOT_REF_KEY, f_tinfo->id,
+ t_tinfo->parent_dirid, t_tinfo->index, new_name,
+ strlen(new_name));
+ if (ret)
+ goto error;
+ ref_key->objectid = t_tinfo->parent_treeid;
+ ref_key->offset = f_tinfo->id;
+
+ key.objectid = f_tinfo->parent_treeid;
+ key.type = BTRFS_ROOT_REF_KEY;
+ key.offset = f_tinfo->id;
+ ret = btrfs_search_slot(trans, tree_root, &key, path,
+ -(sizeof(struct btrfs_root_ref) + f_tinfo->name_len), 1);
+ if (ret)
+ goto error;
+ ret = btrfs_del_item(trans, tree_root, path);
+ if (ret)
+ goto error;
+ } else if (ref_key->type == BTRFS_ROOT_BACKREF_KEY) {
+ ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
+ f_tinfo->id, BTRFS_ROOT_BACKREF_KEY, t_tinfo->parent_treeid,
+ t_tinfo->parent_dirid, t_tinfo->index, new_name,
+ strlen(new_name));
+ if (ret)
+ goto error;
+ ref_key->objectid = f_tinfo->id;
+ ref_key->offset = t_tinfo->parent_treeid;
+
+ key.objectid = f_tinfo->id;
+ key.type = BTRFS_ROOT_BACKREF_KEY;
+ key.offset = f_tinfo->parent_treeid;
+ ret = btrfs_search_slot(trans, tree_root, &key, path,
+ -(sizeof(struct btrfs_root_ref) + f_tinfo->name_len), 1);
+ if (ret)
+ goto error;
+ ret = btrfs_del_item(trans, tree_root, path);
+ if (ret)
+ goto error;
+ }
+ btrfs_release_path(tree_root, path);
+ }
+
+ ret = btrfs_search_slot(trans, tree_root, ref_key, path,
+ strlen(new_name) - f_tinfo->name_len, 1);
+ if (ret)
+ goto error;
+
+ oldref = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_root_ref);
+ name_len = btrfs_root_ref_name_len(path->nodes[0], oldref);
+
+ if (name_len < new_name_len) {
+ ret = btrfs_extend_item(trans, tree_root, path,
+ new_name_len - name_len);
+ if (ret)
+ goto error;
+ } else {
+ ret = btrfs_truncate_item(trans, tree_root, path,
+ sizeof(*oldref) + new_name_len, 1);
+ if (ret)
+ goto error;
+ }
+ oldref = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_root_ref);
+ write_extent_buffer(path->nodes[0], new_name,
+ (unsigned long)(oldref + 1), new_name_len);
+ btrfs_set_root_ref_name_len(path->nodes[0], oldref, new_name_len);
+ btrfs_set_root_ref_dirid(path->nodes[0], oldref, t_tinfo->parent_dirid);
+ btrfs_set_root_ref_sequence(path->nodes[0], oldref, t_tinfo->index);
+
+ btrfs_free_path(path);
+ return 0;
+
+error:
+ btrfs_free_path(path);
+ return 1;
+}
+
+static int btrfs_find_highest_index(struct btrfs_root *fs_root,
+ u64 i_no, u64 *index)
+{
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ int ret;
+
+ key.objectid = i_no;
+ key.type = BTRFS_DIR_INDEX_KEY;
+ key.offset = (u64)-1;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+ ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
+ if (ret <0)
+ goto out;
+ BUG_ON(ret == 0);
+ if (path->slots[0] == 0) {
+ *index = 1ULL;
+ } else {
+ path->slots[0]--;
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ if (key.objectid == i_no && key.type == BTRFS_DIR_INDEX_KEY)
+ *index = key.offset;
+ else {
+ *index = 1ULL;
+ }
+ }
+ ret = 0;
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
+static int btrfs_update_parent_dir_size(struct btrfs_trans_handle *trans,
+ struct btrfs_root *fs_root, struct btrfs_path *path, u64 parent_id,
+ int name_len)
+{
+ struct btrfs_key parent_key = {parent_id, BTRFS_INODE_ITEM_KEY, 0ULL};;
+ struct btrfs_inode_item *parent_inode;
+ u64 dir_size;
+ int ret;
+
+ ret = btrfs_search_slot(trans, fs_root, &parent_key, path, 0, 1);
+ BUG_ON(ret);
+
+ parent_inode = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_inode_item);
+
+ dir_size = btrfs_inode_size(path->nodes[0], parent_inode);
+ btrfs_set_inode_size(path->nodes[0], parent_inode, dir_size+name_len*2);
+ btrfs_mark_buffer_dirty(path->nodes[0]);
+
+ return 0;
+}
+
+static int btrfs_create_dir(struct btrfs_root *root, u64 dirid,
+ char *dir_name, struct revert_packet *rvp)
+{
+ struct btrfs_inode_item inode_item;
+ struct btrfs_dir_item *dir_item;
+ struct btrfs_path *path;
+ struct btrfs_trans_handle *trans;
+ struct btrfs_key location, found_key;
+ int ret;
+ u64 objectid, index = 0;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ dir_item = btrfs_lookup_dir_item(NULL, root, path, dirid,
+ dir_name, strlen(dir_name), 0);
+
+ if (dir_item) {
+ btrfs_dir_item_key_to_cpu(path->nodes[0], dir_item, &found_key);
+ if (rvp) {
+ rvp->backup.id = root->root_key.objectid;
+ rvp->backup.parent_dirid = found_key.objectid;
+ rvp->backup.parent_treeid = root->root_key.objectid;
+ }
+ btrfs_free_path(path);
+ return 0;
+ }
+
+ btrfs_release_path(root, path);
+
+ ret = btrfs_find_highest_inode(root, &objectid);
+ if (ret)
+ return -1;
+
+ ret = btrfs_find_highest_index(root, BTRFS_FIRST_FREE_OBJECTID, &index);
+ if (ret)
+ return -1;
+
+ trans = btrfs_start_transaction(root, 1);
+ if (!trans)
+ return -ENOMEM;
+
+ objectid++;
+ index++;
+ if (rvp) {
+ rvp->backup.id = root->root_key.objectid;
+ rvp->backup.parent_dirid = objectid;
+ rvp->backup.parent_treeid = root->root_key.objectid;
+ }
+
+ memset(&inode_item, 0, sizeof(inode_item));
+ btrfs_set_stack_inode_generation(&inode_item, trans->transid);
+ btrfs_set_stack_inode_size(&inode_item, 0);
+ btrfs_set_stack_inode_nlink(&inode_item, 1);
+ btrfs_set_stack_inode_nbytes(&inode_item, root->leafsize);
+ btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0555);
+ ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
+ if (ret)
+ goto out;
+ ret = btrfs_insert_inode_ref(trans, root, dir_name, strlen(dir_name),
+ objectid, BTRFS_FIRST_FREE_OBJECTID, index);
+ if (ret)
+ goto out;
+
+ location.objectid = objectid;
+ location.offset = 0ULL;
+ location.type = BTRFS_INODE_ITEM_KEY;
+
+ ret = btrfs_insert_dir_item(trans, root, dir_name, strlen(dir_name),
+ BTRFS_FIRST_FREE_OBJECTID, &location, BTRFS_FT_DIR, index);
+ if (ret)
+ goto out;
+ ret = btrfs_update_parent_dir_size(trans, root, path,
+ BTRFS_FIRST_FREE_OBJECTID, strlen(dir_name));
+
+ btrfs_commit_transaction(trans, root);
+out:
+ btrfs_free_path(path);
+ return 0;
+}
+
+static char *generate_uuid_string(char *name)
+{
+ uuid_t uuid;
+ int len = strlen(name);
+ char *ret_name;
+
+ if (len + 37 > BTRFS_VOL_NAME_MAX)
+ len = BTRFS_VOL_NAME_MAX - 37;
+ ret_name = malloc(38+len);
+ if (!ret_name)
+ return NULL;
+ ret_name[37+len]=''\0'';
+ strncpy(ret_name, name, len);
+ ret_name[len] = ''_'';
+ uuid_generate_time(uuid);
+ uuid_unparse(uuid, ret_name + len + 1);
+
+ return ret_name;
+}
+
+static int btrfs_create_backup_link(struct btrfs_trans_handle *trans,
+ struct btrfs_root *backup_root, char *name, struct revert_packet *rvp)
+{
+ struct btrfs_dir_item *dir_item;
+ struct btrfs_path *path;
+ struct btrfs_key location, ref_key;
+ struct btrfs_root *tree_root = backup_root->fs_info->tree_root;
+ int ret;
+
+ if (!name)
+ return -1;
+ path = btrfs_alloc_path();
+ if (!path) {
+ return -ENOMEM;
+ }
+
+ dir_item = btrfs_lookup_dir_item(NULL, backup_root, path,
+ rvp->backup.parent_dirid, name, strlen(name), 0);
+ if (dir_item)
+ goto error;
+
+ btrfs_release_path(backup_root, path);
+
+ ret = btrfs_find_highest_index(backup_root, rvp->backup.parent_dirid,
+ &rvp->backup.index);
+ if (ret)
+ goto error;
+
+ rvp->backup.index++;
+
+ location.objectid = rvp->target.id;
+ location.type = BTRFS_ROOT_ITEM_KEY;
+ location.offset = (u64)-1;
+
+ ret = btrfs_insert_dir_item(trans, backup_root, name, strlen(name),
+ rvp->backup.parent_dirid, &location, BTRFS_FT_DIR,
+ rvp->backup.index);
+ if (ret)
+ goto error;
+
+ ret = btrfs_update_parent_dir_size(trans, backup_root, path,
+ rvp->backup.parent_dirid, strlen(name));
+ if (ret)
+ goto error;
+
+ btrfs_free_path(path);
+
+ ref_key.objectid = rvp->target.id;
+ ref_key.type = BTRFS_ROOT_BACKREF_KEY;
+ ref_key.offset = rvp->target.parent_treeid;
+ ret = btrfs_update_root_ref(trans, tree_root, &ref_key,
&rvp->target,
+ &rvp->backup, name);
+ if (ret)
+ return -1;
+
+ ref_key.objectid = rvp->target.parent_treeid;
+ ref_key.type = BTRFS_ROOT_REF_KEY;
+ ref_key.offset = rvp->target.id;
+ ret = btrfs_update_root_ref(trans, tree_root, &ref_key,
&rvp->target,
+ &rvp->backup, name);
+ if (ret)
+ return -1;
+
+ return 0;
+
+error:
+ btrfs_free_path(path);
+ return -1;
+}
+
+static u64 btrfs_find_current_root(struct btrfs_root *root)
+{
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ struct btrfs_dir_item *dir_item;
+ struct btrfs_root *tree_root = root->fs_info->tree_root;
+ int ret;
+ char *default_name = "default";
+
+ key.objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ key.type = BTRFS_DIR_ITEM_KEY;
+ key.offset = btrfs_name_hash(default_name, strlen(default_name));
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return 0ULL;
+ ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
+ BUG_ON(ret);
+
+ dir_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_dir_item);
+ BUG_ON(IS_ERR(dir_item));
+
+ btrfs_dir_item_key_to_cpu(path->nodes[0], dir_item, &key);
+
+ btrfs_free_path(path);
+ return key.objectid;
+}
+
+static struct btrfs_root *btrfs_read_fs_root_by_objectid(
+ struct btrfs_fs_info *fs_info, u64 tree_id)
+{
+ struct btrfs_key key;
+
+ key.objectid = tree_id;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+
+ return btrfs_read_fs_root(fs_info, &key);
+}
+
+static void btrfs_update_dir_location(struct btrfs_trans_handle *trans,
+ struct btrfs_path *path, u64 tree_id)
+{
+ struct btrfs_dir_item *di_ref;
+ struct btrfs_key location;
+ struct btrfs_disk_key disk_location;
+
+ di_ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_dir_item);
+ BUG_ON(!di_ref);
+ location.objectid = tree_id;
+ location.type = BTRFS_ROOT_ITEM_KEY;
+ location.offset = (u64)-1;
+
+ btrfs_cpu_key_to_disk(&disk_location, &location);
+ btrfs_set_dir_item_key(path->nodes[0], di_ref, &disk_location);
+
+ btrfs_mark_buffer_dirty(path->nodes[0]);
+}
+
+static int btrfs_switch_dir_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct revert_packet *rvp)
+{
+ struct btrfs_root *tree_root, *file_root;
+ struct btrfs_key key;
+ struct btrfs_path *path;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+ file_root = btrfs_read_fs_root_by_objectid(root->fs_info,
+ rvp->target.parent_treeid);
+ if (IS_ERR(file_root))
+ return -EINVAL;
+ tree_root = btrfs_read_fs_root_by_objectid(root->fs_info,
+ BTRFS_ROOT_TREE_OBJECTID);
+ BUG_ON(IS_ERR(tree_root));
+
+ key.objectid = rvp->target.parent_dirid;
+ key.type = BTRFS_DIR_ITEM_KEY;
+ key.offset = btrfs_name_hash(rvp->target.name, rvp->target.name_len);
+
+ ret = btrfs_search_slot(trans, file_root, &key, path, 0, 1);
+ BUG_ON(ret);
+
+ btrfs_update_dir_location(trans, path, rvp->source.id);
+ btrfs_release_path(file_root, path);
+
+ key.objectid = rvp->target.parent_dirid;
+ key.type = BTRFS_DIR_INDEX_KEY;
+ key.offset = rvp->target.index;
+ ret = btrfs_search_slot(trans, file_root, &key, path, 0, 1);
+ BUG_ON(ret);
+
+ btrfs_update_dir_location(trans, path, rvp->source.id);
+ btrfs_free_path(path);
+
+ key.objectid = rvp->source.parent_treeid;
+ key.type = BTRFS_ROOT_REF_KEY;
+ key.offset = rvp->source.id;
+ ret = btrfs_update_root_ref(trans, tree_root, &key, &rvp->source,
+ &rvp->target, rvp->target.name);
+ if (ret)
+ return ret;
+
+ key.objectid = rvp->source.id;
+ key.type = BTRFS_ROOT_BACKREF_KEY;
+ key.offset = rvp->source.parent_treeid;
+ ret = btrfs_update_root_ref(trans, tree_root, &key, &rvp->source,
+ &rvp->target, rvp->target.name);
+
+ return ret;
+}
+
+static int btrfs_del_dir_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, struct tree_info *tinfo)
+{
+ struct btrfs_path *path;
+ struct btrfs_key key;
+ int ret, del_size;
+
+ path = btrfs_alloc_path();
+ key.objectid = tinfo->parent_dirid;
+ key.type = BTRFS_DIR_ITEM_KEY;
+ key.offset = btrfs_name_hash(tinfo->name, tinfo->name_len);
+ del_size = sizeof(struct btrfs_dir_item) + tinfo->name_len;
+
+ ret = btrfs_search_slot(trans, root, &key, path, -del_size, 1);
+ BUG_ON(ret);
+ ret = btrfs_del_item(trans, root, path);
+ if (ret)
+ goto out;
+ btrfs_release_path(root, path);
+
+ key.objectid = tinfo->parent_dirid;
+ key.type = BTRFS_DIR_INDEX_KEY;
+ key.offset = tinfo->index;
+
+ ret = btrfs_search_slot(trans, root, &key, path, -del_size, 1);
+ BUG_ON(ret);
+ ret = btrfs_del_item(trans, root, path);
+ if (ret)
+ goto out;
+ btrfs_release_path(root, path);
+
+ ret = btrfs_update_parent_dir_size(trans, root, path,
+ tinfo->parent_dirid, -tinfo->name_len);
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
+static int btrfs_revert_directory(struct btrfs_fs_info *fs_info,
+ struct revert_packet *rvp)
+{
+ struct btrfs_trans_handle *trans;
+ struct btrfs_root *backup_root, *target_root, *source_root;
+ int ret;
+ char *store_name;
+
+ store_name = generate_uuid_string(rvp->target.name);
+ printf("\tOld target subvolume is moved to default filesystem
root\n");
+ printf("\t (path = /%s/%s)\n",
+ BTRFS_REVERTED_TREE_LOCATION, store_name);
+
+ ret = btrfs_create_dir(fs_info->fs_root, BTRFS_FIRST_FREE_OBJECTID,
+ BTRFS_REVERTED_TREE_LOCATION, rvp);
+ if(ret)
+ goto out_error;
+
+ backup_root = btrfs_read_fs_root_by_objectid(fs_info, rvp->backup.id);
+ if (!backup_root)
+ goto out_error;
+ trans = btrfs_start_transaction(backup_root, 1);
+ if (!trans)
+ goto out_error;
+ ret = btrfs_create_backup_link(trans, backup_root, store_name, rvp);
+ if (ret)
+ goto out_error;
+ btrfs_commit_transaction(trans, backup_root);
+
+ target_root = btrfs_read_fs_root_by_objectid(fs_info,
+ rvp->target.parent_treeid);
+ if (!target_root)
+ goto out_error;
+ trans = btrfs_start_transaction(target_root, 1);
+ if (!trans)
+ goto out_error;
+ ret = btrfs_switch_dir_item(trans, backup_root, rvp);
+ if (ret)
+ goto out_error;
+ btrfs_commit_transaction(trans, target_root);
+
+ source_root = btrfs_read_fs_root_by_objectid(fs_info,
+ rvp->source.parent_treeid);
+ if (!source_root)
+ goto out_error;
+ trans = btrfs_start_transaction(source_root, 1);
+ if (!trans)
+ goto out_error;
+ ret = btrfs_del_dir_item(trans, source_root, &rvp->source);
+ if (ret)
+ goto out_error;
+ btrfs_commit_transaction(trans, source_root);
+
+ free(store_name);
+ return 0;
+
+out_error:
+ free(store_name);
+ return -1;
+}
+
+static char *device;
+
+int main(int argc, char *argv[])
+{
+ struct btrfs_root *root = NULL;
+ struct revert_packet rv_packet;
+ u64 cur_root;
+ int ret = 1;
+
+ rv_packet.source.id = 0ULL;
+ rv_packet.target.id = 0ULL;
+ rv_packet.source.name = NULL;
+ rv_packet.target.name = NULL;
+ while(1) {
+ int c = getopt(argc, argv, "s:t:");
+ if (c < 0)
+ break;
+ switch(c) {
+ case ''s'':
+ rv_packet.source.id = atoll(optarg);
+ break;
+ case ''t'':
+ rv_packet.target.id = atoll(optarg);
+ break;
+ default:
+ print_usage();
+ ret = 1;
+ goto out;
+ }
+ }
+
+ if (rv_packet.source.id == 0ULL) {
+ fprintf(stderr, "source tree is not specified\n");
+ goto error;
+ }
+ if (rv_packet.target.id == 0ULL) {
+ fprintf(stderr, "target tree is not specified\n");
+ goto error;
+ }
+ if (rv_packet.source.id == rv_packet.target.id) {
+ fprintf(stderr, "source tree and target tree are a same tree\n");
+ goto error;
+ }
+
+ argc = argc - optind;
+ device = argv[optind];
+ if (argc != 1) {
+ fprintf(stderr, "device not specified\n");
+ goto error;
+ }
+
+ if (check_mounted(device)) {
+ fprintf(stderr, "%s is mounted\n", device);
+ goto error;
+ }
+
+ root = open_ctree(device, 0, 1);
+ if (!root) {
+ printf("ctree open error.\n");
+ goto error;
+ }
+
+ cur_root = btrfs_find_current_root(root);
+
+ if (find_file_tree(root, &rv_packet.source)) {
+ printf("source tree not exist\n");
+ goto error_out;
+ }
+ if (find_file_tree(root, &rv_packet.target)) {
+ printf("target tree not exist\n");
+ goto error_out;
+ }
+ if (rv_packet.source.id == BTRFS_FS_TREE_OBJECTID)
+ if(rv_packet.target.id != cur_root) {
+ printf("filesystem root(id=%llu) cannot replaces non-root
tree(id=%llu)\n",
+ rv_packet.source.id, rv_packet.target.id);
+ goto error_out;
+ }
+
+ printf("tree reverting utilitiy\n");
+ printf("\t subvolume\t: \"%s\"\n", rv_packet.target.name);
+ printf("\t subvolume id\t: [before] %llu -> [after] %llu\n",
+ rv_packet.target.id, rv_packet.source.id);
+
+ if (rv_packet.target.id == cur_root) {
+ ret = btrfs_revert_root(root->fs_info, &rv_packet);
+ } else {
+ ret = btrfs_revert_directory(root->fs_info, &rv_packet);
+ }
+
+ printf("operation complete\n");
+close_out:
+ close_ctree(root);
+
+out:
+ if (rv_packet.source.name)
+ free(rv_packet.source.name);
+ if (rv_packet.target.name)
+ free(rv_packet.target.name);
+
+ printf("%s\n",BTRFS_BUILD_VERSION);
+ return ret;
+
+error_out:
+ ret = 1;
+ goto close_out;
+
+error:
+ ret = 1;
+ goto out;
+}
--
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
On Thursday 24 December 2009, TARUISI Hiroaki wrote:> New utility(btrfsrevert) added to swap subvolumes. > > With this utility, a subvolume (Source Subvolume) takes place of > another subvolume (Target Subvolume), and target subvolume goes > under hidden directory(".old_trees") in filesystem root(fs tree, > tree id=5), and its name is expanded with random UUID.Hi Taruisi, which is the supposed goal of this program ? If I understand correctly "btrfsrevert" renames subvolumes. But we can rename a subvolume using the mv command. So "btrfsrevert" may be simulated with a couple of ''mv'' command: # btrfsrevert -s vola-id -t volb-id /dev/sdX is equivalent to # mount /dev/sdX/ /mnt # only needed if the filesystem is un-mounted # mkdir /mnt/.old_trees # mv /mnt/volb /mnt/.old_trees/volb.<random-number> # mv /mnt/vola /mnt/volb # umount /mnt Is right ? And moreover btrfsrevert has the limit that the file-system shall not be mounted... On the plus side of btrfsrevert, I can "swap" volumes without having the btrfs module loaded ... BR G.Baroncelli> > This utility cannot operate mounted filesystem. This is only for > unmounted device. > And this utility also cannot operate filesystem root. For now, > if we want to swap filesystem root, we can use btrfsctl with > Josef Bacik''s patch. I wonder which is better, integrating ''root swap'' > ioctl or not supporting ''root swap'' as for this utility... > > A patch follows this mail. > > > man-page-like description and examples are as follows. > > NAME > btrfsrevert - swap subvolumes. > > SYNOPSIS > btrfsrevert -s source_subvolume -t target_subvolume device > > OPTIONS > -s source subvolume > Specify subvolume number which replace target > subvolume. > -t target subvolume > Specify subvolume number which is replaced by > source subvolume. > > device > Specify target device which is not mounted. > > SAMPLES > Consider two subvolumes ''target''(id=256) and ''source''(id=300) > exist in filesystem root. > / + > +- ''target'' (id=256) > +- ''source'' (id=300) > > In this case, following command swaps subvolume, > > # btrfsrevert -s 300 -t 256 /dev/hda1 > > like this. > / + > +- ''target'' (id=300) > | > +- ''.old_tree'' > +- ''target_[random uuid]'' (id=256) > > A subvolume(id:256) is replaced with a subvolume(id:300), > and replaced subvolume(id:256) goes to .old_trees directory. > > Regards, > taruisi > > -- > 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 >-- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijackATinwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512 -- 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
Thank you for your mail. I intended to create a swap utility including root subvolume. That was the goal. Swapping root subvolume is not implemented yet... For now, as you say, in some cases this utility does simple mv commands, but in some cases, it has some advantages. We can swap subvolumes regardless of mounted-subvolume. (only when we mount other subvolume than fs tree) And, because we can identify snapshot (its date or target subvol) with subvolume ID, it is suitable to swap with ID. Regards, taruisi (2009/12/28 5:23), Goffredo Baroncelli wrote:> On Thursday 24 December 2009, TARUISI Hiroaki wrote: >> New utility(btrfsrevert) added to swap subvolumes. >> >> With this utility, a subvolume (Source Subvolume) takes place of >> another subvolume (Target Subvolume), and target subvolume goes >> under hidden directory(".old_trees") in filesystem root(fs tree, >> tree id=5), and its name is expanded with random UUID. > > > Hi Taruisi, > > which is the supposed goal of this program ? If I understand correctly > "btrfsrevert" renames subvolumes. But we can rename a subvolume using the mv > command. So "btrfsrevert" may be simulated with a couple of ''mv'' command: > > # btrfsrevert -s vola-id -t volb-id /dev/sdX > > is equivalent to > > # mount /dev/sdX/ /mnt # only needed if the filesystem is un-mounted > # mkdir /mnt/.old_trees > # mv /mnt/volb /mnt/.old_trees/volb.<random-number> > # mv /mnt/vola /mnt/volb > # umount /mnt > > Is right ? And moreover btrfsrevert has the limit that the file-system shall > not be mounted... > > On the plus side of btrfsrevert, I can "swap" volumes without having the btrfs > module loaded ... > > > BR > G.Baroncelli > >> >> This utility cannot operate mounted filesystem. This is only for >> unmounted device. >> And this utility also cannot operate filesystem root. For now, >> if we want to swap filesystem root, we can use btrfsctl with >> Josef Bacik''s patch. I wonder which is better, integrating ''root swap'' >> ioctl or not supporting ''root swap'' as for this utility... >> >> A patch follows this mail. >> >> >> man-page-like description and examples are as follows. >> >> NAME >> btrfsrevert - swap subvolumes. >> >> SYNOPSIS >> btrfsrevert -s source_subvolume -t target_subvolume device >> >> OPTIONS >> -s source subvolume >> Specify subvolume number which replace target >> subvolume. >> -t target subvolume >> Specify subvolume number which is replaced by >> source subvolume. >> >> device >> Specify target device which is not mounted. >> >> SAMPLES >> Consider two subvolumes ''target''(id=256) and ''source''(id=300) >> exist in filesystem root. >> / + >> +- ''target'' (id=256) >> +- ''source'' (id=300) >> >> In this case, following command swaps subvolume, >> >> # btrfsrevert -s 300 -t 256 /dev/hda1 >> >> like this. >> / + >> +- ''target'' (id=300) >> | >> +- ''.old_tree'' >> +- ''target_[random uuid]'' (id=256) >> >> A subvolume(id:256) is replaced with a subvolume(id:300), >> and replaced subvolume(id:256) goes to .old_trees directory. >> >> Regards, >> taruisi >> >> -- >> 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 >> > >-- taruisi -- 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
Hi Taruisi, On Monday 28 December 2009, TARUISI Hiroaki wrote: [...]> We can swap subvolumes regardless of mounted-subvolume. (only > when we mount other subvolume than fs tree)I resolved this kind of problem as described in my previous email ([RFC] proposal for a btrfs filesystem layout - 20/Nov/2009): I used a sub-volume as root of my system, but I mounted also the root of the btrfs filesystem for handling the sub-volumes under "/var/btrfs". It work quiet well: 1) I can swap the sub-volumes only with the mv commands 2) I can switch to an old snapshot of the root at boot time, because my scripts update the grub entries with the list of the valid snapshots 3) I can switch permanently two sub-volumes exchanging their names 4) I can remove a sub-volume quite easily> And, because we can identify snapshot (its date or target subvol) > with subvolume ID, it is suitable to swap with ID.Why you want to to identify a sub-volume with its id ? I like the idea to identify a sub-volumes with an identifier which is not file-system related. To me the fact that a sub-volume is identified with its "mount point" seems to me a limit instead that an advantage. But it seems that I am alone to thinking that :-( So I am curious about your reasons. BR Goffredo -- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijackATinwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512 -- 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
Buon anno, Goffredo. Taking snapshot in btrfs is very easy, but handling snapshots is very confusing. So, we must make a rule of snapshotting such as your proposal, which seems to me very good and useful. If rules like this are forced regardless of operator''s preference, this utility may become a deadwood. Identification with non-filesystem-related identifier seems to me a good idea. But because subvolume is unique idea in btrfs, identifying subvolumes can be unique, too. Subvolume ID represents some information belong to subvolume (like snapshot date/time... not data which subvolume contains), and not variable. It becomes useful information/identifier to handle snapshots although it''s not friendly to human being. Regards, taruisi>Hi Taruisi, > >On Monday 28 December 2009, TARUISI Hiroaki wrote: >[...] > >> We can swap subvolumes regardless of mounted-subvolume. (only >> when we mount other subvolume than fs tree) >I resolved this kind of problem as described in my previous email ([RFC] >proposal for a btrfs filesystem layout - 20/Nov/2009): I used a sub-volume as >root of my system, but I mounted also the root of the btrfs filesystem for >handling the sub-volumes under "/var/btrfs". It work quiet well: >1) I can swap the sub-volumes only with the mv commands >2) I can switch to an old snapshot of the root at boot time, because my >scripts update the grub entries with the list of the valid snapshots >3) I can switch permanently two sub-volumes exchanging their names >4) I can remove a sub-volume quite easily > >> And, because we can identify snapshot (its date or target subvol) >> with subvolume ID, it is suitable to swap with ID. >Why you want to to identify a sub-volume with its id ? >I like the idea to identify a sub-volumes with an identifier which is not >file-system related. To me the fact that a sub-volume is identified with its >"mount point" seems to me a limit instead that an advantage. But it seems that >I am alone to thinking that :-( >So I am curious about your reasons. > >BR >Goffredo > >-- >gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijackATinwind.it> >Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512-- 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
On Monday 04 January 2010, TARUISI Hiroaki wrote:> Buon anno, Goffredo.あけまして おめでとう Taruisi, (I hope that happy new year is correctly written)> > Taking snapshot in btrfs is very easy, but handling snapshots is > very confusing. So, we must make a rule of snapshotting such as > your proposal, which seems to me very good and useful. > If rules like this are forced regardless of operator''s preference, > this utility may become a deadwood.I detailed this idea in this article http://kreijack.blogspot.com/2010/01/linux-btrfs-example-of-layout.html BR G.Baroncelli -- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijackATinwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512 -- 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
Thanks for your greetings. I read your article, and could follow your idea, which looks very practical rule to me. But we may need some application which support to create or maintain these rules because the relation mount point and subvolumes and snapshots gets complicated as number of subvolumes increases. Regards, taruisi (2010/01/05 2:20), Goffredo Baroncelli wrote:> On Monday 04 January 2010, TARUISI Hiroaki wrote: >> Buon anno, Goffredo. > あけまして おめでとう Taruisi, > > (I hope that happy new year is correctly written) >> >> Taking snapshot in btrfs is very easy, but handling snapshots is >> very confusing. So, we must make a rule of snapshotting such as >> your proposal, which seems to me very good and useful. >> If rules like this are forced regardless of operator''s preference, >> this utility may become a deadwood. > > I detailed this idea in this article > > http://kreijack.blogspot.com/2010/01/linux-btrfs-example-of-layout.html > > BR > G.Baroncelli >-- taruisi -- 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
On Wednesday 06 January 2010, TARUISI Hiroaki wrote:> Thanks for your greetings. > > I read your article, and could follow your idea, which looks > very practical rule to me. > But we may need some application which support to create or maintain > these rules because the relation mount point and subvolumes and > snapshots gets complicated as number of subvolumes increases.I wrote a little script which handle the snapshot creation/deleting/listing and grub config file update. This script supposing the layout which I discussed - under /var/btrfs is mounter the real root btrfs filesystem - under the real root file-system there are the snapshots and the root of the system (rootfs) - in /var/btrfs/snaplist.txt there is the list of snaphsot - in /boot/grub/menu.lst there is the grub configuration In you are interested, I can send you. BR Goffredo> Regards, > taruisi > > (2010/01/05 2:20), Goffredo Baroncelli wrote: > > On Monday 04 January 2010, TARUISI Hiroaki wrote: > >> Buon anno, Goffredo. > > あけまして おめでとう Taruisi, > > > > (I hope that happy new year is correctly written) > >> > >> Taking snapshot in btrfs is very easy, but handling snapshots is > >> very confusing. So, we must make a rule of snapshotting such as > >> your proposal, which seems to me very good and useful. > >> If rules like this are forced regardless of operator''s preference, > >> this utility may become a deadwood. > > > > I detailed this idea in this article > > > > http://kreijack.blogspot.com/2010/01/linux-btrfs-example-of-layout.html > > > > BR > > G.Baroncelli > > > > >-- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijack@inwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512 -- 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
Hello,
here [*] you can find my script.
----> Please pay attention to the fact that it is only tested on my *ubuntu*
box. <----
The program has 4 main commands:
$ ./snapmng.sh
snapmng.sh [-n] create <snapname> [<comment>] Create a new
snapshot.
snapmng.sh list List the snapshots.
snapmng.sh [-n] delete <snapname> Delete a snapshot.
snapmng.sh update-grub Update grub menulist.
snapmng.sh help Show help (this).
If the switch ''-n'' is passed, then
''create'' and ''delete'' commands
don''t update the grub menu.
If <snapname> is equal to ''.'' in the
''create'' command, the name is
generated automatically like snap-YYYYMMDD.
** list
This is the simplest; this function lists the snapshot on the basis of the
content of the file /var/btrfs/snaplist.txt
** update-grub
This is the most triky function. This function update the grub menu on the
basis of the snapshot contained in the /var/btrfs/snaplist.txt.
The first entry of the grub menu is extracted. Then for every snapshots this
entry is added to the end of the "/boot/grub/menu.lst", replacing
"subvol=rootfs" with "subvol=<snapshotname>".
These entries are delimited by the two following rows:
### BEGIN BTRFS SNAPSHOT ITEMS
[...]
### END BTRFS SNAPSHOT ITEMS
So it is possible to update the "/boot/grub/menu.lst" file without
affecting
the other entries.
** create
this command creates a new snapshot and update the grub config file. If the
switch "-n" is passed the menu.lst file will not be updated.
** delete
this command deletes a snapshot and update the grub config file. If the
switch "-n" is passed the menu.lst file will not be updated
I repeat the btrfs filesystem layout.
Nomenclature:
-- root of system -> where there are the typical directories/files like /bin,
/sbin /usr /etc...
-- root of the (btrfs) file-system -> where there are the snapshots or
subvolumes
Under root of the filesystem there are the *subvolume* for the root of the
system. Its name is "rootfs", and contains the standard filesystem
(/bin /usr
/sbin /etc ... ).
The snapshot of the root of the system is still under /
So the filesystem layout is
/
\
+--rootfs system root (subvolume)
| \
| +--/bin
| +--/sbin
| +--/etc
| +--/usr
| [...]
+--snap-123 snapshot of the system root #123
| \
| +--/bin
| +--/sbin
| [...]
+--snap-3456 snapshot of the system root #3456
| \
| +--/bin
| +--/sbin
| [...]
At the boot time as root is not mounted the root of the filesystem, but the
subvolume/snapshot "rootfs"
Tipically in my ubuntu the grub entry is
title Ubuntu 9.10, kernel 2.6.31-17-generic
root (hd0,0)
kernel /vmlinuz root=/dev/sdX ro rootflags=subvol=rootfs
initrd /initrd.img-2.6.31-17-generic
quiet
Note the part "rootflags=subvol=rootfs".
Pay attention that the prefix "rootflags" is debian related (it should
works
for both debian and ubuntu). For examples for Fedora, the prefix would be
"rootfsflags".
for administration purpose the root of the btrfs filesystem is mounted under
/var/btrfs. In my /etc/fstab there are the following lines:
/dev/sdX / btrfs subvol=rootfs,errors=remount-ro,noatime 0 1
/dev/sdX /var/btrfs btrfs subvol=.,errors=remount-ro,noatime 0 1
[*] http://cassiopea.homelinux.net/git/?p=snapmng/.git;a=summary
BR
Goffredo
On Wednesday 06 January 2010, you (Piavlo) wrote:> Hi Goffredo,
>
> I''m interested in your script.
>
> BTW great article - seems to be very similar to how opensolaris handles
> boot environments with zfs.
>
> Also I think it''s better to keep the /boot as separate btrfs
subvolume -
> in order to have only one
> instance of /boot/grub/menu.lst and kernels independent of all the
> rootfs snapshots - of course this will
> work only of grub2 can be told to look for /boot/grub/menu.lst under the
> btrfs boot subvolume - otherwise
> we need to store the /boot as normal directory under the root subvolume
> of the btrfs filesystem.
>
> I''ve implemented your idea , but currently the /boot is stored
under
> ext3 with legacy-grub.
> Need to check it will work with boot inside btrfs with grub2.
>
> Thanks
> Alex
>
> Goffredo Baroncelli wrote:
> > On Wednesday 06 January 2010, TARUISI Hiroaki wrote:
> >
> >> Thanks for your greetings.
> >>
> >> I read your article, and could follow your idea, which looks
> >> very practical rule to me.
> >> But we may need some application which support to create or
maintain
> >> these rules because the relation mount point and subvolumes and
> >> snapshots gets complicated as number of subvolumes increases.
> >>
> >
> > I wrote a little script which handle the snapshot
creation/deleting/listing > > and grub config file update.
> >
> > This script supposing the layout which I discussed
> >
> > - under /var/btrfs is mounter the real root btrfs filesystem
> > - under the real root file-system there are the snapshots and the root
of
the > > system (rootfs)
> > - in /var/btrfs/snaplist.txt there is the list of snaphsot
> > - in /boot/grub/menu.lst there is the grub configuration
> >
> > In you are interested, I can send you.
> >
> > BR
> > Goffredo
> >
> >
>
>
--
gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo)
<kreijackATinwind.it>
Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512