diff options
-rw-r--r-- | fs/nfsd/fault_inject.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 122 | ||||
-rw-r--r-- | fs/nfsd/state.h | 7 |
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 | ||
5968 | static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) | 5968 | static u64 |
5969 | nfsd_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 | ||
6005 | static u64 | ||
6006 | nfsd_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 | ||
5983 | u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) | 6014 | static u64 |
6015 | nfsd_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 | ||
5988 | u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) | 6022 | u64 |
6023 | nfsd_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 | |||
6041 | static void | ||
6042 | nfsd_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 | |||
6055 | u64 | ||
6056 | nfsd_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 | |||
6077 | u64 | ||
6078 | nfsd_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); |
489 | u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64); | 489 | u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64); |
490 | 490 | ||
491 | u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); | 491 | u64 nfsd_inject_print_openowners(struct nfsd_fault_inject_op *); |
492 | u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *, | ||
493 | struct sockaddr_storage *, size_t); | ||
494 | u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64); | ||
495 | |||
492 | u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); | 496 | u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); |
493 | u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); | 497 | u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); |
494 | 498 | ||
495 | u64 nfsd_print_client_openowners(struct nfs4_client *, u64); | ||
496 | u64 nfsd_print_client_delegations(struct nfs4_client *, u64); | 499 | u64 nfsd_print_client_delegations(struct nfs4_client *, u64); |
497 | #else /* CONFIG_NFSD_FAULT_INJECTION */ | 500 | #else /* CONFIG_NFSD_FAULT_INJECTION */ |
498 | static inline int nfsd_fault_inject_init(void) { return 0; } | 501 | static inline int nfsd_fault_inject_init(void) { return 0; } |