static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
{
	struct nfs4_sequence_data *calldata = data;
	struct nfs_client *clp = calldata->clp;

	if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
		return;

	trace_nfs4_sequence(clp, task->tk_status);
	if (task->tk_status < 0) {
		dprintk("%s ERROR %d\n", __func__, task->tk_status);
		if (refcount_read(&clp->cl_count) == 1)
			goto out;

		if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) {
			rpc_restart_call_prepare(task);
			return;
		}
	}
	dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
out:
	dprintk("<-- %s\n", __func__);
}


nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
		    struct nfs_fsinfo *info)
{
	int err;
	struct page *page;
	rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
	struct nfs4_secinfo_flavors *flavors;
	struct nfs4_secinfo4 *secinfo;
	int i;

	page = alloc_page(GFP_KERNEL);
	if (!page) {
		err = -ENOMEM;
		goto out;
	}

	flavors = page_address(page);
	err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);

	/*
	 * Fall back on "guess and check" method if
	 * the server doesn't support SECINFO_NO_NAME
	 */
	if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
		err = nfs4_find_root_sec(server, fhandle, info);
		goto out_freepage;
	}
	if (err)
		goto out_freepage;

	for (i = 0; i < flavors->num_flavors; i++) {
		secinfo = &flavors->flavors[i];

		switch (secinfo->flavor) {
		case RPC_AUTH_NULL:
		case RPC_AUTH_UNIX:
		case RPC_AUTH_GSS:
			flavor = rpcauth_get_pseudoflavor(secinfo->flavor,
					&secinfo->flavor_info);
			break;
		default:
			flavor = RPC_AUTH_MAXFLAVOR;
			break;
		}

		if (!nfs_auth_info_match(&server->auth_info, flavor))
			flavor = RPC_AUTH_MAXFLAVOR;

		if (flavor != RPC_AUTH_MAXFLAVOR) {
			err = nfs4_lookup_root_sec(server, fhandle,
						   info, flavor);
			if (!err)
				break;
		}
	}

	if (flavor == RPC_AUTH_MAXFLAVOR)
		err = -EPERM;

out_freepage:
	put_page(page);
	if (err == -EACCES)
		return -EPERM;
out:
	return err;
}

nfs: Fix getxattr kernel panic and memory overflow

Move the buffer size check to decode_attr_security_label() before memcpy()
Only call memcpy() if the buffer is large enough

Fixes: aa9c2669626c ("NFS: Client implementation of Labeled-NFS")
Signed-off-by: Jeffrey Mitchell <jeffrey.mitchell@starlab.io>
[Trond: clean up duplicate test of label->len != 0]
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>


static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
{
	struct nfs_release_lockowner_data *data = calldata;
	struct nfs_server *server = data->server;

	nfs40_sequence_done(task, &data->res.seq_res);

	switch (task->tk_status) {
	case 0:
		renew_lease(server, data->timestamp);
		break;
	case -NFS4ERR_STALE_CLIENTID:
	case -NFS4ERR_EXPIRED:
		nfs4_schedule_lease_recovery(server->nfs_client);
		break;
	case -NFS4ERR_LEASE_MOVED:
	case -NFS4ERR_DELAY:
		if (nfs4_async_handle_error(task, server,
					    NULL, NULL) == -EAGAIN)
			rpc_restart_call_prepare(task);
	}
}


static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
{
	struct nfs4_exception exception = {
		.interruptible = true,
	};
	int err;
	do {
		err = nfs4_handle_exception(server,
				_nfs4_proc_statfs(server, fhandle, fsstat),
				&exception);
	} while (exception.retry);
	return err;
}


static void nfs4_setclientid_done(struct rpc_task *task, void *calldata)
{
	struct nfs4_setclientid *sc = calldata;

	if (task->tk_status == 0)
		sc->sc_cred = get_rpccred(task->tk_rqstp->rq_cred);
}


static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
		struct nfs_fsinfo *fsinfo)
{
	struct nfs4_fsinfo_arg args = {
		.fh = fhandle,
		.bitmask = server->attr_bitmask,
	};
	struct nfs4_fsinfo_res res = {
		.fsinfo = fsinfo,
	};
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
		.rpc_argp = &args,
		.rpc_resp = &res,
	};

	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
}


static int nfs4_xdr_dec_free_stateid(struct rpc_rqst *rqstp,
				     struct xdr_stream *xdr,
				     void *data)
{
	struct nfs41_free_stateid_res *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_free_stateid(xdr, res);
out:
	return status;
}


static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
{
	nfs41_release_slot(res->sr_slot);
	res->sr_slot = NULL;
}


static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
				       struct xdr_stream *xdr,
				       void *data)
{
	struct nfs_closeres *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	if (res->lr_res) {
		status = decode_layoutreturn(xdr, res->lr_res);
		res->lr_ret = status;
		if (status)
			goto out;
	}
	status = decode_open_downgrade(xdr, res);
out:
	return status;
}


static void nfs4_proc_rename_setup(struct rpc_message *msg,
		struct dentry *old_dentry,
		struct dentry *new_dentry)
{
	struct nfs_renameargs *arg = msg->rpc_argp;
	struct nfs_renameres *res = msg->rpc_resp;
	struct inode *old_inode = d_inode(old_dentry);
	struct inode *new_inode = d_inode(new_dentry);

	if (old_inode)
		nfs4_inode_make_writeable(old_inode);
	if (new_inode)
		nfs4_inode_return_delegation(new_inode);
	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
	res->server = NFS_SB(old_dentry->d_sb);
	nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1, 0);
}


static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode)
{
	struct nfs_delegation *delegation;

	fmode &= FMODE_READ|FMODE_WRITE;
	rcu_read_lock();
	delegation = nfs4_get_valid_delegation(inode);
	if (delegation == NULL || (delegation->type & fmode) == fmode) {
		rcu_read_unlock();
		return;
	}
	rcu_read_unlock();
	nfs4_inode_return_delegation(inode);
}


int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
{
	struct nfs4_exception exception = {
		.interruptible = true,
	};
	int err;
	do {
		err = nfs4_handle_exception(server,
				_nfs4_server_capabilities(server, fhandle),
				&exception);
	} while (exception.retry);
	return err;
}


static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
{
	__be32 *p;

	encode_op_hdr(xdr, OP_LOCKT, decode_lockt_maxsz, hdr);
	p = reserve_space(xdr, 20);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
	encode_lockowner(xdr, &args->lock_owner);
}


static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{
	int error;

	nfs_fattr_init(fsinfo->fattr);
	error = nfs4_do_fsinfo(server, fhandle, fsinfo);
	if (error == 0) {
		/* block layout checks this! */
		server->pnfs_blksize = fsinfo->blksize;
		set_pnfs_layoutdriver(server, fhandle, fsinfo);
	}

	return error;
}


static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
{

	dprintk("--> %s\n", __func__);

	if (!nfs4_sequence_done(task, &hdr->res.seq_res))
		return -EAGAIN;
	if (nfs4_read_stateid_changed(task, &hdr->args))
		return -EAGAIN;
	if (task->tk_status > 0)
		nfs_invalidate_atime(hdr->inode);
	return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) :
				    nfs4_read_done_cb(task, hdr);
}


static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{
	struct nfs4_exception exception = {
		.state = state,
		.inode = state->inode,
		.interruptible = true,
	};
	int err;

	do {
		err = _nfs4_proc_setlk(state, cmd, request);
		if (err == -NFS4ERR_DENIED)
			err = -EAGAIN;
		err = nfs4_handle_exception(NFS_SERVER(state->inode),
				err, &exception);
	} while (exception.retry);
	return err;
}


nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
{ return server->attr_bitmask; }


int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
		struct nfs4_state *state, const nfs4_stateid *stateid)
{
	struct nfs_server *server = NFS_SERVER(state->inode);
	struct nfs4_opendata *opendata;
	int err = 0;

	opendata = nfs4_open_recoverdata_alloc(ctx, state,
			NFS4_OPEN_CLAIM_DELEG_CUR_FH);
	if (IS_ERR(opendata))
		return PTR_ERR(opendata);
	nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
	if (!test_bit(NFS_O_RDWR_STATE, &state->flags)) {
		err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
		if (err)
			goto out;
	}
	if (!test_bit(NFS_O_WRONLY_STATE, &state->flags)) {
		err = nfs4_open_recover_helper(opendata, FMODE_WRITE);
		if (err)
			goto out;
	}
	if (!test_bit(NFS_O_RDONLY_STATE, &state->flags)) {
		err = nfs4_open_recover_helper(opendata, FMODE_READ);
		if (err)
			goto out;
	}
	nfs_state_clear_delegation(state);
out:
	nfs4_opendata_put(opendata);
	return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err);
}


static void nfs4_open_done(struct rpc_task *task, void *calldata)
{
	struct nfs4_opendata *data = calldata;

	data->rpc_status = task->tk_status;

	if (!nfs4_sequence_process(task, &data->o_res.seq_res))
		return;

	if (task->tk_status == 0) {
		if (data->o_res.f_attr->valid & NFS_ATTR_FATTR_TYPE) {
			switch (data->o_res.f_attr->mode & S_IFMT) {
			case S_IFREG:
				break;
			case S_IFLNK:
				data->rpc_status = -ELOOP;
				break;
			case S_IFDIR:
				data->rpc_status = -EISDIR;
				break;
			default:
				data->rpc_status = -ENOTDIR;
			}
		}
		renew_lease(data->o_res.server, data->timestamp);
		if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
			nfs_confirm_seqid(&data->owner->so_seqid, 0);
	}
	data->rpc_done = true;
}


static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
{
	if (res->sr_slot != NULL) {
		if (res->sr_slot->table->session != NULL)
			nfs41_sequence_free_slot(res);
		else
			nfs40_sequence_free_slot(res);
	}
}


static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_message *msg,
				   struct rpc_clnt **clnt)
{
	struct nfs_server *server = NFS_SERVER(data->inode);

	if (data->commit_done_cb == NULL)
		data->commit_done_cb = nfs4_commit_done_cb;
	data->res.server = server;
	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
	nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, 0);
	nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_COMMIT, clnt, msg);
}


static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, unsigned int *savep)
{
	__be32 *p;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;
	*attrlen = be32_to_cpup(p);
	*savep = xdr_stream_pos(xdr);
	return 0;
}


static int nfs4_do_handle_exception(struct nfs_server *server,
		int errorcode, struct nfs4_exception *exception)
{
	struct nfs_client *clp = server->nfs_client;
	struct nfs4_state *state = exception->state;
	const nfs4_stateid *stateid;
	struct inode *inode = exception->inode;
	int ret = errorcode;

	exception->delay = 0;
	exception->recovering = 0;
	exception->retry = 0;

	stateid = nfs4_recoverable_stateid(exception->stateid);
	if (stateid == NULL && state != NULL)
		stateid = nfs4_recoverable_stateid(&state->stateid);

	switch(errorcode) {
		case 0:
			return 0;
		case -NFS4ERR_BADHANDLE:
		case -ESTALE:
			if (inode != NULL && S_ISREG(inode->i_mode))
				pnfs_destroy_layout(NFS_I(inode));
			break;
		case -NFS4ERR_DELEG_REVOKED:
		case -NFS4ERR_ADMIN_REVOKED:
		case -NFS4ERR_EXPIRED:
		case -NFS4ERR_BAD_STATEID:
		case -NFS4ERR_PARTNER_NO_AUTH:
			if (inode != NULL && stateid != NULL) {
				nfs_inode_find_state_and_recover(inode,
						stateid);
				goto wait_on_recovery;
			}
			/* Fall through */
		case -NFS4ERR_OPENMODE:
			if (inode) {
				int err;

				err = nfs_async_inode_return_delegation(inode,
						stateid);
				if (err == 0)
					goto wait_on_recovery;
				if (stateid != NULL && stateid->type == NFS4_DELEGATION_STATEID_TYPE) {
					exception->retry = 1;
					break;
				}
			}
			if (state == NULL)
				break;
			ret = nfs4_schedule_stateid_recovery(server, state);
			if (ret < 0)
				break;
			goto wait_on_recovery;
		case -NFS4ERR_STALE_STATEID:
		case -NFS4ERR_STALE_CLIENTID:
			nfs4_schedule_lease_recovery(clp);
			goto wait_on_recovery;
		case -NFS4ERR_MOVED:
			ret = nfs4_schedule_migration_recovery(server);
			if (ret < 0)
				break;
			goto wait_on_recovery;
		case -NFS4ERR_LEASE_MOVED:
			nfs4_schedule_lease_moved_recovery(clp);
			goto wait_on_recovery;
#if defined(CONFIG_NFS_V4_1)
		case -NFS4ERR_BADSESSION:
		case -NFS4ERR_BADSLOT:
		case -NFS4ERR_BAD_HIGH_SLOT:
		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
		case -NFS4ERR_DEADSESSION:
		case -NFS4ERR_SEQ_FALSE_RETRY:
		case -NFS4ERR_SEQ_MISORDERED:
			/* Handled in nfs41_sequence_process() */
			goto wait_on_recovery;
#endif /* defined(CONFIG_NFS_V4_1) */
		case -NFS4ERR_FILE_OPEN:
			if (exception->timeout > HZ) {
				/* We have retried a decent amount, time to
				 * fail
				 */
				ret = -EBUSY;
				break;
			}
			/* Fall through */
		case -NFS4ERR_DELAY:
			nfs_inc_server_stats(server, NFSIOS_DELAY);
			/* Fall through */
		case -NFS4ERR_GRACE:
		case -NFS4ERR_LAYOUTTRYLATER:
		case -NFS4ERR_RECALLCONFLICT:
			exception->delay = 1;
			return 0;

		case -NFS4ERR_RETRY_UNCACHED_REP:
		case -NFS4ERR_OLD_STATEID:
			exception->retry = 1;
			break;
		case -NFS4ERR_BADOWNER:
			/* The following works around a Linux server bug! */
		case -NFS4ERR_BADNAME:
			if (server->caps & NFS_CAP_UIDGID_NOMAP) {
				server->caps &= ~NFS_CAP_UIDGID_NOMAP;
				exception->retry = 1;
				printk(KERN_WARNING "NFS: v4 server %s "
						"does not accept raw "
						"uid/gids. "
						"Reenabling the idmapper.\n",
						server->nfs_client->cl_hostname);
			}
	}
	/* We failed to handle the error */
	return nfs4_map_errors(ret);
wait_on_recovery:
	exception->recovering = 1;
	return 0;
}


