aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-07-30 08:27:21 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-08-05 10:55:07 -0400
commit016200c37341b62df14ec642b0b30b4b70bc09af (patch)
tree6743fbe072309619c3f27f81754385cc86deebdd /fs/nfsd
parent3738d50e7f6d04dd58d219cf9111bf927c17c6f2 (diff)
nfsd: add more granular locking to forget_locks fault injector
...instead of relying on the client_mutex. Signed-off-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/fault_inject.c8
-rw-r--r--fs/nfsd/nfs4state.c132
-rw-r--r--fs/nfsd/state.h7
3 files changed, 131 insertions, 16 deletions
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index 76ecdff37ea2..a444d821d2a5 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -140,11 +140,9 @@ static struct nfsd_fault_inject_op inject_ops[] = {
140 }, 140 },
141 { 141 {
142 .file = "forget_locks", 142 .file = "forget_locks",
143 .get = nfsd_inject_get, 143 .get = nfsd_inject_print_locks,
144 .set_val = nfsd_inject_set, 144 .set_val = nfsd_inject_forget_locks,
145 .set_clnt = nfsd_inject_set_client, 145 .set_clnt = nfsd_inject_forget_client_locks,
146 .forget = nfsd_forget_client_locks,
147 .print = nfsd_print_client_locks,
148 }, 146 },
149 { 147 {
150 .file = "forget_openowners", 148 .file = "forget_openowners",
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b661294144ba..48ae0a66d512 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5723,6 +5723,12 @@ nfs4_check_open_reclaim(clientid_t *clid,
5723} 5723}
5724 5724
5725#ifdef CONFIG_NFSD_FAULT_INJECTION 5725#ifdef CONFIG_NFSD_FAULT_INJECTION
5726static inline void
5727put_client(struct nfs4_client *clp)
5728{
5729 atomic_dec(&clp->cl_refcount);
5730}
5731
5726u64 5732u64
5727nfsd_inject_print_clients(struct nfsd_fault_inject_op *op) 5733nfsd_inject_print_clients(struct nfsd_fault_inject_op *op)
5728{ 5734{
@@ -5810,6 +5816,22 @@ static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
5810 printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 5816 printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
5811} 5817}
5812 5818
5819static void
5820nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst,
5821 struct list_head *collect)
5822{
5823 struct nfs4_client *clp = lst->st_stid.sc_client;
5824 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5825 nfsd_net_id);
5826
5827 if (!collect)
5828 return;
5829
5830 lockdep_assert_held(&nn->client_lock);
5831 atomic_inc(&clp->cl_refcount);
5832 list_add(&lst->st_locks, collect);
5833}
5834
5813static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 5835static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
5814 struct list_head *collect, 5836 struct list_head *collect,
5815 void (*func)(struct nfs4_ol_stateid *)) 5837 void (*func)(struct nfs4_ol_stateid *))
@@ -5819,6 +5841,7 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
5819 struct nfs4_ol_stateid *lst, *lst_next; 5841 struct nfs4_ol_stateid *lst, *lst_next;
5820 u64 count = 0; 5842 u64 count = 0;
5821 5843
5844 spin_lock(&clp->cl_lock);
5822 list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 5845 list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
5823 list_for_each_entry_safe(stp, st_next, 5846 list_for_each_entry_safe(stp, st_next,
5824 &oop->oo_owner.so_stateids, st_perstateowner) { 5847 &oop->oo_owner.so_stateids, st_perstateowner) {
@@ -5826,31 +5849,122 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
5826 &stp->st_locks, st_locks) { 5849 &stp->st_locks, st_locks) {
5827 if (func) { 5850 if (func) {
5828 func(lst); 5851 func(lst);
5829 if (collect) 5852 nfsd_inject_add_lock_to_list(lst,
5830 list_add(&lst->st_locks, 5853 collect);
5831 collect);
5832 } 5854 }
5833 if (++count == max) 5855 ++count;
5834 return count; 5856 /*
5857 * Despite the fact that these functions deal
5858 * with 64-bit integers for "count", we must
5859 * ensure that it doesn't blow up the
5860 * clp->cl_refcount. Throw a warning if we
5861 * start to approach INT_MAX here.
5862 */
5863 WARN_ON_ONCE(count == (INT_MAX / 2));
5864 if (count == max)
5865 goto out;
5835 } 5866 }
5836 } 5867 }
5837 } 5868 }
5869out:
5870 spin_unlock(&clp->cl_lock);
5838 5871
5839 return count; 5872 return count;
5840} 5873}
5841 5874
5842u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) 5875static u64
5876nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect,
5877 u64 max)
5843{ 5878{
5844 return nfsd_foreach_client_lock(clp, max, NULL, release_lock_stateid); 5879 return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid);
5845} 5880}
5846 5881
5847u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) 5882static u64
5883nfsd_print_client_locks(struct nfs4_client *clp)
5848{ 5884{
5849 u64 count = nfsd_foreach_client_lock(clp, max, NULL, NULL); 5885 u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL);
5850 nfsd_print_count(clp, count, "locked files"); 5886 nfsd_print_count(clp, count, "locked files");
5851 return count; 5887 return count;
5852} 5888}
5853 5889
5890u64
5891nfsd_inject_print_locks(struct nfsd_fault_inject_op *op)
5892{
5893 struct nfs4_client *clp;
5894 u64 count = 0;
5895 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5896 nfsd_net_id);
5897
5898 if (!nfsd_netns_ready(nn))
5899 return 0;
5900
5901 spin_lock(&nn->client_lock);
5902 list_for_each_entry(clp, &nn->client_lru, cl_lru)
5903 count += nfsd_print_client_locks(clp);
5904 spin_unlock(&nn->client_lock);
5905
5906 return count;
5907}
5908
5909static void
5910nfsd_reap_locks(struct list_head *reaplist)
5911{
5912 struct nfs4_client *clp;
5913 struct nfs4_ol_stateid *stp, *next;
5914
5915 list_for_each_entry_safe(stp, next, reaplist, st_locks) {
5916 list_del_init(&stp->st_locks);
5917 clp = stp->st_stid.sc_client;
5918 nfs4_put_stid(&stp->st_stid);
5919 put_client(clp);
5920 }
5921}
5922
5923u64
5924nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *op,
5925 struct sockaddr_storage *addr, size_t addr_size)
5926{
5927 unsigned int count = 0;
5928 struct nfs4_client *clp;
5929 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5930 nfsd_net_id);
5931 LIST_HEAD(reaplist);
5932
5933 if (!nfsd_netns_ready(nn))
5934 return count;
5935
5936 spin_lock(&nn->client_lock);
5937 clp = nfsd_find_client(addr, addr_size);
5938 if (clp)
5939 count = nfsd_collect_client_locks(clp, &reaplist, 0);
5940 spin_unlock(&nn->client_lock);
5941 nfsd_reap_locks(&reaplist);
5942 return count;
5943}
5944
5945u64
5946nfsd_inject_forget_locks(struct nfsd_fault_inject_op *op, u64 max)
5947{
5948 u64 count = 0;
5949 struct nfs4_client *clp;
5950 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5951 nfsd_net_id);
5952 LIST_HEAD(reaplist);
5953
5954 if (!nfsd_netns_ready(nn))
5955 return count;
5956
5957 spin_lock(&nn->client_lock);
5958 list_for_each_entry(clp, &nn->client_lru, cl_lru) {
5959 count += nfsd_collect_client_locks(clp, &reaplist, max - count);
5960 if (max != 0 && count >= max)
5961 break;
5962 }
5963 spin_unlock(&nn->client_lock);
5964 nfsd_reap_locks(&reaplist);
5965 return count;
5966}
5967
5854static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) 5968static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *))
5855{ 5969{
5856 struct nfs4_openowner *oop, *next; 5970 struct nfs4_openowner *oop, *next;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index eb3b35a74795..028947688d57 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -483,12 +483,15 @@ u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *,
483 struct sockaddr_storage *, size_t); 483 struct sockaddr_storage *, size_t);
484u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64); 484u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64);
485 485
486u64 nfsd_forget_client_locks(struct nfs4_client*, u64); 486u64 nfsd_inject_print_locks(struct nfsd_fault_inject_op *);
487u64 nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *,
488 struct sockaddr_storage *, size_t);
489u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64);
490
487u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); 491u64 nfsd_forget_client_openowners(struct nfs4_client *, u64);
488u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); 492u64 nfsd_forget_client_delegations(struct nfs4_client *, u64);
489u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); 493u64 nfsd_recall_client_delegations(struct nfs4_client *, u64);
490 494
491u64 nfsd_print_client_locks(struct nfs4_client *, u64);
492u64 nfsd_print_client_openowners(struct nfs4_client *, u64); 495u64 nfsd_print_client_openowners(struct nfs4_client *, u64);
493u64 nfsd_print_client_delegations(struct nfs4_client *, u64); 496u64 nfsd_print_client_delegations(struct nfs4_client *, u64);
494#else /* CONFIG_NFSD_FAULT_INJECTION */ 497#else /* CONFIG_NFSD_FAULT_INJECTION */