diff options
Diffstat (limited to 'fs/btrfs')
| -rw-r--r-- | fs/btrfs/extent_io.c | 9 | ||||
| -rw-r--r-- | fs/btrfs/file.c | 40 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 33 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 5 | ||||
| -rw-r--r-- | fs/btrfs/verity.c | 64 | 
5 files changed, 91 insertions, 60 deletions
| diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ac3fca5a5e41..6954ae763b86 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -484,10 +484,8 @@ static void end_bio_extent_writepage(struct btrfs_bio *bbio)  				   bvec->bv_offset, bvec->bv_len);  		btrfs_finish_ordered_extent(bbio->ordered, page, start, len, !error); -		if (error) { -			btrfs_page_clear_uptodate(fs_info, page, start, len); +		if (error)  			mapping_set_error(page->mapping, error); -		}  		btrfs_page_clear_writeback(fs_info, page, start, len);  	} @@ -1456,8 +1454,6 @@ done:  	if (ret) {  		btrfs_mark_ordered_io_finished(BTRFS_I(inode), page, page_start,  					       PAGE_SIZE, !ret); -		btrfs_page_clear_uptodate(btrfs_sb(inode->i_sb), page, -					  page_start, PAGE_SIZE);  		mapping_set_error(page->mapping, ret);  	}  	unlock_page(page); @@ -1624,8 +1620,6 @@ static void extent_buffer_write_end_io(struct btrfs_bio *bbio)  		struct page *page = bvec->bv_page;  		u32 len = bvec->bv_len; -		if (!uptodate) -			btrfs_page_clear_uptodate(fs_info, page, start, len);  		btrfs_page_clear_writeback(fs_info, page, start, len);  		bio_offset += len;  	} @@ -2201,7 +2195,6 @@ void extent_write_locked_range(struct inode *inode, struct page *locked_page,  		if (ret) {  			btrfs_mark_ordered_io_finished(BTRFS_I(inode), page,  						       cur, cur_len, !ret); -			btrfs_page_clear_uptodate(fs_info, page, cur, cur_len);  			mapping_set_error(page->mapping, ret);  		}  		btrfs_page_unlock_writer(fs_info, page, cur, cur_len); diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index ca46a529d56b..361535c71c0f 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1106,6 +1106,25 @@ void btrfs_check_nocow_unlock(struct btrfs_inode *inode)  	btrfs_drew_write_unlock(&inode->root->snapshot_lock);  } +static void update_time_for_write(struct inode *inode) +{ +	struct timespec64 now, ctime; + +	if (IS_NOCMTIME(inode)) +		return; + +	now = current_time(inode); +	if (!timespec64_equal(&inode->i_mtime, &now)) +		inode->i_mtime = now; + +	ctime = inode_get_ctime(inode); +	if (!timespec64_equal(&ctime, &now)) +		inode_set_ctime_to_ts(inode, now); + +	if (IS_I_VERSION(inode)) +		inode_inc_iversion(inode); +} +  static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,  			     size_t count)  { @@ -1137,10 +1156,7 @@ static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,  	 * need to start yet another transaction to update the inode as we will  	 * update the inode when we finish writing whatever data we write.  	 */ -	if (!IS_NOCMTIME(inode)) { -		inode->i_mtime = inode_set_ctime_current(inode); -		inode_inc_iversion(inode); -	} +	update_time_for_write(inode);  	start_pos = round_down(pos, fs_info->sectorsize);  	oldsize = i_size_read(inode); @@ -1451,8 +1467,13 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)  	if (iocb->ki_flags & IOCB_NOWAIT)  		ilock_flags |= BTRFS_ILOCK_TRY; -	/* If the write DIO is within EOF, use a shared lock */ -	if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode)) +	/* +	 * If the write DIO is within EOF, use a shared lock and also only if +	 * security bits will likely not be dropped by file_remove_privs() called +	 * from btrfs_write_check(). Either will need to be rechecked after the +	 * lock was acquired. +	 */ +	if (iocb->ki_pos + iov_iter_count(from) <= i_size_read(inode) && IS_NOSEC(inode))  		ilock_flags |= BTRFS_ILOCK_SHARED;  relock: @@ -1460,6 +1481,13 @@ relock:  	if (err < 0)  		return err; +	/* Shared lock cannot be used with security bits set. */ +	if ((ilock_flags & BTRFS_ILOCK_SHARED) && !IS_NOSEC(inode)) { +		btrfs_inode_unlock(BTRFS_I(inode), ilock_flags); +		ilock_flags &= ~BTRFS_ILOCK_SHARED; +		goto relock; +	} +  	err = generic_write_checks(iocb, from);  	if (err <= 0) {  		btrfs_inode_unlock(BTRFS_I(inode), ilock_flags); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f09fbdc43f0f..7814b9d654ce 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1085,9 +1085,6 @@ static void submit_uncompressed_range(struct btrfs_inode *inode,  			btrfs_mark_ordered_io_finished(inode, locked_page,  						       page_start, PAGE_SIZE,  						       !ret); -			btrfs_page_clear_uptodate(inode->root->fs_info, -						  locked_page, page_start, -						  PAGE_SIZE);  			mapping_set_error(locked_page->mapping, ret);  			unlock_page(locked_page);  		} @@ -2791,7 +2788,6 @@ out_page:  		mapping_set_error(page->mapping, ret);  		btrfs_mark_ordered_io_finished(inode, page, page_start,  					       PAGE_SIZE, !ret); -		btrfs_page_clear_uptodate(fs_info, page, page_start, PAGE_SIZE);  		clear_page_dirty_for_io(page);  	}  	btrfs_page_clear_checked(fs_info, page, page_start, PAGE_SIZE); @@ -5769,20 +5765,24 @@ out:  static int btrfs_get_dir_last_index(struct btrfs_inode *dir, u64 *index)  { -	if (dir->index_cnt == (u64)-1) { -		int ret; +	int ret = 0; +	btrfs_inode_lock(dir, 0); +	if (dir->index_cnt == (u64)-1) {  		ret = btrfs_inode_delayed_dir_index_count(dir);  		if (ret) {  			ret = btrfs_set_inode_index_count(dir);  			if (ret) -				return ret; +				goto out;  		}  	} -	*index = dir->index_cnt; +	/* index_cnt is the index number of next new entry, so decrement it. */ +	*index = dir->index_cnt - 1; +out: +	btrfs_inode_unlock(dir, 0); -	return 0; +	return ret;  }  /* @@ -5817,6 +5817,19 @@ static int btrfs_opendir(struct inode *inode, struct file *file)  	return 0;  } +static loff_t btrfs_dir_llseek(struct file *file, loff_t offset, int whence) +{ +	struct btrfs_file_private *private = file->private_data; +	int ret; + +	ret = btrfs_get_dir_last_index(BTRFS_I(file_inode(file)), +				       &private->last_index); +	if (ret) +		return ret; + +	return generic_file_llseek(file, offset, whence); +} +  struct dir_entry {  	u64 ino;  	u64 offset; @@ -10868,7 +10881,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {  };  static const struct file_operations btrfs_dir_file_operations = { -	.llseek		= generic_file_llseek, +	.llseek		= btrfs_dir_llseek,  	.read		= generic_read_dir,  	.iterate_shared	= btrfs_real_readdir,  	.open		= btrfs_opendir, diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 09bfe68d2ea3..cffdd6f7f8e8 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2150,7 +2150,7 @@ static struct file_system_type btrfs_fs_type = {  	.name		= "btrfs",  	.mount		= btrfs_mount,  	.kill_sb	= btrfs_kill_super, -	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | FS_MGTIME, +	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA,  };  static struct file_system_type btrfs_root_fs_type = { @@ -2158,8 +2158,7 @@ static struct file_system_type btrfs_root_fs_type = {  	.name		= "btrfs",  	.mount		= btrfs_mount_root,  	.kill_sb	= btrfs_kill_super, -	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | -			  FS_ALLOW_IDMAP | FS_MGTIME, +	.fs_flags	= FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | FS_ALLOW_IDMAP,  };  MODULE_ALIAS_FS("btrfs"); diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c index c5ff16f9e9fa..744f4f4d4c68 100644 --- a/fs/btrfs/verity.c +++ b/fs/btrfs/verity.c @@ -715,7 +715,7 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode,  						pgoff_t index,  						unsigned long num_ra_pages)  { -	struct page *page; +	struct folio *folio;  	u64 off = (u64)index << PAGE_SHIFT;  	loff_t merkle_pos = merkle_file_pos(inode);  	int ret; @@ -726,29 +726,36 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode,  		return ERR_PTR(-EFBIG);  	index += merkle_pos >> PAGE_SHIFT;  again: -	page = find_get_page_flags(inode->i_mapping, index, FGP_ACCESSED); -	if (page) { -		if (PageUptodate(page)) -			return page; +	folio = __filemap_get_folio(inode->i_mapping, index, FGP_ACCESSED, 0); +	if (!IS_ERR(folio)) { +		if (folio_test_uptodate(folio)) +			goto out; -		lock_page(page); -		/* -		 * We only insert uptodate pages, so !Uptodate has to be -		 * an error -		 */ -		if (!PageUptodate(page)) { -			unlock_page(page); -			put_page(page); +		folio_lock(folio); +		/* If it's not uptodate after we have the lock, we got a read error. */ +		if (!folio_test_uptodate(folio)) { +			folio_unlock(folio); +			folio_put(folio);  			return ERR_PTR(-EIO);  		} -		unlock_page(page); -		return page; +		folio_unlock(folio); +		goto out;  	} -	page = __page_cache_alloc(mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS)); -	if (!page) +	folio = filemap_alloc_folio(mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS), +				    0); +	if (!folio)  		return ERR_PTR(-ENOMEM); +	ret = filemap_add_folio(inode->i_mapping, folio, index, GFP_NOFS); +	if (ret) { +		folio_put(folio); +		/* Did someone else insert a folio here? */ +		if (ret == -EEXIST) +			goto again; +		return ERR_PTR(ret); +	} +  	/*  	 * Merkle item keys are indexed from byte 0 in the merkle tree.  	 * They have the form: @@ -756,28 +763,19 @@ again:  	 * [ inode objectid, BTRFS_MERKLE_ITEM_KEY, offset in bytes ]  	 */  	ret = read_key_bytes(BTRFS_I(inode), BTRFS_VERITY_MERKLE_ITEM_KEY, off, -			     page_address(page), PAGE_SIZE, page); +			     folio_address(folio), PAGE_SIZE, &folio->page);  	if (ret < 0) { -		put_page(page); +		folio_put(folio);  		return ERR_PTR(ret);  	}  	if (ret < PAGE_SIZE) -		memzero_page(page, ret, PAGE_SIZE - ret); +		folio_zero_segment(folio, ret, PAGE_SIZE); -	SetPageUptodate(page); -	ret = add_to_page_cache_lru(page, inode->i_mapping, index, GFP_NOFS); +	folio_mark_uptodate(folio); +	folio_unlock(folio); -	if (!ret) { -		/* Inserted and ready for fsverity */ -		unlock_page(page); -	} else { -		put_page(page); -		/* Did someone race us into inserting this page? */ -		if (ret == -EEXIST) -			goto again; -		page = ERR_PTR(ret); -	} -	return page; +out: +	return folio_file_page(folio, index);  }  /* | 
