diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
| -rw-r--r-- | fs/btrfs/tree-log.c | 33 | 
1 files changed, 23 insertions, 10 deletions
| diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index f06454a55e00..561884f60d35 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3578,9 +3578,16 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,  	}  	btrfs_release_path(path); -	/* find the first key from this transaction again */ +	/* +	 * Find the first key from this transaction again.  See the note for +	 * log_new_dir_dentries, if we're logging a directory recursively we +	 * won't be holding its i_mutex, which means we can modify the directory +	 * while we're logging it.  If we remove an entry between our first +	 * search and this search we'll not find the key again and can just +	 * bail. +	 */  	ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0); -	if (WARN_ON(ret != 0)) +	if (ret != 0)  		goto done;  	/* @@ -4544,6 +4551,19 @@ static int logged_inode_size(struct btrfs_root *log, struct btrfs_inode *inode,  		item = btrfs_item_ptr(path->nodes[0], path->slots[0],  				      struct btrfs_inode_item);  		*size_ret = btrfs_inode_size(path->nodes[0], item); +		/* +		 * If the in-memory inode's i_size is smaller then the inode +		 * size stored in the btree, return the inode's i_size, so +		 * that we get a correct inode size after replaying the log +		 * when before a power failure we had a shrinking truncate +		 * followed by addition of a new name (rename / new hard link). +		 * Otherwise return the inode size from the btree, to avoid +		 * data loss when replaying a log due to previously doing a +		 * write that expands the inode's size and logging a new name +		 * immediately after. +		 */ +		if (*size_ret > inode->vfs_inode.i_size) +			*size_ret = inode->vfs_inode.i_size;  	}  	btrfs_release_path(path); @@ -4705,15 +4725,8 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans,  					struct btrfs_file_extent_item);  		if (btrfs_file_extent_type(leaf, extent) == -		    BTRFS_FILE_EXTENT_INLINE) { -			len = btrfs_file_extent_ram_bytes(leaf, extent); -			ASSERT(len == i_size || -			       (len == fs_info->sectorsize && -				btrfs_file_extent_compression(leaf, extent) != -				BTRFS_COMPRESS_NONE) || -			       (len < i_size && i_size < fs_info->sectorsize)); +		    BTRFS_FILE_EXTENT_INLINE)  			return 0; -		}  		len = btrfs_file_extent_num_bytes(leaf, extent);  		/* Last extent goes beyond i_size, no need to log a hole. */ |