コード例 #1
0
ファイル: callback.c プロジェクト: johnny/CobraDroidBeta
static int nfs_callback_authenticate(struct svc_rqst *rqstp)
{
	struct nfs_client *clp;
	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
	int ret = SVC_OK;

	/* Don't talk to strangers */
	clp = nfs_find_client(svc_addr(rqstp), 4);
	if (clp == NULL)
		return SVC_DROP;

	dprintk("%s: %s NFSv4 callback!\n", __func__,
			svc_print_addr(rqstp, buf, sizeof(buf)));

	switch (rqstp->rq_authop->flavour) {
		case RPC_AUTH_NULL:
			if (rqstp->rq_proc != CB_NULL)
				ret = SVC_DENIED;
			break;
		case RPC_AUTH_UNIX:
			break;
		case RPC_AUTH_GSS:
			ret = check_gss_callback_principal(clp, rqstp);
			break;
		default:
			ret = SVC_DENIED;
	}
	nfs_put_client(clp);
	return ret;
}
コード例 #2
0
ファイル: callback_proc.c プロジェクト: Adjustxx/Savaged-Zen
/* Reduce the fore channel's max_slots to the target value */
__be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy)
{
	struct nfs_client *clp;
	struct nfs4_slot_table *fc_tbl;
	__be32 status;

	status = htonl(NFS4ERR_OP_NOT_IN_SESSION);
	clp = nfs_find_client(args->crsa_addr, 4);
	if (clp == NULL)
		goto out;

	dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR),
		args->crsa_target_max_slots);

	fc_tbl = &clp->cl_session->fc_slot_table;

	status = htonl(NFS4ERR_BAD_HIGH_SLOT);
	if (args->crsa_target_max_slots > fc_tbl->max_slots ||
	    args->crsa_target_max_slots < 1)
		goto out_putclient;

	status = htonl(NFS4_OK);
	if (args->crsa_target_max_slots == fc_tbl->max_slots)
		goto out_putclient;

	fc_tbl->target_max_slots = args->crsa_target_max_slots;
	nfs41_handle_recall_slot(clp);
out_putclient:
	nfs_put_client(clp);	/* balance nfs_find_client */
out:
	dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
	return status;
}
コード例 #3
0
ファイル: callback_proc.c プロジェクト: Adjustxx/Savaged-Zen
/*
 * Returns a pointer to a held 'struct nfs_client' that matches the server's
 * address, major version number, and session ID.  It is the caller's
 * responsibility to release the returned reference.
 *
 * Returns NULL if there are no connections with sessions, or if no session
 * matches the one of interest.
 */
 static struct nfs_client *find_client_with_session(
	const struct sockaddr *addr, u32 nfsversion,
	struct nfs4_sessionid *sessionid)
{
	struct nfs_client *clp;

	clp = nfs_find_client(addr, 4);
	if (clp == NULL)
		return NULL;

	do {
		struct nfs_client *prev = clp;

		if (clp->cl_session != NULL) {
			if (memcmp(clp->cl_session->sess_id.data,
					sessionid->data,
					NFS4_MAX_SESSIONID_LEN) == 0) {
				/* Returns a held reference to clp */
				return clp;
			}
		}
		clp = nfs_find_client_next(prev);
		nfs_put_client(prev);
	} while (clp != NULL);

	return NULL;
}
コード例 #4
0
static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
{
	struct cb_compound_hdr_arg hdr_arg = { 0 };
	struct cb_compound_hdr_res hdr_res = { NULL };
	struct xdr_stream xdr_in, xdr_out;
	__be32 *p, status;
	struct cb_process_state cps = {
		.drc_status = 0,
		.clp = NULL,
		.slotid = NFS4_NO_SLOT,
		.net = rqstp->rq_xprt->xpt_net,
	};
	unsigned int nops = 0;

	dprintk("%s: start\n", __func__);

	xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);

	p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
	xdr_init_encode(&xdr_out, &rqstp->rq_res, p);

	status = decode_compound_hdr_arg(&xdr_in, &hdr_arg);
	if (status == __constant_htonl(NFS4ERR_RESOURCE))
		return rpc_garbage_args;

	if (hdr_arg.minorversion == 0) {
		cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident);
		if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
			return rpc_drop_reply;
	}

	hdr_res.taglen = hdr_arg.taglen;
	hdr_res.tag = hdr_arg.tag;
	if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
		return rpc_system_err;

	while (status == 0 && nops != hdr_arg.nops) {
		status = process_op(hdr_arg.minorversion, nops, rqstp,
				    &xdr_in, argp, &xdr_out, resp, &cps);
		nops++;
	}

	if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) {
		status = htonl(NFS4ERR_RESOURCE);
		nops--;
	}

	*hdr_res.status = status;
	*hdr_res.nops = htonl(nops);
	nfs4_cb_free_slot(&cps);
	nfs_put_client(cps.clp);
	dprintk("%s: done, status = %u\n", __func__, ntohl(status));
	return rpc_success;
}