static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
					  struct xdr_stream *xdr,
					  const void *data)
{
	const struct nfs41_reclaim_complete_args *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args)
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_reclaim_complete(xdr, args, &hdr);
	encode_nops(&hdr);
}


int nfs4_sequence_done(struct rpc_task *task,
		       struct nfs4_sequence_res *res)
{
	return nfs40_sequence_done(task, res);
}


static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
			      struct nfs_fsinfo *info)
{
	int error;
	struct nfs_fattr *fattr = info->fattr;
	struct nfs4_label *label = fattr->label;

	error = nfs4_server_capabilities(server, mntfh);
	if (error < 0) {
		dprintk("nfs4_get_root: getcaps error = %d\n", -error);
		return error;
	}

	error = nfs4_proc_getattr(server, mntfh, fattr, label, NULL);
	if (error < 0) {
		dprintk("nfs4_get_root: getattr error = %d\n", -error);
		goto out;
	}

	if (fattr->valid & NFS_ATTR_FATTR_FSID &&
	    !nfs_fsid_equal(&server->fsid, &fattr->fsid))
		memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));

out:
	return error;
}


static int _nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
		u64 cookie, struct page **pages, unsigned int count, bool plus)
{
	struct inode		*dir = d_inode(dentry);
	struct nfs4_readdir_arg args = {
		.fh = NFS_FH(dir),
		.pages = pages,
		.pgbase = 0,
		.count = count,
		.bitmask = NFS_SERVER(d_inode(dentry))->attr_bitmask,
		.plus = plus,
	};
	struct nfs4_readdir_res res;
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
		.rpc_argp = &args,
		.rpc_resp = &res,
		.rpc_cred = cred,
	};
	int			status;

	dprintk("%s: dentry = %pd2, cookie = %Lu\n", __func__,
			dentry,
			(unsigned long long)cookie);
	nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);
	res.pgbase = args.pgbase;
	status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
	if (status >= 0) {
		memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);
		status += args.pgbase;
	}

	nfs_invalidate_atime(dir);

	dprintk("%s: returns %d\n", __func__, status);
	return status;
}


static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors, bool use_integrity)
{
	int status;
	struct rpc_clnt *clnt = NFS_SERVER(dir)->client;
	struct nfs_client *clp = NFS_SERVER(dir)->nfs_client;
	struct nfs4_secinfo_arg args = {
		.dir_fh = NFS_FH(dir),
		.name   = name,
	};
	struct nfs4_secinfo_res res = {
		.flavors     = flavors,
	};
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO],
		.rpc_argp = &args,
		.rpc_resp = &res,
	};
	struct nfs4_call_sync_data data = {
		.seq_server = NFS_SERVER(dir),
		.seq_args = &args.seq_args,
		.seq_res = &res.seq_res,
	};
	struct rpc_task_setup task_setup = {
		.rpc_client = clnt,
		.rpc_message = &msg,
		.callback_ops = clp->cl_mvops->call_sync_ops,
		.callback_data = &data,
		.flags = RPC_TASK_NO_ROUND_ROBIN,
	};
	const struct cred *cred = NULL;

	if (use_integrity) {
		clnt = clp->cl_rpcclient;
		task_setup.rpc_client = clnt;

		cred = nfs4_get_clid_cred(clp);
		msg.rpc_cred = cred;
	}

	dprintk("NFS call  secinfo %s\n", name->name);

	nfs4_state_protect(clp, NFS_SP4_MACH_CRED_SECINFO, &clnt, &msg);
	nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
	status = nfs4_call_sync_custom(&task_setup);

	dprintk("NFS reply  secinfo: %d\n", status);

	put_cred(cred);
	return status;
}


static int _nfs41_proc_get_locations(struct inode *inode,
				     struct nfs4_fs_locations *locations,
				     struct page *page, const struct cred *cred)
{
	struct nfs_server *server = NFS_SERVER(inode);
	struct rpc_clnt *clnt = server->client;
	u32 bitmask[2] = {
		[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
	};
	struct nfs4_fs_locations_arg args = {
		.fh		= NFS_FH(inode),
		.page		= page,
		.bitmask	= bitmask,
		.migration	= 1,		/* skip LOOKUP */
	};
	struct nfs4_fs_locations_res res = {
		.fs_locations	= locations,
		.migration	= 1,
	};
	struct rpc_message msg = {
		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
		.rpc_argp	= &args,
		.rpc_resp	= &res,
		.rpc_cred	= cred,
	};
	int status;

	nfs_fattr_init(&locations->fattr);
	locations->server = server;
	locations->nlocations = 0;

	nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
	status = nfs4_call_sync_sequence(clnt, server, &msg,
					&args.seq_args, &res.seq_res);
	if (status == NFS4_OK &&
	    res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
		status = -NFS4ERR_LEASE_MOVED;
	return status;
}


int nfs4_proc_get_locations(struct inode *inode,
			    struct nfs4_fs_locations *locations,
			    struct page *page, const struct cred *cred)
{
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
	const struct nfs4_mig_recovery_ops *ops =
					clp->cl_mvops->mig_recovery_ops;
	struct nfs4_exception exception = {
		.interruptible = true,
	};
	int status;

	dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
		(unsigned long long)server->fsid.major,
		(unsigned long long)server->fsid.minor,
		clp->cl_hostname);
	nfs_display_fhandle(NFS_FH(inode), __func__);

	do {
		status = ops->get_locations(inode, locations, page, cred);
		if (status != -NFS4ERR_DELAY)
			break;
		nfs4_handle_exception(server, status, &exception);
	} while (exception.retry);
	return status;
}


static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
{
	struct nfs4_sequence_data *calldata = data;
	struct nfs_client *clp = calldata->clp;
	struct nfs4_sequence_args *args;
	struct nfs4_sequence_res *res;

	args = task->tk_msg.rpc_argp;
	res = task->tk_msg.rpc_resp;

	nfs4_setup_sequence(clp, args, res, task);
}


static ssize_t decode_nfs4_string(struct xdr_stream *xdr,
		struct nfs4_string *name, gfp_t gfp_flags)
{
	ssize_t ret;

	ret = xdr_stream_decode_string_dup(xdr, &name->data,
			XDR_MAX_NETOBJ, gfp_flags);
	name->len = 0;
	if (ret > 0)
		name->len = ret;
	return ret;
}


static int nfs4_do_setattr(struct inode *inode, const struct cred *cred,
			   struct nfs_fattr *fattr, struct iattr *sattr,
			   struct nfs_open_context *ctx, struct nfs4_label *ilabel,
			   struct nfs4_label *olabel)
{
	struct nfs_server *server = NFS_SERVER(inode);
	__u32 bitmask[NFS4_BITMASK_SZ];
	struct nfs4_state *state = ctx ? ctx->state : NULL;
	struct nfs_setattrargs	arg = {
		.fh		= NFS_FH(inode),
		.iap		= sattr,
		.server		= server,
		.bitmask = bitmask,
		.label		= ilabel,
	};
	struct nfs_setattrres  res = {
		.fattr		= fattr,
		.label		= olabel,
		.server		= server,
	};
	struct nfs4_exception exception = {
		.state = state,
		.inode = inode,
		.stateid = &arg.stateid,
	};
	int err;

	do {
		nfs4_bitmap_copy_adjust_setattr(bitmask,
				nfs4_bitmask(server, olabel),
				inode);

		err = _nfs4_do_setattr(inode, &arg, &res, cred, ctx);
		switch (err) {
		case -NFS4ERR_OPENMODE:
			if (!(sattr->ia_valid & ATTR_SIZE)) {
				pr_warn_once("NFSv4: server %s is incorrectly "
						"applying open mode checks to "
						"a SETATTR that is not "
						"changing file size.\n",
						server->nfs_client->cl_hostname);
			}
			if (state && !(state->state & FMODE_WRITE)) {
				err = -EBADF;
				if (sattr->ia_valid & ATTR_OPEN)
					err = -EACCES;
				goto out;
			}
		}
		err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);
out:
	return err;
}


nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
{
	return 0;
}


static int decode_create_session(struct xdr_stream *xdr,
				 struct nfs41_create_session_res *res)
{
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_CREATE_SESSION);
	if (!status)
		status = decode_sessionid(xdr, &res->sessionid);
	if (unlikely(status))
		return status;

	/* seqid, flags */
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		return -EIO;
	res->seqid = be32_to_cpup(p++);
	res->flags = be32_to_cpup(p);

	/* Channel attributes */
	status = decode_chan_attrs(xdr, &res->fc_attrs);
	if (!status)
		status = decode_chan_attrs(xdr, &res->bc_attrs);
	return status;
}


static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
	__be32 *p;

	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		return -EIO;
	hdr->status = be32_to_cpup(p++);
	hdr->taglen = be32_to_cpup(p);

	p = xdr_inline_decode(xdr, hdr->taglen + 4);
	if (unlikely(!p))
		return -EIO;
	hdr->tag = (char *)p;
	p += XDR_QUADLEN(hdr->taglen);
	hdr->nops = be32_to_cpup(p);
	if (unlikely(hdr->nops < 1))
		return nfs4_stat_to_errno(hdr->status);
	return 0;
}


static void nfs4_proc_read_setup(struct nfs_pgio_header *hdr,
				 struct rpc_message *msg)
{
	hdr->timestamp   = jiffies;
	if (!hdr->pgio_done_cb)
		hdr->pgio_done_cb = nfs4_read_done_cb;
	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
	nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0, 0);
}


