From d4c8e34fe8beeb7877ce7f8d2da6affd7231b2cb Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 18 Jun 2014 15:00:19 -0400 Subject: nfsd: properly handle embedded newlines in fault_injection input Currently rpc_pton() fails to handle the case where you echo an address into the file, as it barfs on the newline. Ensure that we NULL out the first occurrence of any newline. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'fs/nfsd/fault_inject.c') diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 2ed05c3cd43d..f1333fc35b33 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -115,11 +115,19 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf, struct net *net = current->nsproxy->net_ns; struct sockaddr_storage sa; u64 val; + char *nl; if (copy_from_user(write_buf, buf, size)) return -EFAULT; write_buf[size] = '\0'; + /* Deal with any embedded newlines in the string */ + nl = strchr(write_buf, '\n'); + if (nl) { + size = nl - write_buf; + *nl = '\0'; + } + size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa)); if (size > 0) nfsd_inject_set_client(file_inode(file)->i_private, &sa, size); -- cgit v1.2.3 From c96223d3b6b2794b6262d1a31d35694760cff5b2 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2014 08:27:16 -0400 Subject: nfsd: abstract out the get and set routines into the fault injection ops Now that we've added more granular locking in other places, it's time to address the fault injection code. This code is currently quite reliant on the client_mutex for protection. Start to change this by adding a new set of fault injection op vectors. For now they all use the legacy ones. In later patches we'll add new routines that can deal with more granular locking. Also, move some of the printk routines into the callers to make the results of the operations more uniform. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 129 ++++++++++++++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 51 deletions(-) (limited to 'fs/nfsd/fault_inject.c') diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index f1333fc35b33..b1159900d934 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -17,79 +17,50 @@ struct nfsd_fault_inject_op { char *file; + u64 (*get)(struct nfsd_fault_inject_op *); + u64 (*set_val)(struct nfsd_fault_inject_op *, u64); + u64 (*set_clnt)(struct nfsd_fault_inject_op *, + struct sockaddr_storage *, size_t); u64 (*forget)(struct nfs4_client *, u64); u64 (*print)(struct nfs4_client *, u64); }; -static struct nfsd_fault_inject_op inject_ops[] = { - { - .file = "forget_clients", - .forget = nfsd_forget_client, - .print = nfsd_print_client, - }, - { - .file = "forget_locks", - .forget = nfsd_forget_client_locks, - .print = nfsd_print_client_locks, - }, - { - .file = "forget_openowners", - .forget = nfsd_forget_client_openowners, - .print = nfsd_print_client_openowners, - }, - { - .file = "forget_delegations", - .forget = nfsd_forget_client_delegations, - .print = nfsd_print_client_delegations, - }, - { - .file = "recall_delegations", - .forget = nfsd_recall_client_delegations, - .print = nfsd_print_client_delegations, - }, -}; - -static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op); static struct dentry *debug_dir; -static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val) +static u64 nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val) { - u64 count = 0; - - if (val == 0) - printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file); - else - printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val); + u64 count; nfs4_lock_state(); count = nfsd_for_n_state(val, op->forget); nfs4_unlock_state(); - printk(KERN_INFO "NFSD: %s: found %llu", op->file, count); + return count; } -static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op, +static u64 nfsd_inject_set_client(struct nfsd_fault_inject_op *op, struct sockaddr_storage *addr, size_t addr_size) { - char buf[INET6_ADDRSTRLEN]; struct nfs4_client *clp; - u64 count; + u64 count = 0; nfs4_lock_state(); clp = nfsd_find_client(addr, addr_size); - if (clp) { + if (clp) count = op->forget(clp, 0); - rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); - printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count); - } nfs4_unlock_state(); + return count; } -static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val) +static u64 nfsd_inject_get(struct nfsd_fault_inject_op *op) { + u64 count; + nfs4_lock_state(); - *val = nfsd_for_n_state(0, op->print); + count = nfsd_for_n_state(0, op->print); nfs4_unlock_state(); + + return count; } static ssize_t fault_inject_read(struct file *file, char __user *buf, @@ -99,9 +70,10 @@ static ssize_t fault_inject_read(struct file *file, char __user *buf, char read_buf[25]; size_t size; loff_t pos = *ppos; + struct nfsd_fault_inject_op *op = file_inode(file)->i_private; if (!pos) - nfsd_inject_get(file_inode(file)->i_private, &val); + val = op->get(op); size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val); return simple_read_from_buffer(buf, len, ppos, read_buf, size); @@ -114,6 +86,7 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf, size_t size = min(sizeof(write_buf) - 1, len); struct net *net = current->nsproxy->net_ns; struct sockaddr_storage sa; + struct nfsd_fault_inject_op *op = file_inode(file)->i_private; u64 val; char *nl; @@ -129,11 +102,20 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf, } size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa)); - if (size > 0) - nfsd_inject_set_client(file_inode(file)->i_private, &sa, size); - else { + if (size > 0) { + val = op->set_clnt(op, &sa, size); + if (val) + pr_info("NFSD [%s]: Client %s had %llu state object(s)\n", + op->file, write_buf, val); + } else { val = simple_strtoll(write_buf, NULL, 0); - nfsd_inject_set(file_inode(file)->i_private, val); + if (val == 0) + pr_info("NFSD Fault Injection: %s (all)", op->file); + else + pr_info("NFSD Fault Injection: %s (n = %llu)", + op->file, val); + val = op->set_val(op, val); + pr_info("NFSD: %s: found %llu", op->file, val); } return len; /* on success, claim we got the whole input */ } @@ -149,6 +131,51 @@ void nfsd_fault_inject_cleanup(void) debugfs_remove_recursive(debug_dir); } +static struct nfsd_fault_inject_op inject_ops[] = { + { + .file = "forget_clients", + .get = nfsd_inject_get, + .set_val = nfsd_inject_set, + .set_clnt = nfsd_inject_set_client, + .forget = nfsd_forget_client, + .print = nfsd_print_client, + }, + { + .file = "forget_locks", + .get = nfsd_inject_get, + .set_val = nfsd_inject_set, + .set_clnt = nfsd_inject_set_client, + .forget = nfsd_forget_client_locks, + .print = nfsd_print_client_locks, + }, + { + .file = "forget_openowners", + .get = nfsd_inject_get, + .set_val = nfsd_inject_set, + .set_clnt = nfsd_inject_set_client, + .forget = nfsd_forget_client_openowners, + .print = nfsd_print_client_openowners, + }, + { + .file = "forget_delegations", + .get = nfsd_inject_get, + .set_val = nfsd_inject_set, + .set_clnt = nfsd_inject_set_client, + .forget = nfsd_forget_client_delegations, + .print = nfsd_print_client_delegations, + }, + { + .file = "recall_delegations", + .get = nfsd_inject_get, + .set_val = nfsd_inject_set, + .set_clnt = nfsd_inject_set_client, + .forget = nfsd_recall_client_delegations, + .print = nfsd_print_client_delegations, + }, +}; + +#define NUM_INJECT_OPS (sizeof(inject_ops)/sizeof(struct nfsd_fault_inject_op)) + int nfsd_fault_inject_init(void) { unsigned int i; -- cgit v1.2.3 From 7ec0e36f1a35c9c241726f6639178fafda654e09 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2014 08:27:17 -0400 Subject: nfsd: add a forget_clients "get" routine with proper locking Add a new "get" routine for forget_clients that relies on the client_lock instead of the client_mutex. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 3 +-- fs/nfsd/nfs4state.c | 30 ++++++++++++++++++++++-------- fs/nfsd/state.h | 4 +++- 3 files changed, 26 insertions(+), 11 deletions(-) (limited to 'fs/nfsd/fault_inject.c') diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index b1159900d934..a0387fd47e14 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -134,11 +134,10 @@ void nfsd_fault_inject_cleanup(void) static struct nfsd_fault_inject_op inject_ops[] = { { .file = "forget_clients", - .get = nfsd_inject_get, + .get = nfsd_inject_print_clients, .set_val = nfsd_inject_set, .set_clnt = nfsd_inject_set_client, .forget = nfsd_forget_client, - .print = nfsd_print_client, }, { .file = "forget_locks", diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2cb559017ac9..2225e1103742 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5723,6 +5723,28 @@ nfs4_check_open_reclaim(clientid_t *clid, } #ifdef CONFIG_NFSD_FAULT_INJECTION +u64 +nfsd_inject_print_clients(struct nfsd_fault_inject_op *op) +{ + struct nfs4_client *clp; + u64 count = 0; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + char buf[INET6_ADDRSTRLEN]; + + if (!nfsd_netns_ready(nn)) + return 0; + + spin_lock(&nn->client_lock); + list_for_each_entry(clp, &nn->client_lru, cl_lru) { + rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); + pr_info("NFS Client: %s\n", buf); + ++count; + } + spin_unlock(&nn->client_lock); + + return count; +} u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) { @@ -5738,14 +5760,6 @@ u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) return 1; } -u64 nfsd_print_client(struct nfs4_client *clp, u64 num) -{ - char buf[INET6_ADDRSTRLEN]; - rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); - printk(KERN_INFO "NFS Client: %s\n", buf); - return 1; -} - static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, const char *type) { diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 0b234500f104..7c7580ea9680 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -471,18 +471,20 @@ extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time); /* nfs fault injection functions */ #ifdef CONFIG_NFSD_FAULT_INJECTION +struct nfsd_fault_inject_op; + int nfsd_fault_inject_init(void); void nfsd_fault_inject_cleanup(void); u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64)); struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t); +u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op); u64 nfsd_forget_client(struct nfs4_client *, u64); u64 nfsd_forget_client_locks(struct nfs4_client*, u64); u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); -u64 nfsd_print_client(struct nfs4_client *, u64); u64 nfsd_print_client_locks(struct nfs4_client *, u64); u64 nfsd_print_client_openowners(struct nfs4_client *, u64); u64 nfsd_print_client_delegations(struct nfs4_client *, u64); -- cgit v1.2.3 From a0926d15271a0139606d54d0521c527746e2815b Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2014 08:27:18 -0400 Subject: nfsd: add a forget_client set_clnt routine ...that relies on the client_lock instead of client_mutex. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 2 +- fs/nfsd/nfs4state.c | 28 ++++++++++++++++++++++++++++ fs/nfsd/state.h | 3 +++ 3 files changed, 32 insertions(+), 1 deletion(-) (limited to 'fs/nfsd/fault_inject.c') diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index a0387fd47e14..5f3ead0c72fb 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -136,7 +136,7 @@ static struct nfsd_fault_inject_op inject_ops[] = { .file = "forget_clients", .get = nfsd_inject_print_clients, .set_val = nfsd_inject_set, - .set_clnt = nfsd_inject_set_client, + .set_clnt = nfsd_inject_forget_client, .forget = nfsd_forget_client, }, { diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2225e1103742..c4c28f8f48a1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5760,6 +5760,34 @@ u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) return 1; } +u64 +nfsd_inject_forget_client(struct nfsd_fault_inject_op *op, + struct sockaddr_storage *addr, size_t addr_size) +{ + u64 count = 0; + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + clp = nfsd_find_client(addr, addr_size); + if (clp) { + if (mark_client_expired_locked(clp) == nfs_ok) + ++count; + else + clp = NULL; + } + spin_unlock(&nn->client_lock); + + if (clp) + expire_client(clp); + + return count; +} + static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, const char *type) { diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 7c7580ea9680..77a1903d58ab 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -480,6 +480,9 @@ struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t); u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op); u64 nfsd_forget_client(struct nfs4_client *, u64); +u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *, + struct sockaddr_storage *, size_t); + u64 nfsd_forget_client_locks(struct nfs4_client*, u64); u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); -- cgit v1.2.3 From 69fc9edf987ca451831575b1e5450a9fe49fbfe0 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2014 08:27:19 -0400 Subject: nfsd: add nfsd_inject_forget_clients ...which uses the client_lock for protection instead of client_mutex. Also remove nfsd_forget_client as there are no more callers. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 3 +-- fs/nfsd/nfs4state.c | 42 ++++++++++++++++++++++++++++-------------- fs/nfsd/state.h | 2 +- 3 files changed, 30 insertions(+), 17 deletions(-) (limited to 'fs/nfsd/fault_inject.c') diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 5f3ead0c72fb..76ecdff37ea2 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -135,9 +135,8 @@ static struct nfsd_fault_inject_op inject_ops[] = { { .file = "forget_clients", .get = nfsd_inject_print_clients, - .set_val = nfsd_inject_set, + .set_val = nfsd_inject_forget_clients, .set_clnt = nfsd_inject_forget_client, - .forget = nfsd_forget_client, }, { .file = "forget_locks", diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c4c28f8f48a1..226d89e2c7b2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5746,20 +5746,6 @@ nfsd_inject_print_clients(struct nfsd_fault_inject_op *op) return count; } -u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) -{ - __be32 ret; - struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); - - spin_lock(&nn->client_lock); - ret = mark_client_expired_locked(clp); - spin_unlock(&nn->client_lock); - if (ret != nfs_ok) - return 0; - expire_client(clp); - return 1; -} - u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *op, struct sockaddr_storage *addr, size_t addr_size) @@ -5788,6 +5774,34 @@ nfsd_inject_forget_client(struct nfsd_fault_inject_op *op, return count; } +u64 +nfsd_inject_forget_clients(struct nfsd_fault_inject_op *op, u64 max) +{ + u64 count = 0; + struct nfs4_client *clp, *next; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { + if (mark_client_expired_locked(clp) == nfs_ok) { + list_add(&clp->cl_lru, &reaplist); + if (max != 0 && ++count >= max) + break; + } + } + spin_unlock(&nn->client_lock); + + list_for_each_entry_safe(clp, next, &reaplist, cl_lru) + expire_client(clp); + + return count; +} + static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, const char *type) { diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 77a1903d58ab..eb3b35a74795 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -479,9 +479,9 @@ u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64)); struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t); u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op); -u64 nfsd_forget_client(struct nfs4_client *, u64); u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *, struct sockaddr_storage *, size_t); +u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64); u64 nfsd_forget_client_locks(struct nfs4_client*, u64); u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); -- cgit v1.2.3 From 016200c37341b62df14ec642b0b30b4b70bc09af Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2014 08:27:21 -0400 Subject: nfsd: add more granular locking to forget_locks fault injector ...instead of relying on the client_mutex. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 8 ++- fs/nfsd/nfs4state.c | 132 +++++++++++++++++++++++++++++++++++++++++++++---- fs/nfsd/state.h | 7 ++- 3 files changed, 131 insertions(+), 16 deletions(-) (limited to 'fs/nfsd/fault_inject.c') 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[] = { }, { .file = "forget_locks", - .get = nfsd_inject_get, - .set_val = nfsd_inject_set, - .set_clnt = nfsd_inject_set_client, - .forget = nfsd_forget_client_locks, - .print = nfsd_print_client_locks, + .get = nfsd_inject_print_locks, + .set_val = nfsd_inject_forget_locks, + .set_clnt = nfsd_inject_forget_client_locks, }, { .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, } #ifdef CONFIG_NFSD_FAULT_INJECTION +static inline void +put_client(struct nfs4_client *clp) +{ + atomic_dec(&clp->cl_refcount); +} + u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op) { @@ -5810,6 +5816,22 @@ static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); } +static void +nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, + struct list_head *collect) +{ + struct nfs4_client *clp = lst->st_stid.sc_client; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + + if (!collect) + return; + + lockdep_assert_held(&nn->client_lock); + atomic_inc(&clp->cl_refcount); + list_add(&lst->st_locks, collect); +} + static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, struct list_head *collect, void (*func)(struct nfs4_ol_stateid *)) @@ -5819,6 +5841,7 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, struct nfs4_ol_stateid *lst, *lst_next; u64 count = 0; + spin_lock(&clp->cl_lock); list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) { @@ -5826,31 +5849,122 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, &stp->st_locks, st_locks) { if (func) { func(lst); - if (collect) - list_add(&lst->st_locks, - collect); + nfsd_inject_add_lock_to_list(lst, + collect); } - if (++count == max) - return count; + ++count; + /* + * Despite the fact that these functions deal + * with 64-bit integers for "count", we must + * ensure that it doesn't blow up the + * clp->cl_refcount. Throw a warning if we + * start to approach INT_MAX here. + */ + WARN_ON_ONCE(count == (INT_MAX / 2)); + if (count == max) + goto out; } } } +out: + spin_unlock(&clp->cl_lock); return count; } -u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) +static u64 +nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, + u64 max) { - return nfsd_foreach_client_lock(clp, max, NULL, release_lock_stateid); + return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); } -u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) +static u64 +nfsd_print_client_locks(struct nfs4_client *clp) { - u64 count = nfsd_foreach_client_lock(clp, max, NULL, NULL); + u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); nfsd_print_count(clp, count, "locked files"); return count; } +u64 +nfsd_inject_print_locks(struct nfsd_fault_inject_op *op) +{ + struct nfs4_client *clp; + u64 count = 0; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + + if (!nfsd_netns_ready(nn)) + return 0; + + spin_lock(&nn->client_lock); + list_for_each_entry(clp, &nn->client_lru, cl_lru) + count += nfsd_print_client_locks(clp); + spin_unlock(&nn->client_lock); + + return count; +} + +static void +nfsd_reap_locks(struct list_head *reaplist) +{ + struct nfs4_client *clp; + struct nfs4_ol_stateid *stp, *next; + + list_for_each_entry_safe(stp, next, reaplist, st_locks) { + list_del_init(&stp->st_locks); + clp = stp->st_stid.sc_client; + nfs4_put_stid(&stp->st_stid); + put_client(clp); + } +} + +u64 +nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *op, + struct sockaddr_storage *addr, size_t addr_size) +{ + unsigned int count = 0; + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + clp = nfsd_find_client(addr, addr_size); + if (clp) + count = nfsd_collect_client_locks(clp, &reaplist, 0); + spin_unlock(&nn->client_lock); + nfsd_reap_locks(&reaplist); + return count; +} + +u64 +nfsd_inject_forget_locks(struct nfsd_fault_inject_op *op, u64 max) +{ + u64 count = 0; + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + list_for_each_entry(clp, &nn->client_lru, cl_lru) { + count += nfsd_collect_client_locks(clp, &reaplist, max - count); + if (max != 0 && count >= max) + break; + } + spin_unlock(&nn->client_lock); + nfsd_reap_locks(&reaplist); + return count; +} + static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) { 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 *, struct sockaddr_storage *, size_t); u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64); -u64 nfsd_forget_client_locks(struct nfs4_client*, u64); +u64 nfsd_inject_print_locks(struct nfsd_fault_inject_op *); +u64 nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *, + struct sockaddr_storage *, size_t); +u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64); + u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); -u64 nfsd_print_client_locks(struct nfs4_client *, u64); u64 nfsd_print_client_openowners(struct nfs4_client *, u64); u64 nfsd_print_client_delegations(struct nfs4_client *, u64); #else /* CONFIG_NFSD_FAULT_INJECTION */ -- cgit v1.2.3 From 82e05efaec9b5b1528771b30c27d060961576827 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2014 08:27:22 -0400 Subject: nfsd: add more granular locking to forget_openowners fault injector ...instead of relying on the client_mutex. Also, fix up the printk output that is generated when the file is read. It currently says that it's reporting the number of open files, but it's actually reporting the number of openowners. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 8 ++-- fs/nfsd/nfs4state.c | 122 +++++++++++++++++++++++++++++++++++++++++++++---- fs/nfsd/state.h | 7 ++- 3 files changed, 122 insertions(+), 15 deletions(-) (limited to 'fs/nfsd/fault_inject.c') 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[] = { }, { .file = "forget_openowners", - .get = nfsd_inject_get, - .set_val = nfsd_inject_set, - .set_clnt = nfsd_inject_set_client, - .forget = nfsd_forget_client_openowners, - .print = nfsd_print_client_openowners, + .get = nfsd_inject_print_openowners, + .set_val = nfsd_inject_forget_openowners, + .set_clnt = nfsd_inject_forget_client_openowners, }, { .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) return count; } -static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) +static u64 +nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, + struct list_head *collect, + void (*func)(struct nfs4_openowner *)) { struct nfs4_openowner *oop, *next; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); u64 count = 0; + lockdep_assert_held(&nn->client_lock); + + spin_lock(&clp->cl_lock); list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { - if (func) + if (func) { func(oop); - if (++count == max) + if (collect) { + atomic_inc(&clp->cl_refcount); + list_add(&oop->oo_perclient, collect); + } + } + ++count; + /* + * Despite the fact that these functions deal with + * 64-bit integers for "count", we must ensure that + * it doesn't blow up the clp->cl_refcount. Throw a + * warning if we start to approach INT_MAX here. + */ + WARN_ON_ONCE(count == (INT_MAX / 2)); + if (count == max) break; } + spin_unlock(&clp->cl_lock); + + return count; +} +static u64 +nfsd_print_client_openowners(struct nfs4_client *clp) +{ + u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); + + nfsd_print_count(clp, count, "openowners"); return count; } -u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) +static u64 +nfsd_collect_client_openowners(struct nfs4_client *clp, + struct list_head *collect, u64 max) { - return nfsd_foreach_client_open(clp, max, release_openowner); + return nfsd_foreach_client_openowner(clp, max, collect, + unhash_openowner_locked); } -u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) +u64 +nfsd_inject_print_openowners(struct nfsd_fault_inject_op *op) { - u64 count = nfsd_foreach_client_open(clp, max, NULL); - nfsd_print_count(clp, count, "open files"); + struct nfs4_client *clp; + u64 count = 0; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + + if (!nfsd_netns_ready(nn)) + return 0; + + spin_lock(&nn->client_lock); + list_for_each_entry(clp, &nn->client_lru, cl_lru) + count += nfsd_print_client_openowners(clp); + spin_unlock(&nn->client_lock); + + return count; +} + +static void +nfsd_reap_openowners(struct list_head *reaplist) +{ + struct nfs4_client *clp; + struct nfs4_openowner *oop, *next; + + list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { + list_del_init(&oop->oo_perclient); + clp = oop->oo_owner.so_client; + release_openowner(oop); + put_client(clp); + } +} + +u64 +nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *op, + struct sockaddr_storage *addr, size_t addr_size) +{ + unsigned int count = 0; + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + clp = nfsd_find_client(addr, addr_size); + if (clp) + count = nfsd_collect_client_openowners(clp, &reaplist, 0); + spin_unlock(&nn->client_lock); + nfsd_reap_openowners(&reaplist); + return count; +} + +u64 +nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *op, u64 max) +{ + u64 count = 0; + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + list_for_each_entry(clp, &nn->client_lru, cl_lru) { + count += nfsd_collect_client_openowners(clp, &reaplist, + max - count); + if (max != 0 && count >= max) + break; + } + spin_unlock(&nn->client_lock); + nfsd_reap_openowners(&reaplist); return count; } 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 *, struct sockaddr_storage *, size_t); u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64); -u64 nfsd_forget_client_openowners(struct nfs4_client *, u64); +u64 nfsd_inject_print_openowners(struct nfsd_fault_inject_op *); +u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *, + struct sockaddr_storage *, size_t); +u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64); + u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); -u64 nfsd_print_client_openowners(struct nfs4_client *, u64); u64 nfsd_print_client_delegations(struct nfs4_client *, u64); #else /* CONFIG_NFSD_FAULT_INJECTION */ static inline int nfsd_fault_inject_init(void) { return 0; } -- cgit v1.2.3 From 98d5c7c5bd378aa1a22549200f49de3ed79d4d0a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2014 08:27:23 -0400 Subject: nfsd: add more granular locking to *_delegations fault injectors ...instead of relying on the client_mutex. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 16 ++--- fs/nfsd/nfs4state.c | 175 +++++++++++++++++++++++++++++++++++++++++-------- fs/nfsd/state.h | 11 ++-- 3 files changed, 162 insertions(+), 40 deletions(-) (limited to 'fs/nfsd/fault_inject.c') diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index d4472cd19807..2479dba71c3c 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -152,19 +152,15 @@ static struct nfsd_fault_inject_op inject_ops[] = { }, { .file = "forget_delegations", - .get = nfsd_inject_get, - .set_val = nfsd_inject_set, - .set_clnt = nfsd_inject_set_client, - .forget = nfsd_forget_client_delegations, - .print = nfsd_print_client_delegations, + .get = nfsd_inject_print_delegations, + .set_val = nfsd_inject_forget_delegations, + .set_clnt = nfsd_inject_forget_client_delegations, }, { .file = "recall_delegations", - .get = nfsd_inject_get, - .set_val = nfsd_inject_set, - .set_clnt = nfsd_inject_set_client, - .forget = nfsd_recall_client_delegations, - .print = nfsd_print_client_delegations, + .get = nfsd_inject_print_delegations, + .set_val = nfsd_inject_recall_delegations, + .set_clnt = nfsd_inject_recall_client_delegations, }, }; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 20bffa8c976c..d18bbb1e334d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -6102,9 +6102,13 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, struct list_head *victims) { struct nfs4_delegation *dp, *next; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); u64 count = 0; - lockdep_assert_held(&state_lock); + lockdep_assert_held(&nn->client_lock); + + spin_lock(&state_lock); list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { if (victims) { /* @@ -6116,62 +6120,180 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, if (dp->dl_time != 0) continue; + atomic_inc(&clp->cl_refcount); unhash_delegation_locked(dp); list_add(&dp->dl_recall_lru, victims); } - if (++count == max) + ++count; + /* + * Despite the fact that these functions deal with + * 64-bit integers for "count", we must ensure that + * it doesn't blow up the clp->cl_refcount. Throw a + * warning if we start to approach INT_MAX here. + */ + WARN_ON_ONCE(count == (INT_MAX / 2)); + if (count == max) break; } + spin_unlock(&state_lock); return count; } -u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max) +static u64 +nfsd_print_client_delegations(struct nfs4_client *clp) { - struct nfs4_delegation *dp, *next; - LIST_HEAD(victims); - u64 count; + u64 count = nfsd_find_all_delegations(clp, 0, NULL); - spin_lock(&state_lock); - count = nfsd_find_all_delegations(clp, max, &victims); - spin_unlock(&state_lock); + nfsd_print_count(clp, count, "delegations"); + return count; +} + +u64 +nfsd_inject_print_delegations(struct nfsd_fault_inject_op *op) +{ + struct nfs4_client *clp; + u64 count = 0; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + + if (!nfsd_netns_ready(nn)) + return 0; - list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) { + spin_lock(&nn->client_lock); + list_for_each_entry(clp, &nn->client_lru, cl_lru) + count += nfsd_print_client_delegations(clp); + spin_unlock(&nn->client_lock); + + return count; +} + +static void +nfsd_forget_delegations(struct list_head *reaplist) +{ + struct nfs4_client *clp; + struct nfs4_delegation *dp, *next; + + list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { list_del_init(&dp->dl_recall_lru); + clp = dp->dl_stid.sc_client; revoke_delegation(dp); + put_client(clp); } +} + +u64 +nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *op, + struct sockaddr_storage *addr, size_t addr_size) +{ + u64 count = 0; + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + clp = nfsd_find_client(addr, addr_size); + if (clp) + count = nfsd_find_all_delegations(clp, 0, &reaplist); + spin_unlock(&nn->client_lock); + + nfsd_forget_delegations(&reaplist); + return count; +} +u64 +nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *op, u64 max) +{ + u64 count = 0; + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + list_for_each_entry(clp, &nn->client_lru, cl_lru) { + count += nfsd_find_all_delegations(clp, max - count, &reaplist); + if (max != 0 && count >= max) + break; + } + spin_unlock(&nn->client_lock); + nfsd_forget_delegations(&reaplist); return count; } -u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) +static void +nfsd_recall_delegations(struct list_head *reaplist) { - struct nfs4_delegation *dp; - LIST_HEAD(victims); - u64 count; + struct nfs4_client *clp; + struct nfs4_delegation *dp, *next; - spin_lock(&state_lock); - count = nfsd_find_all_delegations(clp, max, &victims); - while (!list_empty(&victims)) { - dp = list_first_entry(&victims, struct nfs4_delegation, - dl_recall_lru); + list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { list_del_init(&dp->dl_recall_lru); + clp = dp->dl_stid.sc_client; + /* + * We skipped all entries that had a zero dl_time before, + * so we can now reset the dl_time back to 0. If a delegation + * break comes in now, then it won't make any difference since + * we're recalling it either way. + */ + spin_lock(&state_lock); dp->dl_time = 0; + spin_unlock(&state_lock); nfsd_break_one_deleg(dp); + put_client(clp); } - spin_unlock(&state_lock); +} +u64 +nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *op, + struct sockaddr_storage *addr, + size_t addr_size) +{ + u64 count = 0; + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); + + if (!nfsd_netns_ready(nn)) + return count; + + spin_lock(&nn->client_lock); + clp = nfsd_find_client(addr, addr_size); + if (clp) + count = nfsd_find_all_delegations(clp, 0, &reaplist); + spin_unlock(&nn->client_lock); + + nfsd_recall_delegations(&reaplist); return count; } -u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max) +u64 +nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *op, u64 max) { u64 count = 0; + struct nfs4_client *clp, *next; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + LIST_HEAD(reaplist); - spin_lock(&state_lock); - count = nfsd_find_all_delegations(clp, max, NULL); - spin_unlock(&state_lock); + if (!nfsd_netns_ready(nn)) + return count; - nfsd_print_count(clp, count, "delegations"); + spin_lock(&nn->client_lock); + list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { + count += nfsd_find_all_delegations(clp, max - count, &reaplist); + if (max != 0 && ++count >= max) + break; + } + spin_unlock(&nn->client_lock); + nfsd_recall_delegations(&reaplist); return count; } @@ -6179,7 +6301,8 @@ u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) { struct nfs4_client *clp, *next; u64 count = 0; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); if (!nfsd_netns_ready(nn)) return 0; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index faaf6af7b28d..0a35e7bea5f7 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -493,10 +493,13 @@ u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *, struct sockaddr_storage *, size_t); u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64); -u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); -u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); - -u64 nfsd_print_client_delegations(struct nfs4_client *, u64); +u64 nfsd_inject_print_delegations(struct nfsd_fault_inject_op *); +u64 nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *, + struct sockaddr_storage *, size_t); +u64 nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *, u64); +u64 nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *, + struct sockaddr_storage *, size_t); +u64 nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *, u64); #else /* CONFIG_NFSD_FAULT_INJECTION */ static inline int nfsd_fault_inject_init(void) { return 0; } static inline void nfsd_fault_inject_cleanup(void) {} -- cgit v1.2.3 From 285abdee5335921b6a41f9719c1fc56c478ac561 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 30 Jul 2014 08:27:24 -0400 Subject: nfsd: remove old fault injection infrastructure Remove the old nfsd_for_n_state function and move nfsd_find_client higher up into the file to get rid of forward declaration. Remove the struct nfsd_fault_inject_op arguments from the operations as they are no longer needed by any of them. Finally, remove the old "standard" get and set routines, which also eliminates the client_mutex from this code. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/fault_inject.c | 51 ++++------------------------- fs/nfsd/nfs4state.c | 87 +++++++++++++++++++------------------------------- fs/nfsd/state.h | 45 +++++++++++--------------- 3 files changed, 57 insertions(+), 126 deletions(-) (limited to 'fs/nfsd/fault_inject.c') diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 2479dba71c3c..c16bf5af6831 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -17,52 +17,13 @@ struct nfsd_fault_inject_op { char *file; - u64 (*get)(struct nfsd_fault_inject_op *); - u64 (*set_val)(struct nfsd_fault_inject_op *, u64); - u64 (*set_clnt)(struct nfsd_fault_inject_op *, - struct sockaddr_storage *, size_t); - u64 (*forget)(struct nfs4_client *, u64); - u64 (*print)(struct nfs4_client *, u64); + u64 (*get)(void); + u64 (*set_val)(u64); + u64 (*set_clnt)(struct sockaddr_storage *, size_t); }; static struct dentry *debug_dir; -static u64 nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val) -{ - u64 count; - - nfs4_lock_state(); - count = nfsd_for_n_state(val, op->forget); - nfs4_unlock_state(); - return count; -} - -static u64 nfsd_inject_set_client(struct nfsd_fault_inject_op *op, - struct sockaddr_storage *addr, - size_t addr_size) -{ - struct nfs4_client *clp; - u64 count = 0; - - nfs4_lock_state(); - clp = nfsd_find_client(addr, addr_size); - if (clp) - count = op->forget(clp, 0); - nfs4_unlock_state(); - return count; -} - -static u64 nfsd_inject_get(struct nfsd_fault_inject_op *op) -{ - u64 count; - - nfs4_lock_state(); - count = nfsd_for_n_state(0, op->print); - nfs4_unlock_state(); - - return count; -} - static ssize_t fault_inject_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { @@ -73,7 +34,7 @@ static ssize_t fault_inject_read(struct file *file, char __user *buf, struct nfsd_fault_inject_op *op = file_inode(file)->i_private; if (!pos) - val = op->get(op); + val = op->get(); size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val); return simple_read_from_buffer(buf, len, ppos, read_buf, size); @@ -103,7 +64,7 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf, size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa)); if (size > 0) { - val = op->set_clnt(op, &sa, size); + val = op->set_clnt(&sa, size); if (val) pr_info("NFSD [%s]: Client %s had %llu state object(s)\n", op->file, write_buf, val); @@ -114,7 +75,7 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf, else pr_info("NFSD Fault Injection: %s (n = %llu)", op->file, val); - val = op->set_val(op, val); + val = op->set_val(val); pr_info("NFSD: %s: found %llu", op->file, val); } return len; /* on success, claim we got the whole input */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d18bbb1e334d..90aa953420b6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5729,8 +5729,25 @@ put_client(struct nfs4_client *clp) atomic_dec(&clp->cl_refcount); } +static struct nfs4_client * +nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) +{ + struct nfs4_client *clp; + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, + nfsd_net_id); + + if (!nfsd_netns_ready(nn)) + return NULL; + + list_for_each_entry(clp, &nn->client_lru, cl_lru) { + if (memcmp(&clp->cl_addr, addr, addr_size) == 0) + return clp; + } + return NULL; +} + u64 -nfsd_inject_print_clients(struct nfsd_fault_inject_op *op) +nfsd_inject_print_clients(void) { struct nfs4_client *clp; u64 count = 0; @@ -5753,8 +5770,7 @@ nfsd_inject_print_clients(struct nfsd_fault_inject_op *op) } u64 -nfsd_inject_forget_client(struct nfsd_fault_inject_op *op, - struct sockaddr_storage *addr, size_t addr_size) +nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) { u64 count = 0; struct nfs4_client *clp; @@ -5781,7 +5797,7 @@ nfsd_inject_forget_client(struct nfsd_fault_inject_op *op, } u64 -nfsd_inject_forget_clients(struct nfsd_fault_inject_op *op, u64 max) +nfsd_inject_forget_clients(u64 max) { u64 count = 0; struct nfs4_client *clp, *next; @@ -5888,7 +5904,7 @@ nfsd_print_client_locks(struct nfs4_client *clp) } u64 -nfsd_inject_print_locks(struct nfsd_fault_inject_op *op) +nfsd_inject_print_locks(void) { struct nfs4_client *clp; u64 count = 0; @@ -5921,8 +5937,7 @@ nfsd_reap_locks(struct list_head *reaplist) } u64 -nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *op, - struct sockaddr_storage *addr, size_t addr_size) +nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) { unsigned int count = 0; struct nfs4_client *clp; @@ -5943,7 +5958,7 @@ nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *op, } u64 -nfsd_inject_forget_locks(struct nfsd_fault_inject_op *op, u64 max) +nfsd_inject_forget_locks(u64 max) { u64 count = 0; struct nfs4_client *clp; @@ -6020,7 +6035,7 @@ nfsd_collect_client_openowners(struct nfs4_client *clp, } u64 -nfsd_inject_print_openowners(struct nfsd_fault_inject_op *op) +nfsd_inject_print_openowners(void) { struct nfs4_client *clp; u64 count = 0; @@ -6053,8 +6068,8 @@ nfsd_reap_openowners(struct list_head *reaplist) } u64 -nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *op, - struct sockaddr_storage *addr, size_t addr_size) +nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, + size_t addr_size) { unsigned int count = 0; struct nfs4_client *clp; @@ -6075,7 +6090,7 @@ nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *op, } u64 -nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *op, u64 max) +nfsd_inject_forget_openowners(u64 max) { u64 count = 0; struct nfs4_client *clp; @@ -6149,7 +6164,7 @@ nfsd_print_client_delegations(struct nfs4_client *clp) } u64 -nfsd_inject_print_delegations(struct nfsd_fault_inject_op *op) +nfsd_inject_print_delegations(void) { struct nfs4_client *clp; u64 count = 0; @@ -6182,8 +6197,8 @@ nfsd_forget_delegations(struct list_head *reaplist) } u64 -nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *op, - struct sockaddr_storage *addr, size_t addr_size) +nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, + size_t addr_size) { u64 count = 0; struct nfs4_client *clp; @@ -6205,7 +6220,7 @@ nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *op, } u64 -nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *op, u64 max) +nfsd_inject_forget_delegations(u64 max) { u64 count = 0; struct nfs4_client *clp; @@ -6251,8 +6266,7 @@ nfsd_recall_delegations(struct list_head *reaplist) } u64 -nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *op, - struct sockaddr_storage *addr, +nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, size_t addr_size) { u64 count = 0; @@ -6275,7 +6289,7 @@ nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *op, } u64 -nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *op, u64 max) +nfsd_inject_recall_delegations(u64 max) { u64 count = 0; struct nfs4_client *clp, *next; @@ -6296,41 +6310,6 @@ nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *op, u64 max) nfsd_recall_delegations(&reaplist); return count; } - -u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) -{ - struct nfs4_client *clp, *next; - u64 count = 0; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - - if (!nfsd_netns_ready(nn)) - return 0; - - list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { - count += func(clp, max - count); - if ((max != 0) && (count >= max)) - break; - } - - return count; -} - -struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) -{ - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); - - if (!nfsd_netns_ready(nn)) - return NULL; - - list_for_each_entry(clp, &nn->client_lru, cl_lru) { - if (memcmp(&clp->cl_addr, addr, addr_size) == 0) - return clp; - } - return NULL; -} - #endif /* CONFIG_NFSD_FAULT_INJECTION */ /* diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 0a35e7bea5f7..a02358f2442c 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -471,35 +471,26 @@ extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time); /* nfs fault injection functions */ #ifdef CONFIG_NFSD_FAULT_INJECTION -struct nfsd_fault_inject_op; - int nfsd_fault_inject_init(void); void nfsd_fault_inject_cleanup(void); -u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64)); -struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t); - -u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op); -u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *, - struct sockaddr_storage *, size_t); -u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64); - -u64 nfsd_inject_print_locks(struct nfsd_fault_inject_op *); -u64 nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *, - struct sockaddr_storage *, size_t); -u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64); - -u64 nfsd_inject_print_openowners(struct nfsd_fault_inject_op *); -u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *, - struct sockaddr_storage *, size_t); -u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64); - -u64 nfsd_inject_print_delegations(struct nfsd_fault_inject_op *); -u64 nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *, - struct sockaddr_storage *, size_t); -u64 nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *, u64); -u64 nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *, - struct sockaddr_storage *, size_t); -u64 nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *, u64); + +u64 nfsd_inject_print_clients(void); +u64 nfsd_inject_forget_client(struct sockaddr_storage *, size_t); +u64 nfsd_inject_forget_clients(u64); + +u64 nfsd_inject_print_locks(void); +u64 nfsd_inject_forget_client_locks(struct sockaddr_storage *, size_t); +u64 nfsd_inject_forget_locks(u64); + +u64 nfsd_inject_print_openowners(void); +u64 nfsd_inject_forget_client_openowners(struct sockaddr_storage *, size_t); +u64 nfsd_inject_forget_openowners(u64); + +u64 nfsd_inject_print_delegations(void); +u64 nfsd_inject_forget_client_delegations(struct sockaddr_storage *, size_t); +u64 nfsd_inject_forget_delegations(u64); +u64 nfsd_inject_recall_client_delegations(struct sockaddr_storage *, size_t); +u64 nfsd_inject_recall_delegations(u64); #else /* CONFIG_NFSD_FAULT_INJECTION */ static inline int nfsd_fault_inject_init(void) { return 0; } static inline void nfsd_fault_inject_cleanup(void) {} -- cgit v1.2.3