static struct callback_op callback_ops[] = {
	[0] = {
		.res_maxsize = CB_OP_HDR_RES_MAXSZ,
	},
コード例 #5
0
ファイル: callback_proc.c プロジェクト: Adjustxx/Savaged-Zen
__be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
				struct cb_sequenceres *res)
{
	struct nfs_client *clp;
	int i;
	__be32 status;

	status = htonl(NFS4ERR_BADSESSION);
	clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid);
	if (clp == NULL)
		goto out;

	status = validate_seqid(&clp->cl_session->bc_slot_table, args);
	if (status)
		goto out_putclient;

	/*
	 * Check for pending referring calls.  If a match is found, a
	 * related callback was received before the response to the original
	 * call.
	 */
	if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) {
		status = htonl(NFS4ERR_DELAY);
		goto out_putclient;
	}

	memcpy(&res->csr_sessionid, &args->csa_sessionid,
	       sizeof(res->csr_sessionid));
	res->csr_sequenceid = args->csa_sequenceid;
	res->csr_slotid = args->csa_slotid;
	res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
	res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;

out_putclient:
	nfs_put_client(clp);
out:
	for (i = 0; i < args->csa_nrclists; i++)
		kfree(args->csa_rclists[i].rcl_refcalls);
	kfree(args->csa_rclists);

	if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP))
		res->csr_status = 0;
	else
		res->csr_status = status;
	dprintk("%s: exit with status = %d res->csr_status %d\n", __func__,
		ntohl(status), ntohl(res->csr_status));
	return status;
}
コード例 #6
0
ファイル: callback_proc.c プロジェクト: Adjustxx/Savaged-Zen
__be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
{
	struct nfs_client *clp;
	struct nfs_delegation *delegation;
	struct nfs_inode *nfsi;
	struct inode *inode;

	res->bitmap[0] = res->bitmap[1] = 0;
	res->status = htonl(NFS4ERR_BADHANDLE);
	clp = nfs_find_client(args->addr, 4);
	if (clp == NULL)
		goto out;

	dprintk("NFS: GETATTR callback request from %s\n",
		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));

	inode = nfs_delegation_find_inode(clp, &args->fh);
	if (inode == NULL)
		goto out_putclient;
	nfsi = NFS_I(inode);
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
	if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
		goto out_iput;
	res->size = i_size_read(inode);
	res->change_attr = delegation->change_attr;
	if (nfsi->npages != 0)
		res->change_attr++;
	res->ctime = inode->i_ctime;
	res->mtime = inode->i_mtime;
	res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
		args->bitmap[0];
	res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
		args->bitmap[1];
	res->status = 0;
out_iput:
	rcu_read_unlock();
	iput(inode);
out_putclient:
	nfs_put_client(clp);
out:
	dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status));
	return res->status;
}
コード例 #7
0
__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
{
	struct nfs_client *clp;
	struct inode *inode;
	__be32 res;
	
	res = htonl(NFS4ERR_BADHANDLE);
	clp = nfs_find_client(args->addr, 4);
	if (clp == NULL)
		goto out;

	dprintk("NFS: RECALL callback request from %s\n",
		rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));

	do {
		struct nfs_client *prev = clp;

		inode = nfs_delegation_find_inode(clp, &args->fh);
		if (inode != NULL) {
			/* Set up a helper thread to actually return the delegation */
			switch (nfs_async_inode_return_delegation(inode, &args->stateid,
								  nfs_validate_delegation_stateid(clp))) {
				case 0:
					res = 0;
					break;
				case -ENOENT:
					if (res != 0)
						res = htonl(NFS4ERR_BAD_STATEID);
					break;
				default:
					res = htonl(NFS4ERR_RESOURCE);
			}
			iput(inode);
		}
		clp = nfs_find_client_next(prev);
		nfs_put_client(prev);
	} while (clp != NULL);
out:
	dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
	return res;
}
コード例 #8
0
ファイル: nfs3proc.c プロジェクト: a342604203/nfs
int migrate_nfs_update_server(struct nfs_server *server, const char *hostname,
                              struct sockaddr *sap, size_t salen, struct net *net)
{
    struct nfs_client *clp = server->nfs_client;
    struct rpc_clnt *clnt = server->client;
    struct xprt_create xargs = {
        .ident		= clp->cl_proto,
        .net		= net,
        .dstaddr	= sap,
        .addrlen	= salen,
        .servername	= hostname,
    };
    char buf[INET6_ADDRSTRLEN + 1];
    struct sockaddr_storage address;
    struct sockaddr *localaddr = (struct sockaddr *)&address;
    int error;

