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.1 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.1 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 +-- 1 file changed, 1 insertion(+), 2 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", -- cgit v1.2.1 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 +- 1 file changed, 1 insertion(+), 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, }, { -- cgit v1.2.1 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 +-- 1 file changed, 1 insertion(+), 2 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", -- cgit v1.2.1 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 +++----- 1 file changed, 3 insertions(+), 5 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", -- cgit v1.2.1 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 +++----- 1 file changed, 3 insertions(+), 5 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", -- cgit v1.2.1 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 ++++++---------- 1 file changed, 6 insertions(+), 10 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, }, }; -- cgit v1.2.1 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 ++++++-------------------------------------------- 1 file changed, 6 insertions(+), 45 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 */ -- cgit v1.2.1