* [RFC PATCH v2 0/4] undelete subvolume online version
@ 2018-09-11 11:28 Lu Fengqi
2018-09-11 11:29 ` [RFC PATCH v2 1/4] btrfs: factor out btrfs_link_subvol from create_subvol Lu Fengqi
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Lu Fengqi @ 2018-09-11 11:28 UTC (permalink / raw)
To: linux-btrfs
This patchset will add the BTRFS_IOC_SUBVOL_UNDELETE ioctl for online
btrfs subvolume undelete.
And using the online_undelete version of btrfs-progs, user can recover
the subvolume given by <subvol_id> to the directory given by <dest>. The
optional parameter [-n <name>] can be used to set the name of the
recovered subvolume.
# btrfs subvolume undelete [-n <name>] <subvol_id> <dest>
btrfs online undelete version:
https://github.com/littleroad/linux.git undelete
btrfs-progs online undelete version:
https://github.com/littleroad/btrfs-progs.git online_undelete
Issue: #82
Lu Fengqi (4):
btrfs: factor out btrfs_link_subvol from create_subvol
btrfs: don't BUG_ON() in btrfs_link_subvol()
btrfs: undelete: introduce btrfs_undelete_subvolume
btrfs: undelete: Add BTRFS_IOCTL_SUBVOL_UNDELETE ioctl
fs/btrfs/ioctl.c | 247 +++++++++++++++++++++++++++++++++----
include/uapi/linux/btrfs.h | 7 ++
2 files changed, 231 insertions(+), 23 deletions(-)
--
2.18.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [RFC PATCH v2 1/4] btrfs: factor out btrfs_link_subvol from create_subvol
2018-09-11 11:28 [RFC PATCH v2 0/4] undelete subvolume online version Lu Fengqi
@ 2018-09-11 11:29 ` Lu Fengqi
2018-09-11 11:57 ` Qu Wenruo
2018-09-11 11:29 ` [RFC PATCH v2 2/4] btrfs: don't BUG_ON() in btrfs_link_subvol() Lu Fengqi
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Lu Fengqi @ 2018-09-11 11:29 UTC (permalink / raw)
To: linux-btrfs
The function btrfs_link_subvol is responsible to link the subvolume to
the specified directory, which is the opposite of what
btrfs_unlink_subvol does.
No functional change.
Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 64 +++++++++++++++++++++++++++++++-----------------
1 file changed, 41 insertions(+), 23 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 4905d13dee0a..1b03d07acde2 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -542,6 +542,45 @@ int btrfs_is_empty_uuid(u8 *uuid)
return 1;
}
+static int btrfs_link_subvol(struct btrfs_trans_handle *trans,
+ struct inode *dir, u64 objectid, const char *name,
+ int namelen)
+{
+ struct btrfs_root *root = BTRFS_I(dir)->root;
+ struct btrfs_key key;
+ u64 index = 0;
+ int ret;
+
+ /*
+ * insert the directory item
+ */
+ ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+
+ key.objectid = objectid;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = -1;
+ ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
+ BTRFS_FT_DIR, index);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
+
+ btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
+ ret = btrfs_update_inode(trans, root, dir);
+ BUG_ON(ret);
+
+ ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
+ btrfs_ino(BTRFS_I(dir)), index, name, namelen);
+ BUG_ON(ret);
+
+ return ret;
+}
+
static noinline int create_subvol(struct inode *dir,
struct dentry *dentry,
const char *name, int namelen,
@@ -563,7 +602,6 @@ static noinline int create_subvol(struct inode *dir,
int err;
u64 objectid;
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
- u64 index = 0;
uuid_le new_uuid;
root_item = kzalloc(sizeof(*root_item), GFP_KERNEL);
@@ -677,29 +715,9 @@ static noinline int create_subvol(struct inode *dir,
new_root->highest_objectid = new_dirid;
mutex_unlock(&new_root->objectid_mutex);
- /*
- * insert the directory item
- */
- ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
- if (ret) {
- btrfs_abort_transaction(trans, ret);
- goto fail;
- }
-
- ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
- BTRFS_FT_DIR, index);
- if (ret) {
- btrfs_abort_transaction(trans, ret);
+ ret = btrfs_link_subvol(trans, dir, objectid, name, namelen);
+ if (ret)
goto fail;
- }
-
- btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
- ret = btrfs_update_inode(trans, root, dir);
- BUG_ON(ret);
-
- ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
- btrfs_ino(BTRFS_I(dir)), index, name, namelen);
- BUG_ON(ret);
ret = btrfs_uuid_tree_add(trans, root_item->uuid,
BTRFS_UUID_KEY_SUBVOL, objectid);
--
2.18.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH v2 2/4] btrfs: don't BUG_ON() in btrfs_link_subvol()
2018-09-11 11:28 [RFC PATCH v2 0/4] undelete subvolume online version Lu Fengqi
2018-09-11 11:29 ` [RFC PATCH v2 1/4] btrfs: factor out btrfs_link_subvol from create_subvol Lu Fengqi
@ 2018-09-11 11:29 ` Lu Fengqi
2018-09-11 11:54 ` Qu Wenruo
2018-09-11 11:29 ` [RFC PATCH v2 3/4] btrfs: undelete: introduce btrfs_undelete_subvolume Lu Fengqi
` (2 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Lu Fengqi @ 2018-09-11 11:29 UTC (permalink / raw)
To: linux-btrfs
Both of btrfs_update_inode() and btrfs_add_root_ref() may fail because
of ENOMEM. So there's no reason to panic here, we can replace BUG_ON()
with btrfs_abort_transaction() here.
Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 1b03d07acde2..f6173d4e7ced 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -572,11 +572,17 @@ static int btrfs_link_subvol(struct btrfs_trans_handle *trans,
btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
ret = btrfs_update_inode(trans, root, dir);
- BUG_ON(ret);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
btrfs_ino(BTRFS_I(dir)), index, name, namelen);
- BUG_ON(ret);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ return ret;
+ }
return ret;
}
--
2.18.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH v2 3/4] btrfs: undelete: introduce btrfs_undelete_subvolume
2018-09-11 11:28 [RFC PATCH v2 0/4] undelete subvolume online version Lu Fengqi
2018-09-11 11:29 ` [RFC PATCH v2 1/4] btrfs: factor out btrfs_link_subvol from create_subvol Lu Fengqi
2018-09-11 11:29 ` [RFC PATCH v2 2/4] btrfs: don't BUG_ON() in btrfs_link_subvol() Lu Fengqi
@ 2018-09-11 11:29 ` Lu Fengqi
2018-09-11 11:29 ` [RFC PATCH v2 4/4] btrfs: undelete: Add BTRFS_IOCTL_SUBVOL_UNDELETE ioctl Lu Fengqi
2018-09-11 11:34 ` [RFC PATCH v2 1/2] btrfs-progs: ioctl: add BTRFS_IOC_SUBVOL_UNDELETE to ioctl.h Lu Fengqi
4 siblings, 0 replies; 10+ messages in thread
From: Lu Fengqi @ 2018-09-11 11:29 UTC (permalink / raw)
To: linux-btrfs
The function will do the following things which are almost the opposite
of what btrfs_delete_subvolume() does:
1. link the subvolume to the parent specified;
2. clear root flag and set root_refs to 1;
3. add the subvol to the uuid_tree;
4. delete the orphan_item.
Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index f6173d4e7ced..f088dea53c16 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1880,6 +1880,119 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
return ret;
}
+static int btrfs_undelete_subvolume(struct btrfs_root *root,
+ struct dentry *parent, const char *name,
+ int namelen)
+{
+ struct inode *dir = d_inode(parent);
+ struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
+ struct btrfs_root_item *root_item = &root->root_item;
+ struct btrfs_trans_handle *trans;
+ struct btrfs_block_rsv block_rsv;
+ struct dentry *dentry;
+ struct inode *inode;
+ u64 root_flags;
+ int ret;
+
+ btrfs_debug(fs_info, "Undelete subvolume %llu",
+ root->root_key.objectid);
+
+ /* only care about the intact subvolume */
+ if (btrfs_disk_key_objectid(&root_item->drop_progress) != 0)
+ return 0;
+
+ ret = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT);
+ if (ret == -EINTR)
+ return ret;
+
+ dentry = lookup_one_len(name, parent, namelen);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto out_unlock;
+ }
+
+ down_write(&fs_info->subvol_sem);
+
+ ret = btrfs_may_create(dir, dentry);
+ if (ret)
+ goto out_up_write;
+
+ ret = btrfs_check_dir_item_collision(BTRFS_I(dir)->root, dir->i_ino,
+ name, namelen);
+ if (ret)
+ goto out_up_write;
+
+ btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
+ /*
+ * 1 - parent dir inode
+ * 2 - dir entries
+ * 2 - root ref/backref
+ * 1 - UUID item
+ */
+ ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 6, false);
+ if (ret)
+ goto out_up_write;
+
+ trans = btrfs_start_transaction(BTRFS_I(dir)->root, 0);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ btrfs_subvolume_release_metadata(fs_info, &block_rsv);
+ goto out_up_write;
+ }
+
+ trans->block_rsv = &block_rsv;
+ trans->bytes_reserved = block_rsv.size;
+
+ ret = btrfs_link_subvol(trans, dir, root->root_key.objectid, name,
+ namelen);
+ if (ret)
+ goto fail;
+
+ /* clear BTRFS_ROOT_SUBVOL_DEAD root flag and set root_refs to 1*/
+ root_flags = btrfs_root_flags(root_item);
+ btrfs_set_root_flags(root_item,
+ root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);
+ btrfs_set_root_refs(root_item, 1);
+ ret = btrfs_update_root(trans, fs_info->tree_root,
+ &root->root_key, &root->root_item);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto fail;
+ }
+
+ ret = btrfs_uuid_tree_add(trans, root_item->uuid, BTRFS_UUID_KEY_SUBVOL,
+ root->root_key.objectid);
+ if (ret) {
+ btrfs_abort_transaction(trans, ret);
+ goto fail;
+ }
+
+ ret = btrfs_del_orphan_item(trans, fs_info->tree_root,
+ root->root_key.objectid);
+ if (ret && ret != -ENOENT) {
+ btrfs_abort_transaction(trans, ret);
+ goto fail;
+ }
+fail:
+ trans->block_rsv = NULL;
+ trans->bytes_reserved = 0;
+ btrfs_subvolume_release_metadata(fs_info, &block_rsv);
+ ret = btrfs_commit_transaction(trans);
+ if (!ret) {
+ inode = btrfs_lookup_dentry(dir, dentry);
+ if (IS_ERR(inode))
+ return PTR_ERR(inode);
+ d_instantiate(dentry, inode);
+ fsnotify_mkdir(dir, dentry);
+ }
+out_up_write:
+ up_write(&fs_info->subvol_sem);
+ dput(dentry);
+out_unlock:
+ inode_unlock(dir);
+ return ret;
+}
+
static noinline int btrfs_ioctl_subvol_getflags(struct file *file,
void __user *arg)
{
--
2.18.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH v2 4/4] btrfs: undelete: Add BTRFS_IOCTL_SUBVOL_UNDELETE ioctl
2018-09-11 11:28 [RFC PATCH v2 0/4] undelete subvolume online version Lu Fengqi
` (2 preceding siblings ...)
2018-09-11 11:29 ` [RFC PATCH v2 3/4] btrfs: undelete: introduce btrfs_undelete_subvolume Lu Fengqi
@ 2018-09-11 11:29 ` Lu Fengqi
2018-09-11 11:34 ` [RFC PATCH v2 1/2] btrfs-progs: ioctl: add BTRFS_IOC_SUBVOL_UNDELETE to ioctl.h Lu Fengqi
4 siblings, 0 replies; 10+ messages in thread
From: Lu Fengqi @ 2018-09-11 11:29 UTC (permalink / raw)
To: linux-btrfs
This ioctl will provide user the ability to recover the subvolume of the
given id to the given directory.
Note: It will lock fs_info->cleaner_mutex to keep the cleaner kthread
from deleting the subvolume which we want to recover.
Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
---
fs/btrfs/ioctl.c | 64 ++++++++++++++++++++++++++++++++++++++
include/uapi/linux/btrfs.h | 7 +++++
2 files changed, 71 insertions(+)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index f088dea53c16..3ddf6e1c117b 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1993,6 +1993,68 @@ static int btrfs_undelete_subvolume(struct btrfs_root *root,
return ret;
}
+static int btrfs_ioctl_undelete(struct file *file, void __user *argp)
+{
+ struct btrfs_ioctl_subvol_undelete_args *args;
+ struct inode *inode = file_inode(file);
+ struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ struct btrfs_root *root;
+ int ret = 0;
+
+ if (!S_ISDIR(inode->i_mode))
+ return -ENOTDIR;
+
+ args = memdup_user(argp, sizeof(*args));
+ if (IS_ERR(args))
+ return PTR_ERR(args);
+
+ args->name[BTRFS_PATH_NAME_MAX] = '\0';
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ ret = -EPERM;
+ goto free;
+ }
+
+ ret = mnt_want_write_file(file);
+ if (ret)
+ goto free;
+
+ ret = -ENOENT;
+ spin_lock(&fs_info->trans_lock);
+ list_for_each_entry(root, &fs_info->dead_roots, root_list) {
+ if (root->root_key.objectid == args->subvol_id) {
+ list_del_init(&root->root_list);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock(&fs_info->trans_lock);
+ if (ret)
+ goto drop_write;
+
+ /*
+ * Lock cleaner_mutex to prevent the cleaner kthread from deleting the
+ * subvolume we want to recover so that we can perform the next rescue
+ * in a relaxed manner.
+ */
+ mutex_lock(&fs_info->cleaner_mutex);
+
+ ret = btrfs_undelete_subvolume(root, file->f_path.dentry, args->name,
+ strlen(args->name));
+ if (ret) {
+ btrfs_add_dead_root(root);
+ goto unlock;
+ }
+
+unlock:
+ mutex_unlock(&fs_info->cleaner_mutex);
+drop_write:
+ mnt_drop_write_file(file);
+free:
+ kfree(args);
+ return ret;
+}
+
static noinline int btrfs_ioctl_subvol_getflags(struct file *file,
void __user *arg)
{
@@ -6118,6 +6180,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_get_subvol_rootref(file, argp);
case BTRFS_IOC_INO_LOOKUP_USER:
return btrfs_ioctl_ino_lookup_user(file, argp);
+ case BTRFS_IOC_SUBVOL_UNDELETE:
+ return btrfs_ioctl_undelete(file, argp);
}
return -ENOTTY;
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
index 5ca1d21fc4a7..e6d3c8e24bb8 100644
--- a/include/uapi/linux/btrfs.h
+++ b/include/uapi/linux/btrfs.h
@@ -816,6 +816,11 @@ struct btrfs_ioctl_get_subvol_rootref_args {
__u8 align[7];
};
+struct btrfs_ioctl_subvol_undelete_args {
+ __u64 subvol_id;
+ char name[BTRFS_PATH_NAME_MAX + 1];
+};
+
/* Error codes as returned by the kernel */
enum btrfs_err_code {
BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1,
@@ -940,5 +945,7 @@ enum btrfs_err_code {
struct btrfs_ioctl_get_subvol_rootref_args)
#define BTRFS_IOC_INO_LOOKUP_USER _IOWR(BTRFS_IOCTL_MAGIC, 62, \
struct btrfs_ioctl_ino_lookup_user_args)
+#define BTRFS_IOC_SUBVOL_UNDELETE _IOWR(BTRFS_IOCTL_MAGIC, 63, \
+ struct btrfs_ioctl_subvol_undelete_args)
#endif /* _UAPI_LINUX_BTRFS_H */
--
2.18.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH v2 1/2] btrfs-progs: ioctl: add BTRFS_IOC_SUBVOL_UNDELETE to ioctl.h
2018-09-11 11:28 [RFC PATCH v2 0/4] undelete subvolume online version Lu Fengqi
` (3 preceding siblings ...)
2018-09-11 11:29 ` [RFC PATCH v2 4/4] btrfs: undelete: Add BTRFS_IOCTL_SUBVOL_UNDELETE ioctl Lu Fengqi
@ 2018-09-11 11:34 ` Lu Fengqi
2018-09-11 11:34 ` [RFC PATCH v2 2/2] btrfs-progs: subvolume: undelete: add btrfs subvolume undelete subcommand Lu Fengqi
4 siblings, 1 reply; 10+ messages in thread
From: Lu Fengqi @ 2018-09-11 11:34 UTC (permalink / raw)
To: linux-btrfs
Copied from uapi/linux/btrfs.h.
Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
---
ioctl.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/ioctl.h b/ioctl.h
index 709e996f401c..75978a4e8265 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -670,6 +670,11 @@ struct btrfs_ioctl_send_args_64 {
} __attribute__((packed));
BUILD_ASSERT(sizeof(struct btrfs_ioctl_send_args_64) == 72);
+struct btrfs_ioctl_subvol_undelete_args {
+ __u64 subvol_id;
+ char name[BTRFS_PATH_NAME_MAX + 1];
+};
+
#define BTRFS_IOC_SEND_64_COMPAT_DEFINED 1
/* Error codes as returned by the kernel */
@@ -828,6 +833,8 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
struct btrfs_ioctl_feature_flags[3])
#define BTRFS_IOC_RM_DEV_V2 _IOW(BTRFS_IOCTL_MAGIC, 58, \
struct btrfs_ioctl_vol_args_v2)
+#define BTRFS_IOC_SUBVOL_UNDELETE _IOWR(BTRFS_IOCTL_MAGIC, 63, \
+ struct btrfs_ioctl_subvol_undelete_args)
#ifdef __cplusplus
}
#endif
--
2.18.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [RFC PATCH v2 2/2] btrfs-progs: subvolume: undelete: add btrfs subvolume undelete subcommand
2018-09-11 11:34 ` [RFC PATCH v2 1/2] btrfs-progs: ioctl: add BTRFS_IOC_SUBVOL_UNDELETE to ioctl.h Lu Fengqi
@ 2018-09-11 11:34 ` Lu Fengqi
0 siblings, 0 replies; 10+ messages in thread
From: Lu Fengqi @ 2018-09-11 11:34 UTC (permalink / raw)
To: linux-btrfs
Add the undelete subcommand, this is depend on the
BTRFS_IOC_SUBVOL_UNDELETE ioctl.
Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
---
btrfs-completion | 2 +-
cmds-subvolume.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/btrfs-completion b/btrfs-completion
index ae683f4ecf61..2b43fbd63023 100644
--- a/btrfs-completion
+++ b/btrfs-completion
@@ -30,7 +30,7 @@ _btrfs()
local cmd=${words[1]}
commands='subvolume filesystem balance device scrub check rescue restore inspect-internal property send receive quota qgroup replace help version'
- commands_subvolume='create delete list snapshot find-new get-default set-default show sync'
+ commands_subvolume='create delete list snapshot find-new get-default set-default show sync undelete'
commands_filesystem='defragment sync resize show df du label usage'
commands_balance='start pause cancel resume status'
commands_device='scan add delete remove ready stats usage'
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index e7a884af1f5d..228d0b9e9b34 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -1219,6 +1219,74 @@ out:
return !!ret;
}
+static const char * const cmd_subvol_undelete_usage[] = {
+ "btrfs subvolume undelete [-n <name>] <subvol_id> <dest>",
+ "Undelete the subvolume of the given <subvol_id> to <dest>.",
+ "",
+ "-n <name> recover the subvolume with <name>.",
+ NULL
+};
+
+static int cmd_subvol_undelete(int argc, char **argv)
+{
+ struct btrfs_ioctl_subvol_undelete_args args;
+ bool need_assign_name = true;
+ DIR *dirstream = NULL;
+ char *dest;
+ int fd = -1;
+ int ret;
+
+ memset(&args, 0, sizeof(args));
+
+ while (1) {
+ int c = getopt(argc, argv, "n:");
+
+ if (c < 0)
+ break;
+
+ switch (c) {
+ case 'n':
+ strncpy_null(args.name, optarg);
+ need_assign_name = false;
+ break;
+ default:
+ usage(cmd_subvol_undelete_usage);
+ }
+ }
+ if (!need_assign_name) {
+ if (!test_issubvolname(args.name)) {
+ error("invalid subvolume name: %s", args.name);
+ return -EINVAL;
+ } else if (strlen(args.name) > BTRFS_VOL_NAME_MAX) {
+ error("subvolume name too long: %s", args.name);
+ return -EINVAL;
+ }
+ }
+
+ if (check_argc_exact(argc - optind, 2))
+ usage(cmd_subvol_undelete_usage);
+
+ args.subvol_id = arg_strtou64(argv[optind]);
+ if (need_assign_name)
+ snprintf(args.name, BTRFS_VOL_NAME_MAX, "sub_%llu",
+ args.subvol_id);
+
+ dest = argv[optind + 1];
+ fd = btrfs_open_dir(dest, &dirstream, 1);
+ if (fd < 0) {
+ error("can't access '%s'", dest);
+ return -1;
+ }
+
+ ret = ioctl(fd, BTRFS_IOC_SUBVOL_UNDELETE, &args);
+ if (ret)
+ perror("BTRFS_IOC_SUBVOL_UNDELETE");
+
+ close_file_or_dir(fd, dirstream);
+
+ return ret;
+}
+
static const char subvolume_cmd_group_info[] =
"manage subvolumes: create, delete, list, etc";
@@ -1237,6 +1305,8 @@ const struct cmd_group subvolume_cmd_group = {
NULL, 0 },
{ "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
{ "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
+ { "undelete", cmd_subvol_undelete, cmd_subvol_undelete_usage,
+ NULL, 0 },
NULL_CMD_STRUCT
}
};
--
2.18.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH v2 2/4] btrfs: don't BUG_ON() in btrfs_link_subvol()
2018-09-11 11:29 ` [RFC PATCH v2 2/4] btrfs: don't BUG_ON() in btrfs_link_subvol() Lu Fengqi
@ 2018-09-11 11:54 ` Qu Wenruo
0 siblings, 0 replies; 10+ messages in thread
From: Qu Wenruo @ 2018-09-11 11:54 UTC (permalink / raw)
To: Lu Fengqi, linux-btrfs
[-- Attachment #1.1: Type: text/plain, Size: 1274 bytes --]
On 2018/9/11 下午7:29, Lu Fengqi wrote:
> Both of btrfs_update_inode() and btrfs_add_root_ref() may fail because
> of ENOMEM.
Not only ENOMEM, but also EEXIST/EIO from btrfs_insert_empty_item().
> So there's no reason to panic here, we can replace BUG_ON()
> with btrfs_abort_transaction() here.
Valid cleanup.
Reviewed-by: Qu Wenruo <wqu@suse.com>
Thanks,
Qu
>
> Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
> ---
> fs/btrfs/ioctl.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 1b03d07acde2..f6173d4e7ced 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -572,11 +572,17 @@ static int btrfs_link_subvol(struct btrfs_trans_handle *trans,
>
> btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
> ret = btrfs_update_inode(trans, root, dir);
> - BUG_ON(ret);
> + if (ret) {
> + btrfs_abort_transaction(trans, ret);
> + return ret;
> + }
>
> ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
> btrfs_ino(BTRFS_I(dir)), index, name, namelen);
> - BUG_ON(ret);
> + if (ret) {
> + btrfs_abort_transaction(trans, ret);
> + return ret;
> + }
>
> return ret;
> }
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH v2 1/4] btrfs: factor out btrfs_link_subvol from create_subvol
2018-09-11 11:29 ` [RFC PATCH v2 1/4] btrfs: factor out btrfs_link_subvol from create_subvol Lu Fengqi
@ 2018-09-11 11:57 ` Qu Wenruo
2018-09-11 12:10 ` Lu Fengqi
0 siblings, 1 reply; 10+ messages in thread
From: Qu Wenruo @ 2018-09-11 11:57 UTC (permalink / raw)
To: Lu Fengqi, linux-btrfs
[-- Attachment #1.1: Type: text/plain, Size: 3322 bytes --]
On 2018/9/11 下午7:29, Lu Fengqi wrote:
> The function btrfs_link_subvol is responsible to link the subvolume to
> the specified directory, which is the opposite of what
> btrfs_unlink_subvol does.
>
> No functional change.
>
> Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
The patch itself is OK.
Just small nitpicks inlined below.
> ---
> fs/btrfs/ioctl.c | 64 +++++++++++++++++++++++++++++++-----------------
> 1 file changed, 41 insertions(+), 23 deletions(-)
>
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 4905d13dee0a..1b03d07acde2 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -542,6 +542,45 @@ int btrfs_is_empty_uuid(u8 *uuid)
> return 1;
> }
>
> +static int btrfs_link_subvol(struct btrfs_trans_handle *trans,
> + struct inode *dir, u64 objectid, const char *name,
> + int namelen)
> +{
> + struct btrfs_root *root = BTRFS_I(dir)->root;
> + struct btrfs_key key;
> + u64 index = 0;
> + int ret;
> +
> + /*
> + * insert the directory item
> + */
> + ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
> + if (ret) {
> + btrfs_abort_transaction(trans, ret);
> + return ret;
> + }
> +
> + key.objectid = objectid;
> + key.type = BTRFS_ROOT_ITEM_KEY;
> + key.offset = -1;
> + ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
> + BTRFS_FT_DIR, index);
> + if (ret) {
> + btrfs_abort_transaction(trans, ret);
> + return ret;
> + }
> +
> + btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
> + ret = btrfs_update_inode(trans, root, dir);
> + BUG_ON(ret);
What about clean up this BUG_ON()?
> +
> + ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
> + btrfs_ino(BTRFS_I(dir)), index, name, namelen);
> + BUG_ON(ret);
And this one?
Thanks,
Qu
> +
> + return ret;
> +}
> +
> static noinline int create_subvol(struct inode *dir,
> struct dentry *dentry,
> const char *name, int namelen,
> @@ -563,7 +602,6 @@ static noinline int create_subvol(struct inode *dir,
> int err;
> u64 objectid;
> u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
> - u64 index = 0;
> uuid_le new_uuid;
>
> root_item = kzalloc(sizeof(*root_item), GFP_KERNEL);
> @@ -677,29 +715,9 @@ static noinline int create_subvol(struct inode *dir,
> new_root->highest_objectid = new_dirid;
> mutex_unlock(&new_root->objectid_mutex);
>
> - /*
> - * insert the directory item
> - */
> - ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
> - if (ret) {
> - btrfs_abort_transaction(trans, ret);
> - goto fail;
> - }
> -
> - ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
> - BTRFS_FT_DIR, index);
> - if (ret) {
> - btrfs_abort_transaction(trans, ret);
> + ret = btrfs_link_subvol(trans, dir, objectid, name, namelen);
> + if (ret)
> goto fail;
> - }
> -
> - btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
> - ret = btrfs_update_inode(trans, root, dir);
> - BUG_ON(ret);
> -
> - ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
> - btrfs_ino(BTRFS_I(dir)), index, name, namelen);
> - BUG_ON(ret);
>
> ret = btrfs_uuid_tree_add(trans, root_item->uuid,
> BTRFS_UUID_KEY_SUBVOL, objectid);
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH v2 1/4] btrfs: factor out btrfs_link_subvol from create_subvol
2018-09-11 11:57 ` Qu Wenruo
@ 2018-09-11 12:10 ` Lu Fengqi
0 siblings, 0 replies; 10+ messages in thread
From: Lu Fengqi @ 2018-09-11 12:10 UTC (permalink / raw)
To: Qu Wenruo; +Cc: linux-btrfs
On Tue, Sep 11, 2018 at 07:57:03PM +0800, Qu Wenruo wrote:
>
>
>On 2018/9/11 下午7:29, Lu Fengqi wrote:
>> The function btrfs_link_subvol is responsible to link the subvolume to
>> the specified directory, which is the opposite of what
>> btrfs_unlink_subvol does.
>>
>> No functional change.
>>
>> Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com>
>
>The patch itself is OK.
>
>Just small nitpicks inlined below.
>
>> ---
>> fs/btrfs/ioctl.c | 64 +++++++++++++++++++++++++++++++-----------------
>> 1 file changed, 41 insertions(+), 23 deletions(-)
>>
>> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
>> index 4905d13dee0a..1b03d07acde2 100644
>> --- a/fs/btrfs/ioctl.c
>> +++ b/fs/btrfs/ioctl.c
>> @@ -542,6 +542,45 @@ int btrfs_is_empty_uuid(u8 *uuid)
>> return 1;
>> }
>>
>> +static int btrfs_link_subvol(struct btrfs_trans_handle *trans,
>> + struct inode *dir, u64 objectid, const char *name,
>> + int namelen)
>> +{
>> + struct btrfs_root *root = BTRFS_I(dir)->root;
>> + struct btrfs_key key;
>> + u64 index = 0;
>> + int ret;
>> +
>> + /*
>> + * insert the directory item
>> + */
>> + ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
>> + if (ret) {
>> + btrfs_abort_transaction(trans, ret);
>> + return ret;
>> + }
>> +
>> + key.objectid = objectid;
>> + key.type = BTRFS_ROOT_ITEM_KEY;
>> + key.offset = -1;
>> + ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
>> + BTRFS_FT_DIR, index);
>> + if (ret) {
>> + btrfs_abort_transaction(trans, ret);
>> + return ret;
>> + }
>> +
>> + btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
>> + ret = btrfs_update_inode(trans, root, dir);
>> + BUG_ON(ret);
>
>What about clean up this BUG_ON()?
>
>> +
>> + ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
>> + btrfs_ino(BTRFS_I(dir)), index, name, namelen);
>> + BUG_ON(ret);
>
>And this one?
Sorry, this makes you confused. This is exactly the cleanup done by Patch 2, because
I want to just move the code in Patch 1.
Thanks,
Lu
>
>Thanks,
>Qu
>
>> +
>> + return ret;
>> +}
>> +
>> static noinline int create_subvol(struct inode *dir,
>> struct dentry *dentry,
>> const char *name, int namelen,
>> @@ -563,7 +602,6 @@ static noinline int create_subvol(struct inode *dir,
>> int err;
>> u64 objectid;
>> u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
>> - u64 index = 0;
>> uuid_le new_uuid;
>>
>> root_item = kzalloc(sizeof(*root_item), GFP_KERNEL);
>> @@ -677,29 +715,9 @@ static noinline int create_subvol(struct inode *dir,
>> new_root->highest_objectid = new_dirid;
>> mutex_unlock(&new_root->objectid_mutex);
>>
>> - /*
>> - * insert the directory item
>> - */
>> - ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
>> - if (ret) {
>> - btrfs_abort_transaction(trans, ret);
>> - goto fail;
>> - }
>> -
>> - ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
>> - BTRFS_FT_DIR, index);
>> - if (ret) {
>> - btrfs_abort_transaction(trans, ret);
>> + ret = btrfs_link_subvol(trans, dir, objectid, name, namelen);
>> + if (ret)
>> goto fail;
>> - }
>> -
>> - btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
>> - ret = btrfs_update_inode(trans, root, dir);
>> - BUG_ON(ret);
>> -
>> - ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
>> - btrfs_ino(BTRFS_I(dir)), index, name, namelen);
>> - BUG_ON(ret);
>>
>> ret = btrfs_uuid_tree_add(trans, root_item->uuid,
>> BTRFS_UUID_KEY_SUBVOL, objectid);
>>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2018-09-11 17:09 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-09-11 11:28 [RFC PATCH v2 0/4] undelete subvolume online version Lu Fengqi
2018-09-11 11:29 ` [RFC PATCH v2 1/4] btrfs: factor out btrfs_link_subvol from create_subvol Lu Fengqi
2018-09-11 11:57 ` Qu Wenruo
2018-09-11 12:10 ` Lu Fengqi
2018-09-11 11:29 ` [RFC PATCH v2 2/4] btrfs: don't BUG_ON() in btrfs_link_subvol() Lu Fengqi
2018-09-11 11:54 ` Qu Wenruo
2018-09-11 11:29 ` [RFC PATCH v2 3/4] btrfs: undelete: introduce btrfs_undelete_subvolume Lu Fengqi
2018-09-11 11:29 ` [RFC PATCH v2 4/4] btrfs: undelete: Add BTRFS_IOCTL_SUBVOL_UNDELETE ioctl Lu Fengqi
2018-09-11 11:34 ` [RFC PATCH v2 1/2] btrfs-progs: ioctl: add BTRFS_IOC_SUBVOL_UNDELETE to ioctl.h Lu Fengqi
2018-09-11 11:34 ` [RFC PATCH v2 2/2] btrfs-progs: subvolume: undelete: add btrfs subvolume undelete subcommand Lu Fengqi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).