static int nfs4_sp4_select_mode(struct nfs_client *clp,
				 struct nfs41_state_protection *sp)
{
	static const u32 supported_enforce[NFS4_OP_MAP_NUM_WORDS] = {
		[1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
		      1 << (OP_EXCHANGE_ID - 32) |
		      1 << (OP_CREATE_SESSION - 32) |
		      1 << (OP_DESTROY_SESSION - 32) |
		      1 << (OP_DESTROY_CLIENTID - 32)
	};
	unsigned long flags = 0;
	unsigned int i;
	int ret = 0;

	if (sp->how == SP4_MACH_CRED) {
		/* Print state protect result */
		dfprintk(MOUNT, "Server SP4_MACH_CRED support:\n");
		for (i = 0; i <= LAST_NFS4_OP; i++) {
			if (test_bit(i, sp->enforce.u.longs))
				dfprintk(MOUNT, "  enforce op %d\n", i);
			if (test_bit(i, sp->allow.u.longs))
				dfprintk(MOUNT, "  allow op %d\n", i);
		}

		/* make sure nothing is on enforce list that isn't supported */
		for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++) {
			if (sp->enforce.u.words[i] & ~supported_enforce[i]) {
				dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
				ret = -EINVAL;
				goto out;
			}
		}

		/*
		 * Minimal mode - state operations are allowed to use machine
		 * credential.  Note this already happens by default, so the
		 * client doesn't have to do anything more than the negotiation.
		 *
		 * NOTE: we don't care if EXCHANGE_ID is in the list -
		 *       we're already using the machine cred for exchange_id
		 *       and will never use a different cred.
		 */
		if (test_bit(OP_BIND_CONN_TO_SESSION, sp->enforce.u.longs) &&
		    test_bit(OP_CREATE_SESSION, sp->enforce.u.longs) &&
		    test_bit(OP_DESTROY_SESSION, sp->enforce.u.longs) &&
		    test_bit(OP_DESTROY_CLIENTID, sp->enforce.u.longs)) {
			dfprintk(MOUNT, "sp4_mach_cred:\n");
			dfprintk(MOUNT, "  minimal mode enabled\n");
			__set_bit(NFS_SP4_MACH_CRED_MINIMAL, &flags);
		} else {
			dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
			ret = -EINVAL;
			goto out;
		}

		if (test_bit(OP_CLOSE, sp->allow.u.longs) &&
		    test_bit(OP_OPEN_DOWNGRADE, sp->allow.u.longs) &&
		    test_bit(OP_DELEGRETURN, sp->allow.u.longs) &&
		    test_bit(OP_LOCKU, sp->allow.u.longs)) {
			dfprintk(MOUNT, "  cleanup mode enabled\n");
			__set_bit(NFS_SP4_MACH_CRED_CLEANUP, &flags);
		}

		if (test_bit(OP_LAYOUTRETURN, sp->allow.u.longs)) {
			dfprintk(MOUNT, "  pnfs cleanup mode enabled\n");
			__set_bit(NFS_SP4_MACH_CRED_PNFS_CLEANUP, &flags);
		}

		if (test_bit(OP_SECINFO, sp->allow.u.longs) &&
		    test_bit(OP_SECINFO_NO_NAME, sp->allow.u.longs)) {
			dfprintk(MOUNT, "  secinfo mode enabled\n");
			__set_bit(NFS_SP4_MACH_CRED_SECINFO, &flags);
		}

		if (test_bit(OP_TEST_STATEID, sp->allow.u.longs) &&
		    test_bit(OP_FREE_STATEID, sp->allow.u.longs)) {
			dfprintk(MOUNT, "  stateid mode enabled\n");
			__set_bit(NFS_SP4_MACH_CRED_STATEID, &flags);
		}

		if (test_bit(OP_WRITE, sp->allow.u.longs)) {
			dfprintk(MOUNT, "  write mode enabled\n");
			__set_bit(NFS_SP4_MACH_CRED_WRITE, &flags);
		}

		if (test_bit(OP_COMMIT, sp->allow.u.longs)) {
			dfprintk(MOUNT, "  commit mode enabled\n");
			__set_bit(NFS_SP4_MACH_CRED_COMMIT, &flags);
		}
	}
out:
	clp->cl_sp4_flags = flags;
	return ret;
}


static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
{
	struct nfs_server *server = NFS_SERVER(inode);
	struct page *pages[NFS4ACL_MAXPAGES];
	struct nfs_setaclargs arg = {
		.fh		= NFS_FH(inode),
		.acl_pages	= pages,
		.acl_len	= buflen,
	};
	struct nfs_setaclres res;
	struct rpc_message msg = {
		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_SETACL],
		.rpc_argp	= &arg,
		.rpc_resp	= &res,
	};
	unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
	int ret, i;

	if (!nfs4_server_supports_acls(server))
		return -EOPNOTSUPP;
	if (npages > ARRAY_SIZE(pages))
		return -ERANGE;
	i = nfs4_buf_to_pages_noslab(buf, buflen, arg.acl_pages);
	if (i < 0)
		return i;
	nfs4_inode_make_writeable(inode);
	ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);

	/*
	 * Free each page after tx, so the only ref left is
	 * held by the network stack
	 */
	for (; i > 0; i--)
		put_page(pages[i-1]);

	/*
	 * Acl update can result in inode attribute update.
	 * so mark the attribute cache invalid.
	 */
	spin_lock(&inode->i_lock);
	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE
		| NFS_INO_INVALID_CTIME
		| NFS_INO_REVAL_FORCED;
	spin_unlock(&inode->i_lock);
	nfs_access_zap_cache(inode);
	nfs_zap_acl_cache(inode);
	return ret;
}


static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCKU);
	if (status != -EIO)
		nfs_increment_lock_seqid(status, res->seqid);
	if (status == 0)
		status = decode_lock_stateid(xdr, &res->stateid);
	return status;
}


static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp,
				       struct xdr_stream *xdr,
				       void *data)
{
	struct nfs4_get_lease_time_res *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (!status)
		status = decode_sequence(xdr, &res->lr_seq_res, rqstp);
	if (!status)
		status = decode_putrootfh(xdr);
	if (!status)
		status = decode_fsinfo(xdr, res->lr_fsinfo);
	return status;
}


static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp)
{
	switch(task->tk_status) {
	case -NFS4ERR_DELAY:
		rpc_delay(task, NFS4_POLL_RETRY_MAX);
		return -EAGAIN;
	default:
		nfs4_schedule_lease_recovery(clp);
	}
	return 0;
}


static int nfs4_proc_readlink(struct inode *inode, struct page *page,
		unsigned int pgbase, unsigned int pglen)
{
	struct nfs4_exception exception = {
		.interruptible = true,
	};
	int err;
	do {
		err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
		trace_nfs4_readlink(inode, err);
		err = nfs4_handle_exception(NFS_SERVER(inode), err,
				&exception);
	} while (exception.retry);
	return err;
}


int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid)
{
	struct nfs_server *server = NFS_SERVER(state->inode);
	int err;

	err = nfs4_set_lock_state(state, fl);
	if (err != 0)
		return err;
	err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
	return nfs4_handle_delegation_recall_error(server, state, stateid, fl, err);
}


static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      void *data)
{
	struct nfs_lockt_res *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_lockt(xdr, res);
out:
	return status;
}


static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
			    struct nfs4_layoutget_res *res)
{
	__be32 *p;
	int status;
	u32 layout_count;
	u32 recvd;

	status = decode_op_hdr(xdr, OP_LAYOUTGET);
	if (status)
		goto out;
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	res->return_on_close = be32_to_cpup(p);
	decode_layout_stateid(xdr, &res->stateid);
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	layout_count = be32_to_cpup(p);
	if (!layout_count) {
		dprintk("%s: server responded with empty layout array\n",
			__func__);
		status = -EINVAL;
		goto out;
	}

	p = xdr_inline_decode(xdr, 28);
	if (unlikely(!p))
		goto out_overflow;
	p = xdr_decode_hyper(p, &res->range.offset);
	p = xdr_decode_hyper(p, &res->range.length);
	res->range.iomode = be32_to_cpup(p++);
	res->type = be32_to_cpup(p++);
	res->layoutp->len = be32_to_cpup(p);

	dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n",
		__func__,
		(unsigned long)res->range.offset,
		(unsigned long)res->range.length,
		res->range.iomode,
		res->type,
		res->layoutp->len);

	recvd = xdr_read_pages(xdr, res->layoutp->len);
	if (res->layoutp->len > recvd) {
		dprintk("NFS: server cheating in layoutget reply: "
				"layout len %u > recvd %u\n",
				res->layoutp->len, recvd);
		status = -EINVAL;
		goto out;
	}

	if (layout_count > 1) {
		/* We only handle a length one array at the moment.  Any
		 * further entries are just ignored.  Note that this means
		 * the client may see a response that is less than the
		 * minimum it requested.
		 */
		dprintk("%s: server responded with %d layouts, dropping tail\n",
			__func__, layout_count);
	}

out:
	res->status = status;
	return status;
out_overflow:
	status = -EIO;
	goto out;
}


static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
{
	if (res->sr_slot != NULL)
		nfs40_sequence_free_slot(res);
}


static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
{
	int status = 0;

	time->tv_sec = 0;
	time->tv_nsec = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
		status = decode_attr_time(xdr, time);
		if (status == 0)
			status = NFS_ATTR_FATTR_CTIME;
		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
	}
	dprintk("%s: ctime=%lld\n", __func__, time->tv_sec);
	return status;
}


static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
{
	__be32 *p;
	int ret = 0;

	fsid->major = 0;
	fsid->minor = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
		p = xdr_inline_decode(xdr, 16);
		if (unlikely(!p))
			return -EIO;
		p = xdr_decode_hyper(p, &fsid->major);
		xdr_decode_hyper(p, &fsid->minor);
		bitmap[0] &= ~FATTR4_WORD0_FSID;
		ret = NFS_ATTR_FATTR_FSID;
	}
	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
			(unsigned long long)fsid->major,
			(unsigned long long)fsid->minor);
	return ret;
}


static void nfs_state_set_open_stateid(struct nfs4_state *state,
		const nfs4_stateid *open_stateid,
		fmode_t fmode,
		nfs4_stateid *freeme)
{
	/*
	 * Protect the call to nfs4_state_set_mode_locked and
	 * serialise the stateid update
	 */
	write_seqlock(&state->seqlock);
	nfs_set_open_stateid_locked(state, open_stateid, freeme);
	switch (fmode) {
	case FMODE_READ:
		set_bit(NFS_O_RDONLY_STATE, &state->flags);
		break;
	case FMODE_WRITE:
		set_bit(NFS_O_WRONLY_STATE, &state->flags);
		break;
	case FMODE_READ|FMODE_WRITE:
		set_bit(NFS_O_RDWR_STATE, &state->flags);
	}
	set_bit(NFS_OPEN_STATE, &state->flags);
	write_sequnlock(&state->seqlock);
}


static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
{
	struct nfs4_call_sync_data *data = calldata;

	dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);

	nfs4_setup_sequence(data->seq_server->nfs_client,
			    data->seq_args, data->seq_res, task);
}


static int decode_layoutreturn(struct xdr_stream *xdr,
			       struct nfs4_layoutreturn_res *res)
{
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_LAYOUTRETURN);
	if (status)
		return status;
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;
	res->lrs_present = be32_to_cpup(p);
	if (res->lrs_present)
		status = decode_layout_stateid(xdr, &res->stateid);
	else
		nfs4_stateid_copy(&res->stateid, &invalid_stateid);
	return status;
}


static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
	__be32 *p;
	uint32_t len;
	int status;

	/* Zero handle first to allow comparisons */
	memset(fh, 0, sizeof(*fh));

	status = decode_op_hdr(xdr, OP_GETFH);
	if (status)
		return status;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;
	len = be32_to_cpup(p);
	if (len > NFS4_FHSIZE)
		return -EIO;
	fh->size = len;
	p = xdr_inline_decode(xdr, len);
	if (unlikely(!p))
		return -EIO;
	memcpy(fh->data, p, len);
	return 0;
}


static int nfs41_check_expired_locks(struct nfs4_state *state)
{
	int status, ret = NFS_OK;
	struct nfs4_lock_state *lsp, *prev = NULL;
	struct nfs_server *server = NFS_SERVER(state->inode);

	if (!test_bit(LK_STATE_IN_USE, &state->flags))
		goto out;

	spin_lock(&state->state_lock);
	list_for_each_entry(lsp, &state->lock_states, ls_locks) {
		if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
			const struct cred *cred = lsp->ls_state->owner->so_cred;

			refcount_inc(&lsp->ls_count);
			spin_unlock(&state->state_lock);

			nfs4_put_lock_state(prev);
			prev = lsp;

			status = nfs41_test_and_free_expired_stateid(server,
					&lsp->ls_stateid,
					cred);
			trace_nfs4_test_lock_stateid(state, lsp, status);
			if (status == -NFS4ERR_EXPIRED ||
			    status == -NFS4ERR_BAD_STATEID) {
				clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
				lsp->ls_stateid.type = NFS4_INVALID_STATEID_TYPE;
				if (!recover_lost_locks)
					set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
			} else if (status != NFS_OK) {
				ret = status;
				nfs4_put_lock_state(prev);
				goto out;
			}
			spin_lock(&state->state_lock);
		}
	}
	spin_unlock(&state->state_lock);
	nfs4_put_lock_state(prev);
out:
	return ret;
}


static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
				   struct xdr_stream *xdr,
				   const void *data)
{
	const struct nfs4_layoutget_args *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, NFS_FH(args->inode), &hdr);
	encode_layoutget(xdr, args, &hdr);

	rpc_prepare_reply_pages(req, args->layout.pages, 0,
				args->layout.pglen, hdr.replen);
	encode_nops(&hdr);
}


static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
		struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
		struct nfs4_label *label, const struct nfs_server *server)
{
	unsigned int savep;
	uint32_t attrlen,
		 bitmap[3] = {0};
	int status;

	status = decode_op_hdr(xdr, OP_GETATTR);
	if (status < 0)
		goto xdr_error;

	status = decode_attr_bitmap(xdr, bitmap);
	if (status < 0)
		goto xdr_error;

	status = decode_attr_length(xdr, &attrlen, &savep);
	if (status < 0)
		goto xdr_error;

	status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc,
					label, server);
	if (status < 0)
		goto xdr_error;

	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
	dprintk("%s: xdr returned %d\n", __func__, -status);
	return status;
}


