提交 515d8611 编写于 作者: T Trond Myklebust

NFSv4: Clean up the support for returning multiple delegations

Add a flag to mark delegations as requiring return, then run a garbage
collector. In the future, this will allow for more flexible delegation
management, where delegations may be marked for return if it turns out
that they are not being referenced.
Signed-off-by: NTrond Myklebust <Trond.Myklebust@netapp.com>
上级 9e33bed5
...@@ -255,6 +255,34 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat ...@@ -255,6 +255,34 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
return nfs_do_return_delegation(inode, delegation, 1); return nfs_do_return_delegation(inode, delegation, 1);
} }
/*
* Return all delegations that have been marked for return
*/
static void nfs_client_return_marked_delegations(struct nfs_client *clp)
{
struct nfs_delegation *delegation;
struct inode *inode;
restart:
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
if (!test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
continue;
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL)
continue;
spin_lock(&clp->cl_lock);
delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
spin_unlock(&clp->cl_lock);
rcu_read_unlock();
if (delegation != NULL)
__nfs_inode_return_delegation(inode, delegation);
iput(inode);
goto restart;
}
rcu_read_unlock();
}
/* /*
* This function returns the delegation without reclaiming opens * This function returns the delegation without reclaiming opens
* or protecting against delegation reclaims. * or protecting against delegation reclaims.
...@@ -296,63 +324,46 @@ int nfs_inode_return_delegation(struct inode *inode) ...@@ -296,63 +324,46 @@ int nfs_inode_return_delegation(struct inode *inode)
/* /*
* Return all delegations associated to a super block * Return all delegations associated to a super block
*/ */
void nfs_return_all_delegations(struct super_block *sb) void nfs_super_return_all_delegations(struct super_block *sb)
{ {
struct nfs_client *clp = NFS_SB(sb)->nfs_client; struct nfs_client *clp = NFS_SB(sb)->nfs_client;
struct nfs_delegation *delegation; struct nfs_delegation *delegation;
struct inode *inode;
if (clp == NULL) if (clp == NULL)
return; return;
restart:
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
inode = NULL;
spin_lock(&delegation->lock); spin_lock(&delegation->lock);
if (delegation->inode != NULL && delegation->inode->i_sb == sb) if (delegation->inode != NULL && delegation->inode->i_sb == sb)
inode = igrab(delegation->inode); set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
spin_unlock(&delegation->lock); spin_unlock(&delegation->lock);
if (inode == NULL)
continue;
spin_lock(&clp->cl_lock);
delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
spin_unlock(&clp->cl_lock);
rcu_read_unlock();
if (delegation != NULL)
__nfs_inode_return_delegation(inode, delegation);
iput(inode);
goto restart;
} }
rcu_read_unlock(); rcu_read_unlock();
nfs_client_return_marked_delegations(clp);
}
static void nfs_client_return_all_delegations(struct nfs_client *clp)
{
struct nfs_delegation *delegation;
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list)
set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
rcu_read_unlock();
nfs_client_return_marked_delegations(clp);
} }
static int nfs_do_expire_all_delegations(void *ptr) static int nfs_do_expire_all_delegations(void *ptr)
{ {
struct nfs_client *clp = ptr; struct nfs_client *clp = ptr;
struct nfs_delegation *delegation;
struct inode *inode;
allow_signal(SIGKILL); allow_signal(SIGKILL);
restart:
if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
goto out; goto out;
if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
goto out; goto out;
rcu_read_lock(); nfs_client_return_all_delegations(clp);
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL)
continue;
spin_lock(&clp->cl_lock);
delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
spin_unlock(&clp->cl_lock);
rcu_read_unlock();
if (delegation)
__nfs_inode_return_delegation(inode, delegation);
iput(inode);
goto restart;
}
rcu_read_unlock();
out: out:
nfs_put_client(clp); nfs_put_client(clp);
module_put_and_exit(0); module_put_and_exit(0);
...@@ -379,27 +390,9 @@ void nfs_expire_all_delegations(struct nfs_client *clp) ...@@ -379,27 +390,9 @@ void nfs_expire_all_delegations(struct nfs_client *clp)
*/ */
void nfs_handle_cb_pathdown(struct nfs_client *clp) void nfs_handle_cb_pathdown(struct nfs_client *clp)
{ {
struct nfs_delegation *delegation;
struct inode *inode;
if (clp == NULL) if (clp == NULL)
return; return;
restart: nfs_client_return_all_delegations(clp);
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL)
continue;
spin_lock(&clp->cl_lock);
delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
spin_unlock(&clp->cl_lock);
rcu_read_unlock();
if (delegation != NULL)
__nfs_inode_return_delegation(inode, delegation);
iput(inode);
goto restart;
}
rcu_read_unlock();
} }
struct recall_threadargs { struct recall_threadargs {
......
...@@ -20,12 +20,16 @@ struct nfs_delegation { ...@@ -20,12 +20,16 @@ struct nfs_delegation {
int type; int type;
loff_t maxsize; loff_t maxsize;
__u64 change_attr; __u64 change_attr;
#define NFS_DELEGATION_NEED_RECLAIM 0
unsigned long flags; unsigned long flags;
spinlock_t lock; spinlock_t lock;
struct rcu_head rcu; struct rcu_head rcu;
}; };
enum {
NFS_DELEGATION_NEED_RECLAIM = 0,
NFS_DELEGATION_RETURN,
};
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
int nfs_inode_return_delegation(struct inode *inode); int nfs_inode_return_delegation(struct inode *inode);
...@@ -33,7 +37,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s ...@@ -33,7 +37,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
void nfs_inode_return_delegation_noreclaim(struct inode *inode); void nfs_inode_return_delegation_noreclaim(struct inode *inode);
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
void nfs_return_all_delegations(struct super_block *sb); void nfs_super_return_all_delegations(struct super_block *sb);
void nfs_expire_all_delegations(struct nfs_client *clp); void nfs_expire_all_delegations(struct nfs_client *clp);
void nfs_handle_cb_pathdown(struct nfs_client *clp); void nfs_handle_cb_pathdown(struct nfs_client *clp);
......
...@@ -2433,7 +2433,7 @@ static void nfs4_kill_super(struct super_block *sb) ...@@ -2433,7 +2433,7 @@ static void nfs4_kill_super(struct super_block *sb)
{ {
struct nfs_server *server = NFS_SB(sb); struct nfs_server *server = NFS_SB(sb);
nfs_return_all_delegations(sb); nfs_super_return_all_delegations(sb);
kill_anon_super(sb); kill_anon_super(sb);
nfs4_renewd_prepare_shutdown(server); nfs4_renewd_prepare_shutdown(server);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册