Commit baf67f6a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client updates from Trond Myklebust:
 "Bugfixes:
   - nfs/localio: fix for a memory corruption in nfs_local_read_done
   - Revert "nfs: don't reuse partially completed requests in
     nfs_lock_and_join_requests"
   - nfsv4:
       - ignore SB_RDONLY when mounting nfs
       - Fix a use-after-free problem in open()
   - sunrpc:
       - clear XPRT_SOCK_UPD_TIMEOUT when reseting the transport
       - timeout and cancel TLS handshake with -ETIMEDOUT
       - fix one UAF issue caused by sunrpc kernel tcp socket
       - Fix a hang in TLS sock_close if sk_write_pending
   - pNFS/blocklayout: Fix device registration issues

  Features and cleanups:
   - localio cleanups from Mike Snitzer
   - Clean up refcounting on the nfs version modules
   - __counted_by() annotations
   - nfs: make processes that are waiting for an I/O lock killable"

* tag 'nfs-for-6.13-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (24 commits)
  fs/nfs/io: make nfs_start_io_*() killable
  nfs/blocklayout: Limit repeat device registration on failure
  nfs/blocklayout: Don't attempt unregister for invalid block device
  sunrpc: fix one UAF issue caused by sunrpc kernel tcp socket
  SUNRPC: timeout and cancel TLS handshake with -ETIMEDOUT
  sunrpc: clear XPRT_SOCK_UPD_TIMEOUT when reset transport
  nfs: ignore SB_RDONLY when mounting nfs
  Revert "nfs: don't reuse partially completed requests in nfs_lock_and_join_requests"
  Revert "fs: nfs: fix missing refcnt by replacing folio_set_private by folio_attach_private"
  nfs/localio: must clear res.replen in nfs_local_read_done
  NFSv4.0: Fix a use-after-free problem in the asynchronous open()
  NFSv4.0: Fix the wake up of the next waiter in nfs_release_seqid()
  SUNRPC: Fix a hang in TLS sock_close if sk_write_pending
  sunrpc: remove newlines from tracepoints
  nfs: Annotate struct pnfs_commit_array with __counted_by()
  nfs/localio: eliminate need for nfs_local_fsync_work forward declaration
  nfs/localio: remove extra indirect nfs_to call to check {read,write}_iter
  nfs/localio: eliminate unnecessary kref in nfs_local_fsync_ctx
  nfs/localio: remove redundant suid/sgid handling
  NFS: Implement get_nfs_version()
  ...
parents 0235da0f 38a125b3
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -571,19 +571,32 @@ bl_find_get_deviceid(struct nfs_server *server,
	if (!node)
		return ERR_PTR(-ENODEV);

	/*
	 * Devices that are marked unavailable are left in the cache with a
	 * timeout to avoid sending GETDEVINFO after every LAYOUTGET, or
	 * constantly attempting to register the device.  Once marked as
	 * unavailable they must be deleted and never reused.
	 */
	if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags)) {
		unsigned long end = jiffies;
		unsigned long start = end - PNFS_DEVICE_RETRY_TIMEOUT;

		if (!time_in_range(node->timestamp_unavailable, start, end)) {
			/* Uncork subsequent GETDEVINFO operations for this device */
			nfs4_delete_deviceid(node->ld, node->nfs_client, id);
			goto retry;
		}
		goto out_put;
	}

	if (!bl_register_dev(container_of(node, struct pnfs_block_dev, node)))
	if (!bl_register_dev(container_of(node, struct pnfs_block_dev, node))) {
		/*
		 * If we cannot register, treat this device as transient:
		 * Make a negative cache entry for the device
		 */
		nfs4_mark_deviceid_unavailable(node);
		goto out_put;
	}

	return node;

+2 −4
Original line number Diff line number Diff line
@@ -20,9 +20,6 @@ static void bl_unregister_scsi(struct pnfs_block_dev *dev)
	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
	int status;

	if (!test_and_clear_bit(PNFS_BDEV_REGISTERED, &dev->flags))
		return;

	status = ops->pr_register(bdev, dev->pr_key, 0, false);
	if (status)
		trace_bl_pr_key_unreg_err(bdev, dev->pr_key, status);
@@ -58,7 +55,8 @@ static void bl_unregister_dev(struct pnfs_block_dev *dev)
		return;
	}

	if (dev->type == PNFS_BLOCK_VOLUME_SCSI)
	if (dev->type == PNFS_BLOCK_VOLUME_SCSI &&
		test_and_clear_bit(PNFS_BDEV_REGISTERED, &dev->flags))
		bl_unregister_scsi(dev);
}

+34 −30
Original line number Diff line number Diff line
@@ -55,9 +55,13 @@
#define NFSDBG_FACILITY		NFSDBG_CLIENT

static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
static DEFINE_SPINLOCK(nfs_version_lock);
static DEFINE_MUTEX(nfs_version_mutex);
static LIST_HEAD(nfs_versions);
static DEFINE_RWLOCK(nfs_version_lock);

static struct nfs_subversion *nfs_version_mods[5] = {
	[2] = NULL,
	[3] = NULL,
	[4] = NULL,
};

