a | b | |
---|
| 0 | + | commit 362290ea03b52e4ce4edb43453a51a3b1f1cd33f |
---|
| 0 | + | Author: Filipe David Borba Manana <fdmanana@gmail.com> |
---|
| 0 | + | Date: Sat Apr 5 22:34:45 2014 +0100 |
---|
| 0 | + | |
---|
| 0 | + | Btrfs: send, don't issue unnecessary file truncate commands |
---|
| 0 | + | |
---|
| 0 | + | Every time a file is created or updated, send (either incremental or not) always |
---|
| 0 | + | issues a file truncate command. In several commons scenarios this truncate is not |
---|
| 0 | + | needed and yet it was still issued all the time. The unnecessary cases where the |
---|
| 0 | + | truncate command is not needed are: |
---|
| 0 | + | |
---|
| 0 | + | * We have a new file, and its last extent isn't a hole, so that its last write |
---|
| 0 | + | command ends at the file's size; |
---|
| 0 | + | |
---|
| 0 | + | * For an incremental send, we updated in place an existing file, without changing |
---|
| 0 | + | its size; |
---|
| 0 | + | |
---|
| 0 | + | * For an incremental send, we updated the file, increased its size, and the last |
---|
| 0 | + | file extent item doesn't correspond to a hole. In this case the last write |
---|
| 0 | + | command against the file ends at the file's new size; |
---|
| 0 | + | |
---|
| 0 | + | * For an incremental send, we didn't update the file's data at all, we only changed |
---|
| 0 | + | its mode, group or access/update timestamps. |
---|
| 0 | + | |
---|
| 0 | + | Therefore don't send truncate commands for these cases, reducing the stream's size |
---|
| 0 | + | and saving time. |
---|
| 0 | + | |
---|
| 0 | + | diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c |
---|
| 0 | + | index fa378c7ebffd..46f52b4bbc21 100644 |
---|
| 0 | + | --- a/fs/btrfs/send.c |
---|
| 0 | + | +++ b/fs/btrfs/send.c |
---|
| 0 | + | @@ -120,6 +120,7 @@ struct send_ctx { |
---|
| 0 | + | u64 cur_inode_mode; |
---|
| 0 | + | u64 cur_inode_rdev; |
---|
| 0 | + | u64 cur_inode_last_extent; |
---|
| 0 | + | + u64 cur_inode_max_write_end; |
---|
| 0 | + | |
---|
| 0 | + | u64 send_progress; |
---|
| 0 | + | u64 total_data_size; |
---|
| 0 | + | @@ -4494,6 +4495,8 @@ static int send_hole(struct send_ctx *sctx, u64 end) |
---|
| 0 | + | break; |
---|
| 0 | + | offset += len; |
---|
| 0 | + | } |
---|
| 0 | + | + sctx->cur_inode_max_write_end = max(offset, |
---|
| 0 | + | + sctx->cur_inode_max_write_end); |
---|
| 0 | + | tlv_put_failure: |
---|
| 0 | + | fs_path_free(p); |
---|
| 0 | + | return ret; |
---|
| 0 | + | @@ -4529,6 +4532,10 @@ static int send_write_or_clone(struct send_ctx *sctx, |
---|
| 0 | + | len = btrfs_file_extent_num_bytes(path->nodes[0], ei); |
---|
| 0 | + | } |
---|
| 0 | + | |
---|
| 0 | + | + if (offset >= sctx->cur_inode_size) { |
---|
| 0 | + | + ret = 0; |
---|
| 0 | + | + goto out; |
---|
| 0 | + | + } |
---|
| 0 | + | if (offset + len > sctx->cur_inode_size) |
---|
| 0 | + | len = sctx->cur_inode_size - offset; |
---|
| 0 | + | if (len == 0) { |
---|
| 0 | + | @@ -4560,6 +4567,8 @@ static int send_write_or_clone(struct send_ctx *sctx, |
---|
| 0 | + | } |
---|
| 0 | + | ret = 0; |
---|
| 0 | + | } |
---|
| 0 | + | + sctx->cur_inode_max_write_end = max(offset + len, |
---|
| 0 | + | + sctx->cur_inode_max_write_end); |
---|
| 0 | + | out: |
---|
| 0 | + | return ret; |
---|
| 0 | + | } |
---|
| 0 | + | @@ -4982,6 +4991,7 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) |
---|
| 0 | + | u64 right_gid; |
---|
| 0 | + | int need_chmod = 0; |
---|
| 0 | + | int need_chown = 0; |
---|
| 0 | + | + int need_truncate = 1; |
---|
| 0 | + | int pending_move = 0; |
---|
| 0 | + | int refs_processed = 0; |
---|
| 0 | + | |
---|
| 0 | + | @@ -5022,9 +5032,13 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) |
---|
| 0 | + | need_chown = 1; |
---|
| 0 | + | if (!S_ISLNK(sctx->cur_inode_mode)) |
---|
| 0 | + | need_chmod = 1; |
---|
| 0 | + | + if (sctx->cur_inode_max_write_end == sctx->cur_inode_size) |
---|
| 0 | + | + need_truncate = 0; |
---|
| 0 | + | } else { |
---|
| 0 | + | + u64 old_size; |
---|
| 0 | + | + |
---|
| 0 | + | ret = get_inode_info(sctx->parent_root, sctx->cur_ino, |
---|
| 0 | + | - NULL, NULL, &right_mode, &right_uid, |
---|
| 0 | + | + &old_size, NULL, &right_mode, &right_uid, |
---|
| 0 | + | &right_gid, NULL); |
---|
| 0 | + | if (ret < 0) |
---|
| 0 | + | goto out; |
---|
| 0 | + | @@ -5033,6 +5047,13 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) |
---|
| 0 | + | need_chown = 1; |
---|
| 0 | + | if (!S_ISLNK(sctx->cur_inode_mode) && left_mode != right_mode) |
---|
| 0 | + | need_chmod = 1; |
---|
| 0 | + | + |
---|
| 0 | + | + if (old_size == sctx->cur_inode_size && |
---|
| 0 | + | + sctx->cur_inode_max_write_end <= sctx->cur_inode_size) |
---|
| 0 | + | + need_truncate = 0; |
---|
| 0 | + | + else if (sctx->cur_inode_size > old_size && |
---|
| 0 | + | + sctx->cur_inode_max_write_end == sctx->cur_inode_size) |
---|
| 0 | + | + need_truncate = 0; |
---|
| 0 | + | } |
---|
| 0 | + | |
---|
| 0 | + | truncate_inode: |
---|
| 0 | + | @@ -5052,10 +5073,13 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) |
---|
| 0 | + | goto out; |
---|
| 0 | + | } |
---|
| 0 | + | } |
---|
| 0 | + | - ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen, |
---|
| 0 | + | - sctx->cur_inode_size); |
---|
| 0 | + | - if (ret < 0) |
---|
| 0 | + | - goto out; |
---|
| 0 | + | + if (need_truncate) { |
---|
| 0 | + | + ret = send_truncate(sctx, sctx->cur_ino, |
---|
| 0 | + | + sctx->cur_inode_gen, |
---|
| 0 | + | + sctx->cur_inode_size); |
---|
| 0 | + | + if (ret < 0) |
---|
| 0 | + | + goto out; |
---|
| 0 | + | + } |
---|
| 0 | + | } |
---|
| 0 | + | |
---|
| 0 | + | if (need_chown) { |
---|
| 0 | + | @@ -5110,6 +5134,7 @@ static int changed_inode(struct send_ctx *sctx, |
---|
| 0 | + | sctx->cur_ino = key->objectid; |
---|
| 0 | + | sctx->cur_inode_new_gen = 0; |
---|
| 0 | + | sctx->cur_inode_last_extent = (u64)-1; |
---|
| 0 | + | + sctx->cur_inode_max_write_end = 0; |
---|
| 0 | + | |
---|
| 0 | + | /* |
---|
| 0 | + | * Set send_progress to current inode. This will tell all get_cur_xxx |
---|
... | |
---|