]> err.no Git - linux-2.6/blobdiff - fs/nfsd/nfs4state.c
[ARM] S3C24XX: s3c2410_defconfig: add SCSI support
[linux-2.6] / fs / nfsd / nfs4state.c
index b73e96db1f502dcbdc43ea301b4d0de1a9c1a5c1..8799b8708188a3acf901f1d09b8e773865d139c5 100644 (file)
@@ -1639,6 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        locks_init_lock(&fl);
        fl.fl_lmops = &nfsd_lease_mng_ops;
        fl.fl_flags = FL_LEASE;
+       fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
        fl.fl_end = OFFSET_MAX;
        fl.fl_owner =  (fl_owner_t)dp;
        fl.fl_file = stp->st_vfs_file;
@@ -1647,8 +1648,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        /* vfs_setlease checks to see if delegation should be handed out.
         * the lock_manager callbacks fl_mylease and fl_change are used
         */
-       if ((status = vfs_setlease(stp->st_vfs_file,
-               flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
+       if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) {
                dprintk("NFSD: setlease failed [%d], no delegation\n", status);
                unhash_delegation(dp);
                flag = NFS4_OPEN_DELEGATE_NONE;
@@ -1763,10 +1763,6 @@ out:
        return status;
 }
 
-static struct workqueue_struct *laundry_wq;
-static void laundromat_main(struct work_struct *);
-static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
-
 __be32
 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            clientid_t *clid)
@@ -1874,7 +1870,11 @@ nfs4_laundromat(void)
        return clientid_val;
 }
 
-void
+static struct workqueue_struct *laundry_wq;
+static void laundromat_main(struct work_struct *);
+static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
+
+static void
 laundromat_main(struct work_struct *not_used)
 {
        time_t t;
@@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags)
                && mandatory_lock(inode);
 }
 
+static int check_stateid_generation(stateid_t *in, stateid_t *ref)
+{
+       /* If the client sends us a stateid from the future, it's buggy: */
+       if (in->si_generation > ref->si_generation)
+               return nfserr_bad_stateid;
+       /*
+        * The following, however, can happen.  For example, if the
+        * client sends an open and some IO at the same time, the open
+        * may bump si_generation while the IO is still in flight.
+        * Thanks to hard links and renames, the client never knows what
+        * file an open will affect.  So it could avoid that situation
+        * only by serializing all opens and IO from the same open
+        * owner.  To recover from the old_stateid error, the client
+        * will just have to retry the IO:
+        */
+       if (in->si_generation < ref->si_generation)
+               return nfserr_old_stateid;
+       return nfs_ok;
+}
+
 /*
 * Checks for stateid operations
 */
@@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
                        goto out;
                stidp = &stp->st_stateid;
        }
-       if (stateid->si_generation > stidp->si_generation)
-               goto out;
-
-       /* OLD STATEID */
-       status = nfserr_old_stateid;
-       if (stateid->si_generation < stidp->si_generation)
+       status = check_stateid_generation(stateid, stidp);
+       if (status)
                goto out;
        if (stp) {
                if ((status = nfs4_check_openmode(stp,flags)))
@@ -2036,7 +2052,7 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
                renew_client(stp->st_stateowner->so_client);
                if (filpp)
                        *filpp = stp->st_vfs_file;
-       } else if (dp) {
+       } else {
                if ((status = nfs4_check_delegmode(dp, flags)))
                        goto out;
                renew_client(dp->dl_client);
@@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
 {
        struct nfs4_stateid *stp;
        struct nfs4_stateowner *sop;
+       __be32 status;
 
        dprintk("NFSD: preprocess_seqid_op: seqid=%d " 
                        "stateid = (%08x/%08x/%08x/%08x)\n", seqid,
@@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
                                " confirmed yet!\n");
                return nfserr_bad_stateid;
        }
-       if (stateid->si_generation > stp->st_stateid.si_generation) {
-               dprintk("NFSD: preprocess_seqid_op: future stateid?!\n");
-               return nfserr_bad_stateid;
-       }
-
-       if (stateid->si_generation < stp->st_stateid.si_generation) {
-               dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
-               return nfserr_old_stateid;
-       }
+       status = check_stateid_generation(stateid, &stp->st_stateid);
+       if (status)
+               return status;
        renew_client(sop->so_client);
        return nfs_ok;
 
@@ -2701,9 +2712,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        * Note: locks.c uses the BKL to protect the inode's lock list.
        */
 
-       /* XXX?: Just to divert the locks_release_private at the start of
-        * locks_copy_lock: */
-       locks_init_lock(&conflock);
        err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
        switch (-err) {
        case 0: /* success! */