]> err.no Git - linux-2.6/blobdiff - fs/nfsd/nfs4state.c
Pull sn-features into release branch
[linux-2.6] / fs / nfsd / nfs4state.c
index 7694fb8aae356ffe9585b27a0cfcb2b5bb6c340f..b83f8fb441e15328ed9cff30099a7f637151124d 100644 (file)
@@ -1160,6 +1160,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
        stp->st_deny_bmap = 0;
        __set_bit(open->op_share_access, &stp->st_access_bmap);
        __set_bit(open->op_share_deny, &stp->st_deny_bmap);
+       stp->st_openstp = NULL;
 }
 
 static void
@@ -1988,14 +1989,11 @@ laundromat_main(void *not_used)
        queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
 }
 
-/* search ownerid_hashtbl[] and close_lru for stateid owner
- * (stateid->si_stateownerid)
- */
 static struct nfs4_stateowner *
-find_openstateowner_id(u32 st_id, int flags) {
+search_close_lru(u32 st_id, int flags)
+{
        struct nfs4_stateowner *local = NULL;
 
-       dprintk("NFSD: find_openstateowner_id %d\n", st_id);
        if (flags & CLOSE_STATE) {
                list_for_each_entry(local, &close_lru, so_close_lru) {
                        if (local->so_id == st_id)
@@ -2161,14 +2159,19 @@ out:
        return status;
 }
 
+static inline int
+setlkflg (int type)
+{
+       return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
+               RD_STATE : WR_STATE;
+}
 
 /* 
  * Checks for sequence id mutating operations. 
  */
 static int
-nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
+nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
 {
-       int status;
        struct nfs4_stateid *stp;
        struct nfs4_stateowner *sop;
 
@@ -2176,53 +2179,65 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
                        "stateid = (%08x/%08x/%08x/%08x)\n", seqid,
                stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
                stateid->si_generation);
-                               
+
        *stpp = NULL;
        *sopp = NULL;
 
-       status = nfserr_bad_stateid;
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
                printk("NFSD: preprocess_seqid_op: magic stateid!\n");
-               goto out;
+               return nfserr_bad_stateid;
        }
 
-       status = nfserr_stale_stateid;
        if (STALE_STATEID(stateid))
-               goto out;
+               return nfserr_stale_stateid;
        /*
        * We return BAD_STATEID if filehandle doesn't match stateid, 
        * the confirmed flag is incorrecly set, or the generation 
        * number is incorrect.  
-       * If there is no entry in the openfile table for this id, 
-       * we can't always return BAD_STATEID;
-       * this might be a retransmitted CLOSE which has arrived after 
-       * the openfile has been released.
        */
-       if (!(stp = find_stateid(stateid, flags)))
-               goto no_nfs4_stateid;
-
-       status = nfserr_bad_stateid;
+       stp = find_stateid(stateid, flags);
+       if (stp == NULL) {
+               /*
+                * Also, we should make sure this isn't just the result of
+                * a replayed close:
+                */
+               sop = search_close_lru(stateid->si_stateownerid, flags);
+               if (sop == NULL)
+                       return nfserr_bad_stateid;
+               *sopp = sop;
+               goto check_replay;
+       }
 
-       /* for new lock stateowners:
-        * check that the lock->v.new.open_stateid
-        * refers to an open stateowner
-        *
-        * check that the lockclid (nfs4_lock->v.new.clientid) is the same
-        * as the open_stateid->st_stateowner->so_client->clientid
-        */
-       if (lockclid) {
+       if (lock) {
                struct nfs4_stateowner *sop = stp->st_stateowner;
+               clientid_t *lockclid = &lock->v.new.clientid;
                struct nfs4_client *clp = sop->so_client;
+               int lkflg = 0;
+               int status;
+
+               lkflg = setlkflg(lock->lk_type);
+
+               if (lock->lk_is_new) {
+                       if (!sop->so_is_open_owner)
+                              return nfserr_bad_stateid;
+                       if (!cmp_clid(&clp->cl_clientid, lockclid))
+                              return nfserr_bad_stateid;
+                       /* stp is the open stateid */
+                       status = nfs4_check_openmode(stp, lkflg);
+                       if (status)
+                              return status;
+               } else {
+                       /* stp is the lock stateid */
+                       status = nfs4_check_openmode(stp->st_openstp, lkflg);
+                       if (status)
+                              return status;
+               }
 
-               if (!sop->so_is_open_owner)
-                       goto out;
-               if (!cmp_clid(&clp->cl_clientid, lockclid))
-                       goto out;
        }
 
        if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
                printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
-               goto out;
+               return nfserr_bad_stateid;
        }
 
        *stpp = stp;
@@ -2236,60 +2251,38 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
        if (seqid != sop->so_seqid)
                goto check_replay;
 
-       if (sop->so_confirmed) {
-               if (flags & CONFIRM) {
-                       printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
-                       goto out;
-               }
+       if (sop->so_confirmed && flags & CONFIRM) {
+               printk("NFSD: preprocess_seqid_op: expected"
+                               " unconfirmed stateowner!\n");
+               return nfserr_bad_stateid;
        }
-       else {
-               if (!(flags & CONFIRM)) {
-                       printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
-                       goto out;
-               }
+       if (!sop->so_confirmed && !(flags & CONFIRM)) {
+               printk("NFSD: preprocess_seqid_op: stateowner not"
+                               " confirmed yet!\n");
+               return nfserr_bad_stateid;
        }
        if (stateid->si_generation > stp->st_stateid.si_generation) {
                printk("NFSD: preprocess_seqid_op: future stateid?!\n");
-               goto out;
+               return nfserr_bad_stateid;
        }
 
-       status = nfserr_old_stateid;
        if (stateid->si_generation < stp->st_stateid.si_generation) {
                printk("NFSD: preprocess_seqid_op: old stateid!\n");
-               goto out;
+               return nfserr_old_stateid;
        }
        renew_client(sop->so_client);
-       status = nfs_ok;
-
-out:
-       return status;
-
-no_nfs4_stateid:
-
-       /*
-       * We determine whether this is a bad stateid or a replay, 
-       * starting by trying to look up the stateowner.
-       * If stateowner is not found - stateid is bad.
-       */
-       if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
-               printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
-               status = nfserr_bad_stateid;
-               goto out;
-       }
-       *sopp = sop;
+       return nfs_ok;
 
 check_replay:
        if (seqid == sop->so_seqid - 1) {
                printk("NFSD: preprocess_seqid_op: retransmission?\n");
                /* indicate replay to calling function */
-               status = NFSERR_REPLAY_ME;
-       } else  {
-               printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid, seqid);
-
-               *sopp = NULL;
-               status = nfserr_bad_seqid;
+               return NFSERR_REPLAY_ME;
        }
-       goto out;
+       printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+                       sop->so_seqid, seqid);
+       *sopp = NULL;
+       return nfserr_bad_seqid;
 }
 
 int
@@ -2666,6 +2659,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
        stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
        stp->st_access_bmap = open_stp->st_access_bmap;
        stp->st_deny_bmap = open_stp->st_deny_bmap;
+       stp->st_openstp = open_stp;
 
 out:
        return stp;
@@ -2721,8 +2715,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                                        lock->lk_new_open_seqid,
                                        &lock->lk_new_open_stateid,
                                        CHECK_FH | OPEN_STATE,
-                                       &open_sop, &open_stp,
-                                       &lock->v.new.clientid);
+                                       &open_sop, &open_stp, lock);
                if (status)
                        goto out;
                /* create lockowner and lock stateid */
@@ -2750,7 +2743,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                                       lock->lk_old_lock_seqid, 
                                       &lock->lk_old_lock_stateid, 
                                       CHECK_FH | LOCK_STATE, 
-                                      &lock->lk_stateowner, &lock_stp, NULL);
+                                      &lock->lk_stateowner, &lock_stp, lock);
                if (status)
                        goto out;
        }