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

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

  Features:
   - Add support for multiple NFSv4.1 callbacks in flight
   - Initial patchset for RPC multipath support
   - Adapt RPC/RDMA to use the new completion queue API

  Bugfixes and cleanups:
   - nfs4: nfs4_ff_layout_prepare_ds should return NULL if connection failed
   - Cleanups to remove nfs_inode_dio_wait and nfs4_file_fsync
   - Fix RPC/RDMA credit accounting
   - Properly handle RDMA_ERROR replies
   - xprtrdma: Do not wait if ib_post_send() fails
   - xprtrdma: Segment head and tail XDR buffers on page boundaries
   - xprtrdma cleanups for dprintk, physical_op_map and unused macros"

* tag 'nfs-for-4.6-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (35 commits)
  nfs/blocklayout: make sure making a aligned read request
  nfs4: nfs4_ff_layout_prepare_ds should return NULL if connection failed
  nfs: remove nfs_inode_dio_wait
  nfs: remove nfs4_file_fsync
  xprtrdma: Use new CQ API for RPC-over-RDMA client send CQs
  xprtrdma: Use an anonymous union in struct rpcrdma_mw
  xprtrdma: Use new CQ API for RPC-over-RDMA client receive CQs
  xprtrdma: Serialize credit accounting again
  xprtrdma: Properly handle RDMA_ERROR replies
  rpcrdma: Add RPCRDMA_HDRLEN_ERR
  xprtrdma: Do not wait if ib_post_send() fails
  xprtrdma: Segment head and tail XDR buffers on page boundaries
  xprtrdma: Clean up dprintk format string containing a newline
  xprtrdma: Clean up physical_op_map()
  xprtrdma: Clean up unused RPCRDMA_INLINE_PAD_THRESH macro
  NFS add callback_ops to nfs4_proc_bind_conn_to_session_callback
  pnfs/NFSv4.1: Add multipath capabilities to pNFS flexfiles servers over NFSv3
  SUNRPC: Allow addition of new transports to a struct rpc_clnt
  NFSv4.1: nfs4_proc_bind_conn_to_session must iterate over all connections
  SUNRPC: Make NFS swap work with multipath
  ...
parents 243d5067 f35592a9
Loading
Loading
Loading
Loading
+7 −6
Original line number Original line Diff line number Diff line
@@ -743,7 +743,7 @@ bl_set_layoutdriver(struct nfs_server *server, const struct nfs_fh *fh)


