[PATCH] nfsd4: simplify process-open1 logic
[sfrench/cifs-2.6.git] / fs / nfsd / nfs4state.c
index 92968c94c6e6aa79ac19523216a8d9d9f9b1a8ab..b92dc9e0897324640c3d728768674c461ff102f5 100644 (file)
@@ -624,7 +624,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
        cb->cb_ident = se->se_callback_ident;
        return;
 out_err:
-       printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
+       dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
                "will not receive delegations\n",
                clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
 
@@ -678,13 +678,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
        int                     status;
        char                    dname[HEXDIR_LEN];
        
-       status = nfserr_inval;
        if (!check_name(clname))
-               goto out;
+               return nfserr_inval;
 
        status = nfs4_make_rec_clidname(dname, &clname);
        if (status)
-               goto out;
+               return status;
 
        /* 
         * XXX The Duplicate Request Cache (DRC) has been checked (??)
@@ -1160,6 +1159,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
@@ -1178,7 +1178,6 @@ release_stateid(struct nfs4_stateid *stp, int flags)
                locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
        put_nfs4_file(stp->st_file);
        kmem_cache_free(stateid_slab, stp);
-       stp = NULL;
 }
 
 static void
@@ -1191,22 +1190,6 @@ move_to_close_lru(struct nfs4_stateowner *sop)
        sop->so_time = get_seconds();
 }
 
-static void
-release_state_owner(struct nfs4_stateid *stp, int flag)
-{
-       struct nfs4_stateowner *sop = stp->st_stateowner;
-
-       dprintk("NFSD: release_state_owner\n");
-       release_stateid(stp, flag);
-
-       /* place unused nfs4_stateowners on so_close_lru list to be
-        * released by the laundromat service after the lease period
-        * to enable us to handle CLOSE replay
-        */
-       if (sop->so_confirmed && list_empty(&sop->so_stateids))
-               move_to_close_lru(sop);
-}
-
 static int
 cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) {
        return ((sop->so_owner.len == owner->len) && 
@@ -1295,7 +1278,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
        fp = find_file(ino);
        if (!fp)
                return nfs_ok;
-       ret = nfserr_share_denied;
+       ret = nfserr_locked;
        /* Search for conflicting share reservations */
        list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
                if (test_bit(deny_type, &stp->st_deny_bmap) ||
@@ -1446,94 +1429,61 @@ static struct lock_manager_operations nfsd_lease_mng_ops = {
 };
 
 
-/*
- * nfsd4_process_open1()
- *     lookup stateowner.
- *             found:
- *                     check confirmed 
- *                             confirmed:
- *                                     check seqid
- *                             not confirmed:
- *                                     delete owner
- *                                     create new owner
- *             notfound:
- *                     verify clientid
- *                     create new owner
- *
- * called with nfs4_lock_state() held.
- */
 int
 nfsd4_process_open1(struct nfsd4_open *open)
 {
-       int status;
        clientid_t *clientid = &open->op_clientid;
        struct nfs4_client *clp = NULL;
        unsigned int strhashval;
        struct nfs4_stateowner *sop = NULL;
 
-       status = nfserr_inval;
        if (!check_name(open->op_owner))
-               goto out;
+               return nfserr_inval;
 
        if (STALE_CLIENTID(&open->op_clientid))
                return nfserr_stale_clientid;
 
        strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
        sop = find_openstateowner_str(strhashval, open);
-       if (sop) {
-               open->op_stateowner = sop;
-               /* check for replay */
-               if (open->op_seqid == sop->so_seqid){
-                       if (sop->so_replay.rp_buflen)
-                               return NFSERR_REPLAY_ME;
-                       else {
-                               /* The original OPEN failed so spectacularly
-                                * that we don't even have replay data saved!
-                                * Therefore, we have no choice but to continue
-                                * processing this OPEN; presumably, we'll
-                                * fail again for the same reason.
-                                */
-                               dprintk("nfsd4_process_open1:"
-                                       " replay with no replay cache\n");
-                               goto renew;
-                       }
-               } else if (sop->so_confirmed) {
-                       if (open->op_seqid == sop->so_seqid + 1)
-                               goto renew;
-                       status = nfserr_bad_seqid;
-                       goto out;
-               } else {
-                       /* If we get here, we received an OPEN for an
-                        * unconfirmed nfs4_stateowner. Since the seqid's are
-                        * different, purge the existing nfs4_stateowner, and
-                        * instantiate a new one.
-                        */
-                       clp = sop->so_client;
-                       release_stateowner(sop);
-               }
-       } else {
-               /* nfs4_stateowner not found.
-                * Verify clientid and instantiate new nfs4_stateowner.
-                * If verify fails this is presumably the result of the
-                * client's lease expiring.
-                */
-               status = nfserr_expired;
+       open->op_stateowner = sop;
+       if (!sop) {
+               /* Make sure the client's lease hasn't expired. */
                clp = find_confirmed_client(clientid);
                if (clp == NULL)
-                       goto out;
+                       return nfserr_expired;
+               goto renew;
        }
-       status = nfserr_resource;
-       sop = alloc_init_open_stateowner(strhashval, clp, open);
-       if (sop == NULL)
-               goto out;
-       open->op_stateowner = sop;
+       if (!sop->so_confirmed) {
+               /* Replace unconfirmed owners without checking for replay. */
+               clp = sop->so_client;
+               release_stateowner(sop);
+               open->op_stateowner = NULL;
+               goto renew;
+       }
+       if (open->op_seqid == sop->so_seqid - 1) {
+               if (sop->so_replay.rp_buflen)
+                       return NFSERR_REPLAY_ME;
+               /* The original OPEN failed so spectacularly
+                * that we don't even have replay data saved!
+                * Therefore, we have no choice but to continue
+                * processing this OPEN; presumably, we'll
+                * fail again for the same reason.
+                */
+               dprintk("nfsd4_process_open1: replay with no replay cache\n");
+               goto renew;
+       }
+       if (open->op_seqid != sop->so_seqid)
+               return nfserr_bad_seqid;
 renew:
-       status = nfs_ok;
+       if (open->op_stateowner == NULL) {
+               sop = alloc_init_open_stateowner(strhashval, clp, open);
+               if (sop == NULL)
+                       return nfserr_resource;
+               open->op_stateowner = sop;
+       }
+       list_del_init(&sop->so_close_lru);
        renew_client(sop->so_client);
-out:
-       if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
-               status = nfserr_reclaim_bad;
-       return status;
+       return nfs_ok;
 }
 
 static inline int
@@ -1686,19 +1636,11 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
 }
 
 
-/* decrement seqid on successful reclaim, it will be bumped in encode_open */
 static void
-nfs4_set_claim_prev(struct nfsd4_open *open, int *status)
+nfs4_set_claim_prev(struct nfsd4_open *open)
 {
-       if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
-               if (*status)
-                       *status = nfserr_reclaim_bad;
-               else {
-                       open->op_stateowner->so_confirmed = 1;
-                       open->op_stateowner->so_client->cl_firststate = 1;
-                       open->op_stateowner->so_seqid--;
-               }
-       }
+       open->op_stateowner->so_confirmed = 1;
+       open->op_stateowner->so_client->cl_firststate = 1;
 }
 
 /*
@@ -1830,6 +1772,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
                status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
                if (status)
                        goto out;
+               update_stateid(&stp->st_stateid);
        } else {
                /* Stateid was not found, this is a new OPEN */
                int flags = 0;
@@ -1863,8 +1806,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
 out:
        if (fp)
                put_nfs4_file(fp);
-       /* CLAIM_PREVIOUS has different error returns */
-       nfs4_set_claim_prev(open, &status);
+       if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+               nfs4_set_claim_prev(open);
        /*
        * To finish the open response, we just need to set the rflags.
        */
@@ -1997,14 +1940,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)
@@ -2025,7 +1965,7 @@ STALE_STATEID(stateid_t *stateid)
 {
        if (stateid->si_boot == boot_time)
                return 0;
-       printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
+       dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
                stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
                stateid->si_generation);
        return 1;
@@ -2170,14 +2110,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;
 
@@ -2185,53 +2130,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;
@@ -2242,67 +2199,45 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
        *  For the moment, we ignore the possibility of 
        *  generation number wraparound.
        */
-       if (seqid != sop->so_seqid + 1)
+       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;
        }
