diff options
Diffstat (limited to 'fs/ext4/inode.c')
| -rw-r--r-- | fs/ext4/inode.c | 161 | 
1 files changed, 70 insertions, 91 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 006b7a2070bf..516faa280ced 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -527,7 +527,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,  		return -EFSCORRUPTED;  	/* Lookup extent status tree firstly */ -	if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { +	if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {  		if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) {  			map->m_pblk = ext4_es_pblock(&es) +  					map->m_lblk - es.es_lblk; @@ -695,7 +695,7 @@ found:  		 * extent status tree.  		 */  		if ((flags & EXT4_GET_BLOCKS_PRE_IO) && -		    ext4_es_lookup_extent(inode, map->m_lblk, &es)) { +		    ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) {  			if (ext4_es_is_written(&es))  				goto out_sem;  		} @@ -1024,7 +1024,7 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,  	bh = ext4_getblk(handle, inode, block, map_flags);  	if (IS_ERR(bh))  		return bh; -	if (!bh || buffer_uptodate(bh)) +	if (!bh || ext4_buffer_uptodate(bh))  		return bh;  	ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &bh);  	wait_on_buffer(bh); @@ -1051,7 +1051,7 @@ int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count,  	for (i = 0; i < bh_count; i++)  		/* Note that NULL bhs[i] is valid because of holes. */ -		if (bhs[i] && !buffer_uptodate(bhs[i])) +		if (bhs[i] && !ext4_buffer_uptodate(bhs[i]))  			ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1,  				    &bhs[i]); @@ -1340,6 +1340,9 @@ retry_journal:  	}  	if (ret) { +		bool extended = (pos + len > inode->i_size) && +				!ext4_verity_in_progress(inode); +  		unlock_page(page);  		/*  		 * __block_write_begin may have instantiated a few blocks @@ -1349,11 +1352,11 @@ retry_journal:  		 * Add inode to orphan list in case we crash before  		 * truncate finishes  		 */ -		if (pos + len > inode->i_size && ext4_can_truncate(inode)) +		if (extended && ext4_can_truncate(inode))  			ext4_orphan_add(handle, inode);  		ext4_journal_stop(handle); -		if (pos + len > inode->i_size) { +		if (extended) {  			ext4_truncate_failed_write(inode);  			/*  			 * If truncate failed early the inode might @@ -1406,6 +1409,7 @@ static int ext4_write_end(struct file *file,  	int ret = 0, ret2;  	int i_size_changed = 0;  	int inline_data = ext4_has_inline_data(inode); +	bool verity = ext4_verity_in_progress(inode);  	trace_ext4_write_end(inode, pos, len, copied);  	if (inline_data) { @@ -1423,12 +1427,16 @@ static int ext4_write_end(struct file *file,  	/*  	 * it's important to update i_size while still holding page lock:  	 * page writeout could otherwise come in and zero beyond i_size. +	 * +	 * If FS_IOC_ENABLE_VERITY is running on this inode, then Merkle tree +	 * blocks are being written past EOF, so skip the i_size update.  	 */ -	i_size_changed = ext4_update_inode_size(inode, pos + copied); +	if (!verity) +		i_size_changed = ext4_update_inode_size(inode, pos + copied);  	unlock_page(page);  	put_page(page); -	if (old_size < pos) +	if (old_size < pos && !verity)  		pagecache_isize_extended(inode, old_size, pos);  	/*  	 * Don't mark the inode dirty under page lock. First, it unnecessarily @@ -1439,7 +1447,7 @@ static int ext4_write_end(struct file *file,  	if (i_size_changed || inline_data)  		ext4_mark_inode_dirty(handle, inode); -	if (pos + len > inode->i_size && ext4_can_truncate(inode)) +	if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))  		/* if we have allocated more blocks and copied  		 * less. We will have blocks allocated outside  		 * inode->i_size. So truncate them @@ -1450,7 +1458,7 @@ errout:  	if (!ret)  		ret = ret2; -	if (pos + len > inode->i_size) { +	if (pos + len > inode->i_size && !verity) {  		ext4_truncate_failed_write(inode);  		/*  		 * If truncate failed early the inode might still be @@ -1511,6 +1519,7 @@ static int ext4_journalled_write_end(struct file *file,  	unsigned from, to;  	int size_changed = 0;  	int inline_data = ext4_has_inline_data(inode); +	bool verity = ext4_verity_in_progress(inode);  	trace_ext4_journalled_write_end(inode, pos, len, copied);  	from = pos & (PAGE_SIZE - 1); @@ -1540,13 +1549,14 @@ static int ext4_journalled_write_end(struct file *file,  		if (!partial)  			SetPageUptodate(page);  	} -	size_changed = ext4_update_inode_size(inode, pos + copied); +	if (!verity) +		size_changed = ext4_update_inode_size(inode, pos + copied);  	ext4_set_inode_state(inode, EXT4_STATE_JDATA);  	EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;  	unlock_page(page);  	put_page(page); -	if (old_size < pos) +	if (old_size < pos && !verity)  		pagecache_isize_extended(inode, old_size, pos);  	if (size_changed || inline_data) { @@ -1555,7 +1565,7 @@ static int ext4_journalled_write_end(struct file *file,  			ret = ret2;  	} -	if (pos + len > inode->i_size && ext4_can_truncate(inode)) +	if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))  		/* if we have allocated more blocks and copied  		 * less. We will have blocks allocated outside  		 * inode->i_size. So truncate them @@ -1566,7 +1576,7 @@ errout:  	ret2 = ext4_journal_stop(handle);  	if (!ret)  		ret = ret2; -	if (pos + len > inode->i_size) { +	if (pos + len > inode->i_size && !verity) {  		ext4_truncate_failed_write(inode);  		/*  		 * If truncate failed early the inode might still be @@ -1646,49 +1656,6 @@ void ext4_da_release_space(struct inode *inode, int to_free)  	dquot_release_reservation_block(inode, EXT4_C2B(sbi, to_free));  } -static void ext4_da_page_release_reservation(struct page *page, -					     unsigned int offset, -					     unsigned int length) -{ -	int contiguous_blks = 0; -	struct buffer_head *head, *bh; -	unsigned int curr_off = 0; -	struct inode *inode = page->mapping->host; -	unsigned int stop = offset + length; -	ext4_fsblk_t lblk; - -	BUG_ON(stop > PAGE_SIZE || stop < length); - -	head = page_buffers(page); -	bh = head; -	do { -		unsigned int next_off = curr_off + bh->b_size; - -		if (next_off > stop) -			break; - -		if ((offset <= curr_off) && (buffer_delay(bh))) { -			contiguous_blks++; -			clear_buffer_delay(bh); -		} else if (contiguous_blks) { -			lblk = page->index << -			       (PAGE_SHIFT - inode->i_blkbits); -			lblk += (curr_off >> inode->i_blkbits) - -				contiguous_blks; -			ext4_es_remove_blks(inode, lblk, contiguous_blks); -			contiguous_blks = 0; -		} -		curr_off = next_off; -	} while ((bh = bh->b_this_page) != head); - -	if (contiguous_blks) { -		lblk = page->index << (PAGE_SHIFT - inode->i_blkbits); -		lblk += (curr_off >> inode->i_blkbits) - contiguous_blks; -		ext4_es_remove_blks(inode, lblk, contiguous_blks); -	} - -} -  /*   * Delayed allocation stuff   */ @@ -1868,7 +1835,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,  		  (unsigned long) map->m_lblk);  	/* Lookup extent status tree firstly */ -	if (ext4_es_lookup_extent(inode, iblock, &es)) { +	if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) {  		if (ext4_es_is_hole(&es)) {  			retval = 0;  			down_read(&EXT4_I(inode)->i_data_sem); @@ -2162,7 +2129,8 @@ static int ext4_writepage(struct page *page,  	trace_ext4_writepage(page);  	size = i_size_read(inode); -	if (page->index == size >> PAGE_SHIFT) +	if (page->index == size >> PAGE_SHIFT && +	    !ext4_verity_in_progress(inode))  		len = size & ~PAGE_MASK;  	else  		len = PAGE_SIZE; @@ -2246,7 +2214,8 @@ static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)  	 * after page tables are updated.  	 */  	size = i_size_read(mpd->inode); -	if (page->index == size >> PAGE_SHIFT) +	if (page->index == size >> PAGE_SHIFT && +	    !ext4_verity_in_progress(mpd->inode))  		len = size & ~PAGE_MASK;  	else  		len = PAGE_SIZE; @@ -2345,6 +2314,9 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd,  	ext4_lblk_t blocks = (i_size_read(inode) + i_blocksize(inode) - 1)  							>> inode->i_blkbits; +	if (ext4_verity_in_progress(inode)) +		blocks = EXT_MAX_BLOCKS; +  	do {  		BUG_ON(buffer_locked(bh)); @@ -2785,15 +2757,6 @@ static int ext4_writepages(struct address_space *mapping,  		goto out_writepages;  	} -	if (ext4_should_dioread_nolock(inode)) { -		/* -		 * We may need to convert up to one extent per block in -		 * the page and we may dirty the inode. -		 */ -		rsv_blocks = 1 + ext4_chunk_trans_blocks(inode, -						PAGE_SIZE >> inode->i_blkbits); -	} -  	/*  	 * If we have inline data and arrive here, it means that  	 * we will soon create the block for the 1st page, so @@ -2812,6 +2775,15 @@ static int ext4_writepages(struct address_space *mapping,  		ext4_journal_stop(handle);  	} +	if (ext4_should_dioread_nolock(inode)) { +		/* +		 * We may need to convert up to one extent per block in +		 * the page and we may dirty the inode. +		 */ +		rsv_blocks = 1 + ext4_chunk_trans_blocks(inode, +						PAGE_SIZE >> inode->i_blkbits); +	} +  	if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)  		range_whole = 1; @@ -3061,8 +3033,8 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,  	index = pos >> PAGE_SHIFT; -	if (ext4_nonda_switch(inode->i_sb) || -	    S_ISLNK(inode->i_mode)) { +	if (ext4_nonda_switch(inode->i_sb) || S_ISLNK(inode->i_mode) || +	    ext4_verity_in_progress(inode)) {  		*fsdata = (void *)FALL_BACK_TO_NONDELALLOC;  		return ext4_write_begin(file, mapping, pos,  					len, flags, pagep, fsdata); @@ -3227,24 +3199,6 @@ static int ext4_da_write_end(struct file *file,  	return ret ? ret : copied;  } -static void ext4_da_invalidatepage(struct page *page, unsigned int offset, -				   unsigned int length) -{ -	/* -	 * Drop reserved blocks -	 */ -	BUG_ON(!PageLocked(page)); -	if (!page_has_buffers(page)) -		goto out; - -	ext4_da_page_release_reservation(page, offset, length); - -out: -	ext4_invalidatepage(page, offset, length); - -	return; -} -  /*   * Force all delayed allocation blocks to be allocated for a given inode.   */ @@ -3897,6 +3851,8 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter)  	if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))  		return 0;  #endif +	if (fsverity_active(inode)) +		return 0;  	/*  	 * If we are doing data journalling we don't support O_DIRECT @@ -3985,7 +3941,7 @@ static const struct address_space_operations ext4_da_aops = {  	.write_end		= ext4_da_write_end,  	.set_page_dirty		= ext4_set_page_dirty,  	.bmap			= ext4_bmap, -	.invalidatepage		= ext4_da_invalidatepage, +	.invalidatepage		= ext4_invalidatepage,  	.releasepage		= ext4_releasepage,  	.direct_IO		= ext4_direct_IO,  	.migratepage		= buffer_migrate_page, @@ -4297,6 +4253,15 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)  	trace_ext4_punch_hole(inode, offset, length, 0); +	ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); +	if (ext4_has_inline_data(inode)) { +		down_write(&EXT4_I(inode)->i_mmap_sem); +		ret = ext4_convert_inline_data(inode); +		up_write(&EXT4_I(inode)->i_mmap_sem); +		if (ret) +			return ret; +	} +  	/*  	 * Write out all dirty pages to avoid race conditions  	 * Then release them. @@ -4586,6 +4551,7 @@ static int __ext4_get_inode_loc(struct inode *inode,  	struct buffer_head	*bh;  	struct super_block	*sb = inode->i_sb;  	ext4_fsblk_t		block; +	struct blk_plug		plug;  	int			inodes_per_block, inode_offset;  	iloc->bh = NULL; @@ -4674,6 +4640,7 @@ make_io:  		 * If we need to do any I/O, try to pre-readahead extra  		 * blocks from the inode table.  		 */ +		blk_start_plug(&plug);  		if (EXT4_SB(sb)->s_inode_readahead_blks) {  			ext4_fsblk_t b, end, table;  			unsigned num; @@ -4704,6 +4671,7 @@ make_io:  		get_bh(bh);  		bh->b_end_io = end_buffer_read_sync;  		submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); +		blk_finish_plug(&plug);  		wait_on_buffer(bh);  		if (!buffer_uptodate(bh)) {  			EXT4_ERROR_INODE_BLOCK(inode, block, @@ -4736,6 +4704,8 @@ static bool ext4_should_use_dax(struct inode *inode)  		return false;  	if (ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT))  		return false; +	if (ext4_test_inode_flag(inode, EXT4_INODE_VERITY)) +		return false;  	return true;  } @@ -4760,9 +4730,11 @@ void ext4_set_inode_flags(struct inode *inode)  		new_fl |= S_ENCRYPTED;  	if (flags & EXT4_CASEFOLD_FL)  		new_fl |= S_CASEFOLD; +	if (flags & EXT4_VERITY_FL) +		new_fl |= S_VERITY;  	inode_set_flags(inode, new_fl,  			S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX| -			S_ENCRYPTED|S_CASEFOLD); +			S_ENCRYPTED|S_CASEFOLD|S_VERITY);  }  static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, @@ -5116,6 +5088,9 @@ 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)) +		ext4_error_inode(inode, function, line, 0, +				 "casefold flag without casefold feature");  	brelse(iloc.bh);  	unlock_new_inode(inode); @@ -5552,6 +5527,10 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)  	if (error)  		return error; +	error = fsverity_prepare_setattr(dentry, attr); +	if (error) +		return error; +  	if (is_quota_modification(inode, attr)) {  		error = dquot_initialize(inode);  		if (error)  |