Commit 5dfa01ef authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull vfs fixes from Christian Brauner:
 "This contains a fixes for the current development cycle. Note that AI
  related review sometimes delays fixes a bit because we find more fixes
  for the fixes. I might try and send smaller but more fixes PRs if this
  trend keeps up.

   - Fix various netfslib bugs

   - Fix an out-of-bounds write when listing idmappings

   - Fix the return values in jfs_mkdir() and orangefs_mkdir()

   - Fix a writeback writeback array overflow in fuse

   - Fix a forced iversion increment on lazytime timestamp updates

   - Reject a negative timeval component in kern_select()

   - Fix error return when vfs_mkdir() fails in the cachefiles code

   - Fix wrong error code returned for pidns ioctls"

* tag 'vfs-7.1-rc5.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (31 commits)
  cachefiles: Fix error return when vfs_mkdir() fails
  afs: Fix the locking used by afs_get_link()
  netfs, afs: Fix write skipping in dir/link writepages
  netfs: Fix netfs_read_folio() to wait on writeback
  netfs: Fix folio->private handling in netfs_perform_write()
  netfs: Fix partial invalidation of streaming-write folio
  netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages()
  netfs: Fix leak of request in netfs_write_begin() error handling
  netfs: Fix early put of sink folio in netfs_read_gaps()
  netfs: Fix write streaming disablement if fd open O_RDWR
  netfs: Fix read-gaps to remove netfs_folio from filled folio
  netfs: Fix potential deadlock in write-through mode
  netfs: Fix streaming write being overwritten
  netfs: Defer the emission of trace_netfs_folio()
  netfs: Fix netfs_invalidate_folio() to clear dirty bit if all changes gone
  netfs: Fix overrun check in netfs_extract_user_iter()
  netfs: fix error handling in netfs_extract_user_iter()
  netfs: Fix potential uninitialised var in netfs_extract_user_iter()
  netfs: fix VM_BUG_ON_FOLIO() issue in netfs_write_begin() call
  netfs: Fix zeropoint update where i_size > remote_i_size
  ...
parents 5200f5f4 8a220d1c
Loading
Loading
Loading
Loading
+0 −13
Original line number Diff line number Diff line
@@ -75,17 +75,4 @@ static inline void v9fs_invalidate_inode_attr(struct inode *inode)

int v9fs_open_to_dotl_flags(int flags);

static inline void v9fs_i_size_write(struct inode *inode, loff_t i_size)
{
	/*
	 * 32-bit need the lock, concurrent updates could break the
	 * sequences and make i_size_read() loop forever.
	 * 64-bit updates are atomic and can skip the locking.
	 */
	if (sizeof(i_size) > sizeof(long))
		spin_lock(&inode->i_lock);
	i_size_write(inode, i_size);
	if (sizeof(i_size) > sizeof(long))
		spin_unlock(&inode->i_lock);
}
#endif
+4 −2
Original line number Diff line number Diff line
@@ -1141,11 +1141,13 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
	mode |= inode->i_mode & ~S_IALLUGO;
	inode->i_mode = mode;

	v9inode->netfs.remote_i_size = stat->length;
	spin_lock(&inode->i_lock);
	netfs_write_remote_i_size(inode, stat->length);
	if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))
		v9fs_i_size_write(inode, stat->length);
		i_size_write(inode, stat->length);
	/* not real number of blocks, but 512 byte ones ... */
	inode->i_blocks = (stat->length + 512 - 1) >> 9;
	spin_unlock(&inode->i_lock);
	v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
}

+8 −4
Original line number Diff line number Diff line
@@ -634,10 +634,12 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
		mode |= inode->i_mode & ~S_IALLUGO;
		inode->i_mode = mode;

		v9inode->netfs.remote_i_size = stat->st_size;
		spin_lock(&inode->i_lock);
		netfs_write_remote_i_size(inode, stat->st_size);
		if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))
			v9fs_i_size_write(inode, stat->st_size);
			i_size_write(inode, stat->st_size);
		inode->i_blocks = stat->st_blocks;
		spin_unlock(&inode->i_lock);
	} else {
		if (stat->st_result_mask & P9_STATS_ATIME) {
			inode_set_atime(inode, stat->st_atime_sec,
@@ -662,13 +664,15 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
			mode |= inode->i_mode & ~S_IALLUGO;
			inode->i_mode = mode;
		}
		spin_lock(&inode->i_lock);
		if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) &&
		    stat->st_result_mask & P9_STATS_SIZE) {
			v9inode->netfs.remote_i_size = stat->st_size;
			v9fs_i_size_write(inode, stat->st_size);
			netfs_write_remote_i_size(inode, stat->st_size);
			i_size_write(inode, stat->st_size);
		}
		if (stat->st_result_mask & P9_STATS_BLOCKS)
			inode->i_blocks = stat->st_blocks;
		spin_unlock(&inode->i_lock);
	}
	if (stat->st_result_mask & P9_STATS_GEN)
		inode->i_generation = stat->st_gen;
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ kafs-y := \
	server.o \
	server_list.o \
	super.o \
	symlink.o \
	validation.o \
	vlclient.o \
	vl_alias.o \
+44 −35
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,
static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
		      struct dentry *old_dentry, struct inode *new_dir,
		      struct dentry *new_dentry, unsigned int flags);
static int afs_dir_writepages(struct address_space *mapping,
			      struct writeback_control *wbc);

