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

Commit 53a01c9a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'nfs-for-4.19-1' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client updates from Anna Schumaker:
 "These patches include adding async support for the v4.2 COPY
  operation. I think Bruce is planning to send the server patches for
  the next release, but I figured we could get the client side out of
  the way now since it's been in my tree for a while. This shouldn't
  cause any problems, since the server will still respond with
  synchronous copies even if the client requests async.

  Features:
   - Add support for asynchronous server-side COPY operations

  Stable bufixes:
   - Fix an off-by-one in bl_map_stripe() (v3.17+)
   - NFSv4 client live hangs after live data migration recovery (v4.9+)
   - xprtrdma: Fix disconnect regression (v4.18+)
   - Fix locking in pnfs_generic_recover_commit_reqs (v4.14+)
   - Fix a sleep in atomic context in nfs4_callback_sequence() (v4.9+)

  Other bugfixes and cleanups:
   - Optimizations and fixes involving NFS v4.1 / pNFS layout handling
   - Optimize lseek(fd, SEEK_CUR, 0) on directories to avoid locking
   - Immediately reschedule writeback when the server replies with an
     error
   - Fix excessive attribute revalidation in nfs_execute_ok()
   - Add error checking to nfs_idmap_prepare_message()
   - Use new vm_fault_t return type
   - Return a delegation when reclaiming one that the server has
     recalled
   - Referrals should inherit proto setting from parents
   - Make rpc_auth_create_args a const
   - Improvements to rpc_iostats tracking
   - Fix a potential reference leak when there is an error processing a
     callback
   - Fix rmdir / mkdir / rename nlink accounting
   - Fix updating inode change attribute
   - Fix error handling in nfsn4_sp4_select_mode()
   - Use an appropriate work queue for direct-write completion
   - Don't busy wait if NFSv4 session draining is interrupted"

* tag 'nfs-for-4.19-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (54 commits)
  pNFS: Remove unwanted optimisation of layoutget
  pNFS/flexfiles: ff_layout_pg_init_read should exit on error
  pNFS: Treat RECALLCONFLICT like DELAY...
  pNFS: When updating the stateid in layoutreturn, also update the recall range
  NFSv4: Fix a sleep in atomic context in nfs4_callback_sequence()
  NFSv4: Fix locking in pnfs_generic_recover_commit_reqs
  NFSv4: Fix a typo in nfs4_init_channel_attrs()
  NFSv4: Don't busy wait if NFSv4 session draining is interrupted
  NFS recover from destination server reboot for copies
  NFS add a simple sync nfs4_proc_commit after async COPY
  NFS handle COPY ERR_OFFLOAD_NO_REQS
  NFS send OFFLOAD_CANCEL when COPY killed
  NFS export nfs4_async_handle_error
  NFS handle COPY reply CB_OFFLOAD call race
  NFS add support for asynchronous COPY
  NFS COPY xdr handle async reply
  NFS OFFLOAD_CANCEL xdr
  NFS CB_OFFLOAD xdr
  NFS: Use an appropriate work queue for direct-write completion
  NFSv4: Fix error handling in nfs4_sp4_select_mode()
  ...
