Loading fs/nfs/delegation.c +46 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ */ #include <linux/config.h> #include <linux/completion.h> #include <linux/kthread.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/spinlock.h> Loading Loading @@ -231,6 +232,51 @@ void nfs_return_all_delegations(struct super_block *sb) spin_unlock(&clp->cl_lock); } int nfs_do_expire_all_delegations(void *ptr) { struct nfs4_client *clp = ptr; struct nfs_delegation *delegation; struct inode *inode; int err = 0; allow_signal(SIGKILL); restart: spin_lock(&clp->cl_lock); if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) goto out; if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) goto out; list_for_each_entry(delegation, &clp->cl_delegations, super_list) { inode = igrab(delegation->inode); if (inode == NULL) continue; spin_unlock(&clp->cl_lock); err = nfs_inode_return_delegation(inode); iput(inode); if (!err) goto restart; } out: spin_unlock(&clp->cl_lock); nfs4_put_client(clp); module_put_and_exit(0); } void nfs_expire_all_delegations(struct nfs4_client *clp) { struct task_struct *task; __module_get(THIS_MODULE); atomic_inc(&clp->cl_count); task = kthread_run(nfs_do_expire_all_delegations, clp, "%u.%u.%u.%u-delegreturn", NIPQUAD(clp->cl_addr)); if (!IS_ERR(task)) return; nfs4_put_client(clp); module_put(THIS_MODULE); } /* * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. */ Loading fs/nfs/delegation.h +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); void nfs_return_all_delegations(struct super_block *sb); void nfs_expire_all_delegations(struct nfs4_client *clp); void nfs_handle_cb_pathdown(struct nfs4_client *clp); void nfs_delegation_mark_reclaim(struct nfs4_client *clp); Loading fs/nfs/nfs4_fs.h +1 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ struct idmap; enum nfs4_client_state { NFS4CLNT_STATE_RECOVER = 0, NFS4CLNT_LEASE_EXPIRED, }; /* Loading fs/nfs/nfs4proc.c +19 −1 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; Loading Loading @@ -765,6 +766,15 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf return -EACCES; } int nfs4_recover_expired_lease(struct nfs_server *server) { struct nfs4_client *clp = server->nfs4_state; if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) nfs4_schedule_state_recovery(clp); return nfs4_wait_clnt_recover(server->client, clp); } /* * OPEN_EXPIRED: * reclaim state on the server after a network partition. Loading Loading @@ -840,6 +850,9 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred int open_flags = flags & (FMODE_READ|FMODE_WRITE); int err; err = nfs4_recover_expired_lease(server); if (err != 0) return err; /* Protect against reboot recovery - NOTE ORDER! */ down_read(&clp->cl_sem); /* Protect against delegation recall */ Loading Loading @@ -921,12 +934,16 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st int status; /* Protect against reboot recovery conflicts */ down_read(&clp->cl_sem); status = -ENOMEM; if (!(sp = nfs4_get_state_owner(server, cred))) { dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); goto out_err; } status = nfs4_recover_expired_lease(server); if (status != 0) goto out_err; down_read(&clp->cl_sem); status = -ENOMEM; opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); if (opendata == NULL) goto err_put_state_owner; Loading Loading @@ -2897,6 +2914,7 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp) spin_lock(&clp->cl_lock); clp->cl_lease_time = fsinfo.lease_time * HZ; clp->cl_last_renewal = now; clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); spin_unlock(&clp->cl_lock); } return status; Loading fs/nfs/nfs4renewd.c +8 −1 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ #include <linux/nfs4.h> #include <linux/nfs_fs.h> #include "nfs4_fs.h" #include "delegation.h" #define NFSDBG_FACILITY NFSDBG_PROC Loading @@ -76,6 +77,12 @@ nfs4_renew_state(void *data) timeout = (2 * lease) / 3 + (long)last - (long)now; /* Are we close to a lease timeout? */ if (time_after(now, last + lease/3)) { if (list_empty(&clp->cl_state_owners)) { set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); spin_unlock(&clp->cl_lock); nfs_expire_all_delegations(clp); goto out; } spin_unlock(&clp->cl_lock); /* Queue an asynchronous RENEW. */ nfs4_proc_async_renew(clp); Loading Loading
fs/nfs/delegation.c +46 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ */ #include <linux/config.h> #include <linux/completion.h> #include <linux/kthread.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/spinlock.h> Loading Loading @@ -231,6 +232,51 @@ void nfs_return_all_delegations(struct super_block *sb) spin_unlock(&clp->cl_lock); } int nfs_do_expire_all_delegations(void *ptr) { struct nfs4_client *clp = ptr; struct nfs_delegation *delegation; struct inode *inode; int err = 0; allow_signal(SIGKILL); restart: spin_lock(&clp->cl_lock); if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) goto out; if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) goto out; list_for_each_entry(delegation, &clp->cl_delegations, super_list) { inode = igrab(delegation->inode); if (inode == NULL) continue; spin_unlock(&clp->cl_lock); err = nfs_inode_return_delegation(inode); iput(inode); if (!err) goto restart; } out: spin_unlock(&clp->cl_lock); nfs4_put_client(clp); module_put_and_exit(0); } void nfs_expire_all_delegations(struct nfs4_client *clp) { struct task_struct *task; __module_get(THIS_MODULE); atomic_inc(&clp->cl_count); task = kthread_run(nfs_do_expire_all_delegations, clp, "%u.%u.%u.%u-delegreturn", NIPQUAD(clp->cl_addr)); if (!IS_ERR(task)) return; nfs4_put_client(clp); module_put(THIS_MODULE); } /* * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. */ Loading
fs/nfs/delegation.h +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); void nfs_return_all_delegations(struct super_block *sb); void nfs_expire_all_delegations(struct nfs4_client *clp); void nfs_handle_cb_pathdown(struct nfs4_client *clp); void nfs_delegation_mark_reclaim(struct nfs4_client *clp); Loading
fs/nfs/nfs4_fs.h +1 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ struct idmap; enum nfs4_client_state { NFS4CLNT_STATE_RECOVER = 0, NFS4CLNT_LEASE_EXPIRED, }; /* Loading
fs/nfs/nfs4proc.c +19 −1 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; Loading Loading @@ -765,6 +766,15 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf return -EACCES; } int nfs4_recover_expired_lease(struct nfs_server *server) { struct nfs4_client *clp = server->nfs4_state; if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) nfs4_schedule_state_recovery(clp); return nfs4_wait_clnt_recover(server->client, clp); } /* * OPEN_EXPIRED: * reclaim state on the server after a network partition. Loading Loading @@ -840,6 +850,9 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred int open_flags = flags & (FMODE_READ|FMODE_WRITE); int err; err = nfs4_recover_expired_lease(server); if (err != 0) return err; /* Protect against reboot recovery - NOTE ORDER! */ down_read(&clp->cl_sem); /* Protect against delegation recall */ Loading Loading @@ -921,12 +934,16 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st int status; /* Protect against reboot recovery conflicts */ down_read(&clp->cl_sem); status = -ENOMEM; if (!(sp = nfs4_get_state_owner(server, cred))) { dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); goto out_err; } status = nfs4_recover_expired_lease(server); if (status != 0) goto out_err; down_read(&clp->cl_sem); status = -ENOMEM; opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); if (opendata == NULL) goto err_put_state_owner; Loading Loading @@ -2897,6 +2914,7 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp) spin_lock(&clp->cl_lock); clp->cl_lease_time = fsinfo.lease_time * HZ; clp->cl_last_renewal = now; clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); spin_unlock(&clp->cl_lock); } return status; Loading
fs/nfs/nfs4renewd.c +8 −1 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ #include <linux/nfs4.h> #include <linux/nfs_fs.h> #include "nfs4_fs.h" #include "delegation.h" #define NFSDBG_FACILITY NFSDBG_PROC Loading @@ -76,6 +77,12 @@ nfs4_renew_state(void *data) timeout = (2 * lease) / 3 + (long)last - (long)now; /* Are we close to a lease timeout? */ if (time_after(now, last + lease/3)) { if (list_empty(&clp->cl_state_owners)) { set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); spin_unlock(&clp->cl_lock); nfs_expire_all_delegations(clp); goto out; } spin_unlock(&clp->cl_lock); /* Queue an asynchronous RENEW. */ nfs4_proc_async_renew(clp); Loading