    dfprintk(MOUNT, "zql: --> %s: move FSID %llx:%llx to \"%s\")\n", __func__,
             (unsigned long long)server->fsid.major,
             (unsigned long long)server->fsid.minor,
             hostname);

    error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
    if (error != 0) {
        dfprintk(MOUNT, "zql: <-- %s(): rpc_switch_client_transport returned %d\n",
                 __func__, error);
        goto out;
    }

    error = rpc_localaddr(clnt, localaddr, sizeof(address));
    if (error != 0) {
        dfprintk(MOUNT, "zql: <-- %s(): rpc_localaddr returned %d\n",
                 __func__, error);
        goto out;
    }

    error = -EAFNOSUPPORT;
    if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0) {
        dfprintk(MOUNT, "zql: <-- %s(): rpc_ntop returned %d\n",
                 __func__, error);
        goto out;
    }

    nfs_server_remove_lists(server);
    error = migrate_nfs_set_client(server, hostname, sap, salen, buf,
                                   clp->cl_rpcclient->cl_auth->au_flavor,
                                   clp->cl_proto, clnt->cl_timeout,
                                   clp->cl_minorversion, net);
    nfs_put_client(clp);
    if (error != 0) {
        nfs_server_insert_lists(server);
        dfprintk(MOUNT, "zql: <-- %s(): nfs4_set_client returned %d\n",
                 __func__, error);
        goto out;
    }

    if (server->nfs_client->cl_hostname == NULL)
        server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
    nfs_server_insert_lists(server);

    error = migrate_nfs_probe_destination(server);
    if (error < 0) {
        dfprintk(MOUNT, "zql: error in migrate_nfs_probe_destination\n");
        goto out;
    }

    dfprintk(MOUNT, "zql: <-- %s() succeeded\n", __func__);

out:
    dfprintk(MOUNT, "zql: error in %s()\n", __func__);
    return error;
}

static void zql_update_server(struct nfs_server *server)
{
    /*
     * we do not have to free server,
     * instead, we only update struct nfs_server.
     */
    //nfs_free_server(server);
    /* free old nfs_client, though we can leave it there and use it when switch back */
    //server->nfs_client->rpc_ops->free_client(server->nfs_client);
    //struct nfs_server parent_server;
    //struct nfs_client *parent_client;
    //struct nfs_subversion *nfs_mod;
    struct nfs_parsed_mount_data *parsed;

    //char raw_data[] = "addr=162.105.146.169,vers=3,proto=tcp,mountvers=3,mountproto=udp,mountport=20048";

    /* keep old server parameter, copy original server to a temporary parameter */
    //parent_server = *server;
    //parent_client = parent_server.nfs_client;

    /* generate nfs_parsed_mount_data */
    parsed = nfs_alloc_parsed_mount_data();
    if (parsed == NULL)
        dfprintk(MOUNT, "zql: nfs_alloc_parsed_mount_data error\n");
    /* init nfs_parsed_mount_data */
    if (nfs_zql_control == 168)
        migrate_nfs_validate_text_mount_data168(/*raw_data, */parsed/*, dev_name*/);
    else if (nfs_zql_control == 169)
        migrate_nfs_validate_text_mount_data169(parsed);
    else
        dfprintk(MOUNT, "zql: nfs_zql_control error\n");

    migrate_nfs_update_server(server, parsed->nfs_server.hostname, (struct sockaddr *)&parsed->nfs_server.address,
                              parsed->nfs_server.addrlen, parsed->net);

    /*nfs_mod = get_nfs_version(parsed->version);
    if (IS_ERR(nfs_mod))
    	dfprintk(MOUNT, "zql: get_nfs_version error\n");*/
    /* init server->nfs_client */
    //migrate_nfs_set_client(server, parsed, nfs_mod, parent_server.client->cl_timeout);

    //nfs_init_server_rpcclient(server, parent_server.client->cl_timeout, parsed->selected_flavor);

    //put_nfs_version(nfs_mod);

    nfs_free_parsed_mount_data(parsed);

    return;
}

