Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efd52b5d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client updates from Trond Myklebust:
 "Highlights include:

  Stable bugfixes:

   - Fix breakages in the nfsstat utility due to the inclusion of the
     NFSv4 LOOKUPP operation

   - Fix a NULL pointer dereference in nfs_idmap_prepare_pipe_upcall()
     due to nfs_idmap_legacy_upcall() being called without an 'aux'
     parameter

   - Fix a refcount leak in the standard O_DIRECT error path

   - Fix a refcount leak in the pNFS O_DIRECT fallback to MDS path

   - Fix CPU latency issues with nfs_commit_release_pages()

   - Fix the LAYOUTUNAVAILABLE error case in the file layout type

   - NFS: Fix a race between mmap() and O_DIRECT

  Features:

   - Support the statx() mask and query flags to enable optimisations
     when the user is requesting only attributes that are already up to
     date in the inode cache, or is specifying the AT_STATX_DONT_SYNC
     flag

   - Add a module alias for the SCSI pNFS layout type

  Bugfixes:

   - Automounting when resolving a NFSv4 referral should preserve the
     RDMA transport protocol settings

   - Various other RDMA bugfixes from Chuck

   - pNFS block layout fixes

   - Always set NFS_LOCK_LOST when a lock is lost"

* tag 'nfs-for-4.16-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (69 commits)
  NFS: Fix a race between mmap() and O_DIRECT
  NFS: Remove a redundant call to unmap_mapping_range()
  pnfs/blocklayout: Ensure disk address in block device map
  pnfs/blocklayout: pnfs_block_dev_map uses bytes, not sectors
  lockd: Fix server refcounting
  SUNRPC: Fix null rpc_clnt dereference in rpc_task_queued tracepoint
  SUNRPC: Micro-optimize __rpc_execute
  SUNRPC: task_run_action should display tk_callback
  sunrpc: Format RPC events consistently for display
  SUNRPC: Trace xprt_timer events
  xprtrdma: Correct some documenting comments
  xprtrdma: Fix "bytes registered" accounting
  xprtrdma: Instrument allocation/release of rpcrdma_req/rep objects
  xprtrdma: Add trace points to instrument QP and CQ access upcalls
  xprtrdma: Add trace points in the client-side backchannel code paths
  xprtrdma: Add trace points for connect events
  xprtrdma: Add trace points to instrument MR allocation and recovery
  xprtrdma: Add trace points to instrument memory invalidation
  xprtrdma: Add trace points in reply decoder path
  xprtrdma: Add trace points to instrument memory registration
  ..
parents 1ed2d76e e231c687
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -48,13 +48,13 @@ void nlmclnt_next_cookie(struct nlm_cookie *c)

static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner)
{
	atomic_inc(&lockowner->count);
	refcount_inc(&lockowner->count);
	return lockowner;
}