-       /* XXX renew the client lease here */
-       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;
+       renew_client(sop->so_client);
+       return nfs_ok;
 
 check_replay:
-       if (seqid == sop->so_seqid) {
-               printk("NFSD: preprocess_seqid_op: retransmission?\n");
+       if (seqid == sop->so_seqid - 1) {
+               dprintk("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 +1, 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
-nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
+nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner)
 {
        int status;
        struct nfs4_stateowner *sop;
@@ -2336,8 +2271,10 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
 
        nfsd4_create_clid_dir(sop->so_client);
 out:
-       if (oc->oc_stateowner)
+       if (oc->oc_stateowner) {
                nfs4_get_stateowner(oc->oc_stateowner);
+               *replay_owner = oc->oc_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -2368,7 +2305,7 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
 }
 
 int
-nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
+nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner)
 {
        int status;
        struct nfs4_stateid *stp;
@@ -2410,8 +2347,10 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n
        memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
        status = nfs_ok;
 out:
-       if (od->od_stateowner)
+       if (od->od_stateowner) {
                nfs4_get_stateowner(od->od_stateowner);
+               *replay_owner = od->od_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -2420,7 +2359,7 @@ out:
  * nfs4_unlock_state() called after encode
  */
 int
-nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
+nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner)
 {
        int status;
        struct nfs4_stateid *stp;
@@ -2436,18 +2375,24 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos
                                        CHECK_FH | OPEN_STATE | CLOSE_STATE,
                                        &close->cl_stateowner, &stp, NULL)))
                goto out; 
-       /*
-       *  Return success, but first update the stateid.
-       */
        status = nfs_ok;
        update_stateid(&stp->st_stateid);
        memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
 
-       /* release_state_owner() calls nfsd_close() if needed */
-       release_state_owner(stp, OPEN_STATE);
+       /* release_stateid() calls nfsd_close() if needed */
+       release_stateid(stp, OPEN_STATE);
+
+       /* place unused nfs4_stateowners on so_close_lru list to be
+        * released by the laundromat service after the lease period
+        * to enable us to handle CLOSE replay
+        */
+       if (list_empty(&close->cl_stateowner->so_stateids))
+               move_to_close_lru(close->cl_stateowner);
 out:
-       if (close->cl_stateowner)
+       if (close->cl_stateowner) {
                nfs4_get_stateowner(close->cl_stateowner);
+               *replay_owner = close->cl_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -2516,8 +2461,7 @@ find_stateid(stateid_t *stid, int flags)
                            (local->st_stateid.si_fileid == f_id))
                                return local;
                }
