Skip to content
Snippets Groups Projects
nfs4xdr.c 175 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	status = decode_compound_hdr(xdr, &hdr);
    
    	if (status)
    		goto out;
    
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    
    	status = decode_putfh(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    
    	status = decode_readdir(xdr, rqstp, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     * Decode Read response
     */
    
    static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
    			     struct nfs_readres *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (status)
    		goto out;
    
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    
    	status = decode_putfh(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    
    	status = decode_read(xdr, rqstp, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    		status = res->count;
    out:
    	return status;
    }
    
    /*
     * Decode WRITE response
     */
    
    static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
    			      struct nfs_writeres *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (status)
    		goto out;
    
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    
    	status = decode_putfh(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    
    	status = decode_write(xdr, res);
    
    	if (res->fattr)
    		decode_getfattr(xdr, res->fattr, res->server,
    				!RPC_IS_ASYNC(rqstp->rq_task));
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    		status = res->count;
    out:
    	return status;
    }
    
    /*
     * Decode COMMIT response
     */
    
    static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
    			       struct nfs_writeres *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (status)
    		goto out;
    
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    
    	status = decode_putfh(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    
    	status = decode_commit(xdr, res);
    
    	if (res->fattr)
    		decode_getfattr(xdr, res->fattr, res->server,
    				!RPC_IS_ASYNC(rqstp->rq_task));
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
    
     * Decode FSINFO response
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
    
    Benny Halevy's avatar
    Benny Halevy committed
    			       struct nfs4_fsinfo_res *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (!status)
    
    		status = decode_sequence(xdr, &res->seq_res, req);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_putfh(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_fsinfo(xdr, res->fsinfo);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    /*
    
     * Decode PATHCONF response
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
    
    				 struct nfs4_pathconf_res *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (!status)
    
    		status = decode_sequence(xdr, &res->seq_res, req);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_putfh(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_pathconf(xdr, res->pathconf);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    /*
    
     * Decode STATFS response
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
    
    Benny Halevy's avatar
    Benny Halevy committed
    			       struct nfs4_statfs_res *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (!status)
    
    		status = decode_sequence(xdr, &res->seq_res, req);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_putfh(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_statfs(xdr, res->fsstat);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    /*
    
     * Decode GETATTR_BITMAP response
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req,
    				    struct xdr_stream *xdr,
    				    struct nfs4_server_caps_res *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (status)
    		goto out;
    
    	status = decode_sequence(xdr, &res->seq_res, req);
    
    	if (status)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		goto out;
    
    	status = decode_putfh(xdr);
    	if (status)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		goto out;
    
    	status = decode_server_caps(xdr, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     * Decode RENEW response
     */
    
    static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
    			      void *__unused)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_renew(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    /*
    
     * Decode SETCLIENTID response
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
    				    struct xdr_stream *xdr,
    				    struct nfs4_setclientid_res *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_setclientid(xdr, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    /*
    
     * Decode SETCLIENTID_CONFIRM response
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
    					    struct xdr_stream *xdr,
    					    struct nfs_fsinfo *fsinfo)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_setclientid_confirm(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_putrootfh(xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!status)
    
    		status = decode_fsinfo(xdr, fsinfo);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    /*
    
     * Decode DELEGRETURN response
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
    				    struct xdr_stream *xdr,
    				    struct nfs4_delegreturnres *res)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	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)
    
    	status = decode_putfh(xdr);
    
    	if (status != 0)
    		goto out;
    
    	status = decode_delegreturn(xdr);
    
    	decode_getfattr(xdr, res->fattr, res->server,
    
    			!RPC_IS_ASYNC(rqstp->rq_task));
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    
     * Decode FS_LOCATIONS response
    
    static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
    				     struct xdr_stream *xdr,
    
    				     struct nfs4_fs_locations_res *res)
    
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (status)
    		goto out;
    
    	status = decode_sequence(xdr, &res->seq_res, req);
    
    	if (status)
    
    	status = decode_putfh(xdr);
    	if (status)
    
    	status = decode_lookup(xdr);
    	if (status)
    
    	xdr_enter_page(xdr, PAGE_SIZE);
    	status = decode_getfattr(xdr, &res->fs_locations->fattr,
    
    				 res->fs_locations->server,
    				 !RPC_IS_ASYNC(req->rq_task));
    
    /*
     * Decode SECINFO response
     */
    static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp,
    				struct xdr_stream *xdr,
    				struct nfs4_secinfo_res *res)
    {
    	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);
    	if (status)
    		goto out;
    out:
    	return status;
    }
    
    
    #if defined(CONFIG_NFS_V4_1)
    /*
    
     * Decode EXCHANGE_ID response
    
    static int nfs4_xdr_dec_exchange_id(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_exchange_id(xdr, res);
    
    	return status;
    }
    
     * Decode CREATE_SESSION response
    
    static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp,
    				       struct xdr_stream *xdr,
    
    				       struct nfs41_create_session_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	if (!status)
    
    		status = decode_create_session(xdr, res);
    
     * Decode DESTROY_SESSION response
    
    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);
    
     * Decode SEQUENCE response
    
    static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp,
    				 struct xdr_stream *xdr,
    
    Andy Adamson's avatar
    Andy Adamson committed
    				 struct nfs4_sequence_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    Andy Adamson's avatar
    Andy Adamson committed
    	if (!status)
    
    		status = decode_sequence(xdr, res, rqstp);
    
    Andy Adamson's avatar
    Andy Adamson committed
    	return status;
    }
    
    
    Andy Adamson's avatar
    Andy Adamson committed
    /*
    
     * Decode GET_LEASE_TIME response
    
    Andy Adamson's avatar
    Andy Adamson committed
     */
    
    static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp,
    				       struct xdr_stream *xdr,
    
    Andy Adamson's avatar
    Andy Adamson committed
    				       struct nfs4_get_lease_time_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    Andy Adamson's avatar
    Andy Adamson committed
    	if (!status)
    
    		status = decode_sequence(xdr, &res->lr_seq_res, rqstp);
    
    Andy Adamson's avatar
    Andy Adamson committed
    	if (!status)
    
    		status = decode_putrootfh(xdr);
    
    Andy Adamson's avatar
    Andy Adamson committed
    	if (!status)
    
    		status = decode_fsinfo(xdr, res->lr_fsinfo);
    
    Andy Adamson's avatar
    Andy Adamson committed
    	return status;
    }
    
    
    /*
     * Decode RECLAIM_COMPLETE response
     */
    
    static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
    					 struct xdr_stream *xdr,
    
    					 struct nfs41_reclaim_complete_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    		status = decode_sequence(xdr, &res->seq_res, rqstp);
    
    		status = decode_reclaim_complete(xdr, (void *)NULL);
    
    static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp,
    				      struct xdr_stream *xdr,
    
    				      struct nfs4_getdeviceinfo_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    
    	status = decode_getdeviceinfo(xdr, res->pdev);
    
    static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp,
    				  struct xdr_stream *xdr,
    
    				  struct nfs4_layoutget_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    
    	status = decode_compound_hdr(xdr, &hdr);
    
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    
    	status = decode_putfh(xdr);
    
    	status = decode_layoutget(xdr, rqstp, res);
    
    Benny Halevy's avatar
    Benny Halevy committed
    /*
     * Decode LAYOUTRETURN response
     */
    static int nfs4_xdr_dec_layoutreturn(struct rpc_rqst *rqstp,
    				     struct xdr_stream *xdr,
    				     struct nfs4_layoutreturn_res *res)
    {
    	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_layoutreturn(xdr, res);
    out:
    	return status;
    }
    
    
    Andy Adamson's avatar
    Andy Adamson committed
    /*
     * Decode LAYOUTCOMMIT response
     */
    static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
    				     struct xdr_stream *xdr,
    				     struct nfs4_layoutcommit_res *res)
    {
    	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_layoutcommit(xdr, rqstp, res);
    	if (status)
    		goto out;
    	decode_getfattr(xdr, res->fattr, res->server,
    			!RPC_IS_ASYNC(rqstp->rq_task));
    out:
    	return status;
    }
    
    
    /*
     * Decode SECINFO_NO_NAME response
     */
    static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,
    					struct xdr_stream *xdr,
    					struct nfs4_secinfo_res *res)
    {
    	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(xdr, res);
    out:
    	return status;
    }
    
    #endif /* CONFIG_NFS_V4_1 */
    
    
    /**
     * nfs4_decode_dirent - Decode a single NFSv4 directory entry stored in
     *                      the local page cache.
     * @xdr: XDR stream where entry resides
     * @entry: buffer to fill in with entry data
     * @plus: boolean indicating whether this should be a readdirplus entry
     *
     * Returns zero if successful, otherwise a negative errno value is
     * returned.
     *
     * This function is not invoked during READDIR reply decoding, but
     * rather whenever an application invokes the getdents(2) system call
     * on a directory already in our cache.
     */
    int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
    		       int plus)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	uint32_t bitmap[2] = {0};
    	uint32_t len;
    
    	__be32 *p = xdr_inline_decode(xdr, 4);
    	if (unlikely(!p))
    		goto out_overflow;
    
    	if (*p == xdr_zero) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		if (*p == xdr_zero)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		entry->eof = 1;
    
    		return -EBADCOOKIE;
    
    	p = xdr_inline_decode(xdr, 12);
    	if (unlikely(!p))
    		goto out_overflow;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	entry->prev_cookie = entry->cookie;
    	p = xdr_decode_hyper(p, &entry->cookie);
    
    	entry->len = be32_to_cpup(p);
    
    	p = xdr_inline_decode(xdr, entry->len);
    
    	if (unlikely(!p))
    		goto out_overflow;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	entry->name = (const char *) p;
    
    	/*
    	 * In case the server doesn't return an inode number,
    	 * we fake one here.  (We don't use inode number 0,
    	 * since glibc seems to choke on it...)
    	 */
    	entry->ino = 1;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	if (decode_attr_bitmap(xdr, bitmap) < 0)
    		goto out_overflow;
    
    	if (decode_attr_length(xdr, &len, &p) < 0)
    		goto out_overflow;
    
    
    	if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
    					entry->server, 1) < 0)
    
    		goto out_overflow;
    
    	if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
    		entry->ino = entry->fattr->mounted_on_fileid;
    	else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
    
    		entry->ino = entry->fattr->fileid;
    
    
    	entry->d_type = DT_UNKNOWN;
    	if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
    		entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
    
    
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /*
     * We need to translate between nfs status return values and
     * the local errno values which may not be the same.
     */
    static struct {
    	int stat;
    	int errno;
    } nfs_errtbl[] = {
    	{ NFS4_OK,		0		},
    
    	{ NFS4ERR_PERM,		-EPERM		},
    	{ NFS4ERR_NOENT,	-ENOENT		},
    	{ NFS4ERR_IO,		-errno_NFSERR_IO},
    	{ NFS4ERR_NXIO,		-ENXIO		},
    	{ NFS4ERR_ACCESS,	-EACCES		},
    	{ NFS4ERR_EXIST,	-EEXIST		},
    	{ NFS4ERR_XDEV,		-EXDEV		},
    	{ NFS4ERR_NOTDIR,	-ENOTDIR	},
    	{ NFS4ERR_ISDIR,	-EISDIR		},
    	{ NFS4ERR_INVAL,	-EINVAL		},
    	{ NFS4ERR_FBIG,		-EFBIG		},
    	{ NFS4ERR_NOSPC,	-ENOSPC		},
    	{ NFS4ERR_ROFS,		-EROFS		},
    	{ NFS4ERR_MLINK,	-EMLINK		},
    	{ NFS4ERR_NAMETOOLONG,	-ENAMETOOLONG	},
    	{ NFS4ERR_NOTEMPTY,	-ENOTEMPTY	},
    	{ NFS4ERR_DQUOT,	-EDQUOT		},
    	{ NFS4ERR_STALE,	-ESTALE		},
    	{ NFS4ERR_BADHANDLE,	-EBADHANDLE	},
    	{ NFS4ERR_BAD_COOKIE,	-EBADCOOKIE	},
    	{ NFS4ERR_NOTSUPP,	-ENOTSUPP	},
    	{ NFS4ERR_TOOSMALL,	-ETOOSMALL	},
    
    	{ NFS4ERR_SERVERFAULT,	-EREMOTEIO	},
    
    	{ NFS4ERR_BADTYPE,	-EBADTYPE	},
    	{ NFS4ERR_LOCKED,	-EAGAIN		},
    	{ NFS4ERR_SYMLINK,	-ELOOP		},
    	{ NFS4ERR_OP_ILLEGAL,	-EOPNOTSUPP	},
    	{ NFS4ERR_DEADLOCK,	-EDEADLK	},
    	{ -1,			-EIO		}
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    };
    
    /*
     * Convert an NFS error code to a local one.
     * This one is used jointly by NFSv2 and NFSv3.
     */
    static int
    
    nfs4_stat_to_errno(int stat)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	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. */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	/* 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.
    	 */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    #define PROC(proc, argtype, restype)				\
    [NFSPROC4_CLNT_##proc] = {					\
    	.p_proc   = NFSPROC4_COMPOUND,				\
    
    	.p_encode = (kxdreproc_t)nfs4_xdr_##argtype,		\
    
    	.p_decode = (kxdrdproc_t)nfs4_xdr_##restype,		\
    
    	.p_arglen = NFS4_##argtype##_sz,			\
    	.p_replen = NFS4_##restype##_sz,			\
    
    	.p_statidx = NFSPROC4_CLNT_##proc,			\
    	.p_name   = #proc,					\
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    struct rpc_procinfo	nfs4_procedures[] = {
    
    	PROC(READ,		enc_read,		dec_read),
    	PROC(WRITE,		enc_write,		dec_write),
    	PROC(COMMIT,		enc_commit,		dec_commit),
    	PROC(OPEN,		enc_open,		dec_open),
    	PROC(OPEN_CONFIRM,	enc_open_confirm,	dec_open_confirm),
    	PROC(OPEN_NOATTR,	enc_open_noattr,	dec_open_noattr),
    	PROC(OPEN_DOWNGRADE,	enc_open_downgrade,	dec_open_downgrade),
    	PROC(CLOSE,		enc_close,		dec_close),
    	PROC(SETATTR,		enc_setattr,		dec_setattr),
    	PROC(FSINFO,		enc_fsinfo,		dec_fsinfo),
    	PROC(RENEW,		enc_renew,		dec_renew),
    	PROC(SETCLIENTID,	enc_setclientid,	dec_setclientid),
    	PROC(SETCLIENTID_CONFIRM, enc_setclientid_confirm, dec_setclientid_confirm),
    	PROC(LOCK,		enc_lock,		dec_lock),
    	PROC(LOCKT,		enc_lockt,		dec_lockt),
    	PROC(LOCKU,		enc_locku,		dec_locku),
    	PROC(ACCESS,		enc_access,		dec_access),
    	PROC(GETATTR,		enc_getattr,		dec_getattr),
    	PROC(LOOKUP,		enc_lookup,		dec_lookup),
    	PROC(LOOKUP_ROOT,	enc_lookup_root,	dec_lookup_root),
    	PROC(REMOVE,		enc_remove,		dec_remove),
    	PROC(RENAME,		enc_rename,		dec_rename),
    	PROC(LINK,		enc_link,		dec_link),
    	PROC(SYMLINK,		enc_symlink,		dec_symlink),
    	PROC(CREATE,		enc_create,		dec_create),
    	PROC(PATHCONF,		enc_pathconf,		dec_pathconf),
    	PROC(STATFS,		enc_statfs,		dec_statfs),
    	PROC(READLINK,		enc_readlink,		dec_readlink),
    	PROC(READDIR,		enc_readdir,		dec_readdir),
    	PROC(SERVER_CAPS,	enc_server_caps,	dec_server_caps),
    	PROC(DELEGRETURN,	enc_delegreturn,	dec_delegreturn),
    	PROC(GETACL,		enc_getacl,		dec_getacl),
    	PROC(SETACL,		enc_setacl,		dec_setacl),
    	PROC(FS_LOCATIONS,	enc_fs_locations,	dec_fs_locations),
    	PROC(RELEASE_LOCKOWNER,	enc_release_lockowner,	dec_release_lockowner),
    
    	PROC(SECINFO,		enc_secinfo,		dec_secinfo),
    
    #if defined(CONFIG_NFS_V4_1)
    
    	PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
    	PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
    	PROC(DESTROY_SESSION,	enc_destroy_session,	dec_destroy_session),
    	PROC(SEQUENCE,		enc_sequence,		dec_sequence),
    	PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
    	PROC(RECLAIM_COMPLETE,	enc_reclaim_complete,	dec_reclaim_complete),
    	PROC(GETDEVICEINFO,	enc_getdeviceinfo,	dec_getdeviceinfo),
    	PROC(LAYOUTGET,		enc_layoutget,		dec_layoutget),
    
    Andy Adamson's avatar
    Andy Adamson committed
    	PROC(LAYOUTCOMMIT,	enc_layoutcommit,	dec_layoutcommit),
    
    Benny Halevy's avatar
    Benny Halevy committed
    	PROC(LAYOUTRETURN,	enc_layoutreturn,	dec_layoutreturn),
    
    	PROC(SECINFO_NO_NAME,	enc_secinfo_no_name,	dec_secinfo_no_name),
    
    #endif /* CONFIG_NFS_V4_1 */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    };
    
    struct rpc_version		nfs_version4 = {
    	.number			= 4,
    
    	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	.procs			= nfs4_procedures
    };
    
    /*
     * Local variables:
     *  c-basic-offset: 8
     * End:
     */