const struct file_operations afs_dir_file_operations = {
	.open		= afs_dir_open,
@@ -68,7 +70,7 @@ const struct inode_operations afs_dir_inode_operations = {
};

const struct address_space_operations afs_dir_aops = {
	.writepages	= afs_single_writepages,
	.writepages	= afs_dir_writepages,
};

const struct dentry_operations afs_fs_dentry_operations = {
@@ -233,23 +235,14 @@ static ssize_t afs_do_read_single(struct afs_vnode *dvnode, struct file *file)
	struct iov_iter iter;
	ssize_t ret;
	loff_t i_size;
	bool is_dir = (S_ISDIR(dvnode->netfs.inode.i_mode) &&
		       !test_bit(AFS_VNODE_MOUNTPOINT, &dvnode->flags));

	i_size = i_size_read(&dvnode->netfs.inode);
	if (is_dir) {
	if (i_size < AFS_DIR_BLOCK_SIZE)
		return afs_bad(dvnode, afs_file_error_dir_small);
	if (i_size > AFS_DIR_BLOCK_SIZE * 1024) {
		trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big);
		return -EFBIG;
	}
	} else {
		if (i_size > AFSPATHMAX) {
			trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big);
			return -EFBIG;
		}
	}

	/* Expand the storage.  TODO: Shrink the storage too. */
	if (dvnode->directory_size < i_size) {
@@ -277,24 +270,18 @@ static ssize_t afs_do_read_single(struct afs_vnode *dvnode, struct file *file)
			 * buffer.
			 */
			ret = -ESTALE;
		} else if (is_dir) {
		} else {
			int ret2 = afs_dir_check(dvnode);

			if (ret2 < 0)
				ret = ret2;
		} else if (i_size < folioq_folio_size(dvnode->directory, 0)) {
			/* NUL-terminate a symlink. */
			char *symlink = kmap_local_folio(folioq_folio(dvnode->directory, 0), 0);

			symlink[i_size] = 0;
			kunmap_local(symlink);
		}
	}

	return ret;
}

ssize_t afs_read_single(struct afs_vnode *dvnode, struct file *file)
static ssize_t afs_read_single(struct afs_vnode *dvnode, struct file *file)
{
	ssize_t ret;

@@ -1763,13 +1750,20 @@ static int afs_link(struct dentry *from, struct inode *dir,
	return ret;
}

static void afs_symlink_put(struct afs_operation *op)
{
	kfree(op->create.symlink);
	op->create.symlink = NULL;
	afs_create_put(op);
}

static const struct afs_operation_ops afs_symlink_operation = {
	.issue_afs_rpc	= afs_fs_symlink,
	.issue_yfs_rpc	= yfs_fs_symlink,
	.success	= afs_create_success,
	.aborted	= afs_check_for_remote_deletion,
	.edit_dir	= afs_create_edit_dir,
	.put		= afs_create_put,
	.put		= afs_symlink_put,
};

/*
@@ -1779,7 +1773,9 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,
		       struct dentry *dentry, const char *content)
{
	struct afs_operation *op;
	struct afs_symlink *symlink;
	struct afs_vnode *dvnode = AFS_FS_I(dir);
	size_t clen = strlen(content);
	int ret;

	_enter("{%llx:%llu},{%pd},%s",
@@ -1791,12 +1787,20 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,
		goto error;

	ret = -EINVAL;
	if (strlen(content) >= AFSPATHMAX)
	if (clen >= AFSPATHMAX)
		goto error;

	ret = -ENOMEM;
	symlink = kmalloc_flex(struct afs_symlink, content, clen + 1, GFP_KERNEL);
	if (!symlink)
		goto error;
	refcount_set(&symlink->ref, 1);
	memcpy(symlink->content, content, clen + 1);

	op = afs_alloc_operation(NULL, dvnode->volume);
	if (IS_ERR(op)) {
		ret = PTR_ERR(op);
		kfree(symlink);
		goto error;
	}

@@ -1808,7 +1812,7 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,
	op->dentry		= dentry;
	op->ops			= &afs_symlink_operation;
	op->create.reason	= afs_edit_dir_for_symlink;
	op->create.symlink	= content;
	op->create.symlink	= symlink;
	op->mtime		= current_time(dir);
	ret = afs_do_sync_operation(op);
	afs_dir_unuse_cookie(dvnode, ret);
@@ -2192,28 +2196,33 @@ static int afs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
}

/*
 * Write the file contents to the cache as a single blob.
 * Write the directory contents to the cache as a single blob.
 */
int afs_single_writepages(struct address_space *mapping,
static int afs_dir_writepages(struct address_space *mapping,
			      struct writeback_control *wbc)
{
	struct afs_vnode *dvnode = AFS_FS_I(mapping->host);
	struct iov_iter iter;
	bool is_dir = (S_ISDIR(dvnode->netfs.inode.i_mode) &&
		       !test_bit(AFS_VNODE_MOUNTPOINT, &dvnode->flags));
	int ret = 0;

	/* Need to lock to prevent the folio queue and folios from being thrown
	 * away.
	 */
	if (!down_read_trylock(&dvnode->validate_lock)) {
		if (wbc->sync_mode == WB_SYNC_NONE) {
			/* The VFS will have undirtied the inode. */
			netfs_single_mark_inode_dirty(&dvnode->netfs.inode);
			return 0;
		}
		down_read(&dvnode->validate_lock);
	}

	if (is_dir ?
	    test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) :
	    atomic64_read(&dvnode->cb_expires_at) != AFS_NO_CB_PROMISE) {
	if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
		iov_iter_folio_queue(&iter, ITER_SOURCE, dvnode->directory, 0, 0,
				     i_size_read(&dvnode->netfs.inode));
		ret = netfs_writeback_single(mapping, wbc, &iter);
		if (ret == 1)
			ret = 0; /* Skipped write due to lock conflict. */
	}

	up_read(&dvnode->validate_lock);
Loading