|
@@ -103,11 +103,6 @@ xdr_error: \
|
|
|
(x) = (u64)ntohl(*p++) << 32; \
|
|
|
(x) |= ntohl(*p++); \
|
|
|
} while (0)
|
|
|
-#define READTIME(x) do { \
|
|
|
- p++; \
|
|
|
- (x) = ntohl(*p++); \
|
|
|
- p++; \
|
|
|
-} while (0)
|
|
|
#define READMEM(x,nbytes) do { \
|
|
|
x = (char *)p; \
|
|
|
p += XDR_QUADLEN(nbytes); \
|
|
@@ -190,6 +185,15 @@ static int zero_clientid(clientid_t *clid)
|
|
|
return (clid->cl_boot == 0) && (clid->cl_id == 0);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * defer_free - mark an allocation as deferred freed
|
|
|
+ * @argp: NFSv4 compound argument structure to be freed with
|
|
|
+ * @release: release callback to free @p, typically kfree()
|
|
|
+ * @p: pointer to be freed
|
|
|
+ *
|
|
|
+ * Marks @p to be freed when processing the compound operation
|
|
|
+ * described in @argp finishes.
|
|
|
+ */
|
|
|
static int
|
|
|
defer_free(struct nfsd4_compoundargs *argp,
|
|
|
void (*release)(const void *), void *p)
|
|
@@ -206,6 +210,16 @@ defer_free(struct nfsd4_compoundargs *argp,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * savemem - duplicate a chunk of memory for later processing
|
|
|
+ * @argp: NFSv4 compound argument structure to be freed with
|
|
|
+ * @p: pointer to be duplicated
|
|
|
+ * @nbytes: length to be duplicated
|
|
|
+ *
|
|
|
+ * Returns a pointer to a copy of @nbytes bytes of memory at @p
|
|
|
+ * that are preserved until processing of the NFSv4 compound
|
|
|
+ * operation described by @argp finishes.
|
|
|
+ */
|
|
|
static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
|
|
|
{
|
|
|
if (p == argp->tmp) {
|
|
@@ -257,7 +271,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
|
|
int expected_len, len = 0;
|
|
|
u32 dummy32;
|
|
|
char *buf;
|
|
|
- int host_err;
|
|
|
|
|
|
DECODE_HEAD;
|
|
|
iattr->ia_valid = 0;
|
|
@@ -284,10 +297,9 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
|
|
return nfserr_resource;
|
|
|
|
|
|
*acl = nfs4_acl_new(nace);
|
|
|
- if (*acl == NULL) {
|
|
|
- host_err = -ENOMEM;
|
|
|
- goto out_nfserr;
|
|
|
- }
|
|
|
+ if (*acl == NULL)
|
|
|
+ return nfserr_jukebox;
|
|
|
+
|
|
|
defer_free(argp, kfree, *acl);
|
|
|
|
|
|
(*acl)->naces = nace;
|
|
@@ -425,10 +437,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
|
|
goto xdr_error;
|
|
|
|
|
|
DECODE_TAIL;
|
|
|
-
|
|
|
-out_nfserr:
|
|
|
- status = nfserrno(host_err);
|
|
|
- goto out;
|
|
|
}
|
|
|
|
|
|
static __be32
|
|
@@ -1957,56 +1965,16 @@ static u32 nfs4_file_type(umode_t mode)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-static __be32
|
|
|
-nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, kuid_t uid, kgid_t gid,
|
|
|
- __be32 **p, int *buflen)
|
|
|
-{
|
|
|
- int status;
|
|
|
-
|
|
|
- if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4)
|
|
|
- return nfserr_resource;
|
|
|
- if (whotype != NFS4_ACL_WHO_NAMED)
|
|
|
- status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1));
|
|
|
- else if (gid_valid(gid))
|
|
|
- status = nfsd_map_gid_to_name(rqstp, gid, (u8 *)(*p + 1));
|
|
|
- else
|
|
|
- status = nfsd_map_uid_to_name(rqstp, uid, (u8 *)(*p + 1));
|
|
|
- if (status < 0)
|
|
|
- return nfserrno(status);
|
|
|
- *p = xdr_encode_opaque(*p, NULL, status);
|
|
|
- *buflen -= (XDR_QUADLEN(status) << 2) + 4;
|
|
|
- BUG_ON(*buflen < 0);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static inline __be32
|
|
|
-nfsd4_encode_user(struct svc_rqst *rqstp, kuid_t user, __be32 **p, int *buflen)
|
|
|
-{
|
|
|
- return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, user, INVALID_GID,
|
|
|
- p, buflen);
|
|
|
-}
|
|
|
-
|
|
|
-static inline __be32
|
|
|
-nfsd4_encode_group(struct svc_rqst *rqstp, kgid_t group, __be32 **p, int *buflen)
|
|
|
-{
|
|
|
- return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, INVALID_UID, group,
|
|
|
- p, buflen);
|
|
|
-}
|
|
|
-
|
|
|
static inline __be32
|
|
|
nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace,
|
|
|
__be32 **p, int *buflen)
|
|
|
{
|
|
|
- kuid_t uid = INVALID_UID;
|
|
|
- kgid_t gid = INVALID_GID;
|
|
|
-
|
|
|
- if (ace->whotype == NFS4_ACL_WHO_NAMED) {
|
|
|
- if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
|
|
|
- gid = ace->who_gid;
|
|
|
- else
|
|
|
- uid = ace->who_uid;
|
|
|
- }
|
|
|
- return nfsd4_encode_name(rqstp, ace->whotype, uid, gid, p, buflen);
|
|
|
+ if (ace->whotype != NFS4_ACL_WHO_NAMED)
|
|
|
+ return nfs4_acl_write_who(ace->whotype, p, buflen);
|
|
|
+ else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
|
|
|
+ return nfsd4_encode_group(rqstp, ace->who_gid, p, buflen);
|
|
|
+ else
|
|
|
+ return nfsd4_encode_user(rqstp, ace->who_uid, p, buflen);
|
|
|
}
|
|
|
|
|
|
#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
|
|
@@ -2090,7 +2058,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
|
|
u32 bmval1 = bmval[1];
|
|
|
u32 bmval2 = bmval[2];
|
|
|
struct kstat stat;
|
|
|
- struct svc_fh tempfh;
|
|
|
+ struct svc_fh *tempfh = NULL;
|
|
|
struct kstatfs statfs;
|
|
|
int buflen = count << 2;
|
|
|
__be32 *attrlenp;
|
|
@@ -2137,11 +2105,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
|
|
goto out_nfserr;
|
|
|
}
|
|
|
if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
|
|
|
- fh_init(&tempfh, NFS4_FHSIZE);
|
|
|
- status = fh_compose(&tempfh, exp, dentry, NULL);
|
|
|
+ tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
|
|
|
+ status = nfserr_jukebox;
|
|
|
+ if (!tempfh)
|
|
|
+ goto out;
|
|
|
+ fh_init(tempfh, NFS4_FHSIZE);
|
|
|
+ status = fh_compose(tempfh, exp, dentry, NULL);
|
|
|
if (status)
|
|
|
goto out;
|
|
|
- fhp = &tempfh;
|
|
|
+ fhp = tempfh;
|
|
|
}
|
|
|
if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
|
|
|
| FATTR4_WORD0_SUPPORTED_ATTRS)) {
|
|
@@ -2222,8 +2194,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
|
|
if ((buflen -= 4) < 0)
|
|
|
goto out_resource;
|
|
|
dummy = nfs4_file_type(stat.mode);
|
|
|
- if (dummy == NF4BAD)
|
|
|
- goto out_serverfault;
|
|
|
+ if (dummy == NF4BAD) {
|
|
|
+ status = nfserr_serverfault;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
WRITE32(dummy);
|
|
|
}
|
|
|
if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
|
|
@@ -2317,8 +2291,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
|
|
WRITE32(ace->flag);
|
|
|
WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL);
|
|
|
status = nfsd4_encode_aclname(rqstp, ace, &p, &buflen);
|
|
|
- if (status == nfserr_resource)
|
|
|
- goto out_resource;
|
|
|
if (status)
|
|
|
goto out;
|
|
|
}
|
|
@@ -2379,8 +2351,6 @@ out_acl:
|
|
|
}
|
|
|
if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
|
|
|
status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen);
|
|
|
- if (status == nfserr_resource)
|
|
|
- goto out_resource;
|
|
|
if (status)
|
|
|
goto out;
|
|
|
}
|
|
@@ -2431,15 +2401,11 @@ out_acl:
|
|
|
}
|
|
|
if (bmval1 & FATTR4_WORD1_OWNER) {
|
|
|
status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen);
|
|
|
- if (status == nfserr_resource)
|
|
|
- goto out_resource;
|
|
|
if (status)
|
|
|
goto out;
|
|
|
}
|
|
|
if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
|
|
|
status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen);
|
|
|
- if (status == nfserr_resource)
|
|
|
- goto out_resource;
|
|
|
if (status)
|
|
|
goto out;
|
|
|
}
|
|
@@ -2533,8 +2499,8 @@ out:
|
|
|
security_release_secctx(context, contextlen);
|
|
|
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
|
|
|
kfree(acl);
|
|
|
- if (fhp == &tempfh)
|
|
|
- fh_put(&tempfh);
|
|
|
+ if (tempfh)
|
|
|
+ fh_put(tempfh);
|
|
|
return status;
|
|
|
out_nfserr:
|
|
|
status = nfserrno(err);
|
|
@@ -2542,9 +2508,6 @@ out_nfserr:
|
|
|
out_resource:
|
|
|
status = nfserr_resource;
|
|
|
goto out;
|
|
|
-out_serverfault:
|
|
|
- status = nfserr_serverfault;
|
|
|
- goto out;
|
|
|
}
|
|
|
|
|
|
static inline int attributes_need_mount(u32 *bmval)
|
|
@@ -2621,17 +2584,14 @@ out_put:
|
|
|
static __be32 *
|
|
|
nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
|
|
|
{
|
|
|
- __be32 *attrlenp;
|
|
|
-
|
|
|
if (buflen < 6)
|
|
|
return NULL;
|
|
|
*p++ = htonl(2);
|
|
|
*p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
|
|
|
*p++ = htonl(0); /* bmval1 */
|
|
|
|
|
|
- attrlenp = p++;
|
|
|
+ *p++ = htonl(4); /* attribute length */
|
|
|
*p++ = nfserr; /* no htonl */
|
|
|
- *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
|
|
|
return p;
|
|
|
}
|
|
|
|
|
@@ -3244,7 +3204,7 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
|
|
|
|
|
|
if (rpcauth_get_gssinfo(pf, &info) == 0) {
|
|
|
supported++;
|
|
|
- RESERVE_SPACE(4 + 4 + info.oid.len + 4 + 4);
|
|
|
+ RESERVE_SPACE(4 + 4 + XDR_LEN(info.oid.len) + 4 + 4);
|
|
|
WRITE32(RPC_AUTH_GSS);
|
|
|
WRITE32(info.oid.len);
|
|
|
WRITEMEM(info.oid.data, info.oid.len);
|
|
@@ -3379,35 +3339,43 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
|
|
8 /* eir_clientid */ +
|
|
|
4 /* eir_sequenceid */ +
|
|
|
4 /* eir_flags */ +
|
|
|
- 4 /* spr_how */ +
|
|
|
- 8 /* spo_must_enforce, spo_must_allow */ +
|
|
|
- 8 /* so_minor_id */ +
|
|
|
- 4 /* so_major_id.len */ +
|
|
|
- (XDR_QUADLEN(major_id_sz) * 4) +
|
|
|
- 4 /* eir_server_scope.len */ +
|
|
|
- (XDR_QUADLEN(server_scope_sz) * 4) +
|
|
|
- 4 /* eir_server_impl_id.count (0) */);
|
|
|
+ 4 /* spr_how */);
|
|
|
|
|
|
WRITEMEM(&exid->clientid, 8);
|
|
|
WRITE32(exid->seqid);
|
|
|
WRITE32(exid->flags);
|
|
|
|
|
|
WRITE32(exid->spa_how);
|
|
|
+ ADJUST_ARGS();
|
|
|
+
|
|
|
switch (exid->spa_how) {
|
|
|
case SP4_NONE:
|
|
|
break;
|
|
|
case SP4_MACH_CRED:
|
|
|
+ /* spo_must_enforce, spo_must_allow */
|
|
|
+ RESERVE_SPACE(16);
|
|
|
+
|
|
|
/* spo_must_enforce bitmap: */
|
|
|
WRITE32(2);
|
|
|
WRITE32(nfs4_minimal_spo_must_enforce[0]);
|
|
|
WRITE32(nfs4_minimal_spo_must_enforce[1]);
|
|
|
/* empty spo_must_allow bitmap: */
|
|
|
WRITE32(0);
|
|
|
+
|
|
|
+ ADJUST_ARGS();
|
|
|
break;
|
|
|
default:
|
|
|
WARN_ON_ONCE(1);
|
|
|
}
|
|
|
|
|
|
+ RESERVE_SPACE(
|
|
|
+ 8 /* so_minor_id */ +
|
|
|
+ 4 /* so_major_id.len */ +
|
|
|
+ (XDR_QUADLEN(major_id_sz) * 4) +
|
|
|
+ 4 /* eir_server_scope.len */ +
|
|
|
+ (XDR_QUADLEN(server_scope_sz) * 4) +
|
|
|
+ 4 /* eir_server_impl_id.count (0) */);
|
|
|
+
|
|
|
/* The server_owner struct */
|
|
|
WRITE64(minor_id); /* Minor id */
|
|
|
/* major id */
|
|
@@ -3473,28 +3441,6 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static __be32
|
|
|
-nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, __be32 nfserr,
|
|
|
- struct nfsd4_destroy_session *destroy_session)
|
|
|
-{
|
|
|
- return nfserr;
|
|
|
-}
|
|
|
-
|
|
|
-static __be32
|
|
|
-nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
|
|
|
- struct nfsd4_free_stateid *free_stateid)
|
|
|
-{
|
|
|
- __be32 *p;
|
|
|
-
|
|
|
- if (nfserr)
|
|
|
- return nfserr;
|
|
|
-
|
|
|
- RESERVE_SPACE(4);
|
|
|
- *p++ = nfserr;
|
|
|
- ADJUST_ARGS();
|
|
|
- return nfserr;
|
|
|
-}
|
|
|
-
|
|
|
static __be32
|
|
|
nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
|
|
|
struct nfsd4_sequence *seq)
|
|
@@ -3593,8 +3539,8 @@ static nfsd4_enc nfsd4_enc_ops[] = {
|
|
|
[OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
|
|
|
[OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
|
|
|
[OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
|
|
|
- [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session,
|
|
|
- [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_free_stateid,
|
|
|
+ [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
|
|
|
+ [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
|
|
|
[OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
|
|
|
[OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop,
|
|
|
[OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
|