nfs4_retry_setlk_simple(struct nfs4_state *state, int cmd,
			struct file_lock *request)
{
	int		status = -ERESTARTSYS;
	unsigned long	timeout = NFS4_LOCK_MINTIMEOUT;

	while(!signalled()) {
		status = nfs4_proc_setlk(state, cmd, request);
		if ((status != -EAGAIN) || IS_SETLK(cmd))
			break;
		freezable_schedule_timeout_interruptible(timeout);
		timeout *= 2;
		timeout = min_t(unsigned long, NFS4_LOCK_MAXTIMEOUT, timeout);
		status = -ERESTARTSYS;
	}
	return status;
}


int update_open_stateid(struct nfs4_state *state,
		const nfs4_stateid *open_stateid,
		const nfs4_stateid *delegation,
		fmode_t fmode)
{
	struct nfs_server *server = NFS_SERVER(state->inode);
	struct nfs_client *clp = server->nfs_client;
	struct nfs_inode *nfsi = NFS_I(state->inode);
	struct nfs_delegation *deleg_cur;
	nfs4_stateid freeme = { };
	int ret = 0;

	fmode &= (FMODE_READ|FMODE_WRITE);

	rcu_read_lock();
	spin_lock(&state->owner->so_lock);
	if (open_stateid != NULL) {
		nfs_state_set_open_stateid(state, open_stateid, fmode, &freeme);
		ret = 1;
	}

	deleg_cur = nfs4_get_valid_delegation(state->inode);
	if (deleg_cur == NULL)
		goto no_delegation;

	spin_lock(&deleg_cur->lock);
	if (rcu_dereference(nfsi->delegation) != deleg_cur ||
	   test_bit(NFS_DELEGATION_RETURNING, &deleg_cur->flags) ||
	    (deleg_cur->type & fmode) != fmode)
		goto no_delegation_unlock;

	if (delegation == NULL)
		delegation = &deleg_cur->stateid;
	else if (!nfs4_stateid_match_other(&deleg_cur->stateid, delegation))
		goto no_delegation_unlock;

	nfs_mark_delegation_referenced(deleg_cur);
	nfs_state_set_delegation(state, &deleg_cur->stateid, fmode);
	ret = 1;
no_delegation_unlock:
	spin_unlock(&deleg_cur->lock);
no_delegation:
	if (ret)
		update_open_stateflags(state, fmode);
	spin_unlock(&state->owner->so_lock);
	rcu_read_unlock();

	if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
		nfs4_schedule_state_manager(clp);
	if (freeme.type != 0)
		nfs4_test_and_free_stateid(server, &freeme,
				state->owner->so_cred);

	return ret;
}


static fmode_t _nfs4_ctx_to_accessmode(const struct nfs_open_context *ctx)
{
	 return ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
}


static inline int nfs4_lock_type(struct file_lock *fl, int block)
{
	if (fl->fl_type == F_RDLCK)
		return block ? NFS4_READW_LT : NFS4_READ_LT;
	return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
}


static void nfs4_xdr_enc_lookupp(struct rpc_rqst *req, struct xdr_stream *xdr,
		const void *data)
{
	const struct nfs4_lookupp_arg *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_lookupp(xdr, &hdr);
	encode_getfh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
	encode_nops(&hdr);
}


static void nfs4_xdr_enc_access(struct rpc_rqst *req, struct xdr_stream *xdr,
				const void *data)
{
	const struct nfs4_accessargs *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_access(xdr, args->access, &hdr);
	if (args->bitmask)
		encode_getfattr(xdr, args->bitmask, &hdr);
	encode_nops(&hdr);
}


static void nfs4_locku_prepare(struct rpc_task *task, void *data)
{
	struct nfs4_unlockdata *calldata = data;

	if (test_bit(NFS_CONTEXT_UNLOCK, &calldata->l_ctx->open_context->flags) &&
		nfs_async_iocounter_wait(task, calldata->l_ctx))
		return;

	if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
		goto out_wait;
	if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
		/* Note: exit _without_ running nfs4_locku_done */
		goto out_no_action;
	}
	calldata->timestamp = jiffies;
	if (nfs4_setup_sequence(calldata->server->nfs_client,
				&calldata->arg.seq_args,
				&calldata->res.seq_res,
				task) != 0)
		nfs_release_seqid(calldata->arg.seqid);
	return;
out_no_action:
	task->tk_action = NULL;
out_wait:
	nfs4_sequence_done(task, &calldata->res.seq_res);
}


static int nfs4_delay_interruptible(long *timeout)
{
	might_sleep();

	freezable_schedule_timeout_interruptible_unsafe(nfs4_update_delay(timeout));
	if (!signal_pending(current))
		return 0;
	return __fatal_signal_pending(current) ? -EINTR :-ERESTARTSYS;
}


static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
		struct nfs_open_context *ctx, struct nfs4_lock_state *lsp,
		gfp_t gfp_mask)
{
	struct nfs4_lockdata *p;
	struct inode *inode = lsp->ls_state->inode;
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);

	p = kzalloc(sizeof(*p), gfp_mask);
	if (p == NULL)
		return NULL;

	p->arg.fh = NFS_FH(inode);
	p->arg.fl = &p->fl;
	p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask);
	if (IS_ERR(p->arg.open_seqid))
		goto out_free;
	alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
	p->arg.lock_seqid = alloc_seqid(&lsp->ls_seqid, gfp_mask);
	if (IS_ERR(p->arg.lock_seqid))
		goto out_free_seqid;
	p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
	p->arg.lock_owner.id = lsp->ls_seqid.owner_id;
	p->arg.lock_owner.s_dev = server->s_dev;
	p->res.lock_seqid = p->arg.lock_seqid;
	p->lsp = lsp;
	p->server = server;
	p->ctx = get_nfs_open_context(ctx);
	locks_init_lock(&p->fl);
	locks_copy_lock(&p->fl, fl);
	return p;
out_free_seqid:
	nfs_free_seqid(p->arg.open_seqid);
out_free:
	kfree(p);
	return NULL;
}


static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
{
	encode_op_hdr(xdr, OP_LINK, decode_link_maxsz, hdr);
	encode_string(xdr, name->len, name->name);
}


int nfs4_call_sync(struct rpc_clnt *clnt,
		   struct nfs_server *server,
		   struct rpc_message *msg,
		   struct nfs4_sequence_args *args,
		   struct nfs4_sequence_res *res,
		   int cache_reply)
{
	nfs4_init_sequence(args, res, cache_reply, 0);
	return nfs4_call_sync_sequence(clnt, server, msg, args, res);
}


static int decode_write(struct xdr_stream *xdr, struct nfs_pgio_res *res)
{
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_WRITE);
	if (status)
		return status;

	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		return -EIO;
	res->count = be32_to_cpup(p++);
	res->verf->committed = be32_to_cpup(p++);
	return decode_write_verifier(xdr, &res->verf->verifier);
}


nfs4_stat_to_errno(int stat)
{
	int i;
	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
		if (nfs_errtbl[i].stat == stat)
			return nfs_errtbl[i].errno;
	}
	if (stat <= 10000 || stat > 10100) {
		/* The server is looney tunes. */
		return -EREMOTEIO;
	}
	/* If we cannot translate the error, the recovery routines should
	 * handle it.
	 * Note: remaining NFSv4 error codes have values > 10000, so should
	 * not conflict with native Linux error codes.
	 */
	return -stat;
}


static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,
					struct xdr_stream *xdr,
					void *data)
{
	struct nfs4_secinfo_res *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putrootfh(xdr);
	if (status)
		goto out;
	status = decode_secinfo_no_name(xdr, res);
out:
	return status;
}


static void nfs4_xdr_enc_destroy_clientid(struct rpc_rqst *req,
					 struct xdr_stream *xdr,
					 const void *data)
{
	const struct nfs_client *clp = data;
	struct compound_hdr hdr = {
		.minorversion = clp->cl_mvops->minor_version,
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_destroy_clientid(xdr, clp->cl_clientid, &hdr);
	encode_nops(&hdr);
}


static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res)
{
	struct nfs4_slot *slot = res->sr_slot;
	struct nfs4_slot_table *tbl;

	tbl = slot->table;
	spin_lock(&tbl->slot_tbl_lock);
	if (!nfs41_wake_and_assign_slot(tbl, slot))
		nfs4_free_slot(tbl, slot);
	spin_unlock(&tbl->slot_tbl_lock);

	res->sr_slot = NULL;
}


static int _nfs41_test_stateid(struct nfs_server *server,
		nfs4_stateid *stateid,
		const struct cred *cred)
{
	int status;
	struct nfs41_test_stateid_args args = {
		.stateid = stateid,
	};
	struct nfs41_test_stateid_res res;
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID],
		.rpc_argp = &args,
		.rpc_resp = &res,
		.rpc_cred = cred,
	};
	struct rpc_clnt *rpc_client = server->client;

	nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
		&rpc_client, &msg);

	dprintk("NFS call  test_stateid %p\n", stateid);
	nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
	status = nfs4_call_sync_sequence(rpc_client, server, &msg,
			&args.seq_args, &res.seq_res);
	if (status != NFS_OK) {
		dprintk("NFS reply test_stateid: failed, %d\n", status);
		return status;
	}
	dprintk("NFS reply test_stateid: succeeded, %d\n", -res.status);
	return -res.status;
}


static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr,
			      const void *data)
{
	const struct nfs_pgio_args *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_read(xdr, args, &hdr);

	rpc_prepare_reply_pages(req, args->pages, args->pgbase,
				args->count, hdr.replen);
	req->rq_rcv_buf.flags |= XDRBUF_READ;
	encode_nops(&hdr);
}


static int nfs41_check_delegation_stateid(struct nfs4_state *state)
{
	struct nfs_server *server = NFS_SERVER(state->inode);
	nfs4_stateid stateid;
	struct nfs_delegation *delegation;
	const struct cred *cred = NULL;
	int status, ret = NFS_OK;

	/* Get the delegation credential for use by test/free_stateid */
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(state->inode)->delegation);
	if (delegation == NULL) {
		rcu_read_unlock();
		nfs_state_clear_delegation(state);
		return NFS_OK;
	}

	spin_lock(&delegation->lock);
	nfs4_stateid_copy(&stateid, &delegation->stateid);

	if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
				&delegation->flags)) {
		spin_unlock(&delegation->lock);
		rcu_read_unlock();
		return NFS_OK;
	}

	if (delegation->cred)
		cred = get_cred(delegation->cred);
	spin_unlock(&delegation->lock);
	rcu_read_unlock();
	status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);
	trace_nfs4_test_delegation_stateid(state, NULL, status);
	if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
		nfs_finish_clear_delegation_stateid(state, &stateid);
	else
		ret = status;

	put_cred(cred);
	return ret;
}


static int nfs4_write_done_cb(struct rpc_task *task,
			      struct nfs_pgio_header *hdr)
{
	struct inode *inode = hdr->inode;

	trace_nfs4_write(hdr, task->tk_status);
	if (task->tk_status < 0) {
		struct nfs4_exception exception = {
			.inode = hdr->inode,
			.state = hdr->args.context->state,
			.stateid = &hdr->args.stateid,
		};
		task->tk_status = nfs4_async_handle_exception(task,
				NFS_SERVER(inode), task->tk_status,
				&exception);
		if (exception.retry) {
			rpc_restart_call_prepare(task);
			return -EAGAIN;
		}
	}
	if (task->tk_status >= 0) {
		renew_lease(NFS_SERVER(inode), hdr->timestamp);
		nfs_writeback_update_inode(hdr);
	}
	return 0;
}


static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
{
	struct nfs_open_context *ctx;
	int ret;

	ctx = nfs4_state_find_open_context(state);
	if (IS_ERR(ctx))
		return -EAGAIN;
	clear_bit(NFS_DELEGATED_STATE, &state->flags);
	nfs_state_clear_open_state_flags(state);
	ret = nfs4_do_open_reclaim(ctx, state);
	put_nfs_open_context(ctx);
	return ret;
}