static bool
static bool
is_aligned_req(struct nfs_pageio_descriptor *pgio,
is_aligned_req(struct nfs_pageio_descriptor *pgio,
		struct nfs_page *req, unsigned int alignment)
		struct nfs_page *req, unsigned int alignment, bool is_write)
{
{
	/*
	/*
	 * Always accept buffered writes, higher layers take care of the
	 * Always accept buffered writes, higher layers take care of the
@@ -758,7 +758,8 @@ is_aligned_req(struct nfs_pageio_descriptor *pgio,
	if (IS_ALIGNED(req->wb_bytes, alignment))
	if (IS_ALIGNED(req->wb_bytes, alignment))
		return true;
		return true;


	if (req_offset(req) + req->wb_bytes == i_size_read(pgio->pg_inode)) {
	if (is_write &&
	    (req_offset(req) + req->wb_bytes == i_size_read(pgio->pg_inode))) {
		/*
		/*
		 * If the write goes up to the inode size, just write
		 * If the write goes up to the inode size, just write
		 * the full page.  Data past the inode size is
		 * the full page.  Data past the inode size is
@@ -775,7 +776,7 @@ is_aligned_req(struct nfs_pageio_descriptor *pgio,
static void
static void
bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
bl_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
{
	if (!is_aligned_req(pgio, req, SECTOR_SIZE)) {
	if (!is_aligned_req(pgio, req, SECTOR_SIZE, false)) {
		nfs_pageio_reset_read_mds(pgio);
		nfs_pageio_reset_read_mds(pgio);
		return;
		return;
	}
	}
@@ -791,7 +792,7 @@ static size_t
bl_pg_test_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
bl_pg_test_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
		struct nfs_page *req)
		struct nfs_page *req)
{
{
	if (!is_aligned_req(pgio, req, SECTOR_SIZE))
	if (!is_aligned_req(pgio, req, SECTOR_SIZE, false))
		return 0;
		return 0;
	return pnfs_generic_pg_test(pgio, prev, req);
	return pnfs_generic_pg_test(pgio, prev, req);
}
}
@@ -824,7 +825,7 @@ bl_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
{
{
	u64 wb_size;
	u64 wb_size;


	if (!is_aligned_req(pgio, req, PAGE_SIZE)) {
	if (!is_aligned_req(pgio, req, PAGE_SIZE, true)) {
		nfs_pageio_reset_write_mds(pgio);
		nfs_pageio_reset_write_mds(pgio);
		return;
		return;
	}
	}
@@ -846,7 +847,7 @@ static size_t
bl_pg_test_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
bl_pg_test_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
		 struct nfs_page *req)
		 struct nfs_page *req)
{
{
	if (!is_aligned_req(pgio, req, PAGE_SIZE))
	if (!is_aligned_req(pgio, req, PAGE_SIZE, true))
		return 0;
		return 0;
	return pnfs_generic_pg_test(pgio, prev, req);
	return pnfs_generic_pg_test(pgio, prev, req);
}
}
+2 −1
Original line number Original line Diff line number Diff line
@@ -37,10 +37,11 @@ enum nfs4_callback_opnum {
	OP_CB_ILLEGAL = 10044,
	OP_CB_ILLEGAL = 10044,
};
};


struct nfs4_slot;
struct cb_process_state {
struct cb_process_state {
	__be32			drc_status;
	__be32			drc_status;
	struct nfs_client	*clp;
	struct nfs_client	*clp;
	u32			slotid;
	struct nfs4_slot	*slot;
	u32			minorversion;
	u32			minorversion;
	struct net		*net;
	struct net		*net;
};
};
+37 −32
Original line number Original line Diff line number Diff line
@@ -354,47 +354,38 @@ __be32 nfs4_callback_devicenotify(struct cb_devicenotifyargs *args,
 * a single outstanding callback request at a time.
 * a single outstanding callback request at a time.
 */
 */
static __be32
static __be32
validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot,
		const struct cb_sequenceargs * args)
{
{
	struct nfs4_slot *slot;
	dprintk("%s enter. slotid %u seqid %u, slot table seqid: %u\n",

		__func__, args->csa_slotid, args->csa_sequenceid, slot->seq_nr);
	dprintk("%s enter. slotid %u seqid %u\n",
		__func__, args->csa_slotid, args->csa_sequenceid);


	if (args->csa_slotid >= NFS41_BC_MAX_CALLBACKS)
	if (args->csa_slotid > tbl->server_highest_slotid)
		return htonl(NFS4ERR_BADSLOT);
		return htonl(NFS4ERR_BADSLOT);


	slot = tbl->slots + args->csa_slotid;
	dprintk("%s slot table seqid: %u\n", __func__, slot->seq_nr);

	/* Normal */
	if (likely(args->csa_sequenceid == slot->seq_nr + 1))
		goto out_ok;

	/* Replay */
	/* Replay */
	if (args->csa_sequenceid == slot->seq_nr) {
	if (args->csa_sequenceid == slot->seq_nr) {
		dprintk("%s seqid %u is a replay\n",
		dprintk("%s seqid %u is a replay\n",
			__func__, args->csa_sequenceid);
			__func__, args->csa_sequenceid);
		if (nfs4_test_locked_slot(tbl, slot->slot_nr))
			return htonl(NFS4ERR_DELAY);
		/* Signal process_op to set this error on next op */
		/* Signal process_op to set this error on next op */
		if (args->csa_cachethis == 0)
		if (args->csa_cachethis == 0)
			return htonl(NFS4ERR_RETRY_UNCACHED_REP);
			return htonl(NFS4ERR_RETRY_UNCACHED_REP);


		/* The ca_maxresponsesize_cached is 0 with no DRC */
		/* Liar! We never allowed you to set csa_cachethis != 0 */
		else if (args->csa_cachethis == 1)
		return htonl(NFS4ERR_SEQ_FALSE_RETRY);
			return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);
	}
	}


	/* Wraparound */
	/* Wraparound */
	if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) {
	if (unlikely(slot->seq_nr == 0xFFFFFFFFU)) {
		slot->seq_nr = 1;
		if (args->csa_sequenceid == 1)
		goto out_ok;
			return htonl(NFS4_OK);
	}
	} else if (likely(args->csa_sequenceid == slot->seq_nr + 1))
		return htonl(NFS4_OK);


