diff options
-rw-r--r-- | fs/nfsd/fault_inject.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 132 | ||||
-rw-r--r-- | fs/nfsd/state.h | 7 |
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 |
5726 | static inline void | ||
5727 | put_client(struct nfs4_client *clp) | ||
5728 | { | ||
5729 | atomic_dec(&clp->cl_refcount); | ||
5730 | } | ||
5731 | |||
5726 | u64 | 5732 | u64 |
5727 | nfsd_inject_print_clients(struct nfsd_fault_inject_op *op) | 5733 | nfsd_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 | ||
5819 | static void | ||
5820 | nfsd_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 | |||
5813 | static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, | 5835 | static 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 | } |
5869 | out: | ||
5870 | spin_unlock(&clp->cl_lock); | ||
5838 | 5871 | ||
5839 | return count; | 5872 | return count; |
5840 | } | 5873 | } |
5841 | 5874 | ||
5842 | u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) | 5875 | static u64 |
5876 | nfsd_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 | ||
5847 | u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) | 5882 | static u64 |
5883 | nfsd_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 | ||
5890 | u64 | ||
5891 | nfsd_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 | |||
5909 | static void | ||
5910 | nfsd_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 | |||
5923 | u64 | ||
5924 | nfsd_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 | |||
5945 | u64 | ||
5946 | nfsd_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 | |||
5854 | static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) | 5968 | static 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); |
484 | u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64); | 484 | u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64); |
485 | 485 | ||
486 | u64 nfsd_forget_client_locks(struct nfs4_client*, u64); | 486 | u64 nfsd_inject_print_locks(struct nfsd_fault_inject_op *); |
487 | u64 nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *, | ||
488 | struct sockaddr_storage *, size_t); | ||
489 | u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64); | ||
490 | |||
487 | u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); | 491 | u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); |
488 | u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); | 492 | u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); |
489 | u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); | 493 | u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); |
490 | 494 | ||
491 | u64 nfsd_print_client_locks(struct nfs4_client *, u64); | ||
492 | u64 nfsd_print_client_openowners(struct nfs4_client *, u64); | 495 | u64 nfsd_print_client_openowners(struct nfs4_client *, u64); |
493 | u64 nfsd_print_client_delegations(struct nfs4_client *, u64); | 496 | u64 nfsd_print_client_delegations(struct nfs4_client *, u64); |
494 | #else /* CONFIG_NFSD_FAULT_INJECTION */ | 497 | #else /* CONFIG_NFSD_FAULT_INJECTION */ |