]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfsd/nfs4state.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[mv-sheeva.git] / fs / nfsd / nfs4state.c
index 8b6cd3cf48350cb87904ebbfa75130e86663832c..7b566ec14e1833cac3f7c61d5ab6b5bb169e3abb 100644 (file)
@@ -230,9 +230,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        dp->dl_client = clp;
        get_nfs4_file(fp);
        dp->dl_file = fp;
-       dp->dl_vfs_file = find_readable_file(fp);
-       get_file(dp->dl_vfs_file);
-       dp->dl_flock = NULL;
        dp->dl_type = type;
        dp->dl_stateid.si_boot = boot_time;
        dp->dl_stateid.si_stateownerid = current_delegid++;
@@ -241,8 +238,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
        dp->dl_time = 0;
        atomic_set(&dp->dl_count, 1);
-       list_add(&dp->dl_perfile, &fp->fi_delegations);
-       list_add(&dp->dl_perclnt, &clp->cl_delegations);
        INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
        return dp;
 }
@@ -253,24 +248,18 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
        if (atomic_dec_and_test(&dp->dl_count)) {
                dprintk("NFSD: freeing dp %p\n",dp);
                put_nfs4_file(dp->dl_file);
-               fput(dp->dl_vfs_file);
                kmem_cache_free(deleg_slab, dp);
                num_delegations--;
        }
 }
 
-/* Remove the associated file_lock first, then remove the delegation.
- * lease_modify() is called to remove the FS_LEASE file_lock from
- * the i_flock list, eventually calling nfsd's lock_manager
- * fl_release_callback.
- */
-static void
-nfs4_close_delegation(struct nfs4_delegation *dp)
+static void nfs4_put_deleg_lease(struct nfs4_file *fp)
 {
-       dprintk("NFSD: close_delegation dp %p\n",dp);
-       /* XXX: do we even need this check?: */
-       if (dp->dl_flock)
-               vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock);
+       if (atomic_dec_and_test(&fp->fi_delegees)) {
+               vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
+               fp->fi_lease = NULL;
+               fp->fi_deleg_file = NULL;
+       }
 }
 
 /* Called under the state lock. */
@@ -282,7 +271,7 @@ unhash_delegation(struct nfs4_delegation *dp)
        list_del_init(&dp->dl_perfile);
        list_del_init(&dp->dl_recall_lru);
        spin_unlock(&recall_lock);
-       nfs4_close_delegation(dp);
+       nfs4_put_deleg_lease(dp->dl_file);
        nfs4_put_delegation(dp);
 }
 
@@ -2076,6 +2065,7 @@ alloc_init_file(struct inode *ino)
                fp->fi_inode = igrab(ino);
                fp->fi_id = current_fileid++;
                fp->fi_had_conflict = false;
+               fp->fi_lease = NULL;
                memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
                memset(fp->fi_access, 0, sizeof(fp->fi_access));
                spin_lock(&recall_lock);
@@ -2344,26 +2334,26 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
        nfsd4_cb_recall(dp);
 }
 
-/*
- * Called from break_lease() with lock_flocks() held.
- * Note: we assume break_lease will only call this *once* for any given
- * lease.
- */
+/* Called from break_lease() with lock_flocks() held. */
 static void nfsd_break_deleg_cb(struct file_lock *fl)
 {
-       struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
+       struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
+       struct nfs4_delegation *dp;
 
-       BUG_ON(!dp);
+       BUG_ON(!fp);
+       /* We assume break_lease is only called once per lease: */
+       BUG_ON(fp->fi_had_conflict);
        /*
         * We don't want the locks code to timeout the lease for us;
-        * we'll remove it ourself if the delegation isn't returned
+        * we'll remove it ourself if a delegation isn't returned
         * in time:
         */
        fl->fl_break_time = 0;
 
        spin_lock(&recall_lock);
-       dp->dl_file->fi_had_conflict = true;
-       nfsd_break_one_deleg(dp);
+       fp->fi_had_conflict = true;
+       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
+               nfsd_break_one_deleg(dp);
        spin_unlock(&recall_lock);
 }
 
@@ -2457,10 +2447,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
 {
        struct nfs4_delegation *dp;
 
-       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {
-               if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
+       spin_lock(&recall_lock);
+       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
+               if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) {
+                       spin_unlock(&recall_lock);
                        return dp;
-       }
+               }
+       spin_unlock(&recall_lock);
        return NULL;
 }
 
@@ -2649,28 +2642,51 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f
        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 = dp->dl_vfs_file;
-       BUG_ON(!fl->fl_file);
+       fl->fl_owner = (fl_owner_t)(dp->dl_file);
        fl->fl_pid = current->tgid;
-       dp->dl_flock = fl;
        return fl;
 }
 
 static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
 {
+       struct nfs4_file *fp = dp->dl_file;
        struct file_lock *fl;
        int status;
 
        fl = nfs4_alloc_init_lease(dp, flag);
        if (!fl)
                return -ENOMEM;
-       status = vfs_setlease(dp->dl_vfs_file, fl->fl_type, &fl);
+       fl->fl_file = find_readable_file(fp);
+       list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+       status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
        if (status) {
-               dp->dl_flock = NULL;
+               list_del_init(&dp->dl_perclnt);
                locks_free_lock(fl);
                return -ENOMEM;
        }
+       fp->fi_lease = fl;
+       fp->fi_deleg_file = fl->fl_file;
+       get_file(fp->fi_deleg_file);
+       atomic_set(&fp->fi_delegees, 1);
+       list_add(&dp->dl_perfile, &fp->fi_delegations);
+       return 0;
+}
+
+static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
+{
+       struct nfs4_file *fp = dp->dl_file;
+
+       if (!fp->fi_lease)
+               return nfs4_setlease(dp, flag);
+       spin_lock(&recall_lock);
+       if (fp->fi_had_conflict) {
+               spin_unlock(&recall_lock);
+               return -EAGAIN;
+       }
+       atomic_inc(&fp->fi_delegees);
+       list_add(&dp->dl_perfile, &fp->fi_delegations);
+       spin_unlock(&recall_lock);
+       list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
        return 0;
 }
 
@@ -2715,7 +2731,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
        if (dp == NULL)
                goto out_no_deleg;
-       status = nfs4_setlease(dp, flag);
+       status = nfs4_set_delegation(dp, flag);
        if (status)
                goto out_free;
 
@@ -2731,7 +2747,7 @@ out:
        open->op_delegate_type = flag;
        return;
 out_free:
-       unhash_delegation(dp);
+       nfs4_put_delegation(dp);
 out_no_deleg:
        flag = NFS4_OPEN_DELEGATE_NONE;
        goto out;
@@ -3139,7 +3155,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                        goto out;
                renew_client(dp->dl_client);
                if (filpp) {
-                       *filpp = find_readable_file(dp->dl_file);
+                       *filpp = dp->dl_file->fi_deleg_file;
                        BUG_ON(!*filpp);
                }
        } else { /* open or lock stateid */