	/* Misordered request */
	/* Misordered request */
	return htonl(NFS4ERR_SEQ_MISORDERED);
	return htonl(NFS4ERR_SEQ_MISORDERED);
out_ok:
	tbl->highest_used_slotid = args->csa_slotid;
	return htonl(NFS4_OK);
}
}


/*
/*
@@ -473,6 +464,12 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
	tbl = &clp->cl_session->bc_slot_table;
	tbl = &clp->cl_session->bc_slot_table;
	slot = tbl->slots + args->csa_slotid;
	slot = tbl->slots + args->csa_slotid;


	/* Set up res before grabbing the spinlock */
	memcpy(&res->csr_sessionid, &args->csa_sessionid,
	       sizeof(res->csr_sessionid));
	res->csr_sequenceid = args->csa_sequenceid;
	res->csr_slotid = args->csa_slotid;

	spin_lock(&tbl->slot_tbl_lock);
	spin_lock(&tbl->slot_tbl_lock);
	/* state manager is resetting the session */
	/* state manager is resetting the session */
	if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) {
	if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) {
@@ -485,18 +482,26 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
		goto out_unlock;
		goto out_unlock;
	}
	}


	memcpy(&res->csr_sessionid, &args->csa_sessionid,
	status = htonl(NFS4ERR_BADSLOT);
	       sizeof(res->csr_sessionid));
	slot = nfs4_lookup_slot(tbl, args->csa_slotid);
	res->csr_sequenceid = args->csa_sequenceid;
	if (IS_ERR(slot))
	res->csr_slotid = args->csa_slotid;
		goto out_unlock;
	res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
	res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;


	status = validate_seqid(tbl, args);
	res->csr_highestslotid = tbl->server_highest_slotid;
	res->csr_target_highestslotid = tbl->target_highest_slotid;

	status = validate_seqid(tbl, slot, args);
	if (status)
	if (status)
		goto out_unlock;
		goto out_unlock;
	if (!nfs4_try_to_lock_slot(tbl, slot)) {
		status = htonl(NFS4ERR_DELAY);
		goto out_unlock;
	}
	cps->slot = slot;


	cps->slotid = args->csa_slotid;
	/* The ca_maxresponsesize_cached is 0 with no DRC */
	if (args->csa_cachethis != 0)
		return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE);


	/*
	/*
	 * Check for pending referring calls.  If a match is found, a
	 * Check for pending referring calls.  If a match is found, a
@@ -513,7 +518,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
	 * If CB_SEQUENCE returns an error, then the state of the slot
	 * If CB_SEQUENCE returns an error, then the state of the slot
	 * (sequence ID, cached reply) MUST NOT change.
	 * (sequence ID, cached reply) MUST NOT change.
	 */
	 */
	slot->seq_nr++;
	slot->seq_nr = args->csa_sequenceid;
out_unlock:
out_unlock:
	spin_unlock(&tbl->slot_tbl_lock);
	spin_unlock(&tbl->slot_tbl_lock);


+7 −5
Original line number Original line Diff line number Diff line
@@ -752,7 +752,8 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
	return htonl(NFS_OK);
	return htonl(NFS_OK);
}
}