static void nfs4_close_done(struct rpc_task *task, void *data)
{
	struct nfs4_closedata *calldata = data;
	struct nfs4_state *state = calldata->state;
	struct nfs_server *server = NFS_SERVER(calldata->inode);
	nfs4_stateid *res_stateid = NULL;
	struct nfs4_exception exception = {
		.state = state,
		.inode = calldata->inode,
		.stateid = &calldata->arg.stateid,
	};

	dprintk("%s: begin!\n", __func__);
	if (!nfs4_sequence_done(task, &calldata->res.seq_res))
		return;
	trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);

	/* Handle Layoutreturn errors */
	if (pnfs_roc_done(task, calldata->inode,
				&calldata->arg.lr_args,
				&calldata->res.lr_res,
				&calldata->res.lr_ret) == -EAGAIN)
		goto out_restart;

	/* hmm. we are done with the inode, and in the process of freeing
	 * the state_owner. we keep this around to process errors
	 */
	switch (task->tk_status) {
		case 0:
			res_stateid = &calldata->res.stateid;
			renew_lease(server, calldata->timestamp);
			break;
		case -NFS4ERR_ACCESS:
			if (calldata->arg.bitmask != NULL) {
				calldata->arg.bitmask = NULL;
				calldata->res.fattr = NULL;
				goto out_restart;

			}
			break;
		case -NFS4ERR_OLD_STATEID:
			/* Did we race with OPEN? */
			if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
						state))
				goto out_restart;
			goto out_release;
		case -NFS4ERR_ADMIN_REVOKED:
		case -NFS4ERR_STALE_STATEID:
		case -NFS4ERR_EXPIRED:
			nfs4_free_revoked_stateid(server,
					&calldata->arg.stateid,
					task->tk_msg.rpc_cred);
			/* Fallthrough */
		case -NFS4ERR_BAD_STATEID:
			if (calldata->arg.fmode == 0)
				break;
			/* Fallthrough */
		default:
			task->tk_status = nfs4_async_handle_exception(task,
					server, task->tk_status, &exception);
			if (exception.retry)
				goto out_restart;
	}
	nfs_clear_open_stateid(state, &calldata->arg.stateid,
			res_stateid, calldata->arg.fmode);
out_release:
	task->tk_status = 0;
	nfs_release_seqid(calldata->arg.seqid);
	nfs_refresh_inode(calldata->inode, &calldata->fattr);
	dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
	return;
out_restart:
	task->tk_status = 0;
	rpc_restart_call_prepare(task);
	goto out_release;
}


decode_savefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_SAVEFH);
}


static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp,
				struct xdr_stream *xdr,
				void *data)
{
	struct nfs4_secinfo_res *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_secinfo(xdr, res);
out:
	return status;
}


static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
	__be32 *p;
	int ret = 0;

	*fileid = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			return -EIO;
		xdr_decode_hyper(p, fileid);
		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
		ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
	}
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
	return ret;
}


static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
{
	encode_getattr(xdr, nfs4_fsinfo_bitmap, bitmask,
			ARRAY_SIZE(nfs4_fsinfo_bitmap), hdr);
}


nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
{
	int len = 0;

	if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
		len = security_inode_listsecurity(inode, list, list_len);
		if (list_len && len > list_len)
			return -ERANGE;
	}
	return len;
}


nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
{
	struct nfs4_layoutget *lgp = calldata;
	struct nfs_server *server = NFS_SERVER(lgp->args.inode);

	dprintk("--> %s\n", __func__);
	nfs4_setup_sequence(server->nfs_client, &lgp->args.seq_args,
				&lgp->res.seq_res, task);
	dprintk("<-- %s\n", __func__);
}


static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
{
	struct nfs4_exception exception = { };
	int err;
	do {
		err = __nfs4_proc_set_acl(inode, buf, buflen);
		trace_nfs4_set_acl(inode, err);
		err = nfs4_handle_exception(NFS_SERVER(inode), err,
				&exception);
	} while (exception.retry);
	return err;
}


static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      void *__unused)
{
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (!status)
		status = decode_renew(xdr);
	return status;
}


static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
{
	int status = 0;

	time->tv_sec = 0;
	time->tv_nsec = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
		status = decode_attr_time(xdr, time);
		if (status == 0)
			status = NFS_ATTR_FATTR_MTIME;
		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
	}
	dprintk("%s: mtime=%lld\n", __func__, time->tv_sec);
	return status;
}


nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
		int errorcode, struct nfs4_exception *exception)
{
	struct nfs_client *clp = server->nfs_client;
	int ret;

	ret = nfs4_do_handle_exception(server, errorcode, exception);
	if (exception->delay) {
		rpc_delay(task, nfs4_update_delay(&exception->timeout));
		goto out_retry;
	}
	if (exception->recovering) {
		rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
		if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
			rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
		goto out_retry;
	}
	if (test_bit(NFS_MIG_FAILED, &server->mig_status))
		ret = -EIO;
	return ret;
out_retry:
	if (ret == 0) {
		exception->retry = 1;
		/*
		 * For NFS4ERR_MOVED, the client transport will need to
		 * be recomputed after migration recovery has completed.
		 */
		if (errorcode == -NFS4ERR_MOVED)
			rpc_task_release_transport(task);
	}
	return ret;
}


int decode_layoutreturn(struct xdr_stream *xdr,
			       struct nfs4_layoutreturn_res *res)
{
	return 0;
}


static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp,
					struct xdr_stream *xdr,
					void *res)
{
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (!status)
		status = decode_destroy_session(xdr, res);
	return status;
}


static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
				const void *data)
{
	const struct nfs_getaclargs *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};
	const __u32 nfs4_acl_bitmap[1] = {
		[0] = FATTR4_WORD0_ACL,
	};
	uint32_t replen;

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	replen = hdr.replen + op_decode_hdr_maxsz;
	encode_getattr(xdr, nfs4_acl_bitmap, NULL,
			ARRAY_SIZE(nfs4_acl_bitmap), &hdr);

	rpc_prepare_reply_pages(req, args->acl_pages, 0,
				args->acl_len, replen + 1);
	encode_nops(&hdr);
}


static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
		const struct cred *cred,
		struct nfs4_slot *slot,
		bool is_privileged)
{
	struct nfs4_sequence_data *calldata;
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
		.rpc_cred = cred,
	};
	struct rpc_task_setup task_setup_data = {
		.rpc_client = clp->cl_rpcclient,
		.rpc_message = &msg,
		.callback_ops = &nfs41_sequence_ops,
		.flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
	};
	struct rpc_task *ret;

	ret = ERR_PTR(-EIO);
	if (!refcount_inc_not_zero(&clp->cl_count))
		goto out_err;

	ret = ERR_PTR(-ENOMEM);
	calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
	if (calldata == NULL)
		goto out_put_clp;
	nfs4_init_sequence(&calldata->args, &calldata->res, 0, is_privileged);
	nfs4_sequence_attach_slot(&calldata->args, &calldata->res, slot);
	msg.rpc_argp = &calldata->args;
	msg.rpc_resp = &calldata->res;
	calldata->clp = clp;
	task_setup_data.callback_data = calldata;

	ret = rpc_run_task(&task_setup_data);
	if (IS_ERR(ret))
		goto out_err;
	return ret;
out_put_clp:
	nfs_put_client(clp);
out_err:
	nfs41_release_slot(slot);
	return ret;
}


static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
{
	struct nfs4_lock_state *lsp;
	int status;

	status = nfs4_set_lock_state(state, request);
	if (status != 0)
		return status;
	lsp = request->fl_u.nfs4_fl.owner;
	if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) ||
	    test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
		return 0;
	return nfs4_lock_expired(state, request);
}


nfs4_map_atomic_open_share(struct nfs_server *server,
		fmode_t fmode, int openflags)
{
	u32 res = 0;

	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
	case FMODE_READ:
		res = NFS4_SHARE_ACCESS_READ;
		break;
	case FMODE_WRITE:
		res = NFS4_SHARE_ACCESS_WRITE;
		break;
	case FMODE_READ|FMODE_WRITE:
		res = NFS4_SHARE_ACCESS_BOTH;
	}
	if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
		goto out;
	/* Want no delegation if we're using O_DIRECT */
	if (openflags & O_DIRECT)
		res |= NFS4_SHARE_WANT_NO_DELEG;
out:
	return res;
}


static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
	__be32 *p;
 /*
 * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
 * owner 4 = 32
 */
	encode_nfs4_seqid(xdr, arg->seqid);
	encode_share_access(xdr, arg->share_access);
	p = reserve_space(xdr, 36);
	p = xdr_encode_hyper(p, arg->clientid);
	*p++ = cpu_to_be32(24);
	p = xdr_encode_opaque_fixed(p, "open id:", 8);
	*p++ = cpu_to_be32(arg->server->s_dev);
	*p++ = cpu_to_be32(arg->id.uniquifier);
	xdr_encode_hyper(p, arg->id.create_time);
}


void nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
			    void *data)
{
	struct nfs4_add_xprt_data *adata = (struct nfs4_add_xprt_data *)data;
	struct rpc_task *task;
	int status;

	u32 sp4_how;

	dprintk("--> %s try %s\n", __func__,
		xprt->address_strings[RPC_DISPLAY_ADDR]);

	sp4_how = (adata->clp->cl_sp4_flags == 0 ? SP4_NONE : SP4_MACH_CRED);

	/* Test connection for session trunking. Async exchange_id call */
	task = nfs4_run_exchange_id(adata->clp, adata->cred, sp4_how, xprt);
	if (IS_ERR(task))
		return;

	status = task->tk_status;
	if (status == 0)
		status = nfs4_detect_session_trunking(adata->clp,
				task->tk_msg.rpc_resp, xprt);

	if (status == 0)
		rpc_clnt_xprt_switch_add_xprt(clnt, xprt);

	rpc_put_task(task);
}


static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
				struct nfs_fsinfo *fsinfo)
{
	int status = 0;

	dprintk("%s: bitmap is %x\n", __func__, bitmap[1]);
	if (unlikely(bitmap[1] & (FATTR4_WORD1_FS_LAYOUT_TYPES - 1U)))
		return -EIO;
	if (bitmap[1] & FATTR4_WORD1_FS_LAYOUT_TYPES) {
		status = decode_pnfs_layout_types(xdr, fsinfo);
		bitmap[1] &= ~FATTR4_WORD1_FS_LAYOUT_TYPES;
	}
	return status;
}


static void nfs_state_set_delegation(struct nfs4_state *state,
		const nfs4_stateid *deleg_stateid,
		fmode_t fmode)
{
	/*
	 * Protect the call to nfs4_state_set_mode_locked and
	 * serialise the stateid update
	 */
	write_seqlock(&state->seqlock);
	nfs4_stateid_copy(&state->stateid, deleg_stateid);
	set_bit(NFS_DELEGATED_STATE, &state->flags);
	write_sequnlock(&state->seqlock);
}


static void nfs4_xdr_enc_link(struct rpc_rqst *req, struct xdr_stream *xdr,
			      const void *data)
{
	const struct nfs4_link_arg *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_savefh(xdr, &hdr);
	encode_putfh(xdr, args->dir_fh, &hdr);
	encode_link(xdr, args->name, &hdr);
	encode_restorefh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
	encode_nops(&hdr);
}


static int decode_attr_fh_expire_type(struct xdr_stream *xdr,
				      uint32_t *bitmap, uint32_t *type)
{
	__be32 *p;

	*type = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FH_EXPIRE_TYPE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FH_EXPIRE_TYPE)) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			return -EIO;
		*type = be32_to_cpup(p);
		bitmap[0] &= ~FATTR4_WORD0_FH_EXPIRE_TYPE;
	}
	dprintk("%s: expire type=0x%x\n", __func__, *type);
	return 0;
}


static int nfs4_proc_lookup(struct inode *dir, struct dentry *dentry,
			    struct nfs_fh *fhandle, struct nfs_fattr *fattr,
			    struct nfs4_label *label)
{
	int status;
	struct rpc_clnt *client = NFS_CLIENT(dir);

	status = nfs4_proc_lookup_common(&client, dir, dentry, fhandle, fattr, label);
	if (client != NFS_CLIENT(dir)) {
		rpc_shutdown_client(client);
		nfs_fixup_secinfo_attributes(fattr);
	}
	return status;
}


static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl)
{
	struct nfs_inode *nfsi = NFS_I(inode);

	spin_lock(&inode->i_lock);
	kfree(nfsi->nfs4_acl);
	nfsi->nfs4_acl = acl;
	spin_unlock(&inode->i_lock);
}


