Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 704987 Details for
Bug 911668
BUG: soft lockup - CPU#1 stuck for 23s! with Intel SpeedStep & NFSv4.1 client
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Diff between commit c5f5e9c5d2 and 512e4b291c0 from upstream kernel
patch_c5f5e9c5d2..nfs-for-3.9-2.dif (text/plain), 43.80 KB, created by
Trond Myklebust
on 2013-03-04 13:35:20 UTC
(
hide
)
Description:
Diff between commit c5f5e9c5d2 and 512e4b291c0 from upstream kernel
Filename:
MIME Type:
Creator:
Trond Myklebust
Created:
2013-03-04 13:35:20 UTC
Size:
43.80 KB
patch
obsolete
> fs/lockd/clntproc.c | 3 + > fs/nfs/blocklayout/blocklayout.c | 1 + > fs/nfs/callback_proc.c | 61 ++------------ > fs/nfs/delegation.c | 154 +++++++++++++++++++++++++---------- > fs/nfs/delegation.h | 1 + > fs/nfs/getroot.c | 3 +- > fs/nfs/inode.c | 2 + > fs/nfs/nfs4_fs.h | 4 + > fs/nfs/nfs4filelayout.c | 6 +- > fs/nfs/nfs4filelayout.h | 2 +- > fs/nfs/nfs4proc.c | 152 ++++++++++++++++++++++++---------- > fs/nfs/nfs4state.c | 11 ++- > fs/nfs/objlayout/objio_osd.c | 1 + > fs/nfs/pnfs.c | 171 ++++++++++++++++++++++++++++++++------- > fs/nfs/pnfs.h | 13 ++- > fs/nfs/unlink.c | 23 +++--- > include/linux/nfs_xdr.h | 1 + > include/linux/sunrpc/clnt.h | 1 + > net/sunrpc/auth_gss/auth_gss.c | 3 +- > net/sunrpc/clnt.c | 15 ++++ > net/sunrpc/xprt.c | 6 +- > 21 files changed, 445 insertions(+), 189 deletions(-) > >diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c >index 54f9e6c..52e5120 100644 >--- a/fs/lockd/clntproc.c >+++ b/fs/lockd/clntproc.c >@@ -550,6 +550,9 @@ again: > status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); > if (status < 0) > break; >+ /* Resend the blocking lock request after a server reboot */ >+ if (resp->status == nlm_lck_denied_grace_period) >+ continue; > if (resp->status != nlm_lck_blocked) > break; > } >diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c >index 4fa788c..434b93e 100644 >--- a/fs/nfs/blocklayout/blocklayout.c >+++ b/fs/nfs/blocklayout/blocklayout.c >@@ -1273,6 +1273,7 @@ static const struct nfs_pageio_ops bl_pg_write_ops = { > static struct pnfs_layoutdriver_type blocklayout_type = { > .id = LAYOUT_BLOCK_VOLUME, > .name = "LAYOUT_BLOCK_VOLUME", >+ .owner = THIS_MODULE, > .read_pagelist = bl_read_pagelist, > .write_pagelist = bl_write_pagelist, > .alloc_layout_hdr = bl_alloc_layout_hdr, >diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c >index 264d1aa..2960512 100644 >--- a/fs/nfs/callback_proc.c >+++ b/fs/nfs/callback_proc.c >@@ -183,60 +183,15 @@ static u32 initiate_file_draining(struct nfs_client *clp, > static u32 initiate_bulk_draining(struct nfs_client *clp, > struct cb_layoutrecallargs *args) > { >- struct nfs_server *server; >- struct pnfs_layout_hdr *lo; >- struct inode *ino; >- u32 rv = NFS4ERR_NOMATCHING_LAYOUT; >- struct pnfs_layout_hdr *tmp; >- LIST_HEAD(recall_list); >- LIST_HEAD(free_me_list); >- struct pnfs_layout_range range = { >- .iomode = IOMODE_ANY, >- .offset = 0, >- .length = NFS4_MAX_UINT64, >- }; >- >- spin_lock(&clp->cl_lock); >- rcu_read_lock(); >- list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { >- if ((args->cbl_recall_type == RETURN_FSID) && >- memcmp(&server->fsid, &args->cbl_fsid, >- sizeof(struct nfs_fsid))) >- continue; >+ int stat; > >- list_for_each_entry(lo, &server->layouts, plh_layouts) { >- ino = igrab(lo->plh_inode); >- if (!ino) >- continue; >- spin_lock(&ino->i_lock); >- /* Is this layout in the process of being freed? */ >- if (NFS_I(ino)->layout != lo) { >- spin_unlock(&ino->i_lock); >- iput(ino); >- continue; >- } >- pnfs_get_layout_hdr(lo); >- spin_unlock(&ino->i_lock); >- list_add(&lo->plh_bulk_recall, &recall_list); >- } >- } >- rcu_read_unlock(); >- spin_unlock(&clp->cl_lock); >- >- list_for_each_entry_safe(lo, tmp, >- &recall_list, plh_bulk_recall) { >- ino = lo->plh_inode; >- spin_lock(&ino->i_lock); >- set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags); >- if (pnfs_mark_matching_lsegs_invalid(lo, &free_me_list, &range)) >- rv = NFS4ERR_DELAY; >- list_del_init(&lo->plh_bulk_recall); >- spin_unlock(&ino->i_lock); >- pnfs_free_lseg_list(&free_me_list); >- pnfs_put_layout_hdr(lo); >- iput(ino); >- } >- return rv; >+ if (args->cbl_recall_type == RETURN_FSID) >+ stat = pnfs_destroy_layouts_byfsid(clp, &args->cbl_fsid, true); >+ else >+ stat = pnfs_destroy_layouts_byclid(clp, true); >+ if (stat != 0) >+ return NFS4ERR_DELAY; >+ return NFS4ERR_NOMATCHING_LAYOUT; > } > > static u32 do_callback_layoutrecall(struct nfs_client *clp, >diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c >index 81c5eec..6390a4b 100644 >--- a/fs/nfs/delegation.c >+++ b/fs/nfs/delegation.c >@@ -55,7 +55,8 @@ int nfs4_have_delegation(struct inode *inode, fmode_t flags) > flags &= FMODE_READ|FMODE_WRITE; > rcu_read_lock(); > delegation = rcu_dereference(NFS_I(inode)->delegation); >- if (delegation != NULL && (delegation->type & flags) == flags) { >+ if (delegation != NULL && (delegation->type & flags) == flags && >+ !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { > nfs_mark_delegation_referenced(delegation); > ret = 1; > } >@@ -70,8 +71,10 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ > int status = 0; > > if (inode->i_flock == NULL) >- goto out; >+ return 0; > >+ if (inode->i_flock == NULL) >+ goto out; > /* Protect inode->i_flock using the file locks lock */ > lock_flocks(); > for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { >@@ -94,7 +97,9 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s > { > struct nfs_inode *nfsi = NFS_I(inode); > struct nfs_open_context *ctx; >+ struct nfs4_state_owner *sp; > struct nfs4_state *state; >+ unsigned int seq; > int err; > > again: >@@ -109,9 +114,16 @@ again: > continue; > get_nfs_open_context(ctx); > spin_unlock(&inode->i_lock); >+ sp = state->owner; >+ /* Block nfs4_proc_unlck */ >+ mutex_lock(&sp->so_delegreturn_mutex); >+ seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); > err = nfs4_open_delegation_recall(ctx, state, stateid); >- if (err >= 0) >+ if (!err) > err = nfs_delegation_claim_locks(ctx, state); >+ if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) >+ err = -EAGAIN; >+ mutex_unlock(&sp->so_delegreturn_mutex); > put_nfs_open_context(ctx); > if (err != 0) > return err; >@@ -182,39 +194,91 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation > } > > static struct nfs_delegation * >+nfs_start_delegation_return_locked(struct nfs_inode *nfsi) >+{ >+ struct nfs_delegation *ret = NULL; >+ struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); >+ >+ if (delegation == NULL) >+ goto out; >+ spin_lock(&delegation->lock); >+ if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) >+ ret = delegation; >+ spin_unlock(&delegation->lock); >+out: >+ return ret; >+} >+ >+static struct nfs_delegation * >+nfs_start_delegation_return(struct nfs_inode *nfsi) >+{ >+ struct nfs_delegation *delegation; >+ >+ rcu_read_lock(); >+ delegation = nfs_start_delegation_return_locked(nfsi); >+ rcu_read_unlock(); >+ return delegation; >+} >+ >+static void >+nfs_abort_delegation_return(struct nfs_delegation *delegation, >+ struct nfs_client *clp) >+{ >+ >+ spin_lock(&delegation->lock); >+ clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags); >+ set_bit(NFS_DELEGATION_RETURN, &delegation->flags); >+ spin_unlock(&delegation->lock); >+ set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); >+} >+ >+static struct nfs_delegation * > nfs_detach_delegation_locked(struct nfs_inode *nfsi, >- struct nfs_server *server) >+ struct nfs_delegation *delegation, >+ struct nfs_client *clp) > { >- struct nfs_delegation *delegation = >+ struct nfs_delegation *deleg_cur = > rcu_dereference_protected(nfsi->delegation, >- lockdep_is_held(&server->nfs_client->cl_lock)); >+ lockdep_is_held(&clp->cl_lock)); > >- if (delegation == NULL) >- goto nomatch; >+ if (deleg_cur == NULL || delegation != deleg_cur) >+ return NULL; > > spin_lock(&delegation->lock); >+ set_bit(NFS_DELEGATION_RETURNING, &delegation->flags); > list_del_rcu(&delegation->super_list); > delegation->inode = NULL; > nfsi->delegation_state = 0; > rcu_assign_pointer(nfsi->delegation, NULL); > spin_unlock(&delegation->lock); > return delegation; >-nomatch: >- return NULL; > } > > static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi, >- struct nfs_server *server) >+ struct nfs_delegation *delegation, >+ struct nfs_server *server) > { > struct nfs_client *clp = server->nfs_client; >- struct nfs_delegation *delegation; > > spin_lock(&clp->cl_lock); >- delegation = nfs_detach_delegation_locked(nfsi, server); >+ delegation = nfs_detach_delegation_locked(nfsi, delegation, clp); > spin_unlock(&clp->cl_lock); > return delegation; > } > >+static struct nfs_delegation * >+nfs_inode_detach_delegation(struct inode *inode) >+{ >+ struct nfs_inode *nfsi = NFS_I(inode); >+ struct nfs_server *server = NFS_SERVER(inode); >+ struct nfs_delegation *delegation; >+ >+ delegation = nfs_start_delegation_return(nfsi); >+ if (delegation == NULL) >+ return NULL; >+ return nfs_detach_delegation(nfsi, delegation, server); >+} >+ > /** > * nfs_inode_set_delegation - set up a delegation on an inode > * @inode: inode to which delegation applies >@@ -268,7 +332,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct > delegation = NULL; > goto out; > } >- freeme = nfs_detach_delegation_locked(nfsi, server); >+ freeme = nfs_detach_delegation_locked(nfsi, >+ old_delegation, clp); >+ if (freeme == NULL) >+ goto out; > } > list_add_rcu(&delegation->super_list, &server->delegations); > nfsi->delegation_state = delegation->type; >@@ -292,19 +359,29 @@ out: > /* > * Basic procedure for returning a delegation to the server > */ >-static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) >+static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync) > { >+ struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; > struct nfs_inode *nfsi = NFS_I(inode); > int err; > >- /* >- * Guard against new delegated open/lock/unlock calls and against >- * state recovery >- */ >- down_write(&nfsi->rwsem); >- err = nfs_delegation_claim_opens(inode, &delegation->stateid); >- up_write(&nfsi->rwsem); >- if (err) >+ if (delegation == NULL) >+ return 0; >+ do { >+ err = nfs_delegation_claim_opens(inode, &delegation->stateid); >+ if (!issync || err != -EAGAIN) >+ break; >+ /* >+ * Guard against state recovery >+ */ >+ err = nfs4_wait_clnt_recover(clp); >+ } while (err == 0); >+ >+ if (err) { >+ nfs_abort_delegation_return(delegation, clp); >+ goto out; >+ } >+ if (!nfs_detach_delegation(nfsi, delegation, NFS_SERVER(inode))) > goto out; > > err = nfs_do_return_delegation(inode, delegation, issync); >@@ -340,13 +417,10 @@ restart: > inode = nfs_delegation_grab_inode(delegation); > if (inode == NULL) > continue; >- delegation = nfs_detach_delegation(NFS_I(inode), >- server); >+ delegation = nfs_start_delegation_return_locked(NFS_I(inode)); > rcu_read_unlock(); > >- if (delegation != NULL) >- err = __nfs_inode_return_delegation(inode, >- delegation, 0); >+ err = nfs_end_delegation_return(inode, delegation, 0); > iput(inode); > if (!err) > goto restart; >@@ -367,15 +441,11 @@ restart: > */ > void nfs_inode_return_delegation_noreclaim(struct inode *inode) > { >- struct nfs_server *server = NFS_SERVER(inode); >- struct nfs_inode *nfsi = NFS_I(inode); > struct nfs_delegation *delegation; > >- if (rcu_access_pointer(nfsi->delegation) != NULL) { >- delegation = nfs_detach_delegation(nfsi, server); >- if (delegation != NULL) >- nfs_do_return_delegation(inode, delegation, 0); >- } >+ delegation = nfs_inode_detach_delegation(inode); >+ if (delegation != NULL) >+ nfs_do_return_delegation(inode, delegation, 0); > } > > /** >@@ -390,18 +460,14 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode) > */ > int nfs4_inode_return_delegation(struct inode *inode) > { >- struct nfs_server *server = NFS_SERVER(inode); > struct nfs_inode *nfsi = NFS_I(inode); > struct nfs_delegation *delegation; > int err = 0; > > nfs_wb_all(inode); >- if (rcu_access_pointer(nfsi->delegation) != NULL) { >- delegation = nfs_detach_delegation(nfsi, server); >- if (delegation != NULL) { >- err = __nfs_inode_return_delegation(inode, delegation, 1); >- } >- } >+ delegation = nfs_start_delegation_return(nfsi); >+ if (delegation != NULL) >+ err = nfs_end_delegation_return(inode, delegation, 1); > return err; > } > >@@ -471,7 +537,7 @@ void nfs_remove_bad_delegation(struct inode *inode) > { > struct nfs_delegation *delegation; > >- delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode)); >+ delegation = nfs_inode_detach_delegation(inode); > if (delegation) { > nfs_inode_find_state_and_recover(inode, &delegation->stateid); > nfs_free_delegation(delegation); >@@ -649,7 +715,7 @@ restart: > if (inode == NULL) > continue; > delegation = nfs_detach_delegation(NFS_I(inode), >- server); >+ delegation, server); > rcu_read_unlock(); > > if (delegation != NULL) >diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h >index bbc6a4d..d54d4fc 100644 >--- a/fs/nfs/delegation.h >+++ b/fs/nfs/delegation.h >@@ -29,6 +29,7 @@ enum { > NFS_DELEGATION_NEED_RECLAIM = 0, > NFS_DELEGATION_RETURN, > NFS_DELEGATION_REFERENCED, >+ NFS_DELEGATION_RETURNING, > }; > > int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); >diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c >index 033803c..44efaa8 100644 >--- a/fs/nfs/getroot.c >+++ b/fs/nfs/getroot.c >@@ -126,8 +126,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, > } > spin_unlock(&ret->d_lock); > out: >- if (name) >- kfree(name); >+ kfree(name); > nfs_free_fattr(fsinfo.fattr); > return ret; > } >diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c >index 6acc73c..f52c99f 100644 >--- a/fs/nfs/inode.c >+++ b/fs/nfs/inode.c >@@ -237,6 +237,8 @@ nfs_find_actor(struct inode *inode, void *opaque) > > if (NFS_FILEID(inode) != fattr->fileid) > return 0; >+ if ((S_IFMT & inode->i_mode) != (S_IFMT & fattr->mode)) >+ return 0; > if (nfs_compare_fh(NFS_FH(inode), fh)) > return 0; > if (is_bad_inode(inode) || NFS_STALE(inode)) >diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h >index a3f488b..944c9a5 100644 >--- a/fs/nfs/nfs4_fs.h >+++ b/fs/nfs/nfs4_fs.h >@@ -13,6 +13,8 @@ > > #define NFS4_MAX_LOOP_ON_RECOVER (10) > >+#include <linux/seqlock.h> >+ > struct idmap; > > enum nfs4_client_state { >@@ -90,6 +92,8 @@ struct nfs4_state_owner { > unsigned long so_flags; > struct list_head so_states; > struct nfs_seqid_counter so_seqid; >+ seqcount_t so_reclaim_seqcount; >+ struct mutex so_delegreturn_mutex; > }; > > enum { >diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c >index 194c484..49eeb04 100644 >--- a/fs/nfs/nfs4filelayout.c >+++ b/fs/nfs/nfs4filelayout.c >@@ -99,7 +99,8 @@ static void filelayout_reset_write(struct nfs_write_data *data) > > task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode, > &hdr->pages, >- hdr->completion_ops); >+ hdr->completion_ops, >+ hdr->dreq); > } > } > >@@ -119,7 +120,8 @@ static void filelayout_reset_read(struct nfs_read_data *data) > > task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode, > &hdr->pages, >- hdr->completion_ops); >+ hdr->completion_ops, >+ hdr->dreq); > } > } > >diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h >index 8c07241..b8da955 100644 >--- a/fs/nfs/nfs4filelayout.h >+++ b/fs/nfs/nfs4filelayout.h >@@ -36,7 +36,7 @@ > * Default data server connection timeout and retrans vaules. > * Set by module paramters dataserver_timeo and dataserver_retrans. > */ >-#define NFS4_DEF_DS_TIMEO 60 >+#define NFS4_DEF_DS_TIMEO 600 /* in tenths of a second */ > #define NFS4_DEF_DS_RETRANS 5 > > /* >diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c >index 62fa400..b2671cb 100644 >--- a/fs/nfs/nfs4proc.c >+++ b/fs/nfs/nfs4proc.c >@@ -93,6 +93,8 @@ static int nfs4_map_errors(int err) > return err; > switch (err) { > case -NFS4ERR_RESOURCE: >+ case -NFS4ERR_LAYOUTTRYLATER: >+ case -NFS4ERR_RECALLCONFLICT: > return -EREMOTEIO; > case -NFS4ERR_WRONGSEC: > return -EPERM; >@@ -896,6 +898,8 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) > return 0; > if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) > return 0; >+ if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) >+ return 0; > nfs_mark_delegation_referenced(delegation); > return 1; > } >@@ -973,6 +977,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat > > spin_lock(&deleg_cur->lock); > if (nfsi->delegation != deleg_cur || >+ test_bit(NFS_DELEGATION_RETURNING, &deleg_cur->flags) || > (deleg_cur->type & fmode) != fmode) > goto no_delegation_unlock; > >@@ -1155,6 +1160,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) > data->o_arg.fmode); > iput(inode); > out: >+ nfs_release_seqid(data->o_arg.seqid); > return state; > err_put_inode: > iput(inode); >@@ -1352,19 +1358,18 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state > case -NFS4ERR_BAD_HIGH_SLOT: > case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: > case -NFS4ERR_DEADSESSION: >+ set_bit(NFS_DELEGATED_STATE, &state->flags); > nfs4_schedule_session_recovery(server->nfs_client->cl_session, err); >+ err = -EAGAIN; > goto out; > case -NFS4ERR_STALE_CLIENTID: > case -NFS4ERR_STALE_STATEID: >+ set_bit(NFS_DELEGATED_STATE, &state->flags); > case -NFS4ERR_EXPIRED: > /* Don't recall a delegation if it was lost */ > nfs4_schedule_lease_recovery(server->nfs_client); >+ err = -EAGAIN; > goto out; >- case -ERESTARTSYS: >- /* >- * The show must go on: exit, but mark the >- * stateid as needing recovery. >- */ > case -NFS4ERR_DELEG_REVOKED: > case -NFS4ERR_ADMIN_REVOKED: > case -NFS4ERR_BAD_STATEID: >@@ -1375,6 +1380,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state > err = 0; > goto out; > } >+ set_bit(NFS_DELEGATED_STATE, &state->flags); > err = nfs4_handle_exception(server, err, &exception); > } while (exception.retry); > out: >@@ -1463,7 +1469,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) > struct nfs4_state_owner *sp = data->owner; > > if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) >- return; >+ goto out_wait; > /* > * Check if we still need to send an OPEN call, or if we can use > * a delegation instead. >@@ -1498,6 +1504,7 @@ unlock_no_action: > rcu_read_unlock(); > out_no_action: > task->tk_action = NULL; >+out_wait: > nfs4_sequence_done(task, &data->o_res.seq_res); > } > >@@ -1845,6 +1852,43 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct > sattr->ia_valid |= ATTR_MTIME; > } > >+static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, >+ fmode_t fmode, >+ int flags, >+ struct nfs4_state **res) >+{ >+ struct nfs4_state_owner *sp = opendata->owner; >+ struct nfs_server *server = sp->so_server; >+ struct nfs4_state *state; >+ unsigned int seq; >+ int ret; >+ >+ seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); >+ >+ ret = _nfs4_proc_open(opendata); >+ if (ret != 0) >+ goto out; >+ >+ state = nfs4_opendata_to_nfs4_state(opendata); >+ ret = PTR_ERR(state); >+ if (IS_ERR(state)) >+ goto out; >+ if (server->caps & NFS_CAP_POSIX_LOCK) >+ set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); >+ >+ ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags); >+ if (ret != 0) >+ goto out; >+ >+ if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) { >+ nfs4_schedule_stateid_recovery(server, state); >+ nfs4_wait_clnt_recover(server->nfs_client); >+ } >+ *res = state; >+out: >+ return ret; >+} >+ > /* > * Returns a referenced nfs4_state > */ >@@ -1889,18 +1933,7 @@ static int _nfs4_do_open(struct inode *dir, > if (dentry->d_inode != NULL) > opendata->state = nfs4_get_open_state(dentry->d_inode, sp); > >- status = _nfs4_proc_open(opendata); >- if (status != 0) >- goto err_opendata_put; >- >- state = nfs4_opendata_to_nfs4_state(opendata); >- status = PTR_ERR(state); >- if (IS_ERR(state)) >- goto err_opendata_put; >- if (server->caps & NFS_CAP_POSIX_LOCK) >- set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); >- >- status = nfs4_opendata_access(cred, opendata, state, fmode, flags); >+ status = _nfs4_open_and_get_state(opendata, fmode, flags, &state); > if (status != 0) > goto err_opendata_put; > >@@ -2150,7 +2183,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) > > dprintk("%s: begin!\n", __func__); > if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) >- return; >+ goto out_wait; > > task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; > calldata->arg.fmode = FMODE_READ|FMODE_WRITE; >@@ -2172,16 +2205,14 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) > > if (!call_close) { > /* Note: exit _without_ calling nfs4_close_done */ >- task->tk_action = NULL; >- nfs4_sequence_done(task, &calldata->res.seq_res); >- goto out; >+ goto out_no_action; > } > > if (calldata->arg.fmode == 0) { > task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; > if (calldata->roc && > pnfs_roc_drain(inode, &calldata->roc_barrier, task)) >- goto out; >+ goto out_wait; > } > > nfs_fattr_init(calldata->res.fattr); >@@ -2191,8 +2222,12 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) > &calldata->res.seq_res, > task) != 0) > nfs_release_seqid(calldata->arg.seqid); >-out: > dprintk("%s: done!\n", __func__); >+ return; >+out_no_action: >+ task->tk_action = NULL; >+out_wait: >+ nfs4_sequence_done(task, &calldata->res.seq_res); > } > > static const struct rpc_call_ops nfs4_close_ops = { >@@ -4423,12 +4458,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) > struct nfs4_unlockdata *calldata = data; > > if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) >- return; >+ goto out_wait; > if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) { > /* Note: exit _without_ running nfs4_locku_done */ >- task->tk_action = NULL; >- nfs4_sequence_done(task, &calldata->res.seq_res); >- return; >+ goto out_no_action; > } > calldata->timestamp = jiffies; > if (nfs4_setup_sequence(calldata->server, >@@ -4436,6 +4469,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) > &calldata->res.seq_res, > task) != 0) > nfs_release_seqid(calldata->arg.seqid); >+ return; >+out_no_action: >+ task->tk_action = NULL; >+out_wait: >+ nfs4_sequence_done(task, &calldata->res.seq_res); > } > > static const struct rpc_call_ops nfs4_locku_ops = { >@@ -4482,7 +4520,9 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, > > static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) > { >- struct nfs_inode *nfsi = NFS_I(state->inode); >+ struct inode *inode = state->inode; >+ struct nfs4_state_owner *sp = state->owner; >+ struct nfs_inode *nfsi = NFS_I(inode); > struct nfs_seqid *seqid; > struct nfs4_lock_state *lsp; > struct rpc_task *task; >@@ -4492,12 +4532,17 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * > status = nfs4_set_lock_state(state, request); > /* Unlock _before_ we do the RPC call */ > request->fl_flags |= FL_EXISTS; >+ /* Exclude nfs_delegation_claim_locks() */ >+ mutex_lock(&sp->so_delegreturn_mutex); >+ /* Exclude nfs4_reclaim_open_stateid() - note nesting! */ > down_read(&nfsi->rwsem); > if (do_vfs_lock(request->fl_file, request) == -ENOENT) { > up_read(&nfsi->rwsem); >+ mutex_unlock(&sp->so_delegreturn_mutex); > goto out; > } > up_read(&nfsi->rwsem); >+ mutex_unlock(&sp->so_delegreturn_mutex); > if (status != 0) > goto out; > /* Is this a delegated lock? */ >@@ -4576,7 +4621,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) > > dprintk("%s: begin!\n", __func__); > if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0) >- return; >+ goto out_wait; > /* Do we need to do an open_to_lock_owner? */ > if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) { > if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) { >@@ -4596,6 +4641,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) > nfs_release_seqid(data->arg.open_seqid); > out_release_lock_seqid: > nfs_release_seqid(data->arg.lock_seqid); >+out_wait: >+ nfs4_sequence_done(task, &data->res.seq_res); > dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); > } > >@@ -4813,8 +4860,10 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques > > static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) > { >+ struct nfs4_state_owner *sp = state->owner; > struct nfs_inode *nfsi = NFS_I(state->inode); > unsigned char fl_flags = request->fl_flags; >+ unsigned int seq; > int status = -ENOLCK; > > if ((fl_flags & FL_POSIX) && >@@ -4836,9 +4885,16 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock > status = do_vfs_lock(request->fl_file, request); > goto out_unlock; > } >+ seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); >+ up_read(&nfsi->rwsem); > status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW); > if (status != 0) >+ goto out; >+ down_read(&nfsi->rwsem); >+ if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) { >+ status = -NFS4ERR_DELAY; > goto out_unlock; >+ } > /* Note: we always want to sleep here! */ > request->fl_flags = fl_flags | FL_SLEEP; > if (do_vfs_lock(request->fl_file, request) < 0) >@@ -4945,24 +5001,22 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) > case 0: > case -ESTALE: > goto out; >- case -NFS4ERR_EXPIRED: >- nfs4_schedule_stateid_recovery(server, state); > case -NFS4ERR_STALE_CLIENTID: > case -NFS4ERR_STALE_STATEID: >+ set_bit(NFS_DELEGATED_STATE, &state->flags); >+ case -NFS4ERR_EXPIRED: > nfs4_schedule_lease_recovery(server->nfs_client); >+ err = -EAGAIN; > goto out; > case -NFS4ERR_BADSESSION: > case -NFS4ERR_BADSLOT: > case -NFS4ERR_BAD_HIGH_SLOT: > case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: > case -NFS4ERR_DEADSESSION: >+ set_bit(NFS_DELEGATED_STATE, &state->flags); > nfs4_schedule_session_recovery(server->nfs_client->cl_session, err); >+ err = -EAGAIN; > goto out; >- case -ERESTARTSYS: >- /* >- * The show must go on: exit, but mark the >- * stateid as needing recovery. >- */ > case -NFS4ERR_DELEG_REVOKED: > case -NFS4ERR_ADMIN_REVOKED: > case -NFS4ERR_BAD_STATEID: >@@ -4975,9 +5029,8 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) > /* kill_proc(fl->fl_pid, SIGLOST, 1); */ > err = 0; > goto out; >- case -NFS4ERR_DELAY: >- break; > } >+ set_bit(NFS_DELEGATED_STATE, &state->flags); > err = nfs4_handle_exception(server, err, &exception); > } while (exception.retry); > out: >@@ -5995,6 +6048,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) > struct nfs_server *server = NFS_SERVER(inode); > struct pnfs_layout_hdr *lo; > struct nfs4_state *state = NULL; >+ unsigned long timeo, giveup; > > dprintk("--> %s\n", __func__); > >@@ -6006,7 +6060,10 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) > goto out; > case -NFS4ERR_LAYOUTTRYLATER: > case -NFS4ERR_RECALLCONFLICT: >- task->tk_status = -NFS4ERR_DELAY; >+ timeo = rpc_get_timeout(task->tk_client); >+ giveup = lgp->args.timestamp + timeo; >+ if (time_after(giveup, jiffies)) >+ task->tk_status = -NFS4ERR_DELAY; > break; > case -NFS4ERR_EXPIRED: > case -NFS4ERR_BAD_STATEID: >@@ -6079,11 +6136,13 @@ static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) > static void nfs4_layoutget_release(void *calldata) > { > struct nfs4_layoutget *lgp = calldata; >- struct nfs_server *server = NFS_SERVER(lgp->args.inode); >+ struct inode *inode = lgp->args.inode; >+ struct nfs_server *server = NFS_SERVER(inode); > size_t max_pages = max_response_pages(server); > > dprintk("--> %s\n", __func__); > nfs4_free_pages(lgp->args.layout.pages, max_pages); >+ pnfs_put_layout_hdr(NFS_I(inode)->layout); > put_nfs_open_context(lgp->args.ctx); > kfree(calldata); > dprintk("<-- %s\n", __func__); >@@ -6098,7 +6157,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = { > struct pnfs_layout_segment * > nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) > { >- struct nfs_server *server = NFS_SERVER(lgp->args.inode); >+ struct inode *inode = lgp->args.inode; >+ struct nfs_server *server = NFS_SERVER(inode); > size_t max_pages = max_response_pages(server); > struct rpc_task *task; > struct rpc_message msg = { >@@ -6124,17 +6184,23 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) > return ERR_PTR(-ENOMEM); > } > lgp->args.layout.pglen = max_pages * PAGE_SIZE; >+ lgp->args.timestamp = jiffies; > > lgp->res.layoutp = &lgp->args.layout; > lgp->res.seq_res.sr_slot = NULL; > nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); >+ >+ /* nfs4_layoutget_release calls pnfs_put_layout_hdr */ >+ pnfs_get_layout_hdr(NFS_I(inode)->layout); >+ > task = rpc_run_task(&task_setup_data); > if (IS_ERR(task)) > return ERR_CAST(task); > status = nfs4_wait_for_completion_rpc_task(task); > if (status == 0) > status = task->tk_status; >- if (status == 0) >+ /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ >+ if (status == 0 && lgp->res.layoutp->len) > lseg = pnfs_layout_process(lgp); > rpc_put_task(task); > dprintk("<-- %s status=%d\n", __func__, status); >diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c >index e61f68d..6ace365 100644 >--- a/fs/nfs/nfs4state.c >+++ b/fs/nfs/nfs4state.c >@@ -518,6 +518,8 @@ nfs4_alloc_state_owner(struct nfs_server *server, > nfs4_init_seqid_counter(&sp->so_seqid); > atomic_set(&sp->so_count, 1); > INIT_LIST_HEAD(&sp->so_lru); >+ seqcount_init(&sp->so_reclaim_seqcount); >+ mutex_init(&sp->so_delegreturn_mutex); > return sp; > } > >@@ -1390,8 +1392,9 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs > * recovering after a network partition or a reboot from a > * server that doesn't support a grace period. > */ >-restart: > spin_lock(&sp->so_lock); >+ write_seqcount_begin(&sp->so_reclaim_seqcount); >+restart: > list_for_each_entry(state, &sp->so_states, open_states) { > if (!test_and_clear_bit(ops->state_flag_bit, &state->flags)) > continue; >@@ -1412,6 +1415,7 @@ restart: > } > spin_unlock(&state->state_lock); > nfs4_put_open_state(state); >+ spin_lock(&sp->so_lock); > goto restart; > } > } >@@ -1449,12 +1453,17 @@ restart: > goto out_err; > } > nfs4_put_open_state(state); >+ spin_lock(&sp->so_lock); > goto restart; > } >+ write_seqcount_end(&sp->so_reclaim_seqcount); > spin_unlock(&sp->so_lock); > return 0; > out_err: > nfs4_put_open_state(state); >+ spin_lock(&sp->so_lock); >+ write_seqcount_end(&sp->so_reclaim_seqcount); >+ spin_unlock(&sp->so_lock); > return status; > } > >diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c >index c6f9906..88f9611 100644 >--- a/fs/nfs/objlayout/objio_osd.c >+++ b/fs/nfs/objlayout/objio_osd.c >@@ -647,6 +647,7 @@ static struct pnfs_layoutdriver_type objlayout_type = { > .flags = PNFS_LAYOUTRET_ON_SETATTR | > PNFS_LAYOUTRET_ON_ERROR, > >+ .owner = THIS_MODULE, > .alloc_layout_hdr = objlayout_alloc_layout_hdr, > .free_layout_hdr = objlayout_free_layout_hdr, > >diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c >index d00260b..48ac5aa 100644 >--- a/fs/nfs/pnfs.c >+++ b/fs/nfs/pnfs.c >@@ -505,37 +505,147 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) > } > EXPORT_SYMBOL_GPL(pnfs_destroy_layout); > >-/* >- * Called by the state manger to remove all layouts established under an >- * expired lease. >- */ >-void >-pnfs_destroy_all_layouts(struct nfs_client *clp) >+static bool >+pnfs_layout_add_bulk_destroy_list(struct inode *inode, >+ struct list_head *layout_list) > { >- struct nfs_server *server; > struct pnfs_layout_hdr *lo; >- LIST_HEAD(tmp_list); >+ bool ret = false; > >- nfs4_deviceid_mark_client_invalid(clp); >- nfs4_deviceid_purge_client(clp); >+ spin_lock(&inode->i_lock); >+ lo = NFS_I(inode)->layout; >+ if (lo != NULL && list_empty(&lo->plh_bulk_destroy)) { >+ pnfs_get_layout_hdr(lo); >+ list_add(&lo->plh_bulk_destroy, layout_list); >+ ret = true; >+ } >+ spin_unlock(&inode->i_lock); >+ return ret; >+} >+ >+/* Caller must hold rcu_read_lock and clp->cl_lock */ >+static int >+pnfs_layout_bulk_destroy_byserver_locked(struct nfs_client *clp, >+ struct nfs_server *server, >+ struct list_head *layout_list) >+{ >+ struct pnfs_layout_hdr *lo, *next; >+ struct inode *inode; >+ >+ list_for_each_entry_safe(lo, next, &server->layouts, plh_layouts) { >+ inode = igrab(lo->plh_inode); >+ if (inode == NULL) >+ continue; >+ list_del_init(&lo->plh_layouts); >+ if (pnfs_layout_add_bulk_destroy_list(inode, layout_list)) >+ continue; >+ rcu_read_unlock(); >+ spin_unlock(&clp->cl_lock); >+ iput(inode); >+ spin_lock(&clp->cl_lock); >+ rcu_read_lock(); >+ return -EAGAIN; >+ } >+ return 0; >+} >+ >+static int >+pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list, >+ bool is_bulk_recall) >+{ >+ struct pnfs_layout_hdr *lo; >+ struct inode *inode; >+ struct pnfs_layout_range range = { >+ .iomode = IOMODE_ANY, >+ .offset = 0, >+ .length = NFS4_MAX_UINT64, >+ }; >+ LIST_HEAD(lseg_list); >+ int ret = 0; >+ >+ while (!list_empty(layout_list)) { >+ lo = list_entry(layout_list->next, struct pnfs_layout_hdr, >+ plh_bulk_destroy); >+ dprintk("%s freeing layout for inode %lu\n", __func__, >+ lo->plh_inode->i_ino); >+ inode = lo->plh_inode; >+ spin_lock(&inode->i_lock); >+ list_del_init(&lo->plh_bulk_destroy); >+ lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ >+ if (is_bulk_recall) >+ set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags); >+ if (pnfs_mark_matching_lsegs_invalid(lo, &lseg_list, &range)) >+ ret = -EAGAIN; >+ spin_unlock(&inode->i_lock); >+ pnfs_free_lseg_list(&lseg_list); >+ pnfs_put_layout_hdr(lo); >+ iput(inode); >+ } >+ return ret; >+} >+ >+int >+pnfs_destroy_layouts_byfsid(struct nfs_client *clp, >+ struct nfs_fsid *fsid, >+ bool is_recall) >+{ >+ struct nfs_server *server; >+ LIST_HEAD(layout_list); > > spin_lock(&clp->cl_lock); > rcu_read_lock(); >+restart: > list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { >- if (!list_empty(&server->layouts)) >- list_splice_init(&server->layouts, &tmp_list); >+ if (memcmp(&server->fsid, fsid, sizeof(*fsid)) != 0) >+ continue; >+ if (pnfs_layout_bulk_destroy_byserver_locked(clp, >+ server, >+ &layout_list) != 0) >+ goto restart; > } > rcu_read_unlock(); > spin_unlock(&clp->cl_lock); > >- while (!list_empty(&tmp_list)) { >- lo = list_entry(tmp_list.next, struct pnfs_layout_hdr, >- plh_layouts); >- dprintk("%s freeing layout for inode %lu\n", __func__, >- lo->plh_inode->i_ino); >- list_del_init(&lo->plh_layouts); >- pnfs_destroy_layout(NFS_I(lo->plh_inode)); >+ if (list_empty(&layout_list)) >+ return 0; >+ return pnfs_layout_free_bulk_destroy_list(&layout_list, is_recall); >+} >+ >+int >+pnfs_destroy_layouts_byclid(struct nfs_client *clp, >+ bool is_recall) >+{ >+ struct nfs_server *server; >+ LIST_HEAD(layout_list); >+ >+ spin_lock(&clp->cl_lock); >+ rcu_read_lock(); >+restart: >+ list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { >+ if (pnfs_layout_bulk_destroy_byserver_locked(clp, >+ server, >+ &layout_list) != 0) >+ goto restart; > } >+ rcu_read_unlock(); >+ spin_unlock(&clp->cl_lock); >+ >+ if (list_empty(&layout_list)) >+ return 0; >+ return pnfs_layout_free_bulk_destroy_list(&layout_list, is_recall); >+} >+ >+/* >+ * Called by the state manger to remove all layouts established under an >+ * expired lease. >+ */ >+void >+pnfs_destroy_all_layouts(struct nfs_client *clp) >+{ >+ nfs4_deviceid_mark_client_invalid(clp); >+ nfs4_deviceid_purge_client(clp); >+ >+ pnfs_destroy_layouts_byclid(clp, false); > } > > /* >@@ -888,7 +998,7 @@ alloc_init_layout_hdr(struct inode *ino, > atomic_set(&lo->plh_refcount, 1); > INIT_LIST_HEAD(&lo->plh_layouts); > INIT_LIST_HEAD(&lo->plh_segs); >- INIT_LIST_HEAD(&lo->plh_bulk_recall); >+ INIT_LIST_HEAD(&lo->plh_bulk_destroy); > lo->plh_inode = ino; > lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred); > return lo; >@@ -1071,7 +1181,7 @@ pnfs_update_layout(struct inode *ino, > struct nfs_client *clp = server->nfs_client; > struct pnfs_layout_hdr *lo; > struct pnfs_layout_segment *lseg = NULL; >- bool first = false; >+ bool first; > > if (!pnfs_enabled_sb(NFS_SERVER(ino))) > goto out; >@@ -1105,10 +1215,9 @@ pnfs_update_layout(struct inode *ino, > goto out_unlock; > atomic_inc(&lo->plh_outstanding); > >- if (list_empty(&lo->plh_segs)) >- first = true; >- >+ first = list_empty(&lo->plh_layouts) ? true : false; > spin_unlock(&ino->i_lock); >+ > if (first) { > /* The lo must be on the clp list if there is any > * chance of a CB_LAYOUTRECALL(FILE) coming in. >@@ -1312,13 +1421,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); > > int pnfs_write_done_resend_to_mds(struct inode *inode, > struct list_head *head, >- const struct nfs_pgio_completion_ops *compl_ops) >+ const struct nfs_pgio_completion_ops *compl_ops, >+ struct nfs_direct_req *dreq) > { > struct nfs_pageio_descriptor pgio; > LIST_HEAD(failed); > > /* Resend all requests through the MDS */ > nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops); >+ pgio.pg_dreq = dreq; > while (!list_empty(head)) { > struct nfs_page *req = nfs_list_entry(head->next); > >@@ -1353,7 +1464,8 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) > if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) > data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, > &hdr->pages, >- hdr->completion_ops); >+ hdr->completion_ops, >+ hdr->dreq); > } > > /* >@@ -1468,13 +1580,15 @@ EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); > > int pnfs_read_done_resend_to_mds(struct inode *inode, > struct list_head *head, >- const struct nfs_pgio_completion_ops *compl_ops) >+ const struct nfs_pgio_completion_ops *compl_ops, >+ struct nfs_direct_req *dreq) > { > struct nfs_pageio_descriptor pgio; > LIST_HEAD(failed); > > /* Resend all requests through the MDS */ > nfs_pageio_init_read(&pgio, inode, compl_ops); >+ pgio.pg_dreq = dreq; > while (!list_empty(head)) { > struct nfs_page *req = nfs_list_entry(head->next); > >@@ -1505,7 +1619,8 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) > if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) > data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, > &hdr->pages, >- hdr->completion_ops); >+ hdr->completion_ops, >+ hdr->dreq); > } > > /* >diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h >index dbf7bba..94ba804 100644 >--- a/fs/nfs/pnfs.h >+++ b/fs/nfs/pnfs.h >@@ -132,7 +132,7 @@ struct pnfs_layoutdriver_type { > struct pnfs_layout_hdr { > atomic_t plh_refcount; > struct list_head plh_layouts; /* other client layouts */ >- struct list_head plh_bulk_recall; /* clnt list of bulk recalls */ >+ struct list_head plh_bulk_destroy; > struct list_head plh_segs; /* layout segments list */ > nfs4_stateid plh_stateid; > atomic_t plh_outstanding; /* number of RPCs out */ >@@ -196,6 +196,11 @@ struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp); > void pnfs_free_lseg_list(struct list_head *tmp_list); > void pnfs_destroy_layout(struct nfs_inode *); > void pnfs_destroy_all_layouts(struct nfs_client *); >+int pnfs_destroy_layouts_byfsid(struct nfs_client *clp, >+ struct nfs_fsid *fsid, >+ bool is_recall); >+int pnfs_destroy_layouts_byclid(struct nfs_client *clp, >+ bool is_recall); > void pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo); > void pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, > const nfs4_stateid *new, >@@ -225,9 +230,11 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, > > void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); > int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, >- const struct nfs_pgio_completion_ops *compl_ops); >+ const struct nfs_pgio_completion_ops *compl_ops, >+ struct nfs_direct_req *dreq); > int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head, >- const struct nfs_pgio_completion_ops *compl_ops); >+ const struct nfs_pgio_completion_ops *compl_ops, >+ struct nfs_direct_req *dreq); > struct nfs4_threshold *pnfs_mdsthreshold_alloc(void); > > /* nfs4_deviceid_flags */ >diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c >index 13cea63..1f1f38f 100644 >--- a/fs/nfs/unlink.c >+++ b/fs/nfs/unlink.c >@@ -268,8 +268,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) > * point dentry is definitely not a root, so we won't need > * that anymore. > */ >- if (devname_garbage) >- kfree(devname_garbage); >+ kfree(devname_garbage); > return 0; > out_unlock: > spin_unlock(&dentry->d_lock); >@@ -336,20 +335,14 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) > struct inode *old_dir = data->old_dir; > struct inode *new_dir = data->new_dir; > struct dentry *old_dentry = data->old_dentry; >- struct dentry *new_dentry = data->new_dentry; > > if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) { > rpc_restart_call_prepare(task); > return; > } > >- if (task->tk_status != 0) { >+ if (task->tk_status != 0) > nfs_cancel_async_unlink(old_dentry); >- return; >- } >- >- d_drop(old_dentry); >- d_drop(new_dentry); > } > > /** >@@ -550,6 +543,18 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) > error = rpc_wait_for_completion_task(task); > if (error == 0) > error = task->tk_status; >+ switch (error) { >+ case 0: >+ /* The rename succeeded */ >+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); >+ d_move(dentry, sdentry); >+ break; >+ case -ERESTARTSYS: >+ /* The result of the rename is unknown. Play it safe by >+ * forcing a new lookup */ >+ d_drop(dentry); >+ d_drop(sdentry); >+ } > rpc_put_task(task); > out_dput: > dput(sdentry); >diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h >index 29adb12..2250cab 100644 >--- a/include/linux/nfs_xdr.h >+++ b/include/linux/nfs_xdr.h >@@ -233,6 +233,7 @@ struct nfs4_layoutget_args { > struct inode *inode; > struct nfs_open_context *ctx; > nfs4_stateid stateid; >+ unsigned long timestamp; > struct nfs4_layoutdriver_data layout; > }; > >diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h >index 34206b8..21d52d0 100644 >--- a/include/linux/sunrpc/clnt.h >+++ b/include/linux/sunrpc/clnt.h >@@ -160,6 +160,7 @@ void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); > int rpc_protocol(struct rpc_clnt *); > struct net * rpc_net_ns(struct rpc_clnt *); > size_t rpc_max_payload(struct rpc_clnt *); >+unsigned long rpc_get_timeout(struct rpc_clnt *clnt); > void rpc_force_rebind(struct rpc_clnt *); > size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); > const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); >diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c >index e7243f9..911ef00 100644 >--- a/net/sunrpc/auth_gss/auth_gss.c >+++ b/net/sunrpc/auth_gss/auth_gss.c >@@ -247,8 +247,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct > __func__, ctx->gc_expiry, now, timeout); > return q; > err: >- dprintk("RPC: %s returns %ld gc_expiry %lu now %lu timeout %u\n", >- __func__, -PTR_ERR(p), ctx->gc_expiry, now, timeout); >+ dprintk("RPC: %s returns error %ld\n", __func__, -PTR_ERR(p)); > return p; > } > >diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c >index a9f7906..f922fe8 100644 >--- a/net/sunrpc/clnt.c >+++ b/net/sunrpc/clnt.c >@@ -1196,6 +1196,21 @@ size_t rpc_max_payload(struct rpc_clnt *clnt) > EXPORT_SYMBOL_GPL(rpc_max_payload); > > /** >+ * rpc_get_timeout - Get timeout for transport in units of HZ >+ * @clnt: RPC client to query >+ */ >+unsigned long rpc_get_timeout(struct rpc_clnt *clnt) >+{ >+ unsigned long ret; >+ >+ rcu_read_lock(); >+ ret = rcu_dereference(clnt->cl_xprt)->timeout->to_initval; >+ rcu_read_unlock(); >+ return ret; >+} >+EXPORT_SYMBOL_GPL(rpc_get_timeout); >+ >+/** > * rpc_force_rebind - force transport to check that remote port is unchanged > * @clnt: client to rebind > * >diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c >index 846c34f..b7478d5 100644 >--- a/net/sunrpc/xprt.c >+++ b/net/sunrpc/xprt.c >@@ -487,13 +487,17 @@ EXPORT_SYMBOL_GPL(xprt_wake_pending_tasks); > * xprt_wait_for_buffer_space - wait for transport output buffer to clear > * @task: task to be put to sleep > * @action: function pointer to be executed after wait >+ * >+ * Note that we only set the timer for the case of RPC_IS_SOFT(), since >+ * we don't in general want to force a socket disconnection due to >+ * an incomplete RPC call transmission. > */ > void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action) > { > struct rpc_rqst *req = task->tk_rqstp; > struct rpc_xprt *xprt = req->rq_xprt; > >- task->tk_timeout = req->rq_timeout; >+ task->tk_timeout = RPC_IS_SOFT(task) ? req->rq_timeout : 0; > rpc_sleep_on(&xprt->pending, task, action); > } > EXPORT_SYMBOL_GPL(xprt_wait_for_buffer_space);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 911668
:
697862
| 704987