static void nfs4_callback_free_slot(struct nfs4_session *session)
static void nfs4_callback_free_slot(struct nfs4_session *session,
		struct nfs4_slot *slot)
{
{
	struct nfs4_slot_table *tbl = &session->bc_slot_table;
	struct nfs4_slot_table *tbl = &session->bc_slot_table;


@@ -761,15 +762,17 @@ static void nfs4_callback_free_slot(struct nfs4_session *session)
	 * Let the state manager know callback processing done.
	 * Let the state manager know callback processing done.
	 * A single slot, so highest used slotid is either 0 or -1
	 * A single slot, so highest used slotid is either 0 or -1
	 */
	 */
	tbl->highest_used_slotid = NFS4_NO_SLOT;
	nfs4_free_slot(tbl, slot);
	nfs4_slot_tbl_drain_complete(tbl);
	nfs4_slot_tbl_drain_complete(tbl);
	spin_unlock(&tbl->slot_tbl_lock);
	spin_unlock(&tbl->slot_tbl_lock);
}
}


static void nfs4_cb_free_slot(struct cb_process_state *cps)
static void nfs4_cb_free_slot(struct cb_process_state *cps)
{
{
	if (cps->slotid != NFS4_NO_SLOT)
	if (cps->slot) {
		nfs4_callback_free_slot(cps->clp->cl_session);
		nfs4_callback_free_slot(cps->clp->cl_session, cps->slot);
		cps->slot = NULL;
	}
}
}


#else /* CONFIG_NFS_V4_1 */
#else /* CONFIG_NFS_V4_1 */
@@ -893,7 +896,6 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
	struct cb_process_state cps = {
	struct cb_process_state cps = {
		.drc_status = 0,
		.drc_status = 0,
		.clp = NULL,
		.clp = NULL,
		.slotid = NFS4_NO_SLOT,
		.net = SVC_NET(rqstp),
		.net = SVC_NET(rqstp),
	};
	};
	unsigned int nops = 0;
	unsigned int nops = 0;
+7 −5
Original line number Original line Diff line number Diff line
@@ -233,7 +233,7 @@ EXPORT_SYMBOL_GPL(nfs_file_mmap);
 * nfs_file_write() that a write error occurred, and hence cause it to
 * nfs_file_write() that a write error occurred, and hence cause it to
 * fall back to doing a synchronous write.
 * fall back to doing a synchronous write.
 */
 */
int
static int
nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
{
{
	struct nfs_open_context *ctx = nfs_file_open_context(file);
	struct nfs_open_context *ctx = nfs_file_open_context(file);
@@ -263,9 +263,8 @@ nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
out:
out:
	return ret;
	return ret;
}
}
EXPORT_SYMBOL_GPL(nfs_file_fsync_commit);


static int
int
nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
{
	int ret;
	int ret;
@@ -273,13 +272,15 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)


	trace_nfs_fsync_enter(inode);
	trace_nfs_fsync_enter(inode);


	nfs_inode_dio_wait(inode);
	inode_dio_wait(inode);
	do {
	do {
		ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
		ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
		if (ret != 0)
		if (ret != 0)
			break;
			break;
		inode_lock(inode);
		inode_lock(inode);
		ret = nfs_file_fsync_commit(file, start, end, datasync);
		ret = nfs_file_fsync_commit(file, start, end, datasync);
		if (!ret)
			ret = pnfs_sync_inode(inode, !!datasync);
		inode_unlock(inode);
		inode_unlock(inode);
		/*
		/*
		 * If nfs_file_fsync_commit detected a server reboot, then
		 * If nfs_file_fsync_commit detected a server reboot, then
@@ -293,6 +294,7 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
	trace_nfs_fsync_exit(inode, ret);
	trace_nfs_fsync_exit(inode, ret);
	return ret;
	return ret;
}
}
EXPORT_SYMBOL_GPL(nfs_file_fsync);


/*
/*
 * Decide whether a read/modify/write cycle may be more efficient
 * Decide whether a read/modify/write cycle may be more efficient
@@ -368,7 +370,7 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
	/*
	/*
	 * Wait for O_DIRECT to complete
	 * Wait for O_DIRECT to complete
	 */
	 */
	nfs_inode_dio_wait(mapping->host);
	inode_dio_wait(mapping->host);


	page = grab_cache_page_write_begin(mapping, index, flags);
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
	if (!page)
Loading