static void zql_control_test(struct nfs_server *server)
{
    if (nfs_zql_control == 5 || nfs_zql_control == 168
            || nfs_zql_control == 169) {
        dfprintk(MOUNT, "zql: control start ... %d\n", nfs_zql_control);
        while (nfs_zql_control == 5) {
            msleep_interruptible(500);
        }
        if (nfs_zql_control == 168 || nfs_zql_control == 169) {
            spin_lock(&zql_switch_status);
            if (switch_status == 0) {
                switch_status = 1;
                spin_unlock(&zql_switch_status);
                dfprintk(MOUNT, "zql: switch succeed\n");
                dfprintk(MOUNT, "zql: start update server\n");
                zql_update_server(server);
                switch_status = 0;
                nfs_zql_control = 10;
                dfprintk(MOUNT, "zql: update server done\n");
            } else {
                spin_unlock(&zql_switch_status);
                dfprintk(MOUNT, "zql: switch_status check\n");
                while (switch_status == 1) {
                    msleep_interruptible(100);
                }
                dfprintk(MOUNT, "zql: switch_status done\n");
            }
        }
        else if (nfs_zql_control == 4)
            dfprintk(MOUNT, "zql: switch failed\n");
        else
            dfprintk(MOUNT, "zql: unknown failure\n");
    }
}
/* zql code end */

static const struct inode_operations nfs3_dir_inode_operations = {
    .create		= nfs_create,
    .lookup		= nfs_lookup,
    .link		= nfs_link,
    .unlink		= nfs_unlink,
    .symlink	= nfs_symlink,
    .mkdir		= nfs_mkdir,
    .rmdir		= nfs_rmdir,
    .mknod		= nfs_mknod,
    .rename		= nfs_rename,
    .permission	= nfs_permission,
    .getattr	= nfs_getattr,
    .setattr	= nfs_setattr,
#ifdef CONFIG_NFS_V3_ACL
    .listxattr	= nfs3_listxattr,
    .getxattr	= generic_getxattr,
    .setxattr	= generic_setxattr,
    .removexattr	= generic_removexattr,
    .get_acl	= nfs3_get_acl,
    .set_acl	= nfs3_set_acl,
#endif
};

static const struct inode_operations nfs3_file_inode_operations = {
    .permission	= nfs_permission,
    .getattr	= nfs_getattr,
    .setattr	= nfs_setattr,
#ifdef CONFIG_NFS_V3_ACL
    .listxattr	= nfs3_listxattr,
    .getxattr	= generic_getxattr,
    .setxattr	= generic_setxattr,
    .removexattr	= generic_removexattr,
    .get_acl	= nfs3_get_acl,
    .set_acl	= nfs3_set_acl,
#endif
};

const struct nfs_rpc_ops nfs_v3_clientops = {
    .version	= 3,			/* protocol version */
    .dentry_ops	= &nfs_dentry_operations,
    .dir_inode_ops	= &nfs3_dir_inode_operations,
    .file_inode_ops	= &nfs3_file_inode_operations,
    .file_ops	= &nfs_file_operations,
    .getroot	= nfs3_proc_get_root,
    .submount	= nfs_submount,
    .try_mount	= nfs_try_mount,
    .getattr	= nfs3_proc_getattr,
    .setattr	= nfs3_proc_setattr,
    .lookup		= nfs3_proc_lookup,
    .access		= nfs3_proc_access,
    .readlink	= nfs3_proc_readlink,
    .create		= nfs3_proc_create,
    .remove		= nfs3_proc_remove,
    .unlink_setup	= nfs3_proc_unlink_setup,
    .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare,
    .unlink_done	= nfs3_proc_unlink_done,
    .rename_setup	= nfs3_proc_rename_setup,
    .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare,
    .rename_done	= nfs3_proc_rename_done,
    .link		= nfs3_proc_link,
    .symlink	= nfs3_proc_symlink,
    .mkdir		= nfs3_proc_mkdir,
    .rmdir		= nfs3_proc_rmdir,
    .readdir	= nfs3_proc_readdir,
    .mknod		= nfs3_proc_mknod,
    .statfs		= nfs3_proc_statfs,
    .fsinfo		= nfs3_proc_fsinfo,
    .pathconf	= nfs3_proc_pathconf,
    .decode_dirent	= nfs3_decode_dirent,
    .pgio_rpc_prepare = nfs3_proc_pgio_rpc_prepare,
    .read_setup	= nfs3_proc_read_setup,
    .read_done	= nfs3_read_done,
    .write_setup	= nfs3_proc_write_setup,
    .write_done	= nfs3_write_done,
    .commit_setup	= nfs3_proc_commit_setup,
    .commit_rpc_prepare = nfs3_proc_commit_rpc_prepare,
    .commit_done	= nfs3_commit_done,
    .lock		= nfs3_proc_lock,
    .clear_acl_cache = forget_all_cached_acls,
    .close_context	= nfs_close_context,
    .have_delegation = nfs3_have_delegation,
    .return_delegation = nfs3_return_delegation,
    .alloc_client	= nfs_alloc_client,
    .init_client	= nfs_init_client,
    .free_client	= nfs_free_client,
    .create_server	= nfs3_create_server,
    .clone_server	= nfs3_clone_server,
};
コード例 #9
0
ファイル: nfs4client.c プロジェクト: AICP/kernel_moto_shamu
/**
 * nfs4_init_client - Initialise an NFS4 client record
 *
 * @clp: nfs_client to initialise
 * @timeparms: timeout parameters for underlying RPC transport
 * @ip_addr: callback IP address in presentation format
 * @authflavor: authentication flavor for underlying RPC transport
 *
 * Returns pointer to an NFS client, or an ERR_PTR value.
 */
