NFSv4: Use the open stateid if the delegation has the wrong mode
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Sat, 20 Apr 2013 05:25:45 +0000 (01:25 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Sat, 20 Apr 2013 05:39:42 +0000 (01:39 -0400)
Fix nfs4_select_rw_stateid() so that it chooses the open stateid
(or an all-zero stateid) if the delegation does not match the selected
read/write mode.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c

index 7ef19ce6d83262cc40c54410973e21303bd1441a..553a83cc41061fdd18d8b125d5e7b9ffaea8e99e 100644 (file)
@@ -144,6 +144,7 @@ struct nfs4_lock_state {
 enum {
        LK_STATE_IN_USE,
        NFS_DELEGATED_STATE,            /* Current stateid is delegation */
+       NFS_OPEN_STATE,                 /* OPEN stateid is set */
        NFS_O_RDONLY_STATE,             /* OPEN stateid has read-only state */
        NFS_O_WRONLY_STATE,             /* OPEN stateid has write-only state */
        NFS_O_RDWR_STATE,               /* OPEN stateid has read/write state */
index 282d9fa6994af716a44a0c9792a205f776713f95..39849360f9f6069e1c6f9156f2948c3649149b12 100644 (file)
@@ -978,6 +978,7 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *
        if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
                nfs4_stateid_copy(&state->stateid, stateid);
        nfs4_stateid_copy(&state->open_stateid, stateid);
+       set_bit(NFS_OPEN_STATE, &state->flags);
        switch (fmode) {
                case FMODE_READ:
                        set_bit(NFS_O_RDONLY_STATE, &state->flags);
index 1eb17285c99aef208f7954063e457d3a326758ee..b7796950eceb214e3d0d399d2bfae7379b05256c 100644 (file)
@@ -1024,12 +1024,16 @@ out:
 
 static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
 {
+       const nfs4_stateid *src;
        int ret;
        int seq;
 
        do {
+               src = &zero_stateid;
                seq = read_seqbegin(&state->seqlock);
-               nfs4_stateid_copy(dst, &state->stateid);
+               if (test_bit(NFS_OPEN_STATE, &state->flags))
+                       src = &state->open_stateid;
+               nfs4_stateid_copy(dst, src);
                ret = 0;
                smp_rmb();
                if (!list_empty(&state->owner->so_seqid.list))