|
@@ -37,6 +37,7 @@
|
|
|
#define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
|
|
|
#define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
|
|
|
#define NFS3_fattr_sz (21)
|
|
|
+#define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2)
|
|
|
#define NFS3_wcc_attr_sz (6)
|
|
|
#define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
|
|
|
#define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
|
|
@@ -59,7 +60,8 @@
|
|
|
#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
|
|
|
#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
|
|
|
#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
|
|
|
-#define NFS3_readdirargs_sz (NFS3_fh_sz+2)
|
|
|
+#define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3)
|
|
|
+#define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4)
|
|
|
#define NFS3_commitargs_sz (NFS3_fh_sz+3)
|
|
|
|
|
|
#define NFS3_attrstat_sz (1+NFS3_fattr_sz)
|
|
@@ -107,6 +109,22 @@ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
|
|
|
func, xdr->end - xdr->p);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * While encoding arguments, set up the reply buffer in advance to
|
|
|
+ * receive reply data directly into the page cache.
|
|
|
+ */
|
|
|
+static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
|
|
|
+ unsigned int base, unsigned int len,
|
|
|
+ unsigned int bufsize)
|
|
|
+{
|
|
|
+ struct rpc_auth *auth = req->rq_cred->cr_auth;
|
|
|
+ unsigned int replen;
|
|
|
+
|
|
|
+ replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
|
|
|
+ xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* Common NFS XDR functions as inlines
|
|
|
*/
|
|
@@ -153,7 +171,7 @@ out_overflow:
|
|
|
* Encode/decode time.
|
|
|
*/
|
|
|
static inline __be32 *
|
|
|
-xdr_encode_time3(__be32 *p, struct timespec *timep)
|
|
|
+xdr_encode_time3(__be32 *p, const struct timespec *timep)
|
|
|
{
|
|
|
*p++ = htonl(timep->tv_sec);
|
|
|
*p++ = htonl(timep->tv_nsec);
|
|
@@ -205,7 +223,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
|
|
|
}
|
|
|
|
|
|
static inline __be32 *
|
|
|
-xdr_encode_sattr(__be32 *p, struct iattr *attr)
|
|
|
+xdr_encode_sattr(__be32 *p, const struct iattr *attr)
|
|
|
{
|
|
|
if (attr->ia_valid & ATTR_MODE) {
|
|
|
*p++ = xdr_one;
|
|
@@ -306,6 +324,243 @@ xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
|
|
|
return xdr_decode_post_op_attr(p, fattr);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/*
|
|
|
+ * Encode/decode NFSv3 basic data types
|
|
|
+ *
|
|
|
+ * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
|
|
|
+ * "NFS Version 3 Protocol Specification".
|
|
|
+ *
|
|
|
+ * Not all basic data types have their own encoding and decoding
|
|
|
+ * functions. For run-time efficiency, some data types are encoded
|
|
|
+ * or decoded inline.
|
|
|
+ */
|
|
|
+
|
|
|
+static void encode_uint32(struct xdr_stream *xdr, u32 value)
|
|
|
+{
|
|
|
+ __be32 *p = xdr_reserve_space(xdr, 4);
|
|
|
+ *p = cpu_to_be32(value);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * filename3
|
|
|
+ *
|
|
|
+ * typedef string filename3<>;
|
|
|
+ */
|
|
|
+static void encode_filename3(struct xdr_stream *xdr,
|
|
|
+ const char *name, u32 length)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ BUG_ON(length > NFS3_MAXNAMLEN);
|
|
|
+ p = xdr_reserve_space(xdr, 4 + length);
|
|
|
+ xdr_encode_opaque(p, name, length);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * nfspath3
|
|
|
+ *
|
|
|
+ * typedef string nfspath3<>;
|
|
|
+ */
|
|
|
+static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
|
|
|
+ const u32 length)
|
|
|
+{
|
|
|
+ BUG_ON(length > NFS3_MAXPATHLEN);
|
|
|
+ encode_uint32(xdr, length);
|
|
|
+ xdr_write_pages(xdr, pages, 0, length);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * cookie3
|
|
|
+ *
|
|
|
+ * typedef uint64 cookie3
|
|
|
+ */
|
|
|
+static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
|
|
|
+{
|
|
|
+ return xdr_encode_hyper(p, cookie);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * cookieverf3
|
|
|
+ *
|
|
|
+ * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
|
|
|
+ */
|
|
|
+static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
|
|
|
+{
|
|
|
+ memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
|
|
|
+ return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * createverf3
|
|
|
+ *
|
|
|
+ * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
|
|
|
+ */
|
|
|
+static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
|
|
|
+ memcpy(p, verifier, NFS3_CREATEVERFSIZE);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * ftype3
|
|
|
+ *
|
|
|
+ * enum ftype3 {
|
|
|
+ * NF3REG = 1,
|
|
|
+ * NF3DIR = 2,
|
|
|
+ * NF3BLK = 3,
|
|
|
+ * NF3CHR = 4,
|
|
|
+ * NF3LNK = 5,
|
|
|
+ * NF3SOCK = 6,
|
|
|
+ * NF3FIFO = 7
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
|
|
|
+{
|
|
|
+ BUG_ON(type > NF3FIFO);
|
|
|
+ encode_uint32(xdr, type);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * specdata3
|
|
|
+ *
|
|
|
+ * struct specdata3 {
|
|
|
+ * uint32 specdata1;
|
|
|
+ * uint32 specdata2;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ p = xdr_reserve_space(xdr, 8);
|
|
|
+ *p++ = cpu_to_be32(MAJOR(rdev));
|
|
|
+ *p = cpu_to_be32(MINOR(rdev));
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * nfs_fh3
|
|
|
+ *
|
|
|
+ * struct nfs_fh3 {
|
|
|
+ * opaque data<NFS3_FHSIZE>;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ BUG_ON(fh->size > NFS3_FHSIZE);
|
|
|
+ p = xdr_reserve_space(xdr, 4 + fh->size);
|
|
|
+ xdr_encode_opaque(p, fh->data, fh->size);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * sattr3
|
|
|
+ *
|
|
|
+ * enum time_how {
|
|
|
+ * DONT_CHANGE = 0,
|
|
|
+ * SET_TO_SERVER_TIME = 1,
|
|
|
+ * SET_TO_CLIENT_TIME = 2
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * union set_mode3 switch (bool set_it) {
|
|
|
+ * case TRUE:
|
|
|
+ * mode3 mode;
|
|
|
+ * default:
|
|
|
+ * void;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * union set_uid3 switch (bool set_it) {
|
|
|
+ * case TRUE:
|
|
|
+ * uid3 uid;
|
|
|
+ * default:
|
|
|
+ * void;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * union set_gid3 switch (bool set_it) {
|
|
|
+ * case TRUE:
|
|
|
+ * gid3 gid;
|
|
|
+ * default:
|
|
|
+ * void;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * union set_size3 switch (bool set_it) {
|
|
|
+ * case TRUE:
|
|
|
+ * size3 size;
|
|
|
+ * default:
|
|
|
+ * void;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * union set_atime switch (time_how set_it) {
|
|
|
+ * case SET_TO_CLIENT_TIME:
|
|
|
+ * nfstime3 atime;
|
|
|
+ * default:
|
|
|
+ * void;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * union set_mtime switch (time_how set_it) {
|
|
|
+ * case SET_TO_CLIENT_TIME:
|
|
|
+ * nfstime3 mtime;
|
|
|
+ * default:
|
|
|
+ * void;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * struct sattr3 {
|
|
|
+ * set_mode3 mode;
|
|
|
+ * set_uid3 uid;
|
|
|
+ * set_gid3 gid;
|
|
|
+ * set_size3 size;
|
|
|
+ * set_atime atime;
|
|
|
+ * set_mtime mtime;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
|
|
|
+{
|
|
|
+ u32 nbytes;
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * In order to make only a single xdr_reserve_space() call,
|
|
|
+ * pre-compute the total number of bytes to be reserved.
|
|
|
+ * Six boolean values, one for each set_foo field, are always
|
|
|
+ * present in the encoded result, so start there.
|
|
|
+ */
|
|
|
+ nbytes = 6 * 4;
|
|
|
+ if (attr->ia_valid & ATTR_MODE)
|
|
|
+ nbytes += 4;
|
|
|
+ if (attr->ia_valid & ATTR_UID)
|
|
|
+ nbytes += 4;
|
|
|
+ if (attr->ia_valid & ATTR_GID)
|
|
|
+ nbytes += 4;
|
|
|
+ if (attr->ia_valid & ATTR_SIZE)
|
|
|
+ nbytes += 8;
|
|
|
+ if (attr->ia_valid & ATTR_ATIME_SET)
|
|
|
+ nbytes += 8;
|
|
|
+ if (attr->ia_valid & ATTR_MTIME_SET)
|
|
|
+ nbytes += 8;
|
|
|
+ p = xdr_reserve_space(xdr, nbytes);
|
|
|
+
|
|
|
+ xdr_encode_sattr(p, attr);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * diropargs3
|
|
|
+ *
|
|
|
+ * struct diropargs3 {
|
|
|
+ * nfs_fh3 dir;
|
|
|
+ * filename3 name;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
|
|
|
+ const char *name, u32 length)
|
|
|
+{
|
|
|
+ encode_nfs_fh3(xdr, fh);
|
|
|
+ encode_filename3(xdr, name, length);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* NFS encode functions
|
|
|
*/
|
|
@@ -321,6 +576,23 @@ nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.1 GETATTR3args
|
|
|
+ *
|
|
|
+ * struct GETATTR3args {
|
|
|
+ * nfs_fh3 object;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs_fh *fh)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_nfs_fh3(&xdr, fh);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode SETATTR arguments
|
|
|
*/
|
|
@@ -336,6 +608,49 @@ nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.2 SETATTR3args
|
|
|
+ *
|
|
|
+ * union sattrguard3 switch (bool check) {
|
|
|
+ * case TRUE:
|
|
|
+ * nfstime3 obj_ctime;
|
|
|
+ * case FALSE:
|
|
|
+ * void;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * struct SETATTR3args {
|
|
|
+ * nfs_fh3 object;
|
|
|
+ * sattr3 new_attributes;
|
|
|
+ * sattrguard3 guard;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_sattrguard3(struct xdr_stream *xdr,
|
|
|
+ const struct nfs3_sattrargs *args)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ if (args->guard) {
|
|
|
+ p = xdr_reserve_space(xdr, 4 + 8);
|
|
|
+ *p++ = xdr_one;
|
|
|
+ xdr_encode_time3(p, &args->guardtime);
|
|
|
+ } else {
|
|
|
+ p = xdr_reserve_space(xdr, 4);
|
|
|
+ *p = xdr_zero;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_sattrargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_nfs_fh3(&xdr, args->fh);
|
|
|
+ encode_sattr3(&xdr, args->sattr);
|
|
|
+ encode_sattrguard3(&xdr, args);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode directory ops argument
|
|
|
*/
|
|
@@ -348,6 +663,23 @@ nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.3 LOOKUP3args
|
|
|
+ *
|
|
|
+ * struct LOOKUP3args {
|
|
|
+ * diropargs3 what;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_diropargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_diropargs3(&xdr, args->fh, args->name, args->len);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode REMOVE argument
|
|
|
*/
|
|
@@ -372,6 +704,50 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.4 ACCESS3args
|
|
|
+ *
|
|
|
+ * struct ACCESS3args {
|
|
|
+ * nfs_fh3 object;
|
|
|
+ * uint32 access;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_access3args(struct xdr_stream *xdr,
|
|
|
+ const struct nfs3_accessargs *args)
|
|
|
+{
|
|
|
+ encode_nfs_fh3(xdr, args->fh);
|
|
|
+ encode_uint32(xdr, args->access);
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_accessargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_access3args(&xdr, args);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * 3.3.5 READLINK3args
|
|
|
+ *
|
|
|
+ * struct READLINK3args {
|
|
|
+ * nfs_fh3 symlink;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_readlinkargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_nfs_fh3(&xdr, args->fh);
|
|
|
+ prepare_reply_buffer(req, args->pages, args->pgbase,
|
|
|
+ args->pglen, NFS3_readlinkres_sz);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Arguments to a READ call. Since we read data directly into the page
|
|
|
* cache, we also set up the reply iovec here so that iov[1] points
|
|
@@ -397,6 +773,40 @@ nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.6 READ3args
|
|
|
+ *
|
|
|
+ * struct READ3args {
|
|
|
+ * nfs_fh3 file;
|
|
|
+ * offset3 offset;
|
|
|
+ * count3 count;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_read3args(struct xdr_stream *xdr,
|
|
|
+ const struct nfs_readargs *args)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ encode_nfs_fh3(xdr, args->fh);
|
|
|
+
|
|
|
+ p = xdr_reserve_space(xdr, 8 + 4);
|
|
|
+ p = xdr_encode_hyper(p, args->offset);
|
|
|
+ *p = cpu_to_be32(args->count);
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs_readargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_read3args(&xdr, args);
|
|
|
+ prepare_reply_buffer(req, args->pages, args->pgbase,
|
|
|
+ args->count, NFS3_readres_sz);
|
|
|
+ req->rq_rcv_buf.flags |= XDRBUF_READ;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Write arguments. Splice the buffer to be written into the iovec.
|
|
|
*/
|
|
@@ -419,6 +829,52 @@ nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.7 WRITE3args
|
|
|
+ *
|
|
|
+ * enum stable_how {
|
|
|
+ * UNSTABLE = 0,
|
|
|
+ * DATA_SYNC = 1,
|
|
|
+ * FILE_SYNC = 2
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * struct WRITE3args {
|
|
|
+ * nfs_fh3 file;
|
|
|
+ * offset3 offset;
|
|
|
+ * count3 count;
|
|
|
+ * stable_how stable;
|
|
|
+ * opaque data<>;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_write3args(struct xdr_stream *xdr,
|
|
|
+ const struct nfs_writeargs *args)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ encode_nfs_fh3(xdr, args->fh);
|
|
|
+
|
|
|
+ p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
|
|
|
+ p = xdr_encode_hyper(p, args->offset);
|
|
|
+ *p++ = cpu_to_be32(args->count);
|
|
|
+
|
|
|
+ BUG_ON(args->stable > NFS_FILE_SYNC);
|
|
|
+ *p++ = cpu_to_be32(args->stable);
|
|
|
+
|
|
|
+ *p = cpu_to_be32(args->count);
|
|
|
+ xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs_writeargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_write3args(&xdr, args);
|
|
|
+ xdr.buf->flags |= XDRBUF_WRITE;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode CREATE arguments
|
|
|
*/
|
|
@@ -439,6 +895,56 @@ nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *arg
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.8 CREATE3args
|
|
|
+ *
|
|
|
+ * enum createmode3 {
|
|
|
+ * UNCHECKED = 0,
|
|
|
+ * GUARDED = 1,
|
|
|
+ * EXCLUSIVE = 2
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * union createhow3 switch (createmode3 mode) {
|
|
|
+ * case UNCHECKED:
|
|
|
+ * case GUARDED:
|
|
|
+ * sattr3 obj_attributes;
|
|
|
+ * case EXCLUSIVE:
|
|
|
+ * createverf3 verf;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * struct CREATE3args {
|
|
|
+ * diropargs3 where;
|
|
|
+ * createhow3 how;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_createhow3(struct xdr_stream *xdr,
|
|
|
+ const struct nfs3_createargs *args)
|
|
|
+{
|
|
|
+ encode_uint32(xdr, args->createmode);
|
|
|
+ switch (args->createmode) {
|
|
|
+ case NFS3_CREATE_UNCHECKED:
|
|
|
+ case NFS3_CREATE_GUARDED:
|
|
|
+ encode_sattr3(xdr, args->sattr);
|
|
|
+ break;
|
|
|
+ case NFS3_CREATE_EXCLUSIVE:
|
|
|
+ encode_createverf3(xdr, args->verifier);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ BUG();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_createargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_diropargs3(&xdr, args->fh, args->name, args->len);
|
|
|
+ encode_createhow3(&xdr, args);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode MKDIR arguments
|
|
|
*/
|
|
@@ -452,6 +958,25 @@ nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.9 MKDIR3args
|
|
|
+ *
|
|
|
+ * struct MKDIR3args {
|
|
|
+ * diropargs3 where;
|
|
|
+ * sattr3 attributes;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_mkdirargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_diropargs3(&xdr, args->fh, args->name, args->len);
|
|
|
+ encode_sattr3(&xdr, args->sattr);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode SYMLINK arguments
|
|
|
*/
|
|
@@ -469,6 +994,37 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *a
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.10 SYMLINK3args
|
|
|
+ *
|
|
|
+ * struct symlinkdata3 {
|
|
|
+ * sattr3 symlink_attributes;
|
|
|
+ * nfspath3 symlink_data;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * struct SYMLINK3args {
|
|
|
+ * diropargs3 where;
|
|
|
+ * symlinkdata3 symlink;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_symlinkdata3(struct xdr_stream *xdr,
|
|
|
+ const struct nfs3_symlinkargs *args)
|
|
|
+{
|
|
|
+ encode_sattr3(xdr, args->sattr);
|
|
|
+ encode_nfspath3(xdr, args->pages, args->pathlen);
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_symlinkargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
|
|
|
+ encode_symlinkdata3(&xdr, args);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode MKNOD arguments
|
|
|
*/
|
|
@@ -488,6 +1044,86 @@ nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.11 MKNOD3args
|
|
|
+ *
|
|
|
+ * struct devicedata3 {
|
|
|
+ * sattr3 dev_attributes;
|
|
|
+ * specdata3 spec;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * union mknoddata3 switch (ftype3 type) {
|
|
|
+ * case NF3CHR:
|
|
|
+ * case NF3BLK:
|
|
|
+ * devicedata3 device;
|
|
|
+ * case NF3SOCK:
|
|
|
+ * case NF3FIFO:
|
|
|
+ * sattr3 pipe_attributes;
|
|
|
+ * default:
|
|
|
+ * void;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * struct MKNOD3args {
|
|
|
+ * diropargs3 where;
|
|
|
+ * mknoddata3 what;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_devicedata3(struct xdr_stream *xdr,
|
|
|
+ const struct nfs3_mknodargs *args)
|
|
|
+{
|
|
|
+ encode_sattr3(xdr, args->sattr);
|
|
|
+ encode_specdata3(xdr, args->rdev);
|
|
|
+}
|
|
|
+
|
|
|
+static void encode_mknoddata3(struct xdr_stream *xdr,
|
|
|
+ const struct nfs3_mknodargs *args)
|
|
|
+{
|
|
|
+ encode_ftype3(xdr, args->type);
|
|
|
+ switch (args->type) {
|
|
|
+ case NF3CHR:
|
|
|
+ case NF3BLK:
|
|
|
+ encode_devicedata3(xdr, args);
|
|
|
+ break;
|
|
|
+ case NF3SOCK:
|
|
|
+ case NF3FIFO:
|
|
|
+ encode_sattr3(xdr, args->sattr);
|
|
|
+ break;
|
|
|
+ case NF3REG:
|
|
|
+ case NF3DIR:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ BUG();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_mknodargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_diropargs3(&xdr, args->fh, args->name, args->len);
|
|
|
+ encode_mknoddata3(&xdr, args);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * 3.3.12 REMOVE3args
|
|
|
+ *
|
|
|
+ * struct REMOVE3args {
|
|
|
+ * diropargs3 object;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs_removeargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode RENAME arguments
|
|
|
*/
|
|
@@ -502,6 +1138,27 @@ nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.14 RENAME3args
|
|
|
+ *
|
|
|
+ * struct RENAME3args {
|
|
|
+ * diropargs3 from;
|
|
|
+ * diropargs3 to;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs_renameargs *args)
|
|
|
+{
|
|
|
+ const struct qstr *old = args->old_name;
|
|
|
+ const struct qstr *new = args->new_name;
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
|
|
|
+ encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode LINK arguments
|
|
|
*/
|
|
@@ -515,6 +1172,25 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.15 LINK3args
|
|
|
+ *
|
|
|
+ * struct LINK3args {
|
|
|
+ * nfs_fh3 file;
|
|
|
+ * diropargs3 link;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_linkargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_nfs_fh3(&xdr, args->fromfh);
|
|
|
+ encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode arguments to readdir call
|
|
|
*/
|
|
@@ -543,6 +1219,84 @@ nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *a
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.16 READDIR3args
|
|
|
+ *
|
|
|
+ * struct READDIR3args {
|
|
|
+ * nfs_fh3 dir;
|
|
|
+ * cookie3 cookie;
|
|
|
+ * cookieverf3 cookieverf;
|
|
|
+ * count3 count;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_readdir3args(struct xdr_stream *xdr,
|
|
|
+ const struct nfs3_readdirargs *args)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ encode_nfs_fh3(xdr, args->fh);
|
|
|
+
|
|
|
+ p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
|
|
|
+ p = xdr_encode_cookie3(p, args->cookie);
|
|
|
+ p = xdr_encode_cookieverf3(p, args->verf);
|
|
|
+ *p = cpu_to_be32(args->count);
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_readdirargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_readdir3args(&xdr, args);
|
|
|
+ prepare_reply_buffer(req, args->pages, 0,
|
|
|
+ args->count, NFS3_readdirres_sz);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * 3.3.17 READDIRPLUS3args
|
|
|
+ *
|
|
|
+ * struct READDIRPLUS3args {
|
|
|
+ * nfs_fh3 dir;
|
|
|
+ * cookie3 cookie;
|
|
|
+ * cookieverf3 cookieverf;
|
|
|
+ * count3 dircount;
|
|
|
+ * count3 maxcount;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_readdirplus3args(struct xdr_stream *xdr,
|
|
|
+ const struct nfs3_readdirargs *args)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ encode_nfs_fh3(xdr, args->fh);
|
|
|
+
|
|
|
+ p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
|
|
|
+ p = xdr_encode_cookie3(p, args->cookie);
|
|
|
+ p = xdr_encode_cookieverf3(p, args->verf);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * readdirplus: need dircount + buffer size.
|
|
|
+ * We just make sure we make dircount big enough
|
|
|
+ */
|
|
|
+ *p++ = cpu_to_be32(args->count >> 3);
|
|
|
+
|
|
|
+ *p = cpu_to_be32(args->count);
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_readdirargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_readdirplus3args(&xdr, args);
|
|
|
+ prepare_reply_buffer(req, args->pages, 0,
|
|
|
+ args->count, NFS3_readdirres_sz);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Decode the result of a readdir call.
|
|
|
* We just check for syntactical correctness.
|
|
@@ -674,6 +1428,37 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 3.3.21 COMMIT3args
|
|
|
+ *
|
|
|
+ * struct COMMIT3args {
|
|
|
+ * nfs_fh3 file;
|
|
|
+ * offset3 offset;
|
|
|
+ * count3 count;
|
|
|
+ * };
|
|
|
+ */
|
|
|
+static void encode_commit3args(struct xdr_stream *xdr,
|
|
|
+ const struct nfs_writeargs *args)
|
|
|
+{
|
|
|
+ __be32 *p;
|
|
|
+
|
|
|
+ encode_nfs_fh3(xdr, args->fh);
|
|
|
+
|
|
|
+ p = xdr_reserve_space(xdr, 8 + 4);
|
|
|
+ p = xdr_encode_hyper(p, args->offset);
|
|
|
+ *p = cpu_to_be32(args->count);
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs_writeargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_commit3args(&xdr, args);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_NFS_V3_ACL
|
|
|
/*
|
|
|
* Encode GETACL arguments
|
|
@@ -699,6 +1484,21 @@ nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_getaclargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_nfs_fh3(&xdr, args->fh);
|
|
|
+ encode_uint32(&xdr, args->mask);
|
|
|
+ if (args->mask & (NFS_ACL | NFS_DFACL))
|
|
|
+ prepare_reply_buffer(req, args->pages, 0,
|
|
|
+ NFSACL_MAXPAGES << PAGE_SHIFT,
|
|
|
+ ACL3_getaclres_sz);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Encode SETACL arguments
|
|
|
*/
|
|
@@ -731,6 +1531,33 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
|
|
|
NFS_ACL_DEFAULT);
|
|
|
return (err > 0) ? 0 : err;
|
|
|
}
|
|
|
+
|
|
|
+static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
|
|
|
+ const struct nfs3_setaclargs *args)
|
|
|
+{
|
|
|
+ struct xdr_stream xdr;
|
|
|
+ unsigned int base;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
|
|
+ encode_nfs_fh3(&xdr, NFS_FH(args->inode));
|
|
|
+ encode_uint32(&xdr, args->mask);
|
|
|
+ if (args->npages != 0)
|
|
|
+ xdr_write_pages(&xdr, args->pages, 0, args->len);
|
|
|
+
|
|
|
+ base = req->rq_slen;
|
|
|
+ error = nfsacl_encode(xdr.buf, base, args->inode,
|
|
|
+ (args->mask & NFS_ACL) ?
|
|
|
+ args->acl_access : NULL, 1, 0);
|
|
|
+ BUG_ON(error < 0);
|
|
|
+ error = nfsacl_encode(xdr.buf, base + error, args->inode,
|
|
|
+ (args->mask & NFS_DFACL) ?
|
|
|
+ args->acl_default : NULL, 1,
|
|
|
+ NFS_ACL_DEFAULT);
|
|
|
+ BUG_ON(error < 0);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
#endif /* CONFIG_NFS_V3_ACL */
|
|
|
|
|
|
/*
|