diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 48 | 
1 files changed, 42 insertions, 6 deletions
| diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 451fad96ecd..ef96381569a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -317,6 +317,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,  	unsigned long src_ptr;  	unsigned long dst_ptr;  	int overwrite_root = 0; +	bool inode_item = key->type == BTRFS_INODE_ITEM_KEY;  	if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)  		overwrite_root = 1; @@ -326,6 +327,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,  	/* look for the key in the destination tree */  	ret = btrfs_search_slot(NULL, root, key, path, 0, 0); +	if (ret < 0) +		return ret; +  	if (ret == 0) {  		char *src_copy;  		char *dst_copy; @@ -367,6 +371,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,  			return 0;  		} +		/* +		 * We need to load the old nbytes into the inode so when we +		 * replay the extents we've logged we get the right nbytes. +		 */ +		if (inode_item) { +			struct btrfs_inode_item *item; +			u64 nbytes; + +			item = btrfs_item_ptr(path->nodes[0], path->slots[0], +					      struct btrfs_inode_item); +			nbytes = btrfs_inode_nbytes(path->nodes[0], item); +			item = btrfs_item_ptr(eb, slot, +					      struct btrfs_inode_item); +			btrfs_set_inode_nbytes(eb, item, nbytes); +		} +	} else if (inode_item) { +		struct btrfs_inode_item *item; + +		/* +		 * New inode, set nbytes to 0 so that the nbytes comes out +		 * properly when we replay the extents. +		 */ +		item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item); +		btrfs_set_inode_nbytes(eb, item, 0);  	}  insert:  	btrfs_release_path(path); @@ -486,7 +514,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,  	int found_type;  	u64 extent_end;  	u64 start = key->offset; -	u64 saved_nbytes; +	u64 nbytes = 0;  	struct btrfs_file_extent_item *item;  	struct inode *inode = NULL;  	unsigned long size; @@ -496,10 +524,19 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,  	found_type = btrfs_file_extent_type(eb, item);  	if (found_type == BTRFS_FILE_EXTENT_REG || -	    found_type == BTRFS_FILE_EXTENT_PREALLOC) -		extent_end = start + btrfs_file_extent_num_bytes(eb, item); -	else if (found_type == BTRFS_FILE_EXTENT_INLINE) { +	    found_type == BTRFS_FILE_EXTENT_PREALLOC) { +		nbytes = btrfs_file_extent_num_bytes(eb, item); +		extent_end = start + nbytes; + +		/* +		 * We don't add to the inodes nbytes if we are prealloc or a +		 * hole. +		 */ +		if (btrfs_file_extent_disk_bytenr(eb, item) == 0) +			nbytes = 0; +	} else if (found_type == BTRFS_FILE_EXTENT_INLINE) {  		size = btrfs_file_extent_inline_len(eb, item); +		nbytes = btrfs_file_extent_ram_bytes(eb, item);  		extent_end = ALIGN(start + size, root->sectorsize);  	} else {  		ret = 0; @@ -548,7 +585,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,  	}  	btrfs_release_path(path); -	saved_nbytes = inode_get_bytes(inode);  	/* drop any overlapping extents */  	ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1);  	BUG_ON(ret); @@ -635,7 +671,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,  		BUG_ON(ret);  	} -	inode_set_bytes(inode, saved_nbytes); +	inode_add_bytes(inode, nbytes);  	ret = btrfs_update_inode(trans, root, inode);  out:  	if (inode) | 