struct nfs_client *nfs4_init_client(struct nfs_client *clp,
				    const struct rpc_timeout *timeparms,
				    const char *ip_addr,
				    rpc_authflavor_t authflavour)
{
	char buf[INET6_ADDRSTRLEN + 1];
	struct nfs_client *old;
	int error;

	if (clp->cl_cons_state == NFS_CS_READY) {
		/* the client is initialised already */
		dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
		return clp;
	}

	/* Check NFS protocol revision and initialize RPC op vector */
	clp->rpc_ops = &nfs_v4_clientops;

	if (clp->cl_minorversion != 0)
		__set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
	__set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
	error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
	if (error == -EINVAL)
		error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX);
	if (error < 0)
		goto error;

	/* If no clientaddr= option was specified, find a usable cb address */
	if (ip_addr == NULL) {
		struct sockaddr_storage cb_addr;
		struct sockaddr *sap = (struct sockaddr *)&cb_addr;

		error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
		if (error < 0)
			goto error;
		error = rpc_ntop(sap, buf, sizeof(buf));
		if (error < 0)
			goto error;
		ip_addr = (const char *)buf;
	}
	strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));

	error = nfs_idmap_new(clp);
	if (error < 0) {
		dprintk("%s: failed to create idmapper. Error = %d\n",
			__func__, error);
		goto error;
	}
	__set_bit(NFS_CS_IDMAP, &clp->cl_res_state);

	error = nfs4_init_client_minor_version(clp);
	if (error < 0)
		goto error;

	if (!nfs4_has_session(clp))
		nfs_mark_client_ready(clp, NFS_CS_READY);

	error = nfs4_discover_server_trunking(clp, &old);
	if (error < 0)
		goto error;

	if (clp != old)
		clp->cl_preserve_clid = true;
	nfs_put_client(clp);
	return old;

error:
	nfs_mark_client_ready(clp, error);
	nfs_put_client(clp);
	dprintk("<-- nfs4_init_client() = xerror %d\n", error);
	return ERR_PTR(error);
}
コード例 #10
0
ファイル: callback_xdr.c プロジェクト: AshishNamdev/linux
/*
 * Decode, process and encode a COMPOUND
 */
static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
{
	struct cb_compound_hdr_arg hdr_arg = { 0 };
	struct cb_compound_hdr_res hdr_res = { NULL };
	struct xdr_stream xdr_in, xdr_out;
	__be32 *p, status;
	struct cb_process_state cps = {
		.drc_status = 0,
		.clp = NULL,
		.net = SVC_NET(rqstp),
	};
	unsigned int nops = 0;

	dprintk("%s: start\n", __func__);

	xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);

	p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
	xdr_init_encode(&xdr_out, &rqstp->rq_res, p);

	status = decode_compound_hdr_arg(&xdr_in, &hdr_arg);
	if (status == htonl(NFS4ERR_RESOURCE))
		return rpc_garbage_args;

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

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

	while (status == 0 && nops != hdr_arg.nops) {
		status = process_op(nops, rqstp, &xdr_in,
				    argp, &xdr_out, resp, &cps);
		nops++;
	}

	/* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return
	* resource error in cb_compound status without returning op */
	if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) {
		status = htonl(NFS4ERR_RESOURCE);
		nops--;
	}

	*hdr_res.status = status;
	*hdr_res.nops = htonl(nops);
	nfs4_cb_free_slot(&cps);
	nfs_put_client(cps.clp);
	dprintk("%s: done, status = %u\n", __func__, ntohl(status));
	return rpc_success;

out_invalidcred:
	pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n");
	return rpc_autherr_badcred;
}

/*
 * Define NFS4 callback COMPOUND ops.
 */
static struct callback_op callback_ops[] = {
	[0] = {
		.res_maxsize = CB_OP_HDR_RES_MAXSZ,
	},