diff options
Diffstat (limited to 'fs/btrfs/send.c')
| -rw-r--r-- | fs/btrfs/send.c | 47 | 
1 files changed, 37 insertions, 10 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 2891ec4056c6..7664025a5af4 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -4,6 +4,7 @@   */  #include <linux/bsearch.h> +#include <linux/falloc.h>  #include <linux/fs.h>  #include <linux/file.h>  #include <linux/sort.h> @@ -758,7 +759,7 @@ static int send_header(struct send_ctx *sctx)  {  	struct btrfs_stream_header hdr; -	strcpy(hdr.magic, BTRFS_SEND_STREAM_MAGIC); +	strscpy(hdr.magic, BTRFS_SEND_STREAM_MAGIC);  	hdr.version = cpu_to_le32(sctx->proto);  	return write_buf(sctx->send_filp, &hdr, sizeof(hdr),  					&sctx->send_off); @@ -1804,7 +1805,7 @@ static int gen_unique_name(struct send_ctx *sctx,  				ino, gen, idx);  		ASSERT(len < sizeof(tmp));  		tmp_name.name = tmp; -		tmp_name.len = strlen(tmp); +		tmp_name.len = len;  		di = btrfs_lookup_dir_item(NULL, sctx->send_root,  				path, BTRFS_FIRST_FREE_OBJECTID, @@ -1843,7 +1844,7 @@ static int gen_unique_name(struct send_ctx *sctx,  		break;  	} -	ret = fs_path_add(dest, tmp, strlen(tmp)); +	ret = fs_path_add(dest, tmp, len);  out:  	btrfs_free_path(path); @@ -4628,7 +4629,6 @@ static int rbtree_ref_comp(const void *k, const struct rb_node *node)  {  	const struct recorded_ref *data = k;  	const struct recorded_ref *ref = rb_entry(node, struct recorded_ref, node); -	int result;  	if (data->dir > ref->dir)  		return 1; @@ -4642,12 +4642,7 @@ static int rbtree_ref_comp(const void *k, const struct rb_node *node)  		return 1;  	if (data->name_len < ref->name_len)  		return -1; -	result = strcmp(data->name, ref->name); -	if (result > 0) -		return 1; -	if (result < 0) -		return -1; -	return 0; +	return strcmp(data->name, ref->name);  }  static bool rbtree_ref_less(struct rb_node *node, const struct rb_node *parent) @@ -5411,6 +5406,30 @@ tlv_put_failure:  	return ret;  } +static int send_fallocate(struct send_ctx *sctx, u32 mode, u64 offset, u64 len) +{ +	struct fs_path *path; +	int ret; + +	path = get_cur_inode_path(sctx); +	if (IS_ERR(path)) +		return PTR_ERR(path); + +	ret = begin_cmd(sctx, BTRFS_SEND_C_FALLOCATE); +	if (ret < 0) +		return ret; + +	TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); +	TLV_PUT_U32(sctx, BTRFS_SEND_A_FALLOCATE_MODE, mode); +	TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); +	TLV_PUT_U64(sctx, BTRFS_SEND_A_SIZE, len); + +	ret = send_cmd(sctx); + +tlv_put_failure: +	return ret; +} +  static int send_hole(struct send_ctx *sctx, u64 end)  {  	struct fs_path *p = NULL; @@ -5419,6 +5438,14 @@ static int send_hole(struct send_ctx *sctx, u64 end)  	int ret = 0;  	/* +	 * Starting with send stream v2 we have fallocate and can use it to +	 * punch holes instead of sending writes full of zeroes. +	 */ +	if (proto_cmd_ok(sctx, BTRFS_SEND_C_FALLOCATE)) +		return send_fallocate(sctx, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, +				      offset, end - offset); + +	/*  	 * A hole that starts at EOF or beyond it. Since we do not yet support  	 * fallocate (for extent preallocation and hole punching), sending a  	 * write of zeroes starting at EOF or beyond would later require issuing  | 
