diff options
Diffstat (limited to 'fs/ext4/inode.c')
| -rw-r--r-- | fs/ext4/inode.c | 124 | 
1 files changed, 80 insertions, 44 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 89737d5a1614..4ce35f1c8b0a 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1114,7 +1114,7 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,  	pgoff_t index;  	unsigned from, to; -	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) +	if (unlikely(ext4_forced_shutdown(inode->i_sb)))  		return -EIO;  	trace_ext4_write_begin(inode, pos, len); @@ -2213,8 +2213,7 @@ static int mpage_map_and_submit_extent(handle_t *handle,  		if (err < 0) {  			struct super_block *sb = inode->i_sb; -			if (ext4_forced_shutdown(EXT4_SB(sb)) || -			    ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED)) +			if (ext4_forced_shutdown(sb))  				goto invalidate_dirty_pages;  			/*  			 * Let the uper layers retry transient errors. @@ -2534,14 +2533,13 @@ static int ext4_do_writepages(struct mpage_da_data *mpd)  	 * If the filesystem has aborted, it is read-only, so return  	 * right away instead of dumping stack traces later on that  	 * will obscure the real source of the problem.  We test -	 * EXT4_MF_FS_ABORTED instead of sb->s_flag's SB_RDONLY because +	 * fs shutdown state instead of sb->s_flag's SB_RDONLY because  	 * the latter could be true if the filesystem is mounted  	 * read-only, and in that case, ext4_writepages should  	 * *never* be called, so if that ever happens, we would want  	 * the stack trace.  	 */ -	if (unlikely(ext4_forced_shutdown(EXT4_SB(mapping->host->i_sb)) || -		     ext4_test_mount_flag(inode->i_sb, EXT4_MF_FS_ABORTED))) { +	if (unlikely(ext4_forced_shutdown(mapping->host->i_sb))) {  		ret = -EROFS;  		goto out_writepages;  	} @@ -2759,7 +2757,7 @@ static int ext4_writepages(struct address_space *mapping,  	int ret;  	int alloc_ctx; -	if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) +	if (unlikely(ext4_forced_shutdown(sb)))  		return -EIO;  	alloc_ctx = ext4_writepages_down_read(sb); @@ -2798,16 +2796,16 @@ static int ext4_dax_writepages(struct address_space *mapping,  	int ret;  	long nr_to_write = wbc->nr_to_write;  	struct inode *inode = mapping->host; -	struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);  	int alloc_ctx; -	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) +	if (unlikely(ext4_forced_shutdown(inode->i_sb)))  		return -EIO;  	alloc_ctx = ext4_writepages_down_read(inode->i_sb);  	trace_ext4_writepages(inode, wbc); -	ret = dax_writeback_mapping_range(mapping, sbi->s_daxdev, wbc); +	ret = dax_writeback_mapping_range(mapping, +					  EXT4_SB(inode->i_sb)->s_daxdev, wbc);  	trace_ext4_writepages_result(inode, wbc, ret,  				     nr_to_write - wbc->nr_to_write);  	ext4_writepages_up_read(inode->i_sb, alloc_ctx); @@ -2857,7 +2855,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,  	pgoff_t index;  	struct inode *inode = mapping->host; -	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) +	if (unlikely(ext4_forced_shutdown(inode->i_sb)))  		return -EIO;  	index = pos >> PAGE_SHIFT; @@ -2937,14 +2935,73 @@ static int ext4_da_should_update_i_disksize(struct folio *folio,  	return 1;  } +static int ext4_da_do_write_end(struct address_space *mapping, +			loff_t pos, unsigned len, unsigned copied, +			struct page *page) +{ +	struct inode *inode = mapping->host; +	loff_t old_size = inode->i_size; +	bool disksize_changed = false; +	loff_t new_i_size; + +	/* +	 * block_write_end() will mark the inode as dirty with I_DIRTY_PAGES +	 * flag, which all that's needed to trigger page writeback. +	 */ +	copied = block_write_end(NULL, mapping, pos, len, copied, page, NULL); +	new_i_size = pos + copied; + +	/* +	 * It's important to update i_size while still holding page lock, +	 * because page writeout could otherwise come in and zero beyond +	 * i_size. +	 * +	 * Since we are holding inode lock, we are sure i_disksize <= +	 * i_size. We also know that if i_disksize < i_size, there are +	 * delalloc writes pending in the range up to i_size. If the end of +	 * the current write is <= i_size, there's no need to touch +	 * i_disksize since writeback will push i_disksize up to i_size +	 * eventually. If the end of the current write is > i_size and +	 * inside an allocated block which ext4_da_should_update_i_disksize() +	 * checked, we need to update i_disksize here as certain +	 * ext4_writepages() paths not allocating blocks and update i_disksize. +	 */ +	if (new_i_size > inode->i_size) { +		unsigned long end; + +		i_size_write(inode, new_i_size); +		end = (new_i_size - 1) & (PAGE_SIZE - 1); +		if (copied && ext4_da_should_update_i_disksize(page_folio(page), end)) { +			ext4_update_i_disksize(inode, new_i_size); +			disksize_changed = true; +		} +	} + +	unlock_page(page); +	put_page(page); + +	if (old_size < pos) +		pagecache_isize_extended(inode, old_size, pos); + +	if (disksize_changed) { +		handle_t *handle; + +		handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); +		if (IS_ERR(handle)) +			return PTR_ERR(handle); +		ext4_mark_inode_dirty(handle, inode); +		ext4_journal_stop(handle); +	} + +	return copied; +} +  static int ext4_da_write_end(struct file *file,  			     struct address_space *mapping,  			     loff_t pos, unsigned len, unsigned copied,  			     struct page *page, void *fsdata)  {  	struct inode *inode = mapping->host; -	loff_t new_i_size; -	unsigned long start, end;  	int write_mode = (int)(unsigned long)fsdata;  	struct folio *folio = page_folio(page); @@ -2963,30 +3020,7 @@ static int ext4_da_write_end(struct file *file,  	if (unlikely(copied < len) && !PageUptodate(page))  		copied = 0; -	start = pos & (PAGE_SIZE - 1); -	end = start + copied - 1; - -	/* -	 * Since we are holding inode lock, we are sure i_disksize <= -	 * i_size. We also know that if i_disksize < i_size, there are -	 * delalloc writes pending in the range upto i_size. If the end of -	 * the current write is <= i_size, there's no need to touch -	 * i_disksize since writeback will push i_disksize upto i_size -	 * eventually. If the end of the current write is > i_size and -	 * inside an allocated block (ext4_da_should_update_i_disksize() -	 * check), we need to update i_disksize here as certain -	 * ext4_writepages() paths not allocating blocks update i_disksize. -	 * -	 * Note that we defer inode dirtying to generic_write_end() / -	 * ext4_da_write_inline_data_end(). -	 */ -	new_i_size = pos + copied; -	if (copied && new_i_size > inode->i_size && -	    ext4_da_should_update_i_disksize(folio, end)) -		ext4_update_i_disksize(inode, new_i_size); - -	return generic_write_end(file, mapping, pos, len, copied, &folio->page, -				 fsdata); +	return ext4_da_do_write_end(mapping, pos, len, copied, &folio->page);  }  /* @@ -4940,9 +4974,12 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,  				 "iget: bogus i_mode (%o)", inode->i_mode);  		goto bad_inode;  	} -	if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) +	if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) {  		ext4_error_inode(inode, function, line, 0,  				 "casefold flag without casefold feature"); +		ret = -EFSCORRUPTED; +		goto bad_inode; +	}  	if ((err_str = check_igot_inode(inode, flags)) != NULL) {  		ext4_error_inode(inode, function, line, 0, err_str);  		ret = -EFSCORRUPTED; @@ -5131,11 +5168,10 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)  {  	int err; -	if (WARN_ON_ONCE(current->flags & PF_MEMALLOC) || -	    sb_rdonly(inode->i_sb)) +	if (WARN_ON_ONCE(current->flags & PF_MEMALLOC))  		return 0; -	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) +	if (unlikely(ext4_forced_shutdown(inode->i_sb)))  		return -EIO;  	if (EXT4_SB(inode->i_sb)->s_journal) { @@ -5255,7 +5291,7 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,  	const unsigned int ia_valid = attr->ia_valid;  	bool inc_ivers = true; -	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) +	if (unlikely(ext4_forced_shutdown(inode->i_sb)))  		return -EIO;  	if (unlikely(IS_IMMUTABLE(inode))) @@ -5674,7 +5710,7 @@ int ext4_mark_iloc_dirty(handle_t *handle,  {  	int err = 0; -	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) { +	if (unlikely(ext4_forced_shutdown(inode->i_sb))) {  		put_bh(iloc->bh);  		return -EIO;  	} @@ -5700,7 +5736,7 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,  {  	int err; -	if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) +	if (unlikely(ext4_forced_shutdown(inode->i_sb)))  		return -EIO;  	err = ext4_get_inode_loc(inode, iloc);  |