diff options
author | Neil Brown <neilb@cse.unsw.edu.au> | 2005-01-04 05:50:54 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-01-04 05:50:54 -0800 |
commit | 0fe1a2eabab2d0fc1fb5c69326f6d809b194f28b (patch) | |
tree | e56ea48b3d7856cb2197442b7734faa3aa14405e /fs | |
parent | 1bf60786313bb36fc727c7217aa546c5b95e7765 (diff) | |
download | history-0fe1a2eabab2d0fc1fb5c69326f6d809b194f28b.tar.gz |
[PATCH] knfsd: kernel thread for delegation callback
Any task can call break_lease or time_out_leases
on a v4 delegated file which results in a recall callback rpc sent to the
NFSv4 client holding the delegation, and/or the FL_LEASE to be removed.
Spawn a kernel thread to perform the callback.
Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs4state.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f416b5ac1dd6fd..29f52bd05ef196 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -44,6 +44,7 @@ #include <linux/mount.h> #include <linux/workqueue.h> #include <linux/smp_lock.h> +#include <linux/kthread.h> #include <linux/nfs4.h> #include <linux/nfsd/state.h> #include <linux/nfsd/xdr4.h> @@ -1311,6 +1312,101 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access) } } +/* + * Recall a delegation + */ +static int +do_recall(void *__dp) +{ + struct nfs4_delegation *dp = __dp; + + daemonize("nfsv4-recall"); + + atomic_inc(&dp->dl_count); + nfsd4_cb_recall(dp); + return 0; +} + +/* + * Spawn a thread to perform a recall on the delegation represented + * by the lease (file_lock) + * + * Called from break_lease() with lock_kernel() held, + * + */ +static +void nfsd_break_deleg_cb(struct file_lock *fl) +{ + struct nfs4_delegation *dp= (struct nfs4_delegation *)fl->fl_owner; + struct task_struct *t; + + dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); + if (!dp) + return; + + /* schedule delegation for recall */ + spin_lock(&recall_lock); + atomic_set(&dp->dl_state, NFS4_RECALL_IN_PROGRESS); + list_add_tail(&dp->dl_recall_lru, &del_recall_lru); + spin_unlock(&recall_lock); + + /* only place dl_time is set. protected by lock_kernel*/ + dp->dl_time = get_seconds(); + + /* XXX need to merge NFSD_LEASE_TIME with fs/locks.c:lease_break_time */ + fl->fl_break_time = jiffies + NFSD_LEASE_TIME * HZ; + + t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall"); + if (IS_ERR(t)) { + struct nfs4_client *clp = dp->dl_client; + + printk(KERN_INFO "NFSD: Callback thread failed for " + "for client (clientid %08x/%08x)\n", + clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); + } +} + +/* + * The file_lock is being reapd. + * + * Called by locks_free_lock() with lock_kernel() held. + */ +static +void nfsd_release_deleg_cb(struct file_lock *fl) +{ + struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; + + dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d, dl_state %d\n", fl,dp, atomic_read(&dp->dl_count), atomic_read(&dp->dl_state)); + + if (!(fl->fl_flags & FL_LEASE) || !dp) + return; + atomic_set(&dp->dl_state,NFS4_RECALL_COMPLETE); + dp->dl_flock = NULL; +} + +/* + * Set the delegation file_lock back pointer. + * + * Called from __setlease() with lock_kernel() held. + */ +static +void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl) +{ + struct nfs4_delegation *dp = (struct nfs4_delegation *)new->fl_owner; + + dprintk("NFSD: nfsd_copy_lock_deleg_cb: new fl %p dp %p\n", new, dp); + if (!dp) + return; + dp->dl_flock = new; +} + +struct lock_manager_operations nfsd_lease_mng_ops = { + .fl_break = nfsd_break_deleg_cb, + .fl_release_private = nfsd_release_deleg_cb, + .fl_copy_lock = nfsd_copy_lock_deleg_cb, +}; + + /* * nfsd4_process_open1() |