static void nfs4_close_prepare(struct rpc_task *task, void *data)
{
	struct nfs4_closedata *calldata = data;
	struct nfs4_state *state = calldata->state;
	struct inode *inode = calldata->inode;
	struct pnfs_layout_hdr *lo;
	bool is_rdonly, is_wronly, is_rdwr;
	int call_close = 0;

	dprintk("%s: begin!\n", __func__);
	if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
		goto out_wait;

	task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
	spin_lock(&state->owner->so_lock);
	is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
	is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
	is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
	/* Calculate the change in open mode */
	calldata->arg.fmode = 0;
	if (state->n_rdwr == 0) {
		if (state->n_rdonly == 0)
			call_close |= is_rdonly;
		else if (is_rdonly)
			calldata->arg.fmode |= FMODE_READ;
		if (state->n_wronly == 0)
			call_close |= is_wronly;
		else if (is_wronly)
			calldata->arg.fmode |= FMODE_WRITE;
		if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE))
			call_close |= is_rdwr;
	} else if (is_rdwr)
		calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;

	nfs4_sync_open_stateid(&calldata->arg.stateid, state);
	if (!nfs4_valid_open_stateid(state))
		call_close = 0;
	spin_unlock(&state->owner->so_lock);

	if (!call_close) {
		/* Note: exit _without_ calling nfs4_close_done */
		goto out_no_action;
	}

	if (!calldata->lr.roc && nfs4_wait_on_layoutreturn(inode, task)) {
		nfs_release_seqid(calldata->arg.seqid);
		goto out_wait;
	}

	lo = calldata->arg.lr_args ? calldata->arg.lr_args->layout : NULL;
	if (lo && !pnfs_layout_is_valid(lo)) {
		calldata->arg.lr_args = NULL;
		calldata->res.lr_res = NULL;
	}

	if (calldata->arg.fmode == 0)
		task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];

	if (calldata->arg.fmode == 0 || calldata->arg.fmode == FMODE_READ) {
		/* Close-to-open cache consistency revalidation */
		if (!nfs4_have_delegation(inode, FMODE_READ))
			calldata->arg.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
		else
			calldata->arg.bitmask = NULL;
	}

	calldata->arg.share_access =
		nfs4_map_atomic_open_share(NFS_SERVER(inode),
				calldata->arg.fmode, 0);

	if (calldata->res.fattr == NULL)
		calldata->arg.bitmask = NULL;
	else if (calldata->arg.bitmask == NULL)
		calldata->res.fattr = NULL;
	calldata->timestamp = jiffies;
	if (nfs4_setup_sequence(NFS_SERVER(inode)->nfs_client,
				&calldata->arg.seq_args,
				&calldata->res.seq_res,
				task) != 0)
		nfs_release_seqid(calldata->arg.seqid);
	dprintk("%s: done!\n", __func__);
	return;
out_no_action:
	task->tk_action = NULL;
out_wait:
	nfs4_sequence_done(task, &calldata->res.seq_res);
}


nfs4_layoutget_handle_exception(struct rpc_task *task,
		struct nfs4_layoutget *lgp, struct nfs4_exception *exception)
{
	struct inode *inode = lgp->args.inode;
	struct nfs_server *server = NFS_SERVER(inode);
	struct pnfs_layout_hdr *lo;
	int nfs4err = task->tk_status;
	int err, status = 0;
	LIST_HEAD(head);

	dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);

	nfs4_sequence_free_slot(&lgp->res.seq_res);

	switch (nfs4err) {
	case 0:
		goto out;

	/*
	 * NFS4ERR_LAYOUTUNAVAILABLE means we are not supposed to use pnfs
	 * on the file. set tk_status to -ENODATA to tell upper layer to
	 * retry go inband.
	 */
	case -NFS4ERR_LAYOUTUNAVAILABLE:
		status = -ENODATA;
		goto out;
	/*
	 * NFS4ERR_BADLAYOUT means the MDS cannot return a layout of
	 * length lgp->args.minlength != 0 (see RFC5661 section 18.43.3).
	 */
	case -NFS4ERR_BADLAYOUT:
		status = -EOVERFLOW;
		goto out;
	/*
	 * NFS4ERR_LAYOUTTRYLATER is a conflict with another client
	 * (or clients) writing to the same RAID stripe except when
	 * the minlength argument is 0 (see RFC5661 section 18.43.3).
	 *
	 * Treat it like we would RECALLCONFLICT -- we retry for a little
	 * while, and then eventually give up.
	 */
	case -NFS4ERR_LAYOUTTRYLATER:
		if (lgp->args.minlength == 0) {
			status = -EOVERFLOW;
			goto out;
		}
		status = -EBUSY;
		break;
	case -NFS4ERR_RECALLCONFLICT:
		status = -ERECALLCONFLICT;
		break;
	case -NFS4ERR_DELEG_REVOKED:
	case -NFS4ERR_ADMIN_REVOKED:
	case -NFS4ERR_EXPIRED:
	case -NFS4ERR_BAD_STATEID:
		exception->timeout = 0;
		spin_lock(&inode->i_lock);
		lo = NFS_I(inode)->layout;
		/* If the open stateid was bad, then recover it. */
		if (!lo || test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) ||
		    !nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) {
			spin_unlock(&inode->i_lock);
			exception->state = lgp->args.ctx->state;
			exception->stateid = &lgp->args.stateid;
			break;
		}

		/*
		 * Mark the bad layout state as invalid, then retry
		 */
		pnfs_mark_layout_stateid_invalid(lo, &head);
		spin_unlock(&inode->i_lock);
		nfs_commit_inode(inode, 0);
		pnfs_free_lseg_list(&head);
		status = -EAGAIN;
		goto out;
	}

	err = nfs4_handle_exception(server, nfs4err, exception);
	if (!status) {
		if (exception->retry)
			status = -EAGAIN;
		else
			status = err;
	}
out:
	dprintk("<-- %s\n", __func__);
	return status;
}


static void encode_nops(struct compound_hdr *hdr)
{
	WARN_ON_ONCE(hdr->nops > NFS4_MAX_OPS);
	*hdr->nops_p = htonl(hdr->nops);
}


static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
{
	unsigned int attrwords = XDR_QUADLEN(attrlen);
	unsigned int nwords = (xdr_stream_pos(xdr) - savep) >> 2;

	if (unlikely(attrwords != nwords)) {
		dprintk("%s: server returned incorrect attribute length: "
			"%u %c %u\n",
				__func__,
				attrwords << 2,
				(attrwords < nwords) ? '<' : '>',
				nwords << 2);
		return -EIO;
	}
	return 0;
}


static void nfs4_layoutget_release(void *calldata)
{
	struct nfs4_layoutget *lgp = calldata;

	dprintk("--> %s\n", __func__);
	nfs4_sequence_free_slot(&lgp->res.seq_res);
	pnfs_layoutget_free(lgp);
	dprintk("<-- %s\n", __func__);
}


static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
{
	__be32 *p;

	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL);
	encode_string(xdr, name->len, name->name);
}


static int _nfs4_do_set_security_label(struct inode *inode,
		struct nfs4_label *ilabel,
		struct nfs_fattr *fattr,
		struct nfs4_label *olabel)
{

	struct iattr sattr = {0};
	struct nfs_server *server = NFS_SERVER(inode);
	const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
	struct nfs_setattrargs arg = {
		.fh		= NFS_FH(inode),
		.iap		= &sattr,
		.server		= server,
		.bitmask	= bitmask,
		.label		= ilabel,
	};
	struct nfs_setattrres res = {
		.fattr		= fattr,
		.label		= olabel,
		.server		= server,
	};
	struct rpc_message msg = {
		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
		.rpc_argp	= &arg,
		.rpc_resp	= &res,
	};
	int status;

	nfs4_stateid_copy(&arg.stateid, &zero_stateid);

	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
	if (status)
		dprintk("%s failed: %d\n", __func__, status);

	return status;
}


xdr_encode_nfstime4(__be32 *p, const struct timespec64 *t)
{
	p = xdr_encode_hyper(p, t->tv_sec);
	*p++ = cpu_to_be32(t->tv_nsec);
	return p;
}


static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
{
	struct nfs4_get_lease_time_data *data =
			(struct nfs4_get_lease_time_data *)calldata;

	dprintk("--> %s\n", __func__);
	if (!nfs4_sequence_done(task, &data->res->lr_seq_res))
		return;
	switch (task->tk_status) {
	case -NFS4ERR_DELAY:
	case -NFS4ERR_GRACE:
		dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
		rpc_delay(task, NFS4_POLL_RETRY_MIN);
		task->tk_status = 0;
		/* fall through */
	case -NFS4ERR_RETRY_UNCACHED_REP:
		rpc_restart_call_prepare(task);
		return;
	}
	dprintk("<-- %s\n", __func__);
}


static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
		nfs4_stateid *stateid, fmode_t fmode)
{
	clear_bit(NFS_O_RDWR_STATE, &state->flags);
	switch (fmode & (FMODE_READ|FMODE_WRITE)) {
	case FMODE_WRITE:
		clear_bit(NFS_O_RDONLY_STATE, &state->flags);
		break;
	case FMODE_READ:
		clear_bit(NFS_O_WRONLY_STATE, &state->flags);
		break;
	case 0:
		clear_bit(NFS_O_RDONLY_STATE, &state->flags);
		clear_bit(NFS_O_WRONLY_STATE, &state->flags);
		clear_bit(NFS_OPEN_STATE, &state->flags);
	}
	if (stateid == NULL)
		return;
	/* Handle OPEN+OPEN_DOWNGRADE races */
	if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
	    !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
		nfs_resync_open_stateid_locked(state);
		goto out;
	}
	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
		nfs4_stateid_copy(&state->stateid, stateid);
	nfs4_stateid_copy(&state->open_stateid, stateid);
	trace_nfs4_open_stateid_update(state->inode, stateid, 0);
out:
	nfs_state_log_update_open_stateid(state);
}


static int nfs4_map_errors(int err)
{
	if (err >= -1000)
		return err;
	switch (err) {
	case -NFS4ERR_RESOURCE:
	case -NFS4ERR_LAYOUTTRYLATER:
	case -NFS4ERR_RECALLCONFLICT:
		return -EREMOTEIO;
	case -NFS4ERR_WRONGSEC:
	case -NFS4ERR_WRONG_CRED:
		return -EPERM;
	case -NFS4ERR_BADOWNER:
	case -NFS4ERR_BADNAME:
		return -EINVAL;
	case -NFS4ERR_SHARE_DENIED:
		return -EACCES;
	case -NFS4ERR_MINOR_VERS_MISMATCH:
		return -EPROTONOSUPPORT;
	case -NFS4ERR_FILE_OPEN:
		return -EBUSY;
	default:
		dprintk("%s could not handle NFSv4 error %d\n",
				__func__, -err);
		break;
	}
	return -EIO;
}


size_t max_response_pages(struct nfs_server *server)
{
	u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
	return nfs_page_array_len(0, max_resp_sz);
}


static void encode_create_session(struct xdr_stream *xdr,
				  const struct nfs41_create_session_args *args,
				  struct compound_hdr *hdr)
{
	__be32 *p;
	struct nfs_client *clp = args->client;
	struct rpc_clnt *clnt = clp->cl_rpcclient;
	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
	u32 max_resp_sz_cached;

	/*
	 * Assumes OPEN is the biggest non-idempotent compound.
	 * 2 is the verifier.
	 */
	max_resp_sz_cached = (NFS4_dec_open_sz + RPC_REPHDRSIZE + 2)
				* XDR_UNIT + RPC_MAX_AUTH_SIZE;

	encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr);
	p = reserve_space(xdr, 16 + 2*28 + 20 + clnt->cl_nodelen + 12);
	p = xdr_encode_hyper(p, args->clientid);
	*p++ = cpu_to_be32(args->seqid);			/*Sequence id */
	*p++ = cpu_to_be32(args->flags);			/*flags */

	/* Fore Channel */
	*p++ = cpu_to_be32(0);				/* header padding size */
	*p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz);	/* max req size */
	*p++ = cpu_to_be32(args->fc_attrs.max_resp_sz);	/* max resp size */
	*p++ = cpu_to_be32(max_resp_sz_cached);		/* Max resp sz cached */
	*p++ = cpu_to_be32(args->fc_attrs.max_ops);	/* max operations */
	*p++ = cpu_to_be32(args->fc_attrs.max_reqs);	/* max requests */
	*p++ = cpu_to_be32(0);				/* rdmachannel_attrs */

	/* Back Channel */
	*p++ = cpu_to_be32(0);				/* header padding size */
	*p++ = cpu_to_be32(args->bc_attrs.max_rqst_sz);	/* max req size */
	*p++ = cpu_to_be32(args->bc_attrs.max_resp_sz);	/* max resp size */
	*p++ = cpu_to_be32(args->bc_attrs.max_resp_sz_cached);	/* Max resp sz cached */
	*p++ = cpu_to_be32(args->bc_attrs.max_ops);	/* max operations */
	*p++ = cpu_to_be32(args->bc_attrs.max_reqs);	/* max requests */
	*p++ = cpu_to_be32(0);				/* rdmachannel_attrs */

	*p++ = cpu_to_be32(args->cb_program);		/* cb_program */
	*p++ = cpu_to_be32(1);
	*p++ = cpu_to_be32(RPC_AUTH_UNIX);			/* auth_sys */

	/* authsys_parms rfc1831 */
	*p++ = cpu_to_be32(ktime_to_ns(nn->boot_time));	/* stamp */
	p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
	*p++ = cpu_to_be32(0);				/* UID */
	*p++ = cpu_to_be32(0);				/* GID */
	*p = cpu_to_be32(0);				/* No more gids */
}