parents 9157141c 0af4c8be
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -753,6 +753,7 @@ bl_alloc_lseg(struct pnfs_layout_hdr *lo, struct nfs4_layoutget_res *lgr,
	case -ENODEV:
		/* Our extent block devices are unavailable */
		set_bit(NFS_LSEG_UNAVAILABLE, &lseg->pls_flags);
		/* Fall through */
	case 0:
		return lseg;
	default:
+1 −1
Original line number Diff line number Diff line
@@ -204,7 +204,7 @@ static bool bl_map_stripe(struct pnfs_block_dev *dev, u64 offset,
	chunk = div_u64(offset, dev->chunk_size);
	div_u64_rem(chunk, dev->nr_children, &chunk_idx);

	if (chunk_idx > dev->nr_children) {
	if (chunk_idx >= dev->nr_children) {
		dprintk("%s: invalid chunk idx %d (%lld/%lld)\n",
			__func__, chunk_idx, offset, dev->chunk_size);
		/* error, should not happen */
+12 −0
Original line number Diff line number Diff line
@@ -184,6 +184,18 @@ struct cb_notify_lock_args {
extern __be32 nfs4_callback_notify_lock(void *argp, void *resp,
					 struct cb_process_state *cps);
#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2
struct cb_offloadargs {
	struct nfs_fh		coa_fh;
	nfs4_stateid		coa_stateid;
	uint32_t		error;
	uint64_t		wr_count;
	struct nfs_writeverf	wr_writeverf;
};

extern __be32 nfs4_callback_offload(void *args, void *dummy,
				    struct cb_process_state *cps);
#endif /* CONFIG_NFS_V4_2 */
extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
extern __be32 nfs4_callback_getattr(void *argp, void *resp,
				    struct cb_process_state *cps);
+79 −18
Original line number Diff line number Diff line
@@ -215,9 +215,9 @@ static u32 pnfs_check_callback_stateid(struct pnfs_layout_hdr *lo,
{
	u32 oldseq, newseq;

	/* Is the stateid still not initialised? */
	/* Is the stateid not initialised? */
	if (!pnfs_layout_is_valid(lo))
		return NFS4ERR_DELAY;
		return NFS4ERR_NOMATCHING_LAYOUT;

	/* Mismatched stateid? */
	if (!nfs4_stateid_match_other(&lo->plh_stateid, new))
@@ -273,7 +273,6 @@ static u32 initiate_file_draining(struct nfs_client *clp,
	rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid);
	if (rv != NFS_OK)
		goto unlock;
	pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);

	/*
	 * Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return)
@@ -283,13 +282,16 @@ static u32 initiate_file_draining(struct nfs_client *clp,
		goto unlock;
	}

	if (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
	pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
	switch (pnfs_mark_matching_lsegs_return(lo, &free_me_list,
				&args->cbl_range,
				be32_to_cpu(args->cbl_stateid.seqid))) {
	case 0:
	case -EBUSY:
		/* There are layout segments that need to be returned */
		rv = NFS4_OK;
		goto unlock;
	}

		break;
	case -ENOENT:
		/* Embrace your forgetfulness! */
		rv = NFS4ERR_NOMATCHING_LAYOUT;

@@ -297,6 +299,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
			NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
				&args->cbl_range);
		}
	}
unlock:
	spin_unlock(&ino->i_lock);
	pnfs_free_lseg_list(&free_me_list);
@@ -328,8 +331,6 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
static u32 do_callback_layoutrecall(struct nfs_client *clp,
				    struct cb_layoutrecallargs *args)
{
	write_seqcount_begin(&clp->cl_callback_count);
	write_seqcount_end(&clp->cl_callback_count);
	if (args->cbl_recall_type == RETURN_FILE)
		return initiate_file_draining(clp, args);
	return initiate_bulk_draining(clp, args);
@@ -441,11 +442,14 @@ validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot,
 * a match.  If the slot is in use and the sequence numbers match, the
 * client is still waiting for a response to the original request.
 */
static bool referring_call_exists(struct nfs_client *clp,
static int referring_call_exists(struct nfs_client *clp,
				  uint32_t nrclists,
				  struct referring_call_list *rclists)
				  struct referring_call_list *rclists,
				  spinlock_t *lock)
	__releases(lock)
	__acquires(lock)
{
	bool status = false;
	int status = 0;
	int i, j;
	struct nfs4_session *session;
	struct nfs4_slot_table *tbl;
@@ -468,8 +472,10 @@ static bool referring_call_exists(struct nfs_client *clp,

		for (j = 0; j < rclist->rcl_nrefcalls; j++) {
			ref = &rclist->rcl_refcalls[j];
			spin_unlock(lock);
			status = nfs4_slot_wait_on_seqid(tbl, ref->rc_slotid,
					ref->rc_sequenceid, HZ >> 1) < 0;
			spin_lock(lock);
			if (status)
				goto out;
		}
@@ -546,7 +552,8 @@ __be32 nfs4_callback_sequence(void *argp, void *resp,
	 * related callback was received before the response to the original
	 * call.
	 */
	if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) {
	if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists,
				&tbl->slot_tbl_lock) < 0) {
		status = htonl(NFS4ERR_DELAY);
		goto out_unlock;
	}
@@ -660,3 +667,57 @@ __be32 nfs4_callback_notify_lock(void *argp, void *resp,
	return htonl(NFS4_OK);
}
#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2
static void nfs4_copy_cb_args(struct nfs4_copy_state *cp_state,
				struct cb_offloadargs *args)
{
	cp_state->count = args->wr_count;
	cp_state->error = args->error;
	if (!args->error) {
		cp_state->verf.committed = args->wr_writeverf.committed;
		memcpy(&cp_state->verf.verifier.data[0],
			&args->wr_writeverf.verifier.data[0],
			NFS4_VERIFIER_SIZE);
	}
}

__be32 nfs4_callback_offload(void *data, void *dummy,
			     struct cb_process_state *cps)
{
	struct cb_offloadargs *args = data;
	struct nfs_server *server;
	struct nfs4_copy_state *copy;
	bool found = false;

	spin_lock(&cps->clp->cl_lock);
	rcu_read_lock();
	list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
				client_link) {
		list_for_each_entry(copy, &server->ss_copies, copies) {
			if (memcmp(args->coa_stateid.other,
					copy->stateid.other,
					sizeof(args->coa_stateid.other)))
				continue;
			nfs4_copy_cb_args(copy, args);
			complete(&copy->completion);
			found = true;
			goto out;
		}
	}
out:
	rcu_read_unlock();
	if (!found) {
		copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
		if (!copy) {
			spin_unlock(&cps->clp->cl_lock);
			return htonl(NFS4ERR_SERVERFAULT);
		}
		memcpy(&copy->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
		nfs4_copy_cb_args(copy, args);
		list_add_tail(&copy->copies, &cps->clp->pending_cb_stateids);
	}
	spin_unlock(&cps->clp->cl_lock);

	return 0;
}
#endif /* CONFIG_NFS_V4_2 */
+87 −4
Original line number Diff line number Diff line
@@ -38,6 +38,9 @@
#define CB_OP_RECALLSLOT_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
#define CB_OP_NOTIFY_LOCK_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2
#define CB_OP_OFFLOAD_RES_MAXSZ		(CB_OP_HDR_RES_MAXSZ)
#endif /* CONFIG_NFS_V4_2 */

#define NFSDBG_FACILITY NFSDBG_CALLBACK

@@ -527,7 +530,72 @@ static __be32 decode_notify_lock_args(struct svc_rqst *rqstp,
}

#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2
static __be32 decode_write_response(struct xdr_stream *xdr,
					struct cb_offloadargs *args)
{
	__be32 *p;

	/* skip the always zero field */
	p = read_buf(xdr, 4);
	if (unlikely(!p))
		goto out;
	p++;

	/* decode count, stable_how, verifier */
	p = xdr_inline_decode(xdr, 8 + 4);
	if (unlikely(!p))
		goto out;
	p = xdr_decode_hyper(p, &args->wr_count);
	args->wr_writeverf.committed = be32_to_cpup(p);
	p = xdr_inline_decode(xdr, NFS4_VERIFIER_SIZE);
	if (likely(p)) {
		memcpy(&args->wr_writeverf.verifier.data[0], p,
			NFS4_VERIFIER_SIZE);
		return 0;
	}
out:
	return htonl(NFS4ERR_RESOURCE);
}

static __be32 decode_offload_args(struct svc_rqst *rqstp,
					struct xdr_stream *xdr,
					void *data)
{
	struct cb_offloadargs *args = data;
	__be32 *p;
	__be32 status;

	/* decode fh */
	status = decode_fh(xdr, &args->coa_fh);
	if (unlikely(status != 0))
		return status;

	/* decode stateid */
	status = decode_stateid(xdr, &args->coa_stateid);
	if (unlikely(status != 0))
		return status;

	/* decode status */
	p = read_buf(xdr, 4);
	if (unlikely(!p))
		goto out;
	args->error = ntohl(*p++);
	if (!args->error) {
		status = decode_write_response(xdr, args);
		if (unlikely(status != 0))
			return status;
	} else {
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out;
		p = xdr_decode_hyper(p, &args->wr_count);
	}
	return 0;
out:
	return htonl(NFS4ERR_RESOURCE);
}
#endif /* CONFIG_NFS_V4_2 */
static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
	if (unlikely(xdr_stream_encode_opaque(xdr, str, len) < 0))
@@ -773,7 +841,10 @@ preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op)
	if (status != htonl(NFS4ERR_OP_ILLEGAL))
		return status;

	if (op_nr == OP_CB_OFFLOAD)
	if (op_nr == OP_CB_OFFLOAD) {
		*op = &callback_ops[op_nr];
		return htonl(NFS_OK);
	} else
		return htonl(NFS4ERR_NOTSUPP);
	return htonl(NFS4ERR_OP_ILLEGAL);
}
@@ -883,16 +954,21 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)

	if (hdr_arg.minorversion == 0) {
		cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident);
		if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
		if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) {
			if (cps.clp)
				nfs_put_client(cps.clp);
			goto out_invalidcred;
		}
	}

	cps.minorversion = hdr_arg.minorversion;
	hdr_res.taglen = hdr_arg.taglen;
	hdr_res.tag = hdr_arg.tag;
	if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
	if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) {
		if (cps.clp)
			nfs_put_client(cps.clp);
		return rpc_system_err;

	}
	while (status == 0 && nops != hdr_arg.nops) {
		status = process_op(nops, rqstp, &xdr_in,
				    rqstp->rq_argp, &xdr_out, rqstp->rq_resp,
@@ -969,6 +1045,13 @@ static struct callback_op callback_ops[] = {
		.res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ,
	},
#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2
	[OP_CB_OFFLOAD] = {
		.process_op = nfs4_callback_offload,
		.decode_args = decode_offload_args,
		.res_maxsize = CB_OP_OFFLOAD_RES_MAXSZ,
	},
#endif /* CONFIG_NFS_V4_2 */
};

/*
Loading