aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2012-09-06 06:03:32 -0400
committerChris Mason <chris.mason@fusionio.com>2012-10-01 15:19:12 -0400
commit42874b3db7817f662b1d7c6e32f8b63638fa0321 (patch)
tree0b3682ba45ea408e59d11959a2d9fc2430613db9 /fs/btrfs/transaction.c
parent66d8f3dd1c87813d7f1cf8b774cb03e9b8d7e87e (diff)
Btrfs: fix the snapshot that should not exist
The snapshot should be the image of the fs tree before it was created, so the metadata of the snapshot should not exist in the its tree. But now, we found the directory item and directory name index is in both the snapshot tree and the fs tree. It introduces some problems and makes the users feel strange: # mkfs.btrfs /dev/sda1 # mount /dev/sda1 /mnt # mkdir /mnt/1 # cd /mnt/1 # btrfs subvolume snapshot /mnt snap0 # ls -a /mnt/1/snap0/1 . .. [no other file/dir] # ll /mnt/1/snap0/ total 0 drwxr-xr-x 1 root root 10 Ju1 24 12:11 1 ^^^ There is no file/dir in it, but it's size is 10 # cd /mnt/1/snap0/1/snap0 [Enter a unexisted directory successfully...] There is nothing in the directory 1 in snap0, but btrfs told the length of this directory is 10. Beside that, we can enter an unexisted directory, it is very strange to the users. # btrfs subvolume snapshot /mnt/1/snap0 /mnt/snap1 # ll /mnt/1/snap0/1/ total 0 [None] # ll /mnt/snap1/1/ total 0 drwxr-xr-x 1 root root 0 Ju1 24 12:14 snap0 And the source of snap1 did have any directory in Directory 1, but snap1 have a snap0, it is different between the source and the snapshot. So I think we should insert directory item and directory name index and update the parent inode as the last step of snapshot creation, and do not leave the useless metadata in the file tree. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c68
1 files changed, 53 insertions, 15 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 4b6ce5cab44..a86fc723aad 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -955,6 +955,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
955 struct btrfs_root *parent_root; 955 struct btrfs_root *parent_root;
956 struct btrfs_block_rsv *rsv; 956 struct btrfs_block_rsv *rsv;
957 struct inode *parent_inode; 957 struct inode *parent_inode;
958 struct btrfs_path *path;
959 struct btrfs_dir_item *dir_item;
958 struct dentry *parent; 960 struct dentry *parent;
959 struct dentry *dentry; 961 struct dentry *dentry;
960 struct extent_buffer *tmp; 962 struct extent_buffer *tmp;
@@ -967,6 +969,12 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
967 u64 root_flags; 969 u64 root_flags;
968 uuid_le new_uuid; 970 uuid_le new_uuid;
969 971
972 path = btrfs_alloc_path();
973 if (!path) {
974 ret = pending->error = -ENOMEM;
975 goto path_alloc_fail;
976 }
977
970 new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); 978 new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
971 if (!new_root_item) { 979 if (!new_root_item) {
972 ret = pending->error = -ENOMEM; 980 ret = pending->error = -ENOMEM;
@@ -1015,23 +1023,20 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
1015 */ 1023 */
1016 ret = btrfs_set_inode_index(parent_inode, &index); 1024 ret = btrfs_set_inode_index(parent_inode, &index);
1017 BUG_ON(ret); /* -ENOMEM */ 1025 BUG_ON(ret); /* -ENOMEM */
1018 ret = btrfs_insert_dir_item(trans, parent_root, 1026
1019 dentry->d_name.name, dentry->d_name.len, 1027 /* check if there is a file/dir which has the same name. */
1020 parent_inode, &key, 1028 dir_item = btrfs_lookup_dir_item(NULL, parent_root, path,
1021 BTRFS_FT_DIR, index); 1029 btrfs_ino(parent_inode),
1022 if (ret == -EEXIST) { 1030 dentry->d_name.name,
1031 dentry->d_name.len, 0);
1032 if (dir_item != NULL && !IS_ERR(dir_item)) {
1023 pending->error = -EEXIST; 1033 pending->error = -EEXIST;
1024 goto fail; 1034 goto fail;
1025 } else if (ret) { 1035 } else if (IS_ERR(dir_item)) {
1036 ret = PTR_ERR(dir_item);
1026 goto abort_trans; 1037 goto abort_trans;
1027 } 1038 }
1028 1039 btrfs_release_path(path);
1029 btrfs_i_size_write(parent_inode, parent_inode->i_size +
1030 dentry->d_name.len * 2);
1031 parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
1032 ret = btrfs_update_inode(trans, parent_root, parent_inode);
1033 if (ret)
1034 goto abort_trans;
1035 1040
1036 /* 1041 /*
1037 * pull in the delayed directory update 1042 * pull in the delayed directory update
@@ -1123,12 +1128,30 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
1123 ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); 1128 ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
1124 if (ret) 1129 if (ret)
1125 goto abort_trans; 1130 goto abort_trans;
1131
1132 ret = btrfs_insert_dir_item(trans, parent_root,
1133 dentry->d_name.name, dentry->d_name.len,
1134 parent_inode, &key,
1135 BTRFS_FT_DIR, index);
1136 /* We have check then name at the beginning, so it is impossible. */
1137 BUG_ON(ret == -EEXIST);
1138 if (ret)
1139 goto abort_trans;
1140
1141 btrfs_i_size_write(parent_inode, parent_inode->i_size +
1142 dentry->d_name.len * 2);
1143 parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
1144 ret = btrfs_update_inode(trans, parent_root, parent_inode);
1145 if (ret)
1146 goto abort_trans;
1126fail: 1147fail:
1127 dput(parent); 1148 dput(parent);
1128 trans->block_rsv = rsv; 1149 trans->block_rsv = rsv;
1129no_free_objectid: 1150no_free_objectid:
1130 kfree(new_root_item); 1151 kfree(new_root_item);
1131root_item_alloc_fail: 1152root_item_alloc_fail:
1153 btrfs_free_path(path);
1154path_alloc_fail:
1132 btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); 1155 btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
1133 return ret; 1156 return ret;
1134 1157
@@ -1472,13 +1495,28 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
1472 */ 1495 */
1473 mutex_lock(&root->fs_info->reloc_mutex); 1496 mutex_lock(&root->fs_info->reloc_mutex);
1474 1497
1475 ret = btrfs_run_delayed_items(trans, root); 1498 /*
1499 * We needn't worry about the delayed items because we will
1500 * deal with them in create_pending_snapshot(), which is the
1501 * core function of the snapshot creation.
1502 */
1503 ret = create_pending_snapshots(trans, root->fs_info);
1476 if (ret) { 1504 if (ret) {
1477 mutex_unlock(&root->fs_info->reloc_mutex); 1505 mutex_unlock(&root->fs_info->reloc_mutex);
1478 goto cleanup_transaction; 1506 goto cleanup_transaction;
1479 } 1507 }
1480 1508
1481 ret = create_pending_snapshots(trans, root->fs_info); 1509 /*
1510 * We insert the dir indexes of the snapshots and update the inode
1511 * of the snapshots' parents after the snapshot creation, so there
1512 * are some delayed items which are not dealt with. Now deal with
1513 * them.
1514 *
1515 * We needn't worry that this operation will corrupt the snapshots,
1516 * because all the tree which are snapshoted will be forced to COW
1517 * the nodes and leaves.
1518 */
1519 ret = btrfs_run_delayed_items(trans, root);
1482 if (ret) { 1520 if (ret) {
1483 mutex_unlock(&root->fs_info->reloc_mutex); 1521 mutex_unlock(&root->fs_info->reloc_mutex);
1484 goto cleanup_transaction; 1522 goto cleanup_transaction;