|
@@ -1271,7 +1271,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
|
|
u64 disk_num_bytes;
|
|
|
u64 ram_bytes;
|
|
|
int extent_type;
|
|
|
- int ret, err;
|
|
|
+ int ret;
|
|
|
int type;
|
|
|
int nocow;
|
|
|
int check_prev = 1;
|
|
@@ -1403,11 +1403,8 @@ next_slot:
|
|
|
* if there are pending snapshots for this root,
|
|
|
* we fall into common COW way.
|
|
|
*/
|
|
|
- if (!nolock) {
|
|
|
- err = btrfs_start_write_no_snapshotting(root);
|
|
|
- if (!err)
|
|
|
- goto out_check;
|
|
|
- }
|
|
|
+ if (!nolock && atomic_read(&root->snapshot_force_cow))
|
|
|
+ goto out_check;
|
|
|
/*
|
|
|
* force cow if csum exists in the range.
|
|
|
* this ensure that csum for a given extent are
|
|
@@ -1416,9 +1413,6 @@ next_slot:
|
|
|
ret = csum_exist_in_range(fs_info, disk_bytenr,
|
|
|
num_bytes);
|
|
|
if (ret) {
|
|
|
- if (!nolock)
|
|
|
- btrfs_end_write_no_snapshotting(root);
|
|
|
-
|
|
|
/*
|
|
|
* ret could be -EIO if the above fails to read
|
|
|
* metadata.
|
|
@@ -1431,11 +1425,8 @@ next_slot:
|
|
|
WARN_ON_ONCE(nolock);
|
|
|
goto out_check;
|
|
|
}
|
|
|
- if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) {
|
|
|
- if (!nolock)
|
|
|
- btrfs_end_write_no_snapshotting(root);
|
|
|
+ if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr))
|
|
|
goto out_check;
|
|
|
- }
|
|
|
nocow = 1;
|
|
|
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
|
|
|
extent_end = found_key.offset +
|
|
@@ -1448,8 +1439,6 @@ next_slot:
|
|
|
out_check:
|
|
|
if (extent_end <= start) {
|
|
|
path->slots[0]++;
|
|
|
- if (!nolock && nocow)
|
|
|
- btrfs_end_write_no_snapshotting(root);
|
|
|
if (nocow)
|
|
|
btrfs_dec_nocow_writers(fs_info, disk_bytenr);
|
|
|
goto next_slot;
|
|
@@ -1471,8 +1460,6 @@ out_check:
|
|
|
end, page_started, nr_written, 1,
|
|
|
NULL);
|
|
|
if (ret) {
|
|
|
- if (!nolock && nocow)
|
|
|
- btrfs_end_write_no_snapshotting(root);
|
|
|
if (nocow)
|
|
|
btrfs_dec_nocow_writers(fs_info,
|
|
|
disk_bytenr);
|
|
@@ -1492,8 +1479,6 @@ out_check:
|
|
|
ram_bytes, BTRFS_COMPRESS_NONE,
|
|
|
BTRFS_ORDERED_PREALLOC);
|
|
|
if (IS_ERR(em)) {
|
|
|
- if (!nolock && nocow)
|
|
|
- btrfs_end_write_no_snapshotting(root);
|
|
|
if (nocow)
|
|
|
btrfs_dec_nocow_writers(fs_info,
|
|
|
disk_bytenr);
|
|
@@ -1532,8 +1517,6 @@ out_check:
|
|
|
EXTENT_CLEAR_DATA_RESV,
|
|
|
PAGE_UNLOCK | PAGE_SET_PRIVATE2);
|
|
|
|
|
|
- if (!nolock && nocow)
|
|
|
- btrfs_end_write_no_snapshotting(root);
|
|
|
cur_offset = extent_end;
|
|
|
|
|
|
/*
|
|
@@ -6639,6 +6622,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
drop_inode = 1;
|
|
|
} else {
|
|
|
struct dentry *parent = dentry->d_parent;
|
|
|
+ int ret;
|
|
|
+
|
|
|
err = btrfs_update_inode(trans, root, inode);
|
|
|
if (err)
|
|
|
goto fail;
|
|
@@ -6652,7 +6637,12 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
goto fail;
|
|
|
}
|
|
|
d_instantiate(dentry, inode);
|
|
|
- btrfs_log_new_name(trans, BTRFS_I(inode), NULL, parent);
|
|
|
+ ret = btrfs_log_new_name(trans, BTRFS_I(inode), NULL, parent,
|
|
|
+ true, NULL);
|
|
|
+ if (ret == BTRFS_NEED_TRANS_COMMIT) {
|
|
|
+ err = btrfs_commit_transaction(trans);
|
|
|
+ trans = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
fail:
|
|
@@ -9388,14 +9378,21 @@ static int btrfs_rename_exchange(struct inode *old_dir,
|
|
|
u64 new_idx = 0;
|
|
|
u64 root_objectid;
|
|
|
int ret;
|
|
|
- int ret2;
|
|
|
bool root_log_pinned = false;
|
|
|
bool dest_log_pinned = false;
|
|
|
+ struct btrfs_log_ctx ctx_root;
|
|
|
+ struct btrfs_log_ctx ctx_dest;
|
|
|
+ bool sync_log_root = false;
|
|
|
+ bool sync_log_dest = false;
|
|
|
+ bool commit_transaction = false;
|
|
|
|
|
|
/* we only allow rename subvolume link between subvolumes */
|
|
|
if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
|
|
|
return -EXDEV;
|
|
|
|
|
|
+ btrfs_init_log_ctx(&ctx_root, old_inode);
|
|
|
+ btrfs_init_log_ctx(&ctx_dest, new_inode);
|
|
|
+
|
|
|
/* close the race window with snapshot create/destroy ioctl */
|
|
|
if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
|
|
|
down_read(&fs_info->subvol_sem);
|
|
@@ -9542,15 +9539,29 @@ static int btrfs_rename_exchange(struct inode *old_dir,
|
|
|
|
|
|
if (root_log_pinned) {
|
|
|
parent = new_dentry->d_parent;
|
|
|
- btrfs_log_new_name(trans, BTRFS_I(old_inode), BTRFS_I(old_dir),
|
|
|
- parent);
|
|
|
+ ret = btrfs_log_new_name(trans, BTRFS_I(old_inode),
|
|
|
+ BTRFS_I(old_dir), parent,
|
|
|
+ false, &ctx_root);
|
|
|
+ if (ret == BTRFS_NEED_LOG_SYNC)
|
|
|
+ sync_log_root = true;
|
|
|
+ else if (ret == BTRFS_NEED_TRANS_COMMIT)
|
|
|
+ commit_transaction = true;
|
|
|
+ ret = 0;
|
|
|
btrfs_end_log_trans(root);
|
|
|
root_log_pinned = false;
|
|
|
}
|
|
|
if (dest_log_pinned) {
|
|
|
- parent = old_dentry->d_parent;
|
|
|
- btrfs_log_new_name(trans, BTRFS_I(new_inode), BTRFS_I(new_dir),
|
|
|
- parent);
|
|
|
+ if (!commit_transaction) {
|
|
|
+ parent = old_dentry->d_parent;
|
|
|
+ ret = btrfs_log_new_name(trans, BTRFS_I(new_inode),
|
|
|
+ BTRFS_I(new_dir), parent,
|
|
|
+ false, &ctx_dest);
|
|
|
+ if (ret == BTRFS_NEED_LOG_SYNC)
|
|
|
+ sync_log_dest = true;
|
|
|
+ else if (ret == BTRFS_NEED_TRANS_COMMIT)
|
|
|
+ commit_transaction = true;
|
|
|
+ ret = 0;
|
|
|
+ }
|
|
|
btrfs_end_log_trans(dest);
|
|
|
dest_log_pinned = false;
|
|
|
}
|
|
@@ -9583,8 +9594,26 @@ out_fail:
|
|
|
dest_log_pinned = false;
|
|
|
}
|
|
|
}
|
|
|
- ret2 = btrfs_end_transaction(trans);
|
|
|
- ret = ret ? ret : ret2;
|
|
|
+ if (!ret && sync_log_root && !commit_transaction) {
|
|
|
+ ret = btrfs_sync_log(trans, BTRFS_I(old_inode)->root,
|
|
|
+ &ctx_root);
|
|
|
+ if (ret)
|
|
|
+ commit_transaction = true;
|
|
|
+ }
|
|
|
+ if (!ret && sync_log_dest && !commit_transaction) {
|
|
|
+ ret = btrfs_sync_log(trans, BTRFS_I(new_inode)->root,
|
|
|
+ &ctx_dest);
|
|
|
+ if (ret)
|
|
|
+ commit_transaction = true;
|
|
|
+ }
|
|
|
+ if (commit_transaction) {
|
|
|
+ ret = btrfs_commit_transaction(trans);
|
|
|
+ } else {
|
|
|
+ int ret2;
|
|
|
+
|
|
|
+ ret2 = btrfs_end_transaction(trans);
|
|
|
+ ret = ret ? ret : ret2;
|
|
|
+ }
|
|
|
out_notrans:
|
|
|
if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
|
|
|
up_read(&fs_info->subvol_sem);
|
|
@@ -9661,6 +9690,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
int ret;
|
|
|
u64 old_ino = btrfs_ino(BTRFS_I(old_inode));
|
|
|
bool log_pinned = false;
|
|
|
+ struct btrfs_log_ctx ctx;
|
|
|
+ bool sync_log = false;
|
|
|
+ bool commit_transaction = false;
|
|
|
|
|
|
if (btrfs_ino(BTRFS_I(new_dir)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
|
|
|
return -EPERM;
|
|
@@ -9818,8 +9850,15 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
if (log_pinned) {
|
|
|
struct dentry *parent = new_dentry->d_parent;
|
|
|
|
|
|
- btrfs_log_new_name(trans, BTRFS_I(old_inode), BTRFS_I(old_dir),
|
|
|
- parent);
|
|
|
+ btrfs_init_log_ctx(&ctx, old_inode);
|
|
|
+ ret = btrfs_log_new_name(trans, BTRFS_I(old_inode),
|
|
|
+ BTRFS_I(old_dir), parent,
|
|
|
+ false, &ctx);
|
|
|
+ if (ret == BTRFS_NEED_LOG_SYNC)
|
|
|
+ sync_log = true;
|
|
|
+ else if (ret == BTRFS_NEED_TRANS_COMMIT)
|
|
|
+ commit_transaction = true;
|
|
|
+ ret = 0;
|
|
|
btrfs_end_log_trans(root);
|
|
|
log_pinned = false;
|
|
|
}
|
|
@@ -9856,7 +9895,19 @@ out_fail:
|
|
|
btrfs_end_log_trans(root);
|
|
|
log_pinned = false;
|
|
|
}
|
|
|
- btrfs_end_transaction(trans);
|
|
|
+ if (!ret && sync_log) {
|
|
|
+ ret = btrfs_sync_log(trans, BTRFS_I(old_inode)->root, &ctx);
|
|
|
+ if (ret)
|
|
|
+ commit_transaction = true;
|
|
|
+ }
|
|
|
+ if (commit_transaction) {
|
|
|
+ ret = btrfs_commit_transaction(trans);
|
|
|
+ } else {
|
|
|
+ int ret2;
|
|
|
+
|
|
|
+ ret2 = btrfs_end_transaction(trans);
|
|
|
+ ret = ret ? ret : ret2;
|
|
|
+ }
|
|
|
out_notrans:
|
|
|
if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
|
|
|
up_read(&fs_info->subvol_sem);
|