-       } else
-               printk("NFSD: find_stateid: ERROR: no state flag\n");
+       }
        return NULL;
 }
 
@@ -2616,7 +2560,6 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
  * occured. 
  *
  * strhashval = lock_ownerstr_hashval 
- * so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode 
  */
 
 static struct nfs4_stateowner *
@@ -2641,7 +2584,9 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
        sop->so_is_open_owner = 0;
        sop->so_id = current_ownerid++;
        sop->so_client = clp;
-       sop->so_seqid = lock->lk_new_lock_seqid - 1;
+       /* It is the openowner seqid that will be incremented in encode in the
+        * case of new lockowners; so increment the lock seqid manually: */
+       sop->so_seqid = lock->lk_new_lock_seqid + 1;
        sop->so_confirmed = 1;
        rp = &sop->so_replay;
        rp->rp_status = NFSERR_SERVERFAULT;
@@ -2676,6 +2621,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;
@@ -2692,9 +2638,10 @@ check_lock_length(u64 offset, u64 length)
  *  LOCK operation 
  */
 int
-nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
+nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner)
 {
        struct nfs4_stateowner *open_sop = NULL;
+       struct nfs4_stateowner *lock_sop = NULL;
        struct nfs4_stateid *lock_stp;
        struct file *filp;
        struct file_lock file_lock;
@@ -2709,26 +2656,24 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
        if (check_lock_length(lock->lk_offset, lock->lk_length))
                 return nfserr_inval;
 
+       if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {
+               dprintk("NFSD: nfsd4_lock: permission denied!\n");
+               return status;
+       }
+
        nfs4_lock_state();
 
        if (lock->lk_is_new) {
-       /*
-        * Client indicates that this is a new lockowner.
-        * Use open owner and open stateid to create lock owner and lock 
-        * stateid.
-        */
+               /*
+                * Client indicates that this is a new lockowner.
+                * Use open owner and open stateid to create lock owner and
+                * lock stateid.
+                */
                struct nfs4_stateid *open_stp = NULL;
                struct nfs4_file *fp;
                
                status = nfserr_stale_clientid;
-               if (STALE_CLIENTID(&lock->lk_new_clientid)) {
-                       printk("NFSD: nfsd4_lock: clientid is stale!\n");
-                       goto out;
-               }
-
-               /* is the new lock seqid presented by the client zero? */
-               status = nfserr_bad_seqid;
-               if (lock->v.new.lock_seqid != 0)
+               if (STALE_CLIENTID(&lock->lk_new_clientid))
                        goto out;
 
                /* validate and update open stateid and open seqid */
@@ -2736,13 +2681,11 @@ 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);
-               if (status) {
-                       if (lock->lk_reclaim)
-                               status = nfserr_reclaim_bad;
+                                       &lock->lk_replay_owner, &open_stp,
+                                       lock);
+               if (status)
                        goto out;
-               }
+               open_sop = lock->lk_replay_owner;
                /* create lockowner and lock stateid */
                fp = open_stp->st_file;
                strhashval = lock_ownerstr_hashval(fp->fi_inode, 
@@ -2752,34 +2695,27 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                 * the same file, or should they just be allowed (and
                 * create new stateids)? */
                status = nfserr_resource;
-               if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
+               lock_sop = alloc_init_lock_stateowner(strhashval,
+                               open_sop->so_client, open_stp, lock);
+               if (lock_sop == NULL)
                        goto out;
-               if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, 
-                                               fp, open_stp)) == NULL) {
-                       release_stateowner(lock->lk_stateowner);
-                       lock->lk_stateowner = NULL;
+               lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
+               if (lock_stp == NULL)
                        goto out;
-               }
-               /* bump the open seqid used to create the lock */
-               open_sop->so_seqid++;
        } else {
                /* lock (lock owner + lock stateid) already exists */
                status = nfs4_preprocess_seqid_op(current_fh,
                                       lock->lk_old_lock_seqid, 
                                       &lock->lk_old_lock_stateid, 
                                       CHECK_FH | LOCK_STATE, 
-                                      &lock->lk_stateowner, &lock_stp, NULL);
+                                      &lock->lk_replay_owner, &lock_stp, lock);
                if (status)
                        goto out;
