Skip to content

Commit

Permalink
Merge branch 'for-3.3' of git://linux-nfs.org/~bfields/linux
Browse files Browse the repository at this point in the history
* 'for-3.3' of git://linux-nfs.org/~bfields/linux: (31 commits)
  nfsd4: nfsd4_create_clid_dir return value is unused
  NFSD: Change name of extended attribute containing junction
  svcrpc: don't revert to SVC_POOL_DEFAULT on nfsd shutdown
  svcrpc: fix double-free on shutdown of nfsd after changing pool mode
  nfsd4: be forgiving in the absence of the recovery directory
  nfsd4: fix spurious 4.1 post-reboot failures
  NFSD: forget_delegations should use list_for_each_entry_safe
  NFSD: Only reinitilize the recall_lru list under the recall lock
  nfsd4: initialize special stateid's at compile time
  NFSd: use network-namespace-aware cache registering routines
  SUNRPC: create svc_xprt in proper network namespace
  svcrpc: update outdated BKL comment
  nfsd41: allow non-reclaim open-by-fh's in 4.1
  svcrpc: avoid memory-corruption on pool shutdown
  svcrpc: destroy server sockets all at once
  svcrpc: make svc_delete_xprt static
  nfsd: Fix oops when parsing a 0 length export
  nfsd4: Use kmemdup rather than duplicating its implementation
  nfsd4: add a separate (lockowner, inode) lookup
  nfsd4: fix CONFIG_NFSD_FAULT_INJECTION compile error
  ...
  • Loading branch information
torvalds committed Jan 14, 2012
2 parents 8e63dd6 + 7a6ef8c commit 0b48d42
Show file tree
Hide file tree
Showing 26 changed files with 624 additions and 169 deletions.
5 changes: 5 additions & 0 deletions CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,11 @@ S: Bessemerstraat 21
S: Amsterdam
S: The Netherlands

N: NeilBrown
E: neil@brown.name
P: 4096R/566281B9 1BC6 29EB D390 D870 7B5F 497A 39EC 9EDD 5662 81B9
D: NFSD Maintainer 2000-2007

N: Zach Brown
E: zab@zabbo.net
D: maestro pci sound
Expand Down
2 changes: 2 additions & 0 deletions Documentation/filesystems/nfs/00-INDEX
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
- this file (nfs-related documentation).
Exporting
- explanation of how to make filesystems exportable.
fault_injection.txt
- information for using fault injection on the server
knfsd-stats.txt
- statistics which the NFS server makes available to user space.
nfs.txt
Expand Down
69 changes: 69 additions & 0 deletions Documentation/filesystems/nfs/fault_injection.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

Fault Injection
===============
Fault injection is a method for forcing errors that may not normally occur, or
may be difficult to reproduce. Forcing these errors in a controlled environment
can help the developer find and fix bugs before their code is shipped in a
production system. Injecting an error on the Linux NFS server will allow us to
observe how the client reacts and if it manages to recover its state correctly.

NFSD_FAULT_INJECTION must be selected when configuring the kernel to use this
feature.


Using Fault Injection
=====================
On the client, mount the fault injection server through NFS v4.0+ and do some
work over NFS (open files, take locks, ...).

On the server, mount the debugfs filesystem to <debug_dir> and ls
<debug_dir>/nfsd. This will show a list of files that will be used for
injecting faults on the NFS server. As root, write a number n to the file
corresponding to the action you want the server to take. The server will then
process the first n items it finds. So if you want to forget 5 locks, echo '5'
to <debug_dir>/nfsd/forget_locks. A value of 0 will tell the server to forget
all corresponding items. A log message will be created containing the number
of items forgotten (check dmesg).

Go back to work on the client and check if the client recovered from the error
correctly.


Available Faults
================
forget_clients:
The NFS server keeps a list of clients that have placed a mount call. If
this list is cleared, the server will have no knowledge of who the client
is, forcing the client to reauthenticate with the server.

forget_openowners:
The NFS server keeps a list of what files are currently opened and who
they were opened by. Clearing this list will force the client to reopen
its files.

forget_locks:
The NFS server keeps a list of what files are currently locked in the VFS.
Clearing this list will force the client to reclaim its locks (files are
unlocked through the VFS as they are cleared from this list).

