aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/fault_inject.c8
-rw-r--r--fs/nfsd/nfs4state.c122
-rw-r--r--fs/nfsd/state.h7
3 files changed, 122 insertions, 15 deletions
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index a444d821d2a5..d4472cd19807 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -146,11 +146,9 @@ static struct nfsd_fault_inject_op inject_ops[] = {
146 }, 146 },
147 { 147 {
148 .file = "forget_openowners", 148 .file = "forget_openowners",
149 .get = nfsd_inject_get, 149 .get = nfsd_inject_print_openowners,
150 .set_val = nfsd_inject_set, 150 .set_val = nfsd_inject_forget_openowners,
151 .set_clnt = nfsd_inject_set_client, 151 .set_clnt = nfsd_inject_forget_client_openowners,
152 .forget = nfsd_forget_client_openowners,
153 .print = nfsd_print_client_openowners,
154 }, 152 },
155 { 153 {
156 .file = "forget_delegations", 154 .file = "forget_delegations",
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 48ae0a66d512..20bffa8c976c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5965,30 +5965,136 @@ nfsd_inject_forget_locks(struct nfsd_fault_inject_op *op, u64 max)
5965 return count; 5965 return count;
5966} 5966}
5967 5967
5968static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) 5968static u64
5969nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max,
5970 struct list_head *collect,
5971 void (*func)(struct nfs4_openowner *))
5969{ 5972{
5970 struct nfs4_openowner *oop, *next; 5973 struct nfs4_openowner *oop, *next;
5974 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
5975 nfsd_net_id);
5971 u64 count = 0; 5976 u64 count = 0;
5972 5977
5978 lockdep_assert_held(&nn->client_lock);
5979
5980 spin_lock(&clp->cl_lock);
5973 list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 5981 list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
5974 if (func) 5982 if (func) {
5975 func(oop); 5983 func(oop);
5976 if (++count == max) 5984 if (collect) {
5985 atomic_inc(&clp->cl_refcount);
5986 list_add(&oop->oo_perclient, collect);
5987 }
5988 }
5989 ++count;
5990 /*
5991 * Despite the fact that these functions deal with
5992 * 64-bit integers for "count", we must ensure that
5993 * it doesn't blow up the clp->cl_refcount. Throw a
5994 * warning if we start to approach INT_MAX here.
5995 */
5996 WARN_ON_ONCE(count == (INT_MAX / 2));
5997 if (count == max)
5977 break; 5998 break;
5978 } 5999 }
6000 spin_unlock(&clp->cl_lock);
6001
6002 return count;
6003}
5979 6004
6005static u64
6006nfsd_print_client_openowners(struct nfs4_client *clp)
6007{
6008 u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL);
6009
6010 nfsd_print_count(clp, count, "openowners");
5980 return count; 6011 return count;
5981} 6012}
5982 6013
5983u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) 6014static u64
6015nfsd_collect_client_openowners(struct nfs4_client *clp,
6016 struct list_head *collect, u64 max)
5984{ 6017{
5985 return nfsd_foreach_client_open(clp, max, release_openowner); 6018 return nfsd_foreach_client_openowner(clp, max, collect,
6019 unhash_openowner_locked);
5986} 6020}
5987 6021
5988u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) 6022u64
6023nfsd_inject_print_openowners(struct nfsd_fault_inject_op *op)
5989{ 6024{
5990 u64 count = nfsd_foreach_client_open(clp, max, NULL); 6025 struct nfs4_client *clp;
5991 nfsd_print_count(clp, count, "open files"); 6026 u64 count = 0;
6027 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6028 nfsd_net_id);
6029
6030 if (!nfsd_netns_ready(nn))
6031 return 0;
6032
6033 spin_lock(&nn->client_lock);
6034 list_for_each_entry(clp, &nn->client_lru, cl_lru)
6035 count += nfsd_print_client_openowners(clp);
6036 spin_unlock(&nn->client_lock);
6037
6038 return count;
6039}
6040
6041static void
6042nfsd_reap_openowners(struct list_head *reaplist)
6043{
6044 struct nfs4_client *clp;
6045 struct nfs4_openowner *oop, *next;
6046
6047 list_for_each_entry_safe(oop, next, reaplist, oo_perclient) {
6048 list_del_init(&oop->oo_perclient);
6049 clp = oop->oo_owner.so_client;
6050 release_openowner(oop);
6051 put_client(clp);
6052 }
6053}
6054
6055u64
6056nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *op,
6057 struct sockaddr_storage *addr, size_t addr_size)
6058{
6059 unsigned int count = 0;
6060 struct nfs4_client *clp;
6061 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6062 nfsd_net_id);
6063 LIST_HEAD(reaplist);
6064
6065 if (!nfsd_netns_ready(nn))
6066 return count;
6067
6068 spin_lock(&nn->client_lock);
6069 clp = nfsd_find_client(addr, addr_size);
6070 if (clp)
6071 count = nfsd_collect_client_openowners(clp, &reaplist, 0);
6072 spin_unlock(&nn->client_lock);
6073 nfsd_reap_openowners(&reaplist);
6074 return count;
6075}
6076
6077u64
6078nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *op, u64 max)
6079{
6080 u64 count = 0;
6081 struct nfs4_client *clp;
6082 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
6083 nfsd_net_id);
6084 LIST_HEAD(reaplist);
6085
6086 if (!nfsd_netns_ready(nn))
6087 return count;
6088
6089 spin_lock(&nn->client_lock);
6090 list_for_each_entry(clp, &nn->client_lru, cl_lru) {
6091 count += nfsd_collect_client_openowners(clp, &reaplist,
6092 max - count);
6093 if (max != 0 && count >= max)
6094 break;
6095 }
6096 spin_unlock(&nn->client_lock);
6097 nfsd_reap_openowners(&reaplist);
5992 return count; 6098 return count;
5993} 6099}
5994 6100
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 028947688d57..faaf6af7b28d 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -488,11 +488,14 @@ u64 nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *,
488 struct sockaddr_storage *, size_t); 488 struct sockaddr_storage *, size_t);
489u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64); 489u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64);
490 490
491u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); 491u64 nfsd_inject_print_openowners(struct nfsd_fault_inject_op *);
492u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *,
493 struct sockaddr_storage *, size_t);
494u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64);
495
492u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); 496u64 nfsd_forget_client_delegations(struct nfs4_client *, u64);
493u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); 497u64 nfsd_recall_client_delegations(struct nfs4_client *, u64);
494 498
495u64 nfsd_print_client_openowners(struct nfs4_client *, u64);
496u64 nfsd_print_client_delegations(struct nfs4_client *, u64); 499u64 nfsd_print_client_delegations(struct nfs4_client *, u64);
497#else /* CONFIG_NFSD_FAULT_INJECTION */ 500#else /* CONFIG_NFSD_FAULT_INJECTION */
498static inline int nfsd_fault_inject_init(void) { return 0; } 501static inline int nfsd_fault_inject_init(void) { return 0; }