+               lock_sop = lock->lk_replay_owner;
        }
-       /* lock->lk_stateowner and lock_stp have been created or found */
+       /* lock->lk_replay_owner and lock_stp have been created or found */
        filp = lock_stp->st_vfs_file;
 
-       if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) {
-               printk("NFSD: nfsd4_lock: permission denied!\n");
-               goto out;
-       }
-
        status = nfserr_grace;
        if (nfs4_in_grace() && !lock->lk_reclaim)
                goto out;
@@ -2801,7 +2737,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                        status = nfserr_inval;
                goto out;
        }
-       file_lock.fl_owner = (fl_owner_t) lock->lk_stateowner;
+       file_lock.fl_owner = (fl_owner_t)lock_sop;
        file_lock.fl_pid = current->tgid;
        file_lock.fl_file = filp;
        file_lock.fl_flags = FL_POSIX;
@@ -2820,8 +2756,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
        */
 
        status = posix_lock_file(filp, &file_lock);
-       if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
-               file_lock.fl_ops->fl_release_private(&file_lock);
        dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status);
        switch (-status) {
        case 0: /* success! */
@@ -2835,7 +2769,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
                status = nfserr_deadlock;
        default:        
                dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status);
-               goto out_destroy_new_stateid;
+               goto out;
        }
 
 conflicting_lock:
