mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
Merge branch 'leases-devel'
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
commit
e9e8ee40b3
@ -75,6 +75,13 @@ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
|
||||
set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
|
||||
}
|
||||
|
||||
static void nfs_mark_return_delegation(struct nfs_server *server,
|
||||
struct nfs_delegation *delegation)
|
||||
{
|
||||
set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
|
||||
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
|
||||
}
|
||||
|
||||
static bool
|
||||
nfs4_is_valid_delegation(const struct nfs_delegation *delegation,
|
||||
fmode_t flags)
|
||||
@ -293,6 +300,7 @@ nfs_start_delegation_return_locked(struct nfs_inode *nfsi)
|
||||
goto out;
|
||||
spin_lock(&delegation->lock);
|
||||
if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
|
||||
clear_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
|
||||
/* Refcount matched in nfs_end_delegation_return() */
|
||||
ret = nfs_get_delegation(delegation);
|
||||
}
|
||||
@ -314,16 +322,17 @@ nfs_start_delegation_return(struct nfs_inode *nfsi)
|
||||
return delegation;
|
||||
}
|
||||
|
||||
static void
|
||||
nfs_abort_delegation_return(struct nfs_delegation *delegation,
|
||||
struct nfs_client *clp)
|
||||
static void nfs_abort_delegation_return(struct nfs_delegation *delegation,
|
||||
struct nfs_client *clp, int err)
|
||||
{
|
||||
|
||||
spin_lock(&delegation->lock);
|
||||
clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
|
||||
set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
|
||||
if (err == -EAGAIN) {
|
||||
set_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
|
||||
set_bit(NFS4CLNT_DELEGRETURN_DELAYED, &clp->cl_state);
|
||||
}
|
||||
spin_unlock(&delegation->lock);
|
||||
set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
|
||||
}
|
||||
|
||||
static struct nfs_delegation *
|
||||
@ -521,11 +530,18 @@ out:
|
||||
static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync)
|
||||
{
|
||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||
unsigned int mode = O_WRONLY | O_RDWR;
|
||||
int err = 0;
|
||||
|
||||
if (delegation == NULL)
|
||||
return 0;
|
||||
do {
|
||||
|
||||
if (!issync)
|
||||
mode |= O_NONBLOCK;
|
||||
/* Recall of any remaining application leases */
|
||||
err = break_lease(inode, mode);
|
||||
|
||||
while (err == 0) {
|
||||
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
|
||||
break;
|
||||
err = nfs_delegation_claim_opens(inode, &delegation->stateid,
|
||||
@ -536,10 +552,10 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation
|
||||
* Guard against state recovery
|
||||
*/
|
||||
err = nfs4_wait_clnt_recover(clp);
|
||||
} while (err == 0);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
nfs_abort_delegation_return(delegation, clp);
|
||||
nfs_abort_delegation_return(delegation, clp, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -568,6 +584,7 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
|
||||
if (ret)
|
||||
clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
|
||||
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags) ||
|
||||
test_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags) ||
|
||||
test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
|
||||
ret = false;
|
||||
|
||||
@ -647,6 +664,38 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool nfs_server_clear_delayed_delegations(struct nfs_server *server)
|
||||
{
|
||||
struct nfs_delegation *d;
|
||||
bool ret = false;
|
||||
|
||||
list_for_each_entry_rcu (d, &server->delegations, super_list) {
|
||||
if (!test_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags))
|
||||
continue;
|
||||
nfs_mark_return_delegation(server, d);
|
||||
clear_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool nfs_client_clear_delayed_delegations(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_server *server;
|
||||
bool ret = false;
|
||||
|
||||
if (!test_and_clear_bit(NFS4CLNT_DELEGRETURN_DELAYED, &clp->cl_state))
|
||||
goto out;
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu (server, &clp->cl_superblocks, client_link) {
|
||||
if (nfs_server_clear_delayed_delegations(server))
|
||||
ret = true;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_client_return_marked_delegations - return previously marked delegations
|
||||
* @clp: nfs_client to process
|
||||
@ -659,8 +708,14 @@ out:
|
||||
*/
|
||||
int nfs_client_return_marked_delegations(struct nfs_client *clp)
|
||||
{
|
||||
return nfs_client_for_each_server(clp,
|
||||
nfs_server_return_marked_delegations, NULL);
|
||||
int err = nfs_client_for_each_server(
|
||||
clp, nfs_server_return_marked_delegations, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
/* If a return was delayed, sleep to prevent hard looping */
|
||||
if (nfs_client_clear_delayed_delegations(clp))
|
||||
ssleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -698,13 +753,14 @@ int nfs4_inode_return_delegation(struct inode *inode)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
struct nfs_delegation *delegation;
|
||||
int err = 0;
|
||||
|
||||
nfs_wb_all(inode);
|
||||
delegation = nfs_start_delegation_return(nfsi);
|
||||
/* Synchronous recall of any application leases */
|
||||
break_lease(inode, O_WRONLY | O_RDWR);
|
||||
nfs_wb_all(inode);
|
||||
if (delegation != NULL)
|
||||
err = nfs_end_delegation_return(inode, delegation, 1);
|
||||
return err;
|
||||
return nfs_end_delegation_return(inode, delegation, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -775,13 +831,6 @@ static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
|
||||
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
|
||||
}
|
||||
|
||||
static void nfs_mark_return_delegation(struct nfs_server *server,
|
||||
struct nfs_delegation *delegation)
|
||||
{
|
||||
set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
|
||||
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
|
||||
}
|
||||
|
||||
static bool nfs_server_mark_return_all_delegations(struct nfs_server *server)
|
||||
{
|
||||
struct nfs_delegation *delegation;
|
||||
@ -1010,6 +1059,9 @@ int nfs_async_inode_return_delegation(struct inode *inode,
|
||||
nfs_mark_return_delegation(server, delegation);
|
||||
rcu_read_unlock();
|
||||
|
||||
/* If there are any application leases or delegations, recall them */
|
||||
break_lease(inode, O_WRONLY | O_RDWR | O_NONBLOCK);
|
||||
|
||||
nfs_delegation_run_state_manager(clp);
|
||||
return 0;
|
||||
out_enoent:
|
||||
|
@ -36,6 +36,7 @@ enum {
|
||||
NFS_DELEGATION_REVOKED,
|
||||
NFS_DELEGATION_TEST_EXPIRED,
|
||||
NFS_DELEGATION_INODE_FREEING,
|
||||
NFS_DELEGATION_RETURN_DELAYED,
|
||||
};
|
||||
|
||||
int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
|
||||
|
@ -1101,6 +1101,7 @@ EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context);
|
||||
void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
|
||||
{
|
||||
filp->private_data = get_nfs_open_context(ctx);
|
||||
set_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags);
|
||||
if (list_empty(&ctx->list))
|
||||
nfs_inode_attach_open_context(ctx);
|
||||
}
|
||||
@ -1120,6 +1121,8 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, const struct
|
||||
continue;
|
||||
if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode)
|
||||
continue;
|
||||
if (!test_bit(NFS_CONTEXT_FILE_OPEN, &pos->flags))
|
||||
continue;
|
||||
ctx = get_nfs_open_context(pos);
|
||||
if (ctx)
|
||||
break;
|
||||
@ -1135,6 +1138,7 @@ void nfs_file_clear_open_context(struct file *filp)
|
||||
if (ctx) {
|
||||
struct inode *inode = d_inode(ctx->dentry);
|
||||
|
||||
clear_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags);
|
||||
/*
|
||||
* We fatal error on write before. Try to writeback
|
||||
* every page again.
|
||||
|
@ -45,6 +45,7 @@ enum nfs4_client_state {
|
||||
NFS4CLNT_RECALL_RUNNING,
|
||||
NFS4CLNT_RECALL_ANY_LAYOUT_READ,
|
||||
NFS4CLNT_RECALL_ANY_LAYOUT_RW,
|
||||
NFS4CLNT_DELEGRETURN_DELAYED,
|
||||
};
|
||||
|
||||
#define NFS4_RENEW_TIMEOUT 0x01
|
||||
@ -322,7 +323,8 @@ extern int update_open_stateid(struct nfs4_state *state,
|
||||
const nfs4_stateid *open_stateid,
|
||||
const nfs4_stateid *deleg_stateid,
|
||||
fmode_t fmode);
|
||||
|
||||
extern int nfs4_proc_setlease(struct file *file, long arg,
|
||||
struct file_lock **lease, void **priv);
|
||||
extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
|
||||
struct nfs_fsinfo *fsinfo);
|
||||
extern void nfs4_update_changeattr(struct inode *dir,
|
||||
|
@ -435,6 +435,12 @@ void nfs42_ssc_unregister_ops(void)
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
||||
static int nfs4_setlease(struct file *file, long arg, struct file_lock **lease,
|
||||
void **priv)
|
||||
{
|
||||
return nfs4_proc_setlease(file, arg, lease, priv);
|
||||
}
|
||||
|
||||
const struct file_operations nfs4_file_operations = {
|
||||
.read_iter = nfs_file_read,
|
||||
.write_iter = nfs_file_write,
|
||||
@ -448,7 +454,7 @@ const struct file_operations nfs4_file_operations = {
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.check_flags = nfs_check_flags,
|
||||
.setlease = simple_nosetlease,
|
||||
.setlease = nfs4_setlease,
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
.copy_file_range = nfs4_copy_file_range,
|
||||
.llseek = nfs4_file_llseek,
|
||||
|
@ -7435,6 +7435,43 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
|
||||
return nfs4_retry_setlk(state, cmd, request);
|
||||
}
|
||||
|
||||
static int nfs4_delete_lease(struct file *file, void **priv)
|
||||
{
|
||||
return generic_setlease(file, F_UNLCK, NULL, priv);
|
||||
}
|
||||
|
||||
static int nfs4_add_lease(struct file *file, long arg, struct file_lock **lease,
|
||||
void **priv)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
fmode_t type = arg == F_RDLCK ? FMODE_READ : FMODE_WRITE;
|
||||
int ret;
|
||||
|
||||
/* No delegation, no lease */
|
||||
if (!nfs4_have_delegation(inode, type))
|
||||
return -EAGAIN;
|
||||
ret = generic_setlease(file, arg, lease, priv);
|
||||
if (ret || nfs4_have_delegation(inode, type))
|
||||
return ret;
|
||||
/* We raced with a delegation return */
|
||||
nfs4_delete_lease(file, priv);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
int nfs4_proc_setlease(struct file *file, long arg, struct file_lock **lease,
|
||||
void **priv)
|
||||
{
|
||||
switch (arg) {
|
||||
case F_RDLCK:
|
||||
case F_WRLCK:
|
||||
return nfs4_add_lease(file, arg, lease, priv);
|
||||
case F_UNLCK:
|
||||
return nfs4_delete_lease(file, priv);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(state->inode);
|
||||
|
@ -84,6 +84,7 @@ struct nfs_open_context {
|
||||
#define NFS_CONTEXT_RESEND_WRITES (1)
|
||||
#define NFS_CONTEXT_BAD (2)
|
||||
#define NFS_CONTEXT_UNLOCK (3)
|
||||
#define NFS_CONTEXT_FILE_OPEN (4)
|
||||
int error;
|
||||
|
||||
struct list_head list;
|
||||
|
Loading…
Reference in New Issue
Block a user