aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-01-20 18:47:05 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-01-31 19:28:21 -0500
commit4601df20fb3bf2b87e248abc622b8a7e4c3059fb (patch)
treefc415ca673c8b4ced88941e0a11fb933da793c66 /fs/nfs
parent82b0a4c3c171b180629696e8d1d5f52516f711e6 (diff)
NFSv4: Avoid thundering herd issues with nfs_release_seqid
Store a pointer to the rpc_task in struct nfs_seqid so that we can wake up only that request that is able to grab the lock after we've released it. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4state.c21
2 files changed, 16 insertions, 6 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index c45c21a5470f..b133b50dec9a 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -71,6 +71,7 @@ struct nfs_seqid_counter {
71struct nfs_seqid { 71struct nfs_seqid {
72 struct nfs_seqid_counter *sequence; 72 struct nfs_seqid_counter *sequence;
73 struct list_head list; 73 struct list_head list;
74 struct rpc_task *task;
74}; 75};
75 76
76static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status) 77static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status)
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index f0e9881c2aa2..7d098604802c 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -916,20 +916,28 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_m
916 if (new != NULL) { 916 if (new != NULL) {
917 new->sequence = counter; 917 new->sequence = counter;
918 INIT_LIST_HEAD(&new->list); 918 INIT_LIST_HEAD(&new->list);
919 new->task = NULL;
919 } 920 }
920 return new; 921 return new;
921} 922}
922 923
923void nfs_release_seqid(struct nfs_seqid *seqid) 924void nfs_release_seqid(struct nfs_seqid *seqid)
924{ 925{
925 if (!list_empty(&seqid->list)) { 926 struct nfs_seqid_counter *sequence;
926 struct nfs_seqid_counter *sequence = seqid->sequence;
927 927
928 spin_lock(&sequence->lock); 928 if (list_empty(&seqid->list))
929 list_del_init(&seqid->list); 929 return;
930 spin_unlock(&sequence->lock); 930 sequence = seqid->sequence;
931 rpc_wake_up(&sequence->wait); 931 spin_lock(&sequence->lock);
932 list_del_init(&seqid->list);
933 if (!list_empty(&sequence->list)) {
934 struct nfs_seqid *next;
935
936 next = list_first_entry(&sequence->list,
937 struct nfs_seqid, list);
938 rpc_wake_up_queued_task(&sequence->wait, next->task);
932 } 939 }
940 spin_unlock(&sequence->lock);
933} 941}
934 942
935void nfs_free_seqid(struct nfs_seqid *seqid) 943void nfs_free_seqid(struct nfs_seqid *seqid)
@@ -1000,6 +1008,7 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
1000 int status = 0; 1008 int status = 0;
1001 1009
1002 spin_lock(&sequence->lock); 1010 spin_lock(&sequence->lock);
1011 seqid->task = task;
1003 if (list_empty(&seqid->list)) 1012 if (list_empty(&seqid->list))
1004 list_add_tail(&seqid->list, &sequence->list); 1013 list_add_tail(&seqid->list, &sequence->list);
1005 if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) 1014 if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid)