Loading fs/nfs/delegation.c +73 −21 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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); } Loading @@ -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 * Loading Loading @@ -521,11 +530,18 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, 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, Loading @@ -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; } Loading Loading @@ -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; Loading Loading @@ -647,6 +664,38 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server, 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 Loading @@ -659,8 +708,14 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server, */ 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; } /** Loading Loading @@ -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; } /** Loading Loading @@ -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; Loading Loading @@ -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: Loading fs/nfs/delegation.h +1 −0 Original line number Diff line number Diff line Loading @@ -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, Loading fs/nfs/inode.c +4 −0 Original line number Diff line number Diff line Loading @@ -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); } Loading @@ -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; Loading @@ -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. Loading fs/nfs/nfs4_fs.h +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading fs/nfs/nfs4file.c +7 −1 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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, Loading Loading
fs/nfs/delegation.c +73 −21 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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); } Loading @@ -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 * Loading Loading @@ -521,11 +530,18 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, 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, Loading @@ -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; } Loading Loading @@ -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; Loading Loading @@ -647,6 +664,38 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server, 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 Loading @@ -659,8 +708,14 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server, */ 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; } /** Loading Loading @@ -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; } /** Loading Loading @@ -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; Loading Loading @@ -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: Loading
fs/nfs/delegation.h +1 −0 Original line number Diff line number Diff line Loading @@ -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, Loading
fs/nfs/inode.c +4 −0 Original line number Diff line number Diff line Loading @@ -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); } Loading @@ -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; Loading @@ -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. Loading
fs/nfs/nfs4_fs.h +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading
fs/nfs/nfs4file.c +7 −1 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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, Loading