nfsd41: access_valid
authorAndy Adamson <andros@netapp.com>
Fri, 3 Apr 2009 05:28:53 +0000 (08:28 +0300)
committerJ. Bruce Fields <bfields@citi.umich.edu>
Sat, 4 Apr 2009 00:41:21 +0000 (17:41 -0700)
For nfs41, the open share flags are used also for
delegation "wants" and "signals".  Check that they are valid.

Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
include/linux/nfsd/xdr4.h

index 3fdcca53212a522f91f20dbc07c1155de00bc689..db208dd8fdca0e9fc8e47e24fa1f04473e592236 100644 (file)
@@ -910,6 +910,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
        resp->tag = args->tag;
        resp->opcnt = 0;
        resp->rqstp = rqstp;
+       resp->cstate.minorversion = args->minorversion;
        resp->cstate.replay_owner = NULL;
        fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
        fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
index d227f85b5ed2fa31e9dcf0efa0ca795b81f1531a..374aaf3808e8490eb930b4a455d43c8e2fc5d09a 100644 (file)
@@ -1943,11 +1943,21 @@ find_file(struct inode *ino)
        return NULL;
 }
 
-static inline int access_valid(u32 x)
+static inline int access_valid(u32 x, u32 minorversion)
 {
-       if (x < NFS4_SHARE_ACCESS_READ)
+       if ((x & NFS4_SHARE_ACCESS_MASK) < NFS4_SHARE_ACCESS_READ)
                return 0;
-       if (x > NFS4_SHARE_ACCESS_BOTH)
+       if ((x & NFS4_SHARE_ACCESS_MASK) > NFS4_SHARE_ACCESS_BOTH)
+               return 0;
+       x &= ~NFS4_SHARE_ACCESS_MASK;
+       if (minorversion && x) {
+               if ((x & NFS4_SHARE_WANT_MASK) > NFS4_SHARE_WANT_CANCEL)
+                       return 0;
+               if ((x & NFS4_SHARE_WHEN_MASK) > NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED)
+                       return 0;
+               x &= ~(NFS4_SHARE_WANT_MASK | NFS4_SHARE_WHEN_MASK);
+       }
+       if (x)
                return 0;
        return 1;
 }
@@ -2495,7 +2505,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
        __be32 status;
 
        status = nfserr_inval;
-       if (!access_valid(open->op_share_access)
+       if (!access_valid(open->op_share_access, resp->cstate.minorversion)
                        || !deny_valid(open->op_share_deny))
                goto out;
        /*
@@ -3104,7 +3114,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
                        (int)cstate->current_fh.fh_dentry->d_name.len,
                        cstate->current_fh.fh_dentry->d_name.name);
 
-       if (!access_valid(od->od_share_access)
+       if (!access_valid(od->od_share_access, cstate->minorversion)
                        || !deny_valid(od->od_share_deny))
                return nfserr_inval;
 
index b8b3dcba28cc4ec483d30be1513352320aa8b13e..5e16935a1eafd8bb5fb420dc7acecfa565795237 100644 (file)
@@ -53,6 +53,7 @@ struct nfsd4_compound_state {
        struct nfsd4_slot       *slot;
        __be32                  *statp;
        size_t                  iovlen;
+       u32                     minorversion;
        u32                     status;
 };