Skip to content

Commit

Permalink
NFSD: Forget state for a specific client
Browse files Browse the repository at this point in the history
Write the client's ip address to any state file and all appropriate
state for that client will be forgotten.

Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
  • Loading branch information
Bryan Schumaker authored and J. Bruce Fields committed Dec 3, 2012
1 parent d7cc431 commit 6c1e82a
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
37 changes: 33 additions & 4 deletions fs/nfsd/fault_inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/nsproxy.h>
#include <linux/sunrpc/clnt.h>
#include <asm/uaccess.h>

#include "state.h"
#include "netns.h"

struct nfsd_fault_inject_op {
char *file;
Expand Down Expand Up @@ -64,6 +67,24 @@ static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val)
printk(KERN_INFO "NFSD: %s: found %llu", op->file, count);
}

static void 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;

nfs4_lock_state();
clp = nfsd_find_client(addr, addr_size);
if (clp) {
count = op->forget(clp, 0);
rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, 129);
printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count);
}
nfs4_unlock_state();
}

static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val)
{
nfs4_lock_state();
Expand Down Expand Up @@ -100,15 +121,23 @@ static ssize_t fault_inject_read(struct file *file, char __user *buf,
static ssize_t fault_inject_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
char write_buf[24];
char write_buf[INET6_ADDRSTRLEN];
size_t size = min(sizeof(write_buf), len) - 1;
struct net *net = current->nsproxy->net_ns;
struct sockaddr_storage sa;
u64 val;

if (copy_from_user(write_buf, buf, size))
return -EFAULT;

val = simple_strtoll(write_buf, NULL, 0);
nfsd_inject_set(file->f_dentry->d_inode->i_private, val);
write_buf[size] = '\0';

size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
if (size > 0)
nfsd_inject_set_client(file->f_dentry->d_inode->i_private, &sa, size);
else {
val = simple_strtoll(write_buf, NULL, 0);
nfsd_inject_set(file->f_dentry->d_inode->i_private, val);
}
return len; /* on success, claim we got the whole input */
}

Expand Down
15 changes: 15 additions & 0 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -4763,6 +4763,21 @@ u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64))
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 */

/* initialization to perform at module load time: */
Expand Down
1 change: 1 addition & 0 deletions fs/nfsd/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time);
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_forget_client(struct nfs4_client *, u64);
u64 nfsd_forget_client_locks(struct nfs4_client*, u64);
Expand Down

0 comments on commit 6c1e82a

Please sign in to comment.