|
@@ -51,6 +51,78 @@
|
|
|
|
|
|
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
|
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
|
|
|
|
|
|
|
+static u32 nfsd_attrmask[] = {
|
|
|
|
+ NFSD_WRITEABLE_ATTRS_WORD0,
|
|
|
|
+ NFSD_WRITEABLE_ATTRS_WORD1,
|
|
|
|
+ NFSD_WRITEABLE_ATTRS_WORD2
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static u32 nfsd41_ex_attrmask[] = {
|
|
|
|
+ NFSD_SUPPATTR_EXCLCREAT_WORD0,
|
|
|
|
+ NFSD_SUPPATTR_EXCLCREAT_WORD1,
|
|
|
|
+ NFSD_SUPPATTR_EXCLCREAT_WORD2
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static __be32
|
|
|
|
+check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
|
|
+ u32 *bmval, u32 *writable)
|
|
|
|
+{
|
|
|
|
+ struct dentry *dentry = cstate->current_fh.fh_dentry;
|
|
|
|
+ struct svc_export *exp = cstate->current_fh.fh_export;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Check about attributes are supported by the NFSv4 server or not.
|
|
|
|
+ * According to spec, unsupported attributes return ERR_ATTRNOTSUPP.
|
|
|
|
+ */
|
|
|
|
+ if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) ||
|
|
|
|
+ (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) ||
|
|
|
|
+ (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion)))
|
|
|
|
+ return nfserr_attrnotsupp;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported
|
|
|
|
+ * in current environment or not.
|
|
|
|
+ */
|
|
|
|
+ if (bmval[0] & FATTR4_WORD0_ACL) {
|
|
|
|
+ if (!IS_POSIXACL(dentry->d_inode))
|
|
|
|
+ return nfserr_attrnotsupp;
|
|
|
|
+ }
|
|
|
|
+ if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) {
|
|
|
|
+ if (exp->ex_fslocs.locations == NULL)
|
|
|
|
+ return nfserr_attrnotsupp;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * According to spec, read-only attributes return ERR_INVAL.
|
|
|
|
+ */
|
|
|
|
+ if (writable) {
|
|
|
|
+ if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
|
|
|
|
+ (bmval[2] & ~writable[2]))
|
|
|
|
+ return nfserr_inval;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return nfs_ok;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static __be32
|
|
|
|
+nfsd4_check_open_attributes(struct svc_rqst *rqstp,
|
|
|
|
+ struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
|
|
|
|
+{
|
|
|
|
+ __be32 status = nfs_ok;
|
|
|
|
+
|
|
|
|
+ if (open->op_create == NFS4_OPEN_CREATE) {
|
|
|
|
+ if (open->op_createmode == NFS4_CREATE_UNCHECKED
|
|
|
|
+ || open->op_createmode == NFS4_CREATE_GUARDED)
|
|
|
|
+ status = check_attr_support(rqstp, cstate,
|
|
|
|
+ open->op_bmval, nfsd_attrmask);
|
|
|
|
+ else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1)
|
|
|
|
+ status = check_attr_support(rqstp, cstate,
|
|
|
|
+ open->op_bmval, nfsd41_ex_attrmask);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+
|
|
static inline void
|
|
static inline void
|
|
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
|
|
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
|
|
{
|
|
{
|
|
@@ -225,6 +297,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
if (status)
|
|
if (status)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
|
|
+ status = nfsd4_check_open_attributes(rqstp, cstate, open);
|
|
|
|
+ if (status)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
/* Openowner is now set, so sequence id will get bumped. Now we need
|
|
/* Openowner is now set, so sequence id will get bumped. Now we need
|
|
* these checks before we do any creates: */
|
|
* these checks before we do any creates: */
|
|
status = nfserr_grace;
|
|
status = nfserr_grace;
|
|
@@ -395,6 +471,11 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
if (status)
|
|
if (status)
|
|
return status;
|
|
return status;
|
|
|
|
|
|
|
|
+ status = check_attr_support(rqstp, cstate, create->cr_bmval,
|
|
|
|
+ nfsd_attrmask);
|
|
|
|
+ if (status)
|
|
|
|
+ return status;
|
|
|
|
+
|
|
switch (create->cr_type) {
|
|
switch (create->cr_type) {
|
|
case NF4LNK:
|
|
case NF4LNK:
|
|
/* ugh! we have to null-terminate the linktext, or
|
|
/* ugh! we have to null-terminate the linktext, or
|
|
@@ -689,6 +770,12 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
if (status)
|
|
if (status)
|
|
return status;
|
|
return status;
|
|
status = nfs_ok;
|
|
status = nfs_ok;
|
|
|
|
+
|
|
|
|
+ status = check_attr_support(rqstp, cstate, setattr->sa_bmval,
|
|
|
|
+ nfsd_attrmask);
|
|
|
|
+ if (status)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
if (setattr->sa_acl != NULL)
|
|
if (setattr->sa_acl != NULL)
|
|
status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
|
|
status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
|
|
setattr->sa_acl);
|
|
setattr->sa_acl);
|
|
@@ -763,10 +850,10 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|
if (status)
|
|
if (status)
|
|
return status;
|
|
return status;
|
|
|
|
|
|
- if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion))
|
|
|
|
- || (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion))
|
|
|
|
- || (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion)))
|
|
|
|
- return nfserr_attrnotsupp;
|
|
|
|
|
|
+ status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL);
|
|
|
|
+ if (status)
|
|
|
|
+ return status;
|
|
|
|
+
|
|
if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
|
|
if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
|
|
|| (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
|
|
|| (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
|
|
return nfserr_inval;
|
|
return nfserr_inval;
|