diff options
Diffstat (limited to 'fs/ext4/inode.c')
| -rw-r--r-- | fs/ext4/inode.c | 97 | 
1 files changed, 40 insertions, 57 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index bfd3545f1e5d..01c9e4f743ba 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -41,6 +41,7 @@  #include <linux/bitops.h>  #include <linux/iomap.h>  #include <linux/iversion.h> +#include <linux/dax.h>  #include "ext4_jbd2.h"  #include "xattr.h" @@ -337,7 +338,7 @@ stop_handle:  	return;  no_delete:  	if (!list_empty(&EXT4_I(inode)->i_fc_list)) -		ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM); +		ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL);  	ext4_clear_inode(inode);	/* We must guarantee clearing of inode... */  } @@ -741,10 +742,11 @@ out_sem:  			if (ret)  				return ret;  		} -		ext4_fc_track_range(handle, inode, map->m_lblk, -			    map->m_lblk + map->m_len - 1);  	} - +	if (retval > 0 && (map->m_flags & EXT4_MAP_UNWRITTEN || +				map->m_flags & EXT4_MAP_MAPPED)) +		ext4_fc_track_range(handle, inode, map->m_lblk, +					map->m_lblk + map->m_len - 1);  	if (retval < 0)  		ext_debug(inode, "failed with err %d\n", retval);  	return retval; @@ -1222,7 +1224,7 @@ retry_journal:  		/*  		 * __block_write_begin may have instantiated a few blocks  		 * outside i_size.  Trim these off again. Don't need -		 * i_size_read because we hold i_mutex. +		 * i_size_read because we hold i_rwsem.  		 *  		 * Add inode to orphan list in case we crash before  		 * truncate finishes @@ -1844,30 +1846,16 @@ int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,  	return 0;  } -static int bget_one(handle_t *handle, struct inode *inode, -		    struct buffer_head *bh) -{ -	get_bh(bh); -	return 0; -} - -static int bput_one(handle_t *handle, struct inode *inode, -		    struct buffer_head *bh) -{ -	put_bh(bh); -	return 0; -} -  static int __ext4_journalled_writepage(struct page *page,  				       unsigned int len)  {  	struct address_space *mapping = page->mapping;  	struct inode *inode = mapping->host; -	struct buffer_head *page_bufs = NULL;  	handle_t *handle = NULL;  	int ret = 0, err = 0;  	int inline_data = ext4_has_inline_data(inode);  	struct buffer_head *inode_bh = NULL; +	loff_t size;  	ClearPageChecked(page); @@ -1877,14 +1865,6 @@ static int __ext4_journalled_writepage(struct page *page,  		inode_bh = ext4_journalled_write_inline_data(inode, len, page);  		if (inode_bh == NULL)  			goto out; -	} else { -		page_bufs = page_buffers(page); -		if (!page_bufs) { -			BUG(); -			goto out; -		} -		ext4_walk_page_buffers(handle, inode, page_bufs, 0, len, -				       NULL, bget_one);  	}  	/*  	 * We need to release the page lock before we start the @@ -1905,7 +1885,8 @@ static int __ext4_journalled_writepage(struct page *page,  	lock_page(page);  	put_page(page); -	if (page->mapping != mapping) { +	size = i_size_read(inode); +	if (page->mapping != mapping || page_offset(page) > size) {  		/* The page got truncated from under us */  		ext4_journal_stop(handle);  		ret = 0; @@ -1915,6 +1896,13 @@ static int __ext4_journalled_writepage(struct page *page,  	if (inline_data) {  		ret = ext4_mark_inode_dirty(handle, inode);  	} else { +		struct buffer_head *page_bufs = page_buffers(page); + +		if (page->index == size >> PAGE_SHIFT) +			len = size & ~PAGE_MASK; +		else +			len = PAGE_SIZE; +  		ret = ext4_walk_page_buffers(handle, inode, page_bufs, 0, len,  					     NULL, do_journal_get_write_access); @@ -1935,9 +1923,6 @@ static int __ext4_journalled_writepage(struct page *page,  out:  	unlock_page(page);  out_no_pagelock: -	if (!inline_data && page_bufs) -		ext4_walk_page_buffers(NULL, inode, page_bufs, 0, len, -				       NULL, bput_one);  	brelse(inode_bh);  	return ret;  } @@ -2257,7 +2242,6 @@ static int mpage_process_page(struct mpage_da_data *mpd, struct page *page,  			mpd->map.m_len = 0;  			mpd->map.m_flags = 0;  			io_end_vec->size += io_end_size; -			io_end_size = 0;  			err = mpage_process_page_bufs(mpd, head, bh, lblk);  			if (err > 0) @@ -2282,7 +2266,6 @@ static int mpage_process_page(struct mpage_da_data *mpd, struct page *page,  	} while (lblk++, (bh = bh->b_this_page) != head);  	io_end_vec->size += io_end_size; -	io_end_size = 0;  	*map_bh = false;  out:  	*m_lblk = lblk; @@ -3271,7 +3254,7 @@ static bool ext4_inode_datasync_dirty(struct inode *inode)  static void ext4_set_iomap(struct inode *inode, struct iomap *iomap,  			   struct ext4_map_blocks *map, loff_t offset, -			   loff_t length) +			   loff_t length, unsigned int flags)  {  	u8 blkbits = inode->i_blkbits; @@ -3288,8 +3271,10 @@ static void ext4_set_iomap(struct inode *inode, struct iomap *iomap,  	if (map->m_flags & EXT4_MAP_NEW)  		iomap->flags |= IOMAP_F_NEW; -	iomap->bdev = inode->i_sb->s_bdev; -	iomap->dax_dev = EXT4_SB(inode->i_sb)->s_daxdev; +	if (flags & IOMAP_DAX) +		iomap->dax_dev = EXT4_SB(inode->i_sb)->s_daxdev; +	else +		iomap->bdev = inode->i_sb->s_bdev;  	iomap->offset = (u64) map->m_lblk << blkbits;  	iomap->length = (u64) map->m_len << blkbits; @@ -3309,9 +3294,13 @@ static void ext4_set_iomap(struct inode *inode, struct iomap *iomap,  	if (map->m_flags & EXT4_MAP_UNWRITTEN) {  		iomap->type = IOMAP_UNWRITTEN;  		iomap->addr = (u64) map->m_pblk << blkbits; +		if (flags & IOMAP_DAX) +			iomap->addr += EXT4_SB(inode->i_sb)->s_dax_part_off;  	} else if (map->m_flags & EXT4_MAP_MAPPED) {  		iomap->type = IOMAP_MAPPED;  		iomap->addr = (u64) map->m_pblk << blkbits; +		if (flags & IOMAP_DAX) +			iomap->addr += EXT4_SB(inode->i_sb)->s_dax_part_off;  	} else {  		iomap->type = IOMAP_HOLE;  		iomap->addr = IOMAP_NULL_ADDR; @@ -3348,8 +3337,8 @@ retry:  	 * DAX and direct I/O are the only two operations that are currently  	 * supported with IOMAP_WRITE.  	 */ -	WARN_ON(!IS_DAX(inode) && !(flags & IOMAP_DIRECT)); -	if (IS_DAX(inode)) +	WARN_ON(!(flags & (IOMAP_DAX | IOMAP_DIRECT))); +	if (flags & IOMAP_DAX)  		m_flags = EXT4_GET_BLOCKS_CREATE_ZERO;  	/*  	 * We use i_size instead of i_disksize here because delalloc writeback @@ -3420,7 +3409,7 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,  	if (ret < 0)  		return ret;  out: -	ext4_set_iomap(inode, iomap, &map, offset, length); +	ext4_set_iomap(inode, iomap, &map, offset, length, flags);  	return 0;  } @@ -3540,7 +3529,7 @@ static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,  		delalloc = ext4_iomap_is_delalloc(inode, &map);  set_iomap: -	ext4_set_iomap(inode, iomap, &map, offset, length); +	ext4_set_iomap(inode, iomap, &map, offset, length, flags);  	if (delalloc && iomap->type == IOMAP_HOLE)  		iomap->type = IOMAP_DELALLOC; @@ -3780,8 +3769,8 @@ static int ext4_block_zero_page_range(handle_t *handle,  		length = max;  	if (IS_DAX(inode)) { -		return iomap_zero_range(inode, from, length, NULL, -					&ext4_iomap_ops); +		return dax_zero_range(inode, from, length, NULL, +				      &ext4_iomap_ops);  	}  	return __ext4_block_zero_page_range(handle, mapping, from, length);  } @@ -3990,7 +3979,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)  	} -	/* Wait all existing dio workers, newcomers will block on i_mutex */ +	/* Wait all existing dio workers, newcomers will block on i_rwsem */  	inode_dio_wait(inode);  	/* @@ -4140,7 +4129,7 @@ int ext4_truncate(struct inode *inode)  	/*  	 * There is a possibility that we're either freeing the inode  	 * or it's a completely new inode. In those cases we might not -	 * have i_mutex locked because it's not necessary. +	 * have i_rwsem locked because it's not necessary.  	 */  	if (!(inode->i_state & (I_NEW|I_FREEING)))  		WARN_ON(!inode_is_locked(inode)); @@ -4523,7 +4512,7 @@ has_buffer:  static int __ext4_get_inode_loc_noinmem(struct inode *inode,  					struct ext4_iloc *iloc)  { -	ext4_fsblk_t err_blk; +	ext4_fsblk_t err_blk = 0;  	int ret;  	ret = __ext4_get_inode_loc(inode->i_sb, inode->i_ino, NULL, iloc, @@ -4538,7 +4527,7 @@ static int __ext4_get_inode_loc_noinmem(struct inode *inode,  int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc)  { -	ext4_fsblk_t err_blk; +	ext4_fsblk_t err_blk = 0;  	int ret;  	ret = __ext4_get_inode_loc(inode->i_sb, inode->i_ino, inode, iloc, @@ -5282,7 +5271,7 @@ static void ext4_wait_for_tail_page_commit(struct inode *inode)   * transaction are already on disk (truncate waits for pages under   * writeback).   * - * Called with inode->i_mutex down. + * Called with inode->i_rwsem down.   */  int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,  		 struct iattr *attr) @@ -5320,7 +5309,7 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,  		if (error)  			return error;  	} -	ext4_fc_start_update(inode); +  	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||  	    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {  		handle_t *handle; @@ -5344,7 +5333,6 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,  		if (error) {  			ext4_journal_stop(handle); -			ext4_fc_stop_update(inode);  			return error;  		}  		/* Update corresponding info in inode so that everything is in @@ -5356,7 +5344,6 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,  		error = ext4_mark_inode_dirty(handle, inode);  		ext4_journal_stop(handle);  		if (unlikely(error)) { -			ext4_fc_stop_update(inode);  			return error;  		}  	} @@ -5370,12 +5357,10 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,  			struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);  			if (attr->ia_size > sbi->s_bitmap_maxbytes) { -				ext4_fc_stop_update(inode);  				return -EFBIG;  			}  		}  		if (!S_ISREG(inode->i_mode)) { -			ext4_fc_stop_update(inode);  			return -EINVAL;  		} @@ -5427,8 +5412,7 @@ int ext4_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,  				ext4_fc_track_range(handle, inode,  					(attr->ia_size > 0 ? attr->ia_size - 1 : 0) >>  					inode->i_sb->s_blocksize_bits, -					(oldsize > 0 ? oldsize - 1 : 0) >> -					inode->i_sb->s_blocksize_bits); +					EXT_MAX_BLOCKS - 1);  			else  				ext4_fc_track_range(  					handle, inode, @@ -5499,7 +5483,6 @@ err_out:  		ext4_std_error(inode->i_sb, error);  	if (!error)  		error = rc; -	ext4_fc_stop_update(inode);  	return error;  } @@ -6000,7 +5983,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)  		return PTR_ERR(handle);  	ext4_fc_mark_ineligible(inode->i_sb, -		EXT4_FC_REASON_JOURNAL_FLAG_CHANGE); +		EXT4_FC_REASON_JOURNAL_FLAG_CHANGE, handle);  	err = ext4_mark_inode_dirty(handle, inode);  	ext4_handle_sync(handle);  	ext4_journal_stop(handle);  |