static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
	unsigned int savep;
	uint32_t attrlen, bitmap[3] = {0};
	int status;

	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto xdr_error;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto xdr_error;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto xdr_error;
	if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
		goto xdr_error;
	if ((status = decode_attr_fh_expire_type(xdr, bitmap,
						 &res->fh_expire_type)) != 0)
		goto xdr_error;
	if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
		goto xdr_error;
	if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
		goto xdr_error;
	if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
		goto xdr_error;
	if ((status = decode_attr_exclcreat_supported(xdr, bitmap,
				res->exclcreat_bitmask)) != 0)
		goto xdr_error;
	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
	dprintk("%s: xdr returned %d!\n", __func__, -status);
	return status;
}


static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp,
				  struct xdr_stream *xdr,
				  void *data)
{
	struct nfs4_layoutget_res *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_layoutget(xdr, rqstp, res);
out:
	return status;
}


static bool nfs4_refresh_lock_old_stateid(nfs4_stateid *dst,
		struct nfs4_lock_state *lsp)
{
	struct nfs4_state *state = lsp->ls_state;
	bool ret = false;

	spin_lock(&state->state_lock);
	if (!nfs4_stateid_match_other(dst, &lsp->ls_stateid))
		goto out;
	if (!nfs4_stateid_is_newer(&lsp->ls_stateid, dst))
		nfs4_stateid_seqid_inc(dst);
	else
		dst->seqid = lsp->ls_stateid.seqid;
	ret = true;
out:
	spin_unlock(&state->state_lock);
	return ret;
}


static void nfs4_get_lease_time_prepare(struct rpc_task *task,
					void *calldata)
{
	struct nfs4_get_lease_time_data *data =
			(struct nfs4_get_lease_time_data *)calldata;

	dprintk("--> %s\n", __func__);
	/* just setup sequence, do not trigger session recovery
	   since we're invoked within one */
	nfs4_setup_sequence(data->clp,
			&data->args->la_seq_args,
			&data->res->lr_seq_res,
			task);
	dprintk("<-- %s\n", __func__);
}


static int decode_access(struct xdr_stream *xdr, u32 *supported, u32 *access)
{
	__be32 *p;
	uint32_t supp, acc;
	int status;

	status = decode_op_hdr(xdr, OP_ACCESS);
	if (status)
		return status;
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		return -EIO;
	supp = be32_to_cpup(p++);
	acc = be32_to_cpup(p);
	*supported = supp;
	*access = acc;
	return 0;
}


static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			     void *data)
{
	struct nfs4_link_res *res = data;
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_savefh(xdr);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_link(xdr, &res->cinfo);
	if (status)
		goto out;
	/*
	 * Note order: OP_LINK leaves the directory as the current
	 *             filehandle.
	 */
	status = decode_restorefh(xdr);
	if (status)
		goto out;
	decode_getfattr_label(xdr, res->fattr, res->label, res->server);
out:
	return status;
}


static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
{
	int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
				    &data->arg.seq_args, &data->res.seq_res, 1);
	if (status == 0) {
		spin_lock(&dir->i_lock);
		nfs4_update_changeattr_locked(dir, &data->res.dir_cinfo,
				data->res.fattr->time_start,
				NFS_INO_INVALID_DATA);
		/* Creating a directory bumps nlink in the parent */
		if (data->arg.ftype == NF4DIR)
			nfs4_inc_nlink_locked(dir);
		spin_unlock(&dir->i_lock);
		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
	}
	return status;
}


static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
{
	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
	u32 len, recvd;
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_READLINK);
	if (status)
		return status;

	/* Convert length of symlink */
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		return -EIO;
	len = be32_to_cpup(p);
	if (len >= rcvbuf->page_len || len <= 0) {
		dprintk("nfs: server returned giant symlink!\n");
		return -ENAMETOOLONG;
	}
	recvd = xdr_read_pages(xdr, len);
	if (recvd < len) {
		dprintk("NFS: server cheating in readlink reply: "
				"count %u > recvd %u\n", len, recvd);
		return -EIO;
	}
	/*
	 * The XDR encode routine has set things up so that
	 * the link text will be copied directly into the
	 * buffer.  We just have to do overflow-checking,
	 * and and null-terminate the text (the VFS expects
	 * null-termination).
	 */
	xdr_terminate_string(rcvbuf, len);
	return 0;
}


static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
	int		status;
	__be32		verf[2];

	status = decode_op_hdr(xdr, OP_READDIR);
	if (!status)
		status = decode_verifier(xdr, readdir->verifier.data);
	if (unlikely(status))
		return status;
	memcpy(verf, readdir->verifier.data, sizeof(verf));
	dprintk("%s: verifier = %08x:%08x\n",
			__func__, verf[0], verf[1]);
	return xdr_read_pages(xdr, xdr->buf->page_len);
}


static void nfs4_opendata_put(struct nfs4_opendata *p)
{
	if (p != NULL)
		kref_put(&p->kref, nfs4_opendata_free);
}


static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
			       const void *data)
{
	const struct nfs_pgio_args *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_write(xdr, args, &hdr);
	req->rq_snd_buf.flags |= XDRBUF_WRITE;
	if (args->bitmask)
		encode_getfattr(xdr, args->bitmask, &hdr);
	encode_nops(&hdr);
}


static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
		struct page *page, unsigned int len, struct iattr *sattr)
{
	struct nfs4_exception exception = {
		.interruptible = true,
	};
	struct nfs4_label l, *label = NULL;
	int err;

	label = nfs4_label_init_security(dir, dentry, sattr, &l);

	do {
		err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
		trace_nfs4_symlink(dir, &dentry->d_name, err);
		err = nfs4_handle_exception(NFS_SERVER(dir), err,
				&exception);
	} while (exception.retry);

	nfs4_label_release_security(label);
	return err;
}


nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
		 int flags)
{
	struct nfs_server *server = NFS_SERVER(dir);
	struct nfs4_label l, *ilabel = NULL;
	struct nfs_open_context *ctx;
	struct nfs4_state *state;
	int status = 0;

	ctx = alloc_nfs_open_context(dentry, FMODE_READ, NULL);
	if (IS_ERR(ctx))
		return PTR_ERR(ctx);

	ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);

	if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
		sattr->ia_mode &= ~current_umask();
	state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL);
	if (IS_ERR(state)) {
		status = PTR_ERR(state);
		goto out;
	}
out:
	nfs4_label_release_security(ilabel);
	put_nfs_open_context(ctx);
	return status;
}


static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
{
	struct nfs_server *server = NFS_SERVER(inode);
	__u32 bitmask[NFS4_BITMASK_SZ];
	struct nfs4_link_arg arg = {
		.fh     = NFS_FH(inode),
		.dir_fh = NFS_FH(dir),
		.name   = name,
		.bitmask = bitmask,
	};
	struct nfs4_link_res res = {
		.server = server,
		.label = NULL,
	};
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
		.rpc_argp = &arg,
		.rpc_resp = &res,
	};
	int status = -ENOMEM;

	res.fattr = nfs_alloc_fattr();
	if (res.fattr == NULL)
		goto out;

	res.label = nfs4_label_alloc(server, GFP_KERNEL);
	if (IS_ERR(res.label)) {
		status = PTR_ERR(res.label);
		goto out;
	}

	nfs4_inode_make_writeable(inode);
	nfs4_bitmap_copy_adjust_setattr(bitmask, nfs4_bitmask(server, res.label), inode);

	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
	if (!status) {
		nfs4_update_changeattr(dir, &res.cinfo, res.fattr->time_start,
				       NFS_INO_INVALID_DATA);
		status = nfs_post_op_update_inode(inode, res.fattr);
		if (!status)
			nfs_setsecurity(inode, res.fattr, res.label);
	}

	nfs4_label_free(res.label);

out:
	nfs_free_fattr(res.fattr);
	return status;
}


static void nfs4_opendata_free(struct kref *kref)
{
	struct nfs4_opendata *p = container_of(kref,
			struct nfs4_opendata, kref);
	struct super_block *sb = p->dentry->d_sb;

	nfs4_lgopen_release(p->lgp);
	nfs_free_seqid(p->o_arg.seqid);
	nfs4_sequence_free_slot(&p->o_res.seq_res);
	if (p->state != NULL)
		nfs4_put_open_state(p->state);
	nfs4_put_state_owner(p->owner);

	nfs4_label_free(p->a_label);
	nfs4_label_free(p->f_label);

	dput(p->dir);
	dput(p->dentry);
	nfs_sb_deactive(sb);
	nfs_fattr_free_names(&p->f_attr);
	kfree(p->f_attr.mdsthreshold);
	kfree(p);
}


static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     const void *data)
{
	const struct nfs_openargs *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_open(xdr, args, &hdr);
	if (args->access)
		encode_access(xdr, args->access, &hdr);
	encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
	if (args->lg_args) {
		encode_layoutget(xdr, args->lg_args, &hdr);
		rpc_prepare_reply_pages(req, args->lg_args->layout.pages, 0,
					args->lg_args->layout.pglen,
					hdr.replen);
	}
	encode_nops(&hdr);
}


static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
{
	struct nfs4_reclaim_complete_data *calldata = data;

	nfs4_setup_sequence(calldata->clp,
			&calldata->arg.seq_args,
			&calldata->res.seq_res,
			task);
}


encode_setacl(struct xdr_stream *xdr, const struct nfs_setaclargs *arg,
		struct compound_hdr *hdr)
{
	__be32 *p;

	encode_op_hdr(xdr, OP_SETATTR, decode_setacl_maxsz, hdr);
	encode_nfs4_stateid(xdr, &zero_stateid);
	p = reserve_space(xdr, 2*4);
	*p++ = cpu_to_be32(1);
	*p = cpu_to_be32(FATTR4_WORD0_ACL);
	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(arg->acl_len);
	xdr_write_pages(xdr, arg->acl_pages, 0, arg->acl_len);
}


static bool nfs4_match_stateid(const nfs4_stateid *s1,
		const nfs4_stateid *s2)
{
	return nfs4_stateid_match(s1, s2);
}


static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req,
				struct xdr_stream *xdr,
				const void *data)
{
	const struct nfs4_secinfo_arg *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->dir_fh, &hdr);
	encode_secinfo(xdr, args->name, &hdr);
	encode_nops(&hdr);
}


static void nfs4_bitmap_copy_adjust_setattr(__u32 *dst,
		const __u32 *src, struct inode *inode)
{
	nfs4_bitmap_copy_adjust(dst, src, inode);
}


static void nfs40_call_sync_done(struct rpc_task *task, void *calldata)
{
	struct nfs4_call_sync_data *data = calldata;
	nfs4_sequence_done(task, data->seq_res);
}


static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
{
	uint32_t attrs[3] = {
		FATTR4_WORD0_RDATTR_ERROR,
		FATTR4_WORD1_MOUNTED_ON_FILEID,
	};
	uint32_t dircount = readdir->count >> 1;
	__be32 *p, verf[2];
	uint32_t attrlen = 0;
	unsigned int i;

	if (readdir->plus) {
		attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
			FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID;
		attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
			FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
			FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
			FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
		attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
		dircount >>= 1;
	}
	/* Use mounted_on_fileid only if the server supports it */
	if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
		attrs[0] |= FATTR4_WORD0_FILEID;
	for (i = 0; i < ARRAY_SIZE(attrs); i++) {
		attrs[i] &= readdir->bitmask[i];
		if (attrs[i] != 0)
			attrlen = i+1;
	}

	encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
	encode_uint64(xdr, readdir->cookie);
	encode_nfs4_verifier(xdr, &readdir->verifier);
	p = reserve_space(xdr, 12 + (attrlen << 2));
	*p++ = cpu_to_be32(dircount);
	*p++ = cpu_to_be32(readdir->count);
	*p++ = cpu_to_be32(attrlen);
	for (i = 0; i < attrlen; i++)
		*p++ = cpu_to_be32(attrs[i]);
	memcpy(verf, readdir->verifier.data, sizeof(verf));

	dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n",
			__func__,
			(unsigned long long)readdir->cookie,
			verf[0], verf[1],
			attrs[0] & readdir->bitmask[0],
			attrs[1] & readdir->bitmask[1],
			attrs[2] & readdir->bitmask[2]);
}


static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     const void *data)
{
	const struct nfs4_server_caps_arg *args = data;
	const u32 *bitmask = args->bitmask;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fhandle, &hdr);
	encode_getattr(xdr, bitmask, NULL, 3, &hdr);
	encode_nops(&hdr);
}