/*
 * RPC cruft for NFS
@@ -76,38 +80,38 @@ const struct rpc_program nfs_program = {
	.pipe_dir_name		= NFS_PIPE_DIRNAME,
};

static struct nfs_subversion *find_nfs_version(unsigned int version)
static struct nfs_subversion *__find_nfs_version(unsigned int version)
{
	struct nfs_subversion *nfs;
	spin_lock(&nfs_version_lock);

	list_for_each_entry(nfs, &nfs_versions, list) {
		if (nfs->rpc_ops->version == version) {
			spin_unlock(&nfs_version_lock);
	read_lock(&nfs_version_lock);
	nfs = nfs_version_mods[version];
	read_unlock(&nfs_version_lock);
	return nfs;
}
	}

	spin_unlock(&nfs_version_lock);
	return ERR_PTR(-EPROTONOSUPPORT);
}

struct nfs_subversion *get_nfs_version(unsigned int version)
struct nfs_subversion *find_nfs_version(unsigned int version)
{
	struct nfs_subversion *nfs = find_nfs_version(version);
	struct nfs_subversion *nfs = __find_nfs_version(version);

	if (IS_ERR(nfs)) {
		mutex_lock(&nfs_version_mutex);
		request_module("nfsv%d", version);
		nfs = find_nfs_version(version);
		mutex_unlock(&nfs_version_mutex);
	}
	if (!nfs && request_module("nfsv%d", version) == 0)
		nfs = __find_nfs_version(version);

	if (!nfs)
		return ERR_PTR(-EPROTONOSUPPORT);

	if (!IS_ERR(nfs) && !try_module_get(nfs->owner))
	if (!get_nfs_version(nfs))
		return ERR_PTR(-EAGAIN);

	return nfs;
}

int get_nfs_version(struct nfs_subversion *nfs)
{
	return try_module_get(nfs->owner);
}
EXPORT_SYMBOL_GPL(get_nfs_version);

void put_nfs_version(struct nfs_subversion *nfs)
{
	module_put(nfs->owner);
@@ -115,23 +119,23 @@ void put_nfs_version(struct nfs_subversion *nfs)

void register_nfs_version(struct nfs_subversion *nfs)
{
	spin_lock(&nfs_version_lock);
	write_lock(&nfs_version_lock);

	list_add(&nfs->list, &nfs_versions);
	nfs_version_mods[nfs->rpc_ops->version] = nfs;
	nfs_version[nfs->rpc_ops->version] = nfs->rpc_vers;

	spin_unlock(&nfs_version_lock);
	write_unlock(&nfs_version_lock);
}
EXPORT_SYMBOL_GPL(register_nfs_version);

void unregister_nfs_version(struct nfs_subversion *nfs)
{
	spin_lock(&nfs_version_lock);
	write_lock(&nfs_version_lock);

	nfs_version[nfs->rpc_ops->version] = NULL;
	list_del(&nfs->list);
	nfs_version_mods[nfs->rpc_ops->version] = NULL;

	spin_unlock(&nfs_version_lock);
	write_unlock(&nfs_version_lock);
}
EXPORT_SYMBOL_GPL(unregister_nfs_version);

@@ -151,7 +155,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)

	clp->cl_minorversion = cl_init->minorversion;
	clp->cl_nfs_mod = cl_init->nfs_mod;
	if (!try_module_get(clp->cl_nfs_mod->owner))
	if (!get_nfs_version(clp->cl_nfs_mod))
		goto error_dealloc;

	clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;
+18 −3
Original line number Diff line number Diff line
@@ -454,8 +454,16 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter,
	if (user_backed_iter(iter))
		dreq->flags = NFS_ODIRECT_SHOULD_DIRTY;

	if (!swap)
		nfs_start_io_direct(inode);
	if (!swap) {
		result = nfs_start_io_direct(inode);
		if (result) {
			/* release the reference that would usually be
			 * consumed by nfs_direct_read_schedule_iovec()
			 */
			nfs_direct_req_release(dreq);
			goto out_release;
		}
	}

	NFS_I(inode)->read_io += count;
	requested = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
@@ -1007,7 +1015,14 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter,
		requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
							    FLUSH_STABLE);
	} else {
		nfs_start_io_direct(inode);
		result = nfs_start_io_direct(inode);
		if (result) {
			/* release the reference that would usually be
			 * consumed by nfs_direct_write_schedule_iovec()
			 */
			nfs_direct_req_release(dreq);
			goto out_release;
		}

		requested = nfs_direct_write_schedule_iovec(dreq, iter, pos,
							    FLUSH_COND_STABLE);
+11 −3
Original line number Diff line number Diff line
@@ -166,7 +166,10 @@ nfs_file_read(struct kiocb *iocb, struct iov_iter *to)
		iocb->ki_filp,
		iov_iter_count(to), (unsigned long) iocb->ki_pos);

	nfs_start_io_read(inode);
	result = nfs_start_io_read(inode);
	if (result)
		return result;

	result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
	if (!result) {
		result = generic_file_read_iter(iocb, to);
@@ -187,7 +190,10 @@ nfs_file_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe

	dprintk("NFS: splice_read(%pD2, %zu@%llu)\n", in, len, *ppos);

	nfs_start_io_read(inode);
	result = nfs_start_io_read(inode);
	if (result)
		return result;

	result = nfs_revalidate_mapping(inode, in->f_mapping);
	if (!result) {
		result = filemap_splice_read(in, ppos, pipe, len, flags);
@@ -668,7 +674,9 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from)
	nfs_clear_invalid_mapping(file->f_mapping);

	since = filemap_sample_wb_err(file->f_mapping);
	nfs_start_io_write(inode);
	error = nfs_start_io_write(inode);
	if (error)
		return error;
	result = generic_write_checks(iocb, from);
	if (result > 0)
		result = generic_perform_write(iocb, from);
Loading