@@ -2849,22 +2783,13 @@ conflicting_lock:
                goto out;
        }
        nfs4_set_lock_denied(conflock, &lock->lk_denied);
-
-out_destroy_new_stateid:
-       if (lock->lk_is_new) {
-               dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");
-       /*
-       * An error encountered after instantiation of the new
-       * stateid has forced us to destroy it.
-       */
-               if (!seqid_mutating_err(status))
-                       open_sop->so_seqid--;
-
-               release_state_owner(lock_stp, LOCK_STATE);
-       }
 out:
-       if (lock->lk_stateowner)
-               nfs4_get_stateowner(lock->lk_stateowner);
+       if (status && lock->lk_is_new && lock_sop)
+               release_stateowner(lock_sop);
+       if (lock->lk_replay_owner) {
+               nfs4_get_stateowner(lock->lk_replay_owner);
+               *replay_owner = lock->lk_replay_owner;
+       }
        nfs4_unlock_state();
        return status;
 }
@@ -2891,13 +2816,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
        nfs4_lock_state();
 
        status = nfserr_stale_clientid;
-       if (STALE_CLIENTID(&lockt->lt_clientid)) {
-               printk("NFSD: nfsd4_lockt: clientid is stale!\n");
+       if (STALE_CLIENTID(&lockt->lt_clientid))
                goto out;
-       }
 
        if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) {
-               printk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
+               dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
                if (status == nfserr_symlink)
                        status = nfserr_inval;
                goto out;
@@ -2955,7 +2878,7 @@ out:
 }
 
 int
-nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku)
+nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner)
 {
        struct nfs4_stateid *stp;
        struct file *filp = NULL;
@@ -2998,10 +2921,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
        *  Try to unlock the file in the VFS.
        */
        status = posix_lock_file(filp, &file_lock); 
-       if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
-               file_lock.fl_ops->fl_release_private(&file_lock);
        if (status) {
-               printk("NFSD: nfs4_locku: posix_lock_file failed!\n");
+               dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
                goto out_nfserr;
        }
        /*
@@ -3011,8 +2932,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
        memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));
 
 out:
-       if (locku->lu_stateowner)
+       if (locku->lu_stateowner) {
                nfs4_get_stateowner(locku->lu_stateowner);
+               *replay_owner = locku->lu_stateowner;
+       }
        nfs4_unlock_state();
        return status;
 
@@ -3035,9 +2958,10 @@ check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
 
        lock_kernel();
        for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
-               if ((*flpp)->fl_owner == (fl_owner_t)lowner)
+               if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
                        status = 1;
                        goto out;
+               }
        }
 out:
        unlock_kernel();
@@ -3061,10 +2985,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
        /* XXX check for lease expiration */
 
        status = nfserr_stale_clientid;
-       if (STALE_CLIENTID(clid)) {
-               printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n");
+       if (STALE_CLIENTID(clid))
                return status;
-       }
 
        nfs4_lock_state();