forget_delegations:
A delegation is used to assure the client that a file, or part of a file,
has not changed since the delegation was awarded. Clearing this list will
force the client to reaquire its delegation before accessing the file
again.

recall_delegations:
Delegations can be recalled by the server when another client attempts to
access a file. This test will notify the client that its delegation has
been revoked, forcing the client to reaquire the delegation before using
the file again.


tools/nfs/inject_faults.sh script
=================================
This script has been created to ease the fault injection process. This script
will detect the mounted debugfs directory and write to the files located there
based on the arguments passed by the user. For example, running
`inject_faults.sh forget_locks 1` as root will instruct the server to forget
one lock. Running `inject_faults forget_locks` will instruct the server to
forgetall locks.
1 change: 0 additions & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -3775,7 +3775,6 @@ S: Odd Fixes

KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
M: "J. Bruce Fields" <bfields@fieldses.org>
M: Neil Brown <neilb@suse.de>
L: linux-nfs@vger.kernel.org
W: http://nfs.sourceforge.net/
S: Supported
Expand Down
10 changes: 10 additions & 0 deletions fs/nfsd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,13 @@ config NFSD_V4
available from http://linux-nfs.org/.

If unsure, say N.

config NFSD_FAULT_INJECTION
bool "NFS server manual fault injection"
depends on NFSD_V4 && DEBUG_KERNEL
help
This option enables support for manually injecting faults
into the NFS server. This is intended to be used for
testing error recovery on the NFS client.

If unsure, say N.
1 change: 1 addition & 0 deletions fs/nfsd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ obj-$(CONFIG_NFSD) += nfsd.o

nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o
nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
Expand Down
12 changes: 6 additions & 6 deletions fs/nfsd/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
struct svc_expkey key;
struct svc_expkey *ek = NULL;

if (mesg[mlen-1] != '\n')
if (mlen < 1 || mesg[mlen-1] != '\n')
return -EINVAL;
mesg[mlen-1] = 0;

Expand Down Expand Up @@ -1226,12 +1226,12 @@ nfsd_export_init(void)
int rv;
dprintk("nfsd: initializing export module.\n");

rv = cache_register(&svc_export_cache);
rv = cache_register_net(&svc_export_cache, &init_net);
if (rv)
return rv;
rv = cache_register(&svc_expkey_cache);
rv = cache_register_net(&svc_expkey_cache, &init_net);
if (rv)
cache_unregister(&svc_export_cache);
cache_unregister_net(&svc_export_cache, &init_net);
return rv;

}
Expand All @@ -1255,8 +1255,8 @@ nfsd_export_shutdown(void)

dprintk("nfsd: shutting down export module.\n");

cache_unregister(&svc_expkey_cache);
cache_unregister(&svc_export_cache);
cache_unregister_net(&svc_expkey_cache, &init_net);
cache_unregister_net(&svc_export_cache, &init_net);
svcauth_unix_purge();

dprintk("nfsd: export shutdown complete.\n");
Expand Down
91 changes: 91 additions & 0 deletions fs/nfsd/fault_inject.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
*
* Uses debugfs to create fault injection points for client testing
*/

#include <linux/types.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/module.h>

#include "state.h"
#include "fault_inject.h"

struct nfsd_fault_inject_op {
char *file;
void (*func)(u64);
};

static struct nfsd_fault_inject_op inject_ops[] = {
{
.file = "forget_clients",
.func = nfsd_forget_clients,
},
{
.file = "forget_locks",
.func = nfsd_forget_locks,
},
{
.file = "forget_openowners",
.func = nfsd_forget_openowners,
},
{
.file = "forget_delegations",
.func = nfsd_forget_delegations,
},
{
.file = "recall_delegations",
.func = nfsd_recall_delegations,
},
};

static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
static struct dentry *debug_dir;

static int nfsd_inject_set(void *op_ptr, u64 val)
{
struct nfsd_fault_inject_op *op = op_ptr;

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);

op->func(val);
return 0;
}

static int nfsd_inject_get(void *data, u64 *val)
{
return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n");

void nfsd_fault_inject_cleanup(void)
{
debugfs_remove_recursive(debug_dir);
}

int nfsd_fault_inject_init(void)
{
unsigned int i;
struct nfsd_fault_inject_op *op;
mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;

debug_dir = debugfs_create_dir("nfsd", NULL);
if (!debug_dir)
goto fail;

for (i = 0; i < NUM_INJECT_OPS; i++) {
op = &inject_ops[i];
if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd))
goto fail;
}
return 0;