static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
		struct nfs_open_context *ctx,
		struct nfs4_lock_state *lsp,
		struct nfs_seqid *seqid)
{
	struct nfs4_unlockdata *data;
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU],
		.rpc_cred = ctx->cred,
	};
	struct rpc_task_setup task_setup_data = {
		.rpc_client = NFS_CLIENT(lsp->ls_state->inode),
		.rpc_message = &msg,
		.callback_ops = &nfs4_locku_ops,
		.workqueue = nfsiod_workqueue,
		.flags = RPC_TASK_ASYNC,
	};

	nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client,
		NFS_SP4_MACH_CRED_CLEANUP, &task_setup_data.rpc_client, &msg);

	/* Ensure this is an unlock - when canceling a lock, the
	 * canceled lock is passed in, and it won't be an unlock.
	 */
	fl->fl_type = F_UNLCK;
	if (fl->fl_flags & FL_CLOSE)
		set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);

	data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
	if (data == NULL) {
		nfs_free_seqid(seqid);
		return ERR_PTR(-ENOMEM);
	}

	nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1, 0);
	msg.rpc_argp = &data->arg;
	msg.rpc_resp = &data->res;
	task_setup_data.callback_data = data;
	return rpc_run_task(&task_setup_data);
}


static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
	__be32 *p;

	p = reserve_space(xdr, 4);
	switch(arg->createmode) {
	case NFS4_CREATE_UNCHECKED:
		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
		encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
				arg->server, arg->server->attr_bitmask);
		break;
	case NFS4_CREATE_GUARDED:
		*p = cpu_to_be32(NFS4_CREATE_GUARDED);
		encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
				arg->server, arg->server->attr_bitmask);
		break;
	case NFS4_CREATE_EXCLUSIVE:
		*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
		encode_nfs4_verifier(xdr, &arg->u.verifier);
		break;
	case NFS4_CREATE_EXCLUSIVE4_1:
		*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
		encode_nfs4_verifier(xdr, &arg->u.verifier);
		encode_attrs(xdr, arg->u.attrs, arg->label, &arg->umask,
				arg->server, arg->server->exclcreat_bitmask);
	}
}


int nfs4_setup_sequence(struct nfs_client *client,
			struct nfs4_sequence_args *args,
			struct nfs4_sequence_res *res,
			struct rpc_task *task)
{
	struct nfs4_session *session = nfs4_get_session(client);
	struct nfs4_slot_table *tbl  = client->cl_slot_tbl;
	struct nfs4_slot *slot;

	/* slot already allocated? */
	if (res->sr_slot != NULL)
		goto out_start;

	if (session)
		tbl = &session->fc_slot_table;

	spin_lock(&tbl->slot_tbl_lock);
	/* The state manager will wait until the slot table is empty */
	if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
		goto out_sleep;

	slot = nfs4_alloc_slot(tbl);
	if (IS_ERR(slot)) {
		if (slot == ERR_PTR(-ENOMEM))
			goto out_sleep_timeout;
		goto out_sleep;
	}
	spin_unlock(&tbl->slot_tbl_lock);

	nfs4_sequence_attach_slot(args, res, slot);

	trace_nfs4_setup_sequence(session, args);
out_start:
	nfs41_sequence_res_init(res);
	rpc_call_start(task);
	return 0;
out_sleep_timeout:
	/* Try again in 1/4 second */
	if (args->sa_privileged)
		rpc_sleep_on_priority_timeout(&tbl->slot_tbl_waitq, task,
				jiffies + (HZ >> 2), RPC_PRIORITY_PRIVILEGED);
	else
		rpc_sleep_on_timeout(&tbl->slot_tbl_waitq, task,
				NULL, jiffies + (HZ >> 2));
	spin_unlock(&tbl->slot_tbl_lock);
	return -EAGAIN;
out_sleep:
	if (args->sa_privileged)
		rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
				RPC_PRIORITY_PRIVILEGED);
	else
		rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
	spin_unlock(&tbl->slot_tbl_lock);
	return -EAGAIN;
}


static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      const void *data)
{
	const struct nfs4_fs_locations_arg *args = data;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};
	uint32_t replen;

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	if (args->migration) {
		encode_putfh(xdr, args->fh, &hdr);
		replen = hdr.replen;
		encode_fs_locations(xdr, args->bitmask, &hdr);
		if (args->renew)
			encode_renew(xdr, args->clientid, &hdr);
	} else {
		encode_putfh(xdr, args->dir_fh, &hdr);
		encode_lookup(xdr, args->name, &hdr);
		replen = hdr.replen;
		encode_fs_locations(xdr, args->bitmask, &hdr);
	}

	rpc_prepare_reply_pages(req, (struct page **)&args->page, 0,
				PAGE_SIZE, replen + 1);
	encode_nops(&hdr);
}


static int nfs40_sequence_done(struct rpc_task *task,
			       struct nfs4_sequence_res *res)
{
	if (res->sr_slot != NULL)
		nfs40_sequence_free_slot(res);
	return 1;
}


static bool nfs4_mode_match_open_stateid(struct nfs4_state *state,
		fmode_t fmode)
{
	switch(fmode & (FMODE_READ|FMODE_WRITE)) {
	case FMODE_READ|FMODE_WRITE:
		return state->n_rdwr != 0;
	case FMODE_WRITE:
		return state->n_wronly != 0;
	case FMODE_READ:
		return state->n_rdonly != 0;
	}
	WARN_ON_ONCE(1);
	return false;
}


static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
{
	struct nfs4_delegreturndata *data = calldata;
	struct nfs4_exception exception = {
		.inode = data->inode,
		.stateid = &data->stateid,
	};

	if (!nfs4_sequence_done(task, &data->res.seq_res))
		return;

	trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);

	/* Handle Layoutreturn errors */
	if (pnfs_roc_done(task, data->inode,
				&data->args.lr_args,
				&data->res.lr_res,
				&data->res.lr_ret) == -EAGAIN)
		goto out_restart;

	switch (task->tk_status) {
	case 0:
		renew_lease(data->res.server, data->timestamp);
		break;
	case -NFS4ERR_ADMIN_REVOKED:
	case -NFS4ERR_DELEG_REVOKED:
	case -NFS4ERR_EXPIRED:
		nfs4_free_revoked_stateid(data->res.server,
				data->args.stateid,
				task->tk_msg.rpc_cred);
		/* Fallthrough */
	case -NFS4ERR_BAD_STATEID:
	case -NFS4ERR_STALE_STATEID:
	case -ETIMEDOUT:
		task->tk_status = 0;
		break;
	case -NFS4ERR_OLD_STATEID:
		if (!nfs4_refresh_delegation_stateid(&data->stateid, data->inode))
			nfs4_stateid_seqid_inc(&data->stateid);
		if (data->args.bitmask) {
			data->args.bitmask = NULL;
			data->res.fattr = NULL;
		}
		goto out_restart;
	case -NFS4ERR_ACCESS:
		if (data->args.bitmask) {
			data->args.bitmask = NULL;
			data->res.fattr = NULL;
			goto out_restart;
		}
		/* Fallthrough */
	default:
		task->tk_status = nfs4_async_handle_exception(task,
				data->res.server, task->tk_status,
				&exception);
		if (exception.retry)
			goto out_restart;
	}
	nfs_delegation_mark_returned(data->inode, data->args.stateid);
	data->rpc_status = task->tk_status;
	return;
out_restart:
	task->tk_status = 0;
	rpc_restart_call_prepare(task);
}


encode_layoutreturn(struct xdr_stream *xdr,
		    const struct nfs4_layoutreturn_args *args,
		    struct compound_hdr *hdr)
{
	__be32 *p;

	encode_op_hdr(xdr, OP_LAYOUTRETURN, decode_layoutreturn_maxsz, hdr);
	p = reserve_space(xdr, 16);
	*p++ = cpu_to_be32(0);		/* reclaim. always 0 for now */
	*p++ = cpu_to_be32(args->layout_type);
	*p++ = cpu_to_be32(args->range.iomode);
	*p = cpu_to_be32(RETURN_FILE);
	p = reserve_space(xdr, 16);
	p = xdr_encode_hyper(p, args->range.offset);
	p = xdr_encode_hyper(p, args->range.length);
	spin_lock(&args->inode->i_lock);
	encode_nfs4_stateid(xdr, &args->stateid);
	spin_unlock(&args->inode->i_lock);
	if (args->ld_private->ops && args->ld_private->ops->encode)
		args->ld_private->ops->encode(xdr, args, args->ld_private);
	else
		encode_uint32(xdr, 0);
}


static int nfs4_proc_sequence(struct nfs_client *clp, const struct cred *cred)
{
	struct rpc_task *task;
	int ret;

	task = _nfs41_proc_sequence(clp, cred, NULL, true);
	if (IS_ERR(task)) {
		ret = PTR_ERR(task);
		goto out;
	}
	ret = rpc_wait_for_completion_task(task);
	if (!ret)
		ret = task->tk_status;
	rpc_put_task(task);
out:
	dprintk("<-- %s status=%d\n", __func__, ret);
	return ret;
}


int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
{
	if (res->sr_slot == NULL)
		return 1;
	if (!res->sr_slot->table->session)
		return nfs40_sequence_done(task, res);
	return nfs41_sequence_done(task, res);
}


static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
				     struct nfs41_create_session_res *res)
{
	int ret;

	ret = nfs4_verify_fore_channel_attrs(args, res);
	if (ret)
		return ret;
	return nfs4_verify_back_channel_attrs(args, res);
}


static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args,
		struct nfs41_create_session_res *res)
{
	struct nfs4_channel_attrs *sent = &args->bc_attrs;
	struct nfs4_channel_attrs *rcvd = &res->bc_attrs;

	if (!(res->flags & SESSION4_BACK_CHAN))
		goto out;
	if (rcvd->max_rqst_sz > sent->max_rqst_sz)
		return -EINVAL;
	if (rcvd->max_resp_sz < sent->max_resp_sz)
		return -EINVAL;
	if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
		return -EINVAL;
	if (rcvd->max_ops > sent->max_ops)
		return -EINVAL;
	if (rcvd->max_reqs > sent->max_reqs)
		return -EINVAL;
out:
	return 0;
}


nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
{
	struct inode *inode = lgp->args.inode;
	struct nfs_server *server = NFS_SERVER(inode);
	struct rpc_task *task;
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
		.rpc_argp = &lgp->args,
		.rpc_resp = &lgp->res,
		.rpc_cred = lgp->cred,
	};
	struct rpc_task_setup task_setup_data = {
		.rpc_client = server->client,
		.rpc_message = &msg,
		.callback_ops = &nfs4_layoutget_call_ops,
		.callback_data = lgp,
		.flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF,
	};
	struct pnfs_layout_segment *lseg = NULL;
	struct nfs4_exception exception = {
		.inode = inode,
		.timeout = *timeout,
	};
	int status = 0;

	dprintk("--> %s\n", __func__);

	/* nfs4_layoutget_release calls pnfs_put_layout_hdr */
	pnfs_get_layout_hdr(NFS_I(inode)->layout);

	nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0, 0);

	task = rpc_run_task(&task_setup_data);

	status = rpc_wait_for_completion_task(task);
	if (status != 0)
		goto out;

	if (task->tk_status < 0) {
		status = nfs4_layoutget_handle_exception(task, lgp, &exception);
		*timeout = exception.timeout;
	} else if (lgp->res.layoutp->len == 0) {
		status = -EAGAIN;
		*timeout = nfs4_update_delay(&exception.timeout);
	} else
		lseg = pnfs_layout_process(lgp);
out:
	trace_nfs4_layoutget(lgp->args.ctx,
			&lgp->args.range,
			&lgp->res.range,
			&lgp->res.stateid,
			status);

	rpc_put_task(task);
	dprintk("<-- %s status=%d\n", __func__, status);
	if (status)
		return ERR_PTR(status);
	return lseg;
}


nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
{
	struct nfs_client *clp = NFS_SERVER(state->inode)->nfs_client;
	struct nfs_delegation *delegation;
	int delegation_flags = 0;

	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(state->inode)->delegation);
	if (delegation)
		delegation_flags = delegation->flags;
	rcu_read_unlock();
	switch (data->o_arg.claim) {
	default:
		break;
	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
	case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
		pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
				   "returning a delegation for "
				   "OPEN(CLAIM_DELEGATE_CUR)\n",
				   clp->cl_hostname);
		return;
	}
	if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
		nfs_inode_set_delegation(state->inode,
				data->owner->so_cred,
				data->o_res.delegation_type,
				&data->o_res.delegation,
				data->o_res.pagemod_limit);
	else
		nfs_inode_reclaim_delegation(state->inode,
				data->owner->so_cred,
				data->o_res.delegation_type,
				&data->o_res.delegation,
				data->o_res.pagemod_limit);

	if (data->o_res.do_recall)
		nfs_async_inode_return_delegation(state->inode,
						  &data->o_res.delegation);
}


static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
		const struct cred *cred)
{
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_CLIENTID],
		.rpc_argp = clp,
		.rpc_cred = cred,
	};
	int status;

	status = rpc_call_sync(clp->cl_rpcclient, &msg,
			       RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
	trace_nfs4_destroy_clientid(clp, status);
	if (status)
		dprintk("NFS: Got error %d from the server %s on "
			"DESTROY_CLIENTID.", status, clp->cl_hostname);
	return status;
}