static void nlm_put_lockowner(struct nlm_lockowner *lockowner)
{
	if (!atomic_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
	if (!refcount_dec_and_lock(&lockowner->count, &lockowner->host->h_lock))
		return;
	list_del(&lockowner->list);
	spin_unlock(&lockowner->host->h_lock);
@@ -105,7 +105,7 @@ static struct nlm_lockowner *nlm_find_lockowner(struct nlm_host *host, fl_owner_
		res = __nlm_find_lockowner(host, owner);
		if (res == NULL && new != NULL) {
			res = new;
			atomic_set(&new->count, 1);
			refcount_set(&new->count, 1);
			new->owner = owner;
			new->pid = __nlm_alloc_pid(host);
			new->host = nlm_get_host(host);
@@ -204,7 +204,7 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
	for(;;) {
		call = kzalloc(sizeof(*call), GFP_KERNEL);
		if (call != NULL) {
			atomic_set(&call->a_count, 1);
			refcount_set(&call->a_count, 1);
			locks_init_lock(&call->a_args.lock.fl);
			locks_init_lock(&call->a_res.lock.fl);
			call->a_host = nlm_get_host(host);
@@ -222,7 +222,7 @@ void nlmclnt_release_call(struct nlm_rqst *call)
{
	const struct nlmclnt_operations *nlmclnt_ops = call->a_host->h_nlmclnt_ops;

	if (!atomic_dec_and_test(&call->a_count))
	if (!refcount_dec_and_test(&call->a_count))
		return;
	if (nlmclnt_ops && nlmclnt_ops->nlmclnt_release_call)
		nlmclnt_ops->nlmclnt_release_call(call->a_callback_data);
@@ -678,7 +678,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
		goto out;
	}

	atomic_inc(&req->a_count);
	refcount_inc(&req->a_count);
	status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
			NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
	if (status < 0)
@@ -769,7 +769,7 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
	nlmclnt_setlockargs(req, fl);
	req->a_args.block = block;

	atomic_inc(&req->a_count);
	refcount_inc(&req->a_count);
	status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
			NLMPROC_CANCEL, &nlmclnt_cancel_ops);
	if (status == 0 && req->a_res.status == nlm_lck_denied)
+12 −10
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
	unsigned long now = jiffies;

	if (nsm != NULL)
		atomic_inc(&nsm->sm_count);
		refcount_inc(&nsm->sm_count);
	else {
		host = NULL;
		nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
@@ -151,7 +151,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
	host->h_state      = 0;
	host->h_nsmstate   = 0;
	host->h_pidcount   = 0;
	atomic_set(&host->h_count, 1);
	refcount_set(&host->h_count, 1);
	mutex_init(&host->h_mutex);
	host->h_nextrebind = now + NLM_HOST_REBIND;
	host->h_expires    = now + NLM_HOST_EXPIRE;
@@ -290,7 +290,7 @@ void nlmclnt_release_host(struct nlm_host *host)

	WARN_ON_ONCE(host->h_server);

	if (atomic_dec_and_test(&host->h_count)) {
	if (refcount_dec_and_test(&host->h_count)) {
		WARN_ON_ONCE(!list_empty(&host->h_lockowners));
		WARN_ON_ONCE(!list_empty(&host->h_granted));
		WARN_ON_ONCE(!list_empty(&host->h_reclaim));
@@ -388,6 +388,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
	ln->nrhosts++;
	nrhosts++;

	refcount_inc(&host->h_count);

	dprintk("lockd: %s created host %s (%s)\n",
		__func__, host->h_name, host->h_addrbuf);

@@ -410,7 +412,7 @@ void nlmsvc_release_host(struct nlm_host *host)
	dprintk("lockd: release server host %s\n", host->h_name);

	WARN_ON_ONCE(!host->h_server);
	atomic_dec(&host->h_count);
	refcount_dec(&host->h_count);
}

/*
@@ -504,7 +506,7 @@ struct nlm_host * nlm_get_host(struct nlm_host *host)
{
	if (host) {
		dprintk("lockd: get host %s\n", host->h_name);
		atomic_inc(&host->h_count);
		refcount_inc(&host->h_count);
		host->h_expires = jiffies + NLM_HOST_EXPIRE;
	}
	return host;
@@ -593,7 +595,7 @@ static void nlm_complain_hosts(struct net *net)
		if (net && host->net != net)
			continue;
		dprintk("       %s (cnt %d use %d exp %ld net %x)\n",
			host->h_name, atomic_read(&host->h_count),
			host->h_name, refcount_read(&host->h_count),
			host->h_inuse, host->h_expires, host->net->ns.inum);
	}
}
@@ -662,15 +664,15 @@ nlm_gc_hosts(struct net *net)
	for_each_host_safe(host, next, chain, nlm_server_hosts) {
		if (net && host->net != net)
			continue;
		if (atomic_read(&host->h_count) || host->h_inuse
		 || time_before(jiffies, host->h_expires)) {
		if (host->h_inuse || time_before(jiffies, host->h_expires)) {
			dprintk("nlm_gc_hosts skipping %s "
				"(cnt %d use %d exp %ld net %x)\n",
				host->h_name, atomic_read(&host->h_count),
				host->h_name, refcount_read(&host->h_count),
				host->h_inuse, host->h_expires,
				host->net->ns.inum);
			continue;
		}
		if (refcount_dec_if_one(&host->h_count))
			nlm_destroy_host_locked(host);
	}

+7 −7
Original line number Diff line number Diff line
@@ -191,7 +191,7 @@ void nsm_unmonitor(const struct nlm_host *host)
	struct nsm_res	res;
	int status;

	if (atomic_read(&nsm->sm_count) == 1
	if (refcount_read(&nsm->sm_count) == 1
	 && nsm->sm_monitored && !nsm->sm_sticky) {
		dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);

@@ -279,7 +279,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
	if (unlikely(new == NULL))
		return NULL;

	atomic_set(&new->sm_count, 1);
	refcount_set(&new->sm_count, 1);
	new->sm_name = (char *)(new + 1);
	memcpy(nsm_addr(new), sap, salen);
	new->sm_addrlen = salen;
@@ -337,13 +337,13 @@ struct nsm_handle *nsm_get_handle(const struct net *net,
		cached = nsm_lookup_addr(&ln->nsm_handles, sap);

	if (cached != NULL) {
		atomic_inc(&cached->sm_count);
		refcount_inc(&cached->sm_count);
		spin_unlock(&nsm_lock);
		kfree(new);
		dprintk("lockd: found nsm_handle for %s (%s), "
				"cnt %d\n", cached->sm_name,
				cached->sm_addrbuf,
				atomic_read(&cached->sm_count));
				refcount_read(&cached->sm_count));
		return cached;
	}

@@ -388,12 +388,12 @@ struct nsm_handle *nsm_reboot_lookup(const struct net *net,
		return cached;
	}

	atomic_inc(&cached->sm_count);
	refcount_inc(&cached->sm_count);
	spin_unlock(&nsm_lock);

	dprintk("lockd: host %s (%s) rebooted, cnt %d\n",
			cached->sm_name, cached->sm_addrbuf,
			atomic_read(&cached->sm_count));
			refcount_read(&cached->sm_count));
	return cached;
}

@@ -404,7 +404,7 @@ struct nsm_handle *nsm_reboot_lookup(const struct net *net,
 */
void nsm_release(struct nsm_handle *nsm)
{
	if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
	if (refcount_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
		list_del(&nsm->sm_link);
		spin_unlock(&nsm_lock);
		dprintk("lockd: destroyed nsm_handle for %s (%s)\n",
+1 −1
Original line number Diff line number Diff line
@@ -295,7 +295,7 @@ static void nlmsvc_callback_exit(struct rpc_task *task, void *data)

void nlmsvc_release_call(struct nlm_rqst *call)
{
	if (!atomic_dec_and_test(&call->a_count))
	if (!refcount_dec_and_test(&call->a_count))
		return;
	nlmsvc_release_host(call->a_host);
	kfree(call);
+87 −7
Original line number Diff line number Diff line
@@ -137,6 +137,11 @@ bl_alloc_init_bio(int npg, struct block_device *bdev, sector_t disk_sector,
	return bio;
}

static bool offset_in_map(u64 offset, struct pnfs_block_dev_map *map)
{
	return offset >= map->start && offset < map->start + map->len;
}

static struct bio *
do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect,
		struct page *page, struct pnfs_block_dev_map *map,
@@ -156,8 +161,8 @@ do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect,

	/* translate to physical disk offset */
	disk_addr = (u64)isect << SECTOR_SHIFT;
	if (disk_addr < map->start || disk_addr >= map->start + map->len) {
		if (!dev->map(dev, disk_addr, map))
	if (!offset_in_map(disk_addr, map)) {
		if (!dev->map(dev, disk_addr, map) || !offset_in_map(disk_addr, map))
			return ERR_PTR(-EIO);
		bio = bl_submit_bio(bio);
	}
@@ -184,6 +189,29 @@ do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect,
	return bio;
}

static void bl_mark_devices_unavailable(struct nfs_pgio_header *header, bool rw)
{
	struct pnfs_block_layout *bl = BLK_LSEG2EXT(header->lseg);
	size_t bytes_left = header->args.count;
	sector_t isect, extent_length = 0;
	struct pnfs_block_extent be;

	isect = header->args.offset >> SECTOR_SHIFT;
	bytes_left += header->args.offset - (isect << SECTOR_SHIFT);

	while (bytes_left > 0) {
		if (!ext_tree_lookup(bl, isect, &be, rw))
				return;
		extent_length = be.be_length - (isect - be.be_f_offset);
		nfs4_mark_deviceid_unavailable(be.be_device);
		isect += extent_length;
		if (bytes_left > extent_length << SECTOR_SHIFT)
			bytes_left -= extent_length << SECTOR_SHIFT;
		else
			bytes_left = 0;
	}
}

static void bl_end_io_read(struct bio *bio)
{
	struct parallel_io *par = bio->bi_private;
@@ -194,6 +222,7 @@ static void bl_end_io_read(struct bio *bio)
		if (!header->pnfs_error)
			header->pnfs_error = -EIO;
		pnfs_set_lo_fail(header->lseg);
		bl_mark_devices_unavailable(header, false);
	}

	bio_put(bio);
@@ -323,6 +352,7 @@ static void bl_end_io_write(struct bio *bio)
		if (!header->pnfs_error)
			header->pnfs_error = -EIO;
		pnfs_set_lo_fail(header->lseg);
		bl_mark_devices_unavailable(header, true);
	}
	bio_put(bio);
	put_parallel(par);
@@ -552,6 +582,31 @@ static int decode_sector_number(__be32 **rp, sector_t *sp)
	return 0;
}

static struct nfs4_deviceid_node *
bl_find_get_deviceid(struct nfs_server *server,
		const struct nfs4_deviceid *id, struct rpc_cred *cred,
		gfp_t gfp_mask)
{
	struct nfs4_deviceid_node *node;
	unsigned long start, end;

retry:
	node = nfs4_find_get_deviceid(server, id, cred, gfp_mask);
	if (!node)
		return ERR_PTR(-ENODEV);

	if (test_bit(NFS_DEVICEID_UNAVAILABLE, &node->flags) == 0)
		return node;

	end = jiffies;
	start = end - PNFS_DEVICE_RETRY_TIMEOUT;
	if (!time_in_range(node->timestamp_unavailable, start, end)) {
		nfs4_delete_deviceid(node->ld, node->nfs_client, id);
		goto retry;
	}
	return ERR_PTR(-ENODEV);
}

static int
bl_alloc_extent(struct xdr_stream *xdr, struct pnfs_layout_hdr *lo,
		struct layout_verification *lv, struct list_head *extents,
@@ -573,16 +628,18 @@ bl_alloc_extent(struct xdr_stream *xdr, struct pnfs_layout_hdr *lo,
	memcpy(&id, p, NFS4_DEVICEID4_SIZE);
	p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);

	error = -EIO;
	be->be_device = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &id,
	be->be_device = bl_find_get_deviceid(NFS_SERVER(lo->plh_inode), &id,
						lo->plh_lc_cred, gfp_mask);
	if (!be->be_device)
	if (IS_ERR(be->be_device)) {
		error = PTR_ERR(be->be_device);
		goto out_free_be;
	}

	/*
	 * The next three values are read in as bytes, but stored in the
	 * extent structure in 512-byte granularity.
	 */
	error = -EIO;
	if (decode_sector_number(&p, &be->be_f_offset) < 0)
		goto out_put_deviceid;
	if (decode_sector_number(&p, &be->be_length) < 0)
@@ -692,11 +749,16 @@ bl_alloc_lseg(struct pnfs_layout_hdr *lo, struct nfs4_layoutget_res *lgr,
	__free_page(scratch);
out:
	dprintk("%s returns %d\n", __func__, status);
	if (status) {
	switch (status) {
	case -ENODEV:
		/* Our extent block devices are unavailable */
		set_bit(NFS_LSEG_UNAVAILABLE, &lseg->pls_flags);
	case 0:
		return lseg;
	default:
		kfree(lseg);
		return ERR_PTR(status);
	}
	return lseg;
}

static void
@@ -798,6 +860,13 @@ bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
	}

	pnfs_generic_pg_init_read(pgio, req);

	if (pgio->pg_lseg &&
		test_bit(NFS_LSEG_UNAVAILABLE, &pgio->pg_lseg->pls_flags)) {
		pnfs_error_mark_layout_for_return(pgio->pg_inode, pgio->pg_lseg);
		pnfs_set_lo_fail(pgio->pg_lseg);
		nfs_pageio_reset_read_mds(pgio);
	}
}

/*
@@ -853,6 +922,14 @@ bl_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
		wb_size = nfs_dreq_bytes_left(pgio->pg_dreq);

	pnfs_generic_pg_init_write(pgio, req, wb_size);

	if (pgio->pg_lseg &&
		test_bit(NFS_LSEG_UNAVAILABLE, &pgio->pg_lseg->pls_flags)) {

		pnfs_error_mark_layout_for_return(pgio->pg_inode, pgio->pg_lseg);
		pnfs_set_lo_fail(pgio->pg_lseg);
		nfs_pageio_reset_write_mds(pgio);
	}
}

/*
@@ -887,6 +964,7 @@ static struct pnfs_layoutdriver_type blocklayout_type = {
	.name				= "LAYOUT_BLOCK_VOLUME",
	.owner				= THIS_MODULE,
	.flags				= PNFS_LAYOUTRET_ON_SETATTR |
					  PNFS_LAYOUTRET_ON_ERROR |
					  PNFS_READ_WHOLE_PAGE,
	.read_pagelist			= bl_read_pagelist,
	.write_pagelist			= bl_write_pagelist,
@@ -910,6 +988,7 @@ static struct pnfs_layoutdriver_type scsilayout_type = {
	.name				= "LAYOUT_SCSI",
	.owner				= THIS_MODULE,
	.flags				= PNFS_LAYOUTRET_ON_SETATTR |
					  PNFS_LAYOUTRET_ON_ERROR |
					  PNFS_READ_WHOLE_PAGE,
	.read_pagelist			= bl_read_pagelist,
	.write_pagelist			= bl_write_pagelist,
@@ -967,6 +1046,7 @@ static void __exit nfs4blocklayout_exit(void)
}

MODULE_ALIAS("nfs-layouttype4-3");
MODULE_ALIAS("nfs-layouttype4-5");

module_init(nfs4blocklayout_init);
module_exit(nfs4blocklayout_exit);
Loading