fail:
nfsd_fault_inject_cleanup();
return -ENOMEM;
}
28 changes: 28 additions & 0 deletions fs/nfsd/fault_inject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
*
* Function definitions for fault injection
*/

#ifndef LINUX_NFSD_FAULT_INJECT_H
#define LINUX_NFSD_FAULT_INJECT_H

#ifdef CONFIG_NFSD_FAULT_INJECTION
int nfsd_fault_inject_init(void);
void nfsd_fault_inject_cleanup(void);
void nfsd_forget_clients(u64);
void nfsd_forget_locks(u64);
void nfsd_forget_openowners(u64);
void nfsd_forget_delegations(u64);
void nfsd_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) {}
static inline void nfsd_forget_clients(u64 num) {}
static inline void nfsd_forget_locks(u64 num) {}
static inline void nfsd_forget_openowners(u64 num) {}
static inline void nfsd_forget_delegations(u64 num) {}
static inline void nfsd_recall_delegations(u64 num) {}
#endif /* CONFIG_NFSD_FAULT_INJECTION */

#endif /* LINUX_NFSD_FAULT_INJECT_H */
11 changes: 6 additions & 5 deletions fs/nfsd/nfs4idmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <linux/seq_file.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <net/net_namespace.h>
#include "idmap.h"
#include "nfsd.h"

Expand Down Expand Up @@ -466,20 +467,20 @@ nfsd_idmap_init(void)
{
int rv;

rv = cache_register(&idtoname_cache);
rv = cache_register_net(&idtoname_cache, &init_net);
if (rv)
return rv;
rv = cache_register(&nametoid_cache);
rv = cache_register_net(&nametoid_cache, &init_net);
if (rv)
cache_unregister(&idtoname_cache);
cache_unregister_net(&idtoname_cache, &init_net);
return rv;
}

void
nfsd_idmap_shutdown(void)
{
cache_unregister(&idtoname_cache);
cache_unregister(&nametoid_cache);
cache_unregister_net(&idtoname_cache, &init_net);
cache_unregister_net(&nametoid_cache, &init_net);
}

static int
Expand Down
7 changes: 3 additions & 4 deletions fs/nfsd/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,6 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
{
__be32 status;

/* Only reclaims from previously confirmed clients are valid */
if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
return status;

/* We don't know the target directory, and therefore can not
* set the change info
*/
Expand Down Expand Up @@ -373,6 +369,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
break;
case NFS4_OPEN_CLAIM_PREVIOUS:
open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
status = nfs4_check_open_reclaim(&open->op_clientid);
if (status)
goto out;
case NFS4_OPEN_CLAIM_FH:
case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
status = do_open_fhandle(rqstp, &cstate->current_fh,
Expand Down
22 changes: 14 additions & 8 deletions fs/nfsd/nfs4recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
return status;
}

int
nfsd4_create_clid_dir(struct nfs4_client *clp)
void nfsd4_create_clid_dir(struct nfs4_client *clp)
{
const struct cred *original_cred;
char *dname = clp->cl_recdir;
Expand All @@ -127,13 +126,14 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)

dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);

if (!rec_file || clp->cl_firststate)
return 0;

if (clp->cl_firststate)
return;
clp->cl_firststate = 1;
if (!rec_file)
return;
status = nfs4_save_creds(&original_cred);
if (status < 0)
return status;
return;

dir = rec_file->f_path.dentry;
/* lock the parent */
Expand All @@ -144,8 +144,15 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
status = PTR_ERR(dentry);
goto out_unlock;
}
status = -EEXIST;
if (dentry->d_inode)
/*
* In the 4.1 case, where we're called from
* reclaim_complete(), records from the previous reboot
* may still be left, so this is OK.
*
* In the 4.0 case, we should never get here; but we may
* as well be forgiving and just succeed silently.
*/
goto out_put;
status = mnt_want_write_file(rec_file);
if (status)
Expand All @@ -164,7 +171,6 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
" and is writeable", status,
user_recovery_dirname);
nfs4_reset_creds(original_cred);
return status;
}

typedef int (recdir_func)(struct dentry *, struct dentry *);
Expand Down
Loading

0 comments on commit 0b48d42

Please sign in to comment.