Skip to content
Snippets Groups Projects
nfs4xdr.c 115 KiB
Newer Older
  • Learn to ignore specific revisions
  • Linus Torvalds's avatar
    Linus Torvalds committed
    	return 0;
    }
    
    static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
    {
    	uint32_t *p;
    
    
    	RESERVE_SPACE(8+sizeof(arg->stateid->data));
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	WRITE32(OP_OPEN_DOWNGRADE);
    
    	WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data));
    
    	WRITE32(arg->seqid->sequence->counter);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	encode_share_access(xdr, arg->open_flags);
    	return 0;
    }
    
    static int
    encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
    {
    	int len = fh->size;
    	uint32_t *p;
    
    	RESERVE_SPACE(8 + len);
    	WRITE32(OP_PUTFH);
    	WRITE32(len);
    	WRITEMEM(fh->data, len);
    
    	return 0;
    }
    
    static int encode_putrootfh(struct xdr_stream *xdr)
    {
            uint32_t *p;
            
            RESERVE_SPACE(4);
            WRITE32(OP_PUTROOTFH);
    
            return 0;
    }
    
    static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
    {
    	nfs4_stateid stateid;
    	uint32_t *p;
    
    	RESERVE_SPACE(16);
    	if (ctx->state != NULL) {
    		nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
    		WRITEMEM(stateid.data, sizeof(stateid.data));
    	} else
    		WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
    }
    
    static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(4);
    	WRITE32(OP_READ);
    
    	encode_stateid(xdr, args->context);
    
    	RESERVE_SPACE(12);
    	WRITE64(args->offset);
    	WRITE32(args->count);
    
    	return 0;
    }
    
    static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
    {
    	struct rpc_auth *auth = req->rq_task->tk_auth;
    
    	uint32_t attrs[2] = {
    		FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
    		FATTR4_WORD1_MOUNTED_ON_FILEID,
    	};
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int replen;
    	uint32_t *p;
    
    	RESERVE_SPACE(32+sizeof(nfs4_verifier));
    	WRITE32(OP_READDIR);
    	WRITE64(readdir->cookie);
    	WRITEMEM(readdir->verifier.data, sizeof(readdir->verifier.data));
    	WRITE32(readdir->count >> 1);  /* We're not doing readdirplus */
    	WRITE32(readdir->count);
    	WRITE32(2);
    
    	/* Switch to mounted_on_fileid if the server supports it */
    	if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
    		attrs[0] &= ~FATTR4_WORD0_FILEID;
    	else
    		attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
    	WRITE32(attrs[0] & readdir->bitmask[0]);
    	WRITE32(attrs[1] & readdir->bitmask[1]);
    
    	dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n",
    			__FUNCTION__,
    			(unsigned long long)readdir->cookie,
    			((u32 *)readdir->verifier.data)[0],
    			((u32 *)readdir->verifier.data)[1],
    			attrs[0] & readdir->bitmask[0],
    			attrs[1] & readdir->bitmask[1]);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/* set up reply kvec
    	 *    toplevel_status + taglen + rescount + OP_PUTFH + status
    	 *      + OP_READDIR + status + verifer(2)  = 9
    	 */
    	replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
    	xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
    			 readdir->pgbase, readdir->count);
    
    	dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
    			__FUNCTION__, replen, readdir->pages,
    			readdir->pgbase, readdir->count);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	return 0;
    }
    
    static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
    {
    	struct rpc_auth *auth = req->rq_task->tk_auth;
    	unsigned int replen;
    	uint32_t *p;
    
    	RESERVE_SPACE(4);
    	WRITE32(OP_READLINK);
    
    	/* set up reply kvec
    	 *    toplevel_status + taglen + rescount + OP_PUTFH + status
    	 *      + OP_READLINK + status + string length = 8
    	 */
    	replen = (RPC_REPHDRSIZE + auth->au_rslack + 8) << 2;
    	xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages,
    			readlink->pgbase, readlink->pglen);
    	
    	return 0;
    }
    
    static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(8 + name->len);
    	WRITE32(OP_REMOVE);
    	WRITE32(name->len);
    	WRITEMEM(name->name, name->len);
    
    	return 0;
    }
    
    static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(8 + oldname->len);
    	WRITE32(OP_RENAME);
    	WRITE32(oldname->len);
    	WRITEMEM(oldname->name, oldname->len);
    	
    	RESERVE_SPACE(4 + newname->len);
    	WRITE32(newname->len);
    	WRITEMEM(newname->name, newname->len);
    
    	return 0;
    }
    
    
    static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(12);
    	WRITE32(OP_RENEW);
    	WRITE64(client_stateid->cl_clientid);
    
    	return 0;
    }
    
    
    static int
    encode_restorefh(struct xdr_stream *xdr)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(4);
    	WRITE32(OP_RESTOREFH);
    
    	return 0;
    }
    
    
    static int
    encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(4+sizeof(zero_stateid.data));
    	WRITE32(OP_SETATTR);
    	WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
    	RESERVE_SPACE(2*4);
    	WRITE32(1);
    	WRITE32(FATTR4_WORD0_ACL);
    	if (arg->acl_len % 4)
    		return -EINVAL;
    	RESERVE_SPACE(4);
    	WRITE32(arg->acl_len);
    	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
    	return 0;
    }
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    static int
    encode_savefh(struct xdr_stream *xdr)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(4);
    	WRITE32(OP_SAVEFH);
    
    	return 0;
    }
    
    static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
    {
    	int status;
    	uint32_t *p;
    	
            RESERVE_SPACE(4+sizeof(arg->stateid.data));
            WRITE32(OP_SETATTR);
    	WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
    
            if ((status = encode_attrs(xdr, arg->iap, server)))
    		return status;
    
            return 0;
    }
    
    static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data));
    	WRITE32(OP_SETCLIENTID);
    	WRITEMEM(setclientid->sc_verifier->data, sizeof(setclientid->sc_verifier->data));
    
    	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
    	RESERVE_SPACE(4);
    	WRITE32(setclientid->sc_prog);
    	encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
    	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
    	RESERVE_SPACE(4);
    	WRITE32(setclientid->sc_cb_ident);
    
    	return 0;
    }
    
    
    static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
            uint32_t *p;
    
            RESERVE_SPACE(12 + sizeof(client_state->cl_confirm.data));
            WRITE32(OP_SETCLIENTID_CONFIRM);
            WRITE64(client_state->cl_clientid);
            WRITEMEM(client_state->cl_confirm.data, sizeof(client_state->cl_confirm.data));
    
            return 0;
    }
    
    static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(4);
    	WRITE32(OP_WRITE);
    
    	encode_stateid(xdr, args->context);
    
    	RESERVE_SPACE(16);
    	WRITE64(args->offset);
    	WRITE32(args->stable);
    	WRITE32(args->count);
    
    	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
    
    	return 0;
    }
    
    static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
    {
    	uint32_t *p;
    
    	RESERVE_SPACE(20);
    
    	WRITE32(OP_DELEGRETURN);
    	WRITEMEM(stateid->data, sizeof(stateid->data));
    	return 0;
    
    }
    /*
     * END OF "GENERIC" ENCODE ROUTINES.
     */
    
    /*
     * Encode an ACCESS request
     */
    static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	if ((status = encode_putfh(&xdr, args->fh)) == 0)
    		status = encode_access(&xdr, args->access);
    	return status;
    }
    
    /*
     * Encode LOOKUP request
     */
    static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 4,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
    		goto out;
    	if ((status = encode_lookup(&xdr, args->name)) != 0)
    		goto out;
    	if ((status = encode_getfh(&xdr)) != 0)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    out:
    	return status;
    }
    
    /*
     * Encode LOOKUP_ROOT request
     */
    static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 3,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	if ((status = encode_putrootfh(&xdr)) != 0)
    		goto out;
    	if ((status = encode_getfh(&xdr)) == 0)
    		status = encode_getfattr(&xdr, args->bitmask);
    out:
    	return status;
    }
    
    /*
     * Encode REMOVE request
     */
    static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    
    	if ((status = encode_putfh(&xdr, args->fh)) != 0)
    		goto out;
    	if ((status = encode_remove(&xdr, args->name)) != 0)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    out:
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    /*
     * Encode RENAME request
     */
    static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	if ((status = encode_putfh(&xdr, args->old_dir)) != 0)
    		goto out;
    	if ((status = encode_savefh(&xdr)) != 0)
    		goto out;
    	if ((status = encode_putfh(&xdr, args->new_dir)) != 0)
    		goto out;
    
    	if ((status = encode_rename(&xdr, args->old_name, args->new_name)) != 0)
    		goto out;
    	if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
    		goto out;
    	if ((status = encode_restorefh(&xdr)) != 0)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     * Encode LINK request
     */
    static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	if ((status = encode_putfh(&xdr, args->fh)) != 0)
    		goto out;
    	if ((status = encode_savefh(&xdr)) != 0)
    		goto out;
    	if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
    		goto out;
    
    	if ((status = encode_link(&xdr, args->name)) != 0)
    		goto out;
    	if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
    		goto out;
    	if ((status = encode_restorefh(&xdr)) != 0)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     * Encode CREATE request
     */
    static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
    		goto out;
    
    	if ((status = encode_savefh(&xdr)) != 0)
    		goto out;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if ((status = encode_create(&xdr, args)) != 0)
    		goto out;
    	if ((status = encode_getfh(&xdr)) != 0)
    		goto out;
    
    	if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
    		goto out;
    	if ((status = encode_restorefh(&xdr)) != 0)
    		goto out;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	status = encode_getfattr(&xdr, args->bitmask);
    out:
    	return status;
    }
    
    /*
     * Encode SYMLINK request
     */
    static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
    {
    	return nfs4_xdr_enc_create(req, p, args);
    }
    
    /*
     * Encode GETATTR request
     */
    static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	if ((status = encode_putfh(&xdr, args->fh)) == 0)
    		status = encode_getfattr(&xdr, args->bitmask);
    	return status;
    }
    
    /*
     * Encode a CLOSE request
     */
    static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
    {
            struct xdr_stream xdr;
            struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
            };
            int status;
    
            xdr_init_encode(&xdr, &req->rq_snd_buf, p);
            encode_compound_hdr(&xdr, &hdr);
            status = encode_putfh(&xdr, args->fh);
            if(status)
                    goto out;
            status = encode_close(&xdr, args);
    
    	if (status != 0)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
            return status;
    }
    
    /*
     * Encode an OPEN request
     */
    static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    
    	if (status)
    		goto out;
    	status = encode_savefh(&xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (status)
    		goto out;
    	status = encode_open(&xdr, args);
    	if (status)
    		goto out;
    	status = encode_getfh(&xdr);
    	if (status)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    	if (status)
    		goto out;
    	status = encode_restorefh(&xdr);
    	if (status)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     * Encode an OPEN_CONFIRM request
     */
    static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops   = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if(status)
    		goto out;
    	status = encode_open_confirm(&xdr, args);
    out:
    	return status;
    }
    
    /*
     * Encode an OPEN request with no attributes.
     */
    static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (status)
    		goto out;
    	status = encode_open(&xdr, args);
    
    	if (status)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     * Encode an OPEN_DOWNGRADE request
     */
    static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (status)
    		goto out;
    	status = encode_open_downgrade(&xdr, args);
    
    	if (status != 0)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     * Encode a LOCK request
     */
    
    static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_args *args)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops   = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if(status)
    		goto out;
    	status = encode_lock(&xdr, args);
    out:
    	return status;
    }
    
    /*
     * Encode a LOCKT request
     */
    
    static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockt_args *args)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops   = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if(status)
    		goto out;
    	status = encode_lockt(&xdr, args);
    out:
    	return status;
    }
    
    /*
     * Encode a LOCKU request
     */
    
    static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_locku_args *args)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops   = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if(status)
    		goto out;
    	status = encode_locku(&xdr, args);
    out:
    	return status;
    }
    
    /*
     * Encode a READLINK request
     */
    static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if(status)
    		goto out;
    	status = encode_readlink(&xdr, args, req);
    out:
    	return status;
    }
    
    /*
     * Encode a READDIR request
     */
    static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if(status)
    		goto out;
    	status = encode_readdir(&xdr, args, req);
    out:
    	return status;
    }
    
    /*
     * Encode a READ request
     */
    static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
    {
    	struct rpc_auth	*auth = req->rq_task->tk_auth;
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 2,
    	};
    	int replen, status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (status)
    		goto out;
    	status = encode_read(&xdr, args);
    	if (status)
    		goto out;
    
    	/* set up reply kvec
    	 *    toplevel status + taglen=0 + rescount + OP_PUTFH + status
    	 *       + OP_READ + status + eof + datalen = 9
    	 */
    	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2;
    	xdr_inline_pages(&req->rq_rcv_buf, replen,
    			 args->pages, args->pgbase, args->count);
    out:
    	return status;
    }
    
    /*
     * Encode an SETATTR request
     */
    static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
    
    {
            struct xdr_stream xdr;
            struct compound_hdr hdr = {
                    .nops   = 3,
            };
            int status;
    
            xdr_init_encode(&xdr, &req->rq_snd_buf, p);
            encode_compound_hdr(&xdr, &hdr);
            status = encode_putfh(&xdr, args->fh);
            if(status)
                    goto out;
            status = encode_setattr(&xdr, args, args->server);
            if(status)
                    goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    out:
            return status;
    }
    
    
    /*
     * Encode a GETACL request
     */
    static int
    nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,
    		struct nfs_getaclargs *args)
    {
    	struct xdr_stream xdr;
    	struct rpc_auth *auth = req->rq_task->tk_auth;
    	struct compound_hdr hdr = {
    		.nops   = 2,
    	};
    	int replen, status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (status)
    		goto out;
    	status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
    	/* set up reply buffer: */
    	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2;
    	xdr_inline_pages(&req->rq_rcv_buf, replen,
    		args->acl_pages, args->acl_pgbase, args->acl_len);
    out:
    	return status;
    }
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /*
     * Encode a WRITE request
     */
    static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (status)
    		goto out;
    	status = encode_write(&xdr, args);
    
    	if (status)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     *  a COMMIT request
     */
    static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (status)
    		goto out;
    	status = encode_commit(&xdr, args);
    
    	if (status)
    		goto out;
    	status = encode_getfattr(&xdr, args->bitmask);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out:
    	return status;
    }
    
    /*
     * FSINFO request
     */
    static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops	= 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (!status)
    		status = encode_fsinfo(&xdr, args->bitmask);
    	return status;
    }
    
    /*
     * a PATHCONF request
     */
    static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (!status)
    		status = encode_getattr_one(&xdr,
    				args->bitmask[0] & nfs4_pathconf_bitmap[0]);
    	return status;
    }
    
    /*
     * a STATFS request
     */
    static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, args->fh);
    	if (status == 0)
    		status = encode_getattr_two(&xdr,
    				args->bitmask[0] & nfs4_statfs_bitmap[0],
    				args->bitmask[1] & nfs4_statfs_bitmap[1]);
    	return status;
    }
    
    /*
     * GETATTR_BITMAP request
     */
    static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops = 2,
    	};
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_putfh(&xdr, fhandle);
    	if (status == 0)
    		status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
    				FATTR4_WORD0_LINK_SUPPORT|
    				FATTR4_WORD0_SYMLINK_SUPPORT|
    				FATTR4_WORD0_ACLSUPPORT);
    	return status;
    }
    
    /*
     * a RENEW request
     */
    
    static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops	= 1,
    	};
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	return encode_renew(&xdr, clp);
    }
    
    /*
     * a SETCLIENTID request
     */
    static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc)
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops	= 1,
    	};
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	return encode_setclientid(&xdr, sc);
    }
    
    /*
     * a SETCLIENTID_CONFIRM request
     */
    
    static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct xdr_stream xdr;
    	struct compound_hdr hdr = {
    		.nops	= 3,
    	};
    	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
    	int status;
    
    	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
    	encode_compound_hdr(&xdr, &hdr);
    	status = encode_setclientid_confirm(&xdr, clp);
    	if (!status)
    		status = encode_putrootfh(&xdr);
    	if (!status)
    		status = encode_fsinfo(&xdr, lease_bitmap);
    	return status;
    }
    
    /*
     * DELEGRETURN request
     */
    static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const struct nfs4_delegreturnargs *args)