]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfsd/nfs4state.c
nfsd4: fix downgrade/lock logic
[mv-sheeva.git] / fs / nfsd / nfs4state.c
index 7ab572f9f3882dce8bb05c2cf491fcbeb62f82fe..69b266db7f5cf18cfb42f4e71e1e9973bd634711 100644 (file)
@@ -162,13 +162,22 @@ static struct list_head   ownerstr_hashtbl[OWNER_HASH_SIZE];
 static struct list_head file_hashtbl[FILE_HASH_SIZE];
 static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
 
-static inline void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
+static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
 {
        BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
        atomic_inc(&fp->fi_access[oflag]);
 }
 
-static inline void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
+static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
+{
+       if (oflag == O_RDWR) {
+               __nfs4_file_get_access(fp, O_RDONLY);
+               __nfs4_file_get_access(fp, O_WRONLY);
+       } else
+               __nfs4_file_get_access(fp, oflag);
+}
+
+static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
 {
        if (fp->fi_fds[oflag]) {
                fput(fp->fi_fds[oflag]);
@@ -176,7 +185,7 @@ static inline void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
        }
 }
 
-static inline void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
+static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
 {
        if (atomic_dec_and_test(&fp->fi_access[oflag])) {
                nfs4_file_put_fd(fp, O_RDWR);
@@ -184,6 +193,15 @@ static inline void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
        }
 }
 
+static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
+{
+       if (oflag == O_RDWR) {
+               __nfs4_file_put_access(fp, O_RDONLY);
+               __nfs4_file_put_access(fp, O_WRONLY);
+       } else
+               __nfs4_file_put_access(fp, oflag);
+}
+
 static struct nfs4_delegation *
 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
 {
@@ -2432,14 +2450,13 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
 static __be32
 nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
 {
-       u32 op_share_access, new_access;
+       u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
+       bool new_access;
        __be32 status;
 
-       set_access(&new_access, stp->st_access_bmap);
-       new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK;
-
+       new_access = !test_bit(op_share_access, &stp->st_access_bmap);
        if (new_access) {
-               status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access);
+               status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access);
                if (status)
                        return status;
        }
@@ -2452,7 +2469,6 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c
                return status;
        }
        /* remember the open */
-       op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
        __set_bit(op_share_access, &stp->st_access_bmap);
        __set_bit(open->op_share_deny, &stp->st_deny_bmap);
 
@@ -2965,7 +2981,6 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                                *filpp = find_readable_file(stp->st_file);
                        else
                                *filpp = find_writeable_file(stp->st_file);
-                       BUG_ON(!*filpp); /* assured by check_openmode */
                }
        }
        status = nfs_ok;
@@ -3421,11 +3436,9 @@ static inline void
 nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
 {
        struct nfs4_stateowner *sop;
-       unsigned int hval;
 
        if (fl->fl_lmops == &nfsd_posix_mng_ops) {
                sop = (struct nfs4_stateowner *) fl->fl_owner;
-               hval = lockownerid_hashval(sop->so_id);
                kref_get(&sop->so_ref);
                deny->ld_sop = sop;
                deny->ld_clientid = sop->so_client->cl_clientid;
@@ -3545,7 +3558,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct nfs4_stateowner *open_sop = NULL;
        struct nfs4_stateowner *lock_sop = NULL;
        struct nfs4_stateid *lock_stp;
-       struct file *filp;
+       struct nfs4_file *fp;
+       struct file *filp = NULL;
        struct file_lock file_lock;
        struct file_lock conflock;
        __be32 status = 0;
@@ -3575,7 +3589,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                 * lock stateid.
                 */
                struct nfs4_stateid *open_stp = NULL;
-               struct nfs4_file *fp;
                
                status = nfserr_stale_clientid;
                if (!nfsd4_has_session(cstate) &&
@@ -3618,6 +3631,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                if (status)
                        goto out;
                lock_sop = lock->lk_replay_owner;
+               fp = lock_stp->st_file;
        }
        /* lock->lk_replay_owner and lock_stp have been created or found */
 
@@ -3632,13 +3646,19 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        switch (lock->lk_type) {
                case NFS4_READ_LT:
                case NFS4_READW_LT:
-                       filp = find_readable_file(lock_stp->st_file);
+                       if (find_readable_file(lock_stp->st_file)) {
+                               nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ);
+                               filp = find_readable_file(lock_stp->st_file);
+                       }
                        file_lock.fl_type = F_RDLCK;
                        cmd = F_SETLK;
                break;
                case NFS4_WRITE_LT:
                case NFS4_WRITEW_LT:
-                       filp = find_writeable_file(lock_stp->st_file);
+                       if (find_writeable_file(lock_stp->st_file)) {
+                               nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE);
+                               filp = find_writeable_file(lock_stp->st_file);
+                       }
                        file_lock.fl_type = F_WRLCK;
                        cmd = F_SETLK;
                break;