Re: [RFC v2] NFSD: Added basic fault injection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 06/27/2011 08:42 AM, Bryan Schumaker wrote:
> On 06/23/2011 03:55 PM, J. Bruce Fields wrote:
>> On Fri, May 20, 2011 at 02:13:22PM -0400, Bryan Schumaker wrote:
>>> I have been looking at adding fault injection to the NFS server in order
>>> to test the client's state manager and recovery threads.  Simulating
>>> errors on the server seems like the easiest way to guarentee that
>>> specific errors happen, and happen when we tell them to.
>>>
>>> This patch uses debugfs to add a simple framework for fault injection to
>>> the server.  This framework is a config option, and can be enabled
>>> through CONFIG_NFSD_FAULT_INJECTION.  Assuming you have debugfs mounted
>>> to /sys/debug, a set of files will be created in /sys/debug/nfsd/.
>>> Writing to any of these files will cause the corresponding action and
>>> write a log entry to dmesg.
>>>
>>> Changes in v2:
>>> - Replaced "forget all state owners" with "forget all open owners"
>>> - Include fs/nfsd/fault_inject.c in the patch
>>>
>>> Suggestions?  Comments?
>>
>> If this is still the most recent version of the patch, and if you can
>> confirm that this has been tried and found useful for testing the
>> client, then I'll go ahead and apply for 3.1.
> 
> Yes, this is the most recent version of the patch.  It is part of my Jenkins setup, but I haven't been running it on a regular basis recently.

Trond and I just talked about more things to add in for fault injection, so I'll hopefully have a new version sometime in the near future.

> 
> - Bryan
> 
>>
>> --b.
>>
>>>
>>> - Bryan
>>> ---
>>> diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
>>> index 18b3e89..8c02eab 100644
>>> --- a/fs/nfsd/Kconfig
>>> +++ b/fs/nfsd/Kconfig
>>> @@ -91,3 +91,16 @@ 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.
>>> +
>>> +
>>> +
>>> diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
>>> index 9b118ee..69eae75 100644
>>> --- a/fs/nfsd/Makefile
>>> +++ b/fs/nfsd/Makefile
>>> @@ -5,7 +5,8 @@
>>>  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
>>> +			   export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o \
>>> +			   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
>>> diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
>>> new file mode 100644
>>> index 0000000..3dd1c32
>>> --- /dev/null
>>> +++ b/fs/nfsd/fault_inject.c
>>> @@ -0,0 +1,106 @@
>>> +
>>> +#ifdef CONFIG_NFSD_FAULT_INJECTION
>>> +
>>> +#include <linux/types.h>
>>> +#include <linux/fs.h>
>>> +#include <linux/debugfs.h>
>>> +#include <linux/module.h>
>>> +
>>> +#include "state.h"
>>> +#include "nfsd.h"
>>> +
>>> +static void nfsd_forget_everything(void);
>>> +
>>> +struct nfsd_fault_inject_op {
>>> +	char *name;
>>> +	char *text;
>>> +	int file_data;
>>> +	void (*func)(void);
>>> +};
>>> +
>>> +#define INJECTION_OP(op_name, op_text, op_func) \
>>> +{				\
>>> +	.name = op_name,	\
>>> +	.text = op_text,	\
>>> +	.func = op_func,	\
>>> +}
>>> +
>>> +static struct nfsd_fault_inject_op inject_ops[] = {
>>> +	INJECTION_OP("forget_clients",     "forget all clients",     nfsd_forget_all_clients),
>>> +	INJECTION_OP("forget_locks",       "forget all locks",       nfsd_forget_all_locks),
>>> +	INJECTION_OP("forget_open_owners", "forget all open owners", nfsd_forget_all_open_owners),
>>> +	INJECTION_OP("forget_delegations", "forget all delegations", nfsd_forget_all_delegations),
>>> +	INJECTION_OP("forget_everything",  "forget everything",      nfsd_forget_everything),
>>> +	INJECTION_OP("recall_delegations", "recall all delegations", nfsd_recall_all_delegations),
>>> +};
>>> +
>>> +static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
>>> +static struct dentry *debug_dir;
>>> +
>>> +static void nfsd_forget_everything(void)
>>> +{
>>> +	nfsd_forget_all_clients();
>>> +	nfsd_forget_all_locks();
>>> +	nfsd_forget_all_open_owners();
>>> +	nfsd_forget_all_delegations();
>>> +}
>>> +
>>> +static int nfsd_inject_set(void *data, u64 val)
>>> +{
>>> +	int i;
>>> +	for (i = 0; i < NUM_INJECT_OPS; i++) {
>>> +		if (&inject_ops[i].file_data == data) {
>>> +			printk(KERN_INFO "%s %s Server will %s", __FILE__, __func__, inject_ops[i].text);
>>> +			inject_ops[i].func();
>>> +		}
>>> +	}
>>> +	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_cleanup_fault_inject(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];
>>> +		debugfs_create_file(op->name, mode, debug_dir, &op->file_data, &fops_nfsd);
>>> +	}
>>> +	return 0;
>>> +fail:
>>> +	nfsd_cleanup_fault_inject();
>>> +	return -ENOMEM;
>>> +}
>>> +
>>> +#else /* CONFIG_NFSD_FAULT_INJECTION */
>>> +
>>> +inline void
>>> +nfsd_cleanup_fault_inject(void)
>>> +{}
>>> +
>>> +inline int
>>> +nfsd_fault_inject_init(void)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +#endif /* CONFIG_NFSD_FAULT_INJECTION */
>>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>>> index 4cf04e1..f555e02 100644
>>> --- a/fs/nfsd/nfs4state.c
>>> +++ b/fs/nfsd/nfs4state.c
>>> @@ -4274,6 +4274,144 @@ nfs4_check_open_reclaim(clientid_t *clid)
>>>  	return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
>>>  }
>>>  
>>> +#ifdef CONFIG_NFSD_FAULT_INJECTION
>>> +
>>> +void nfsd_forget_all_clients(void)
>>> +{
>>> +	struct nfs4_client *clp;
>>> +	struct list_head *pos, *next, reaplist;
>>> +	int count = 0;
>>> +
>>> +	nfs4_lock_state();
>>> +	INIT_LIST_HEAD(&reaplist);
>>> +
>>> +	spin_lock(&client_lock);
>>> +	list_for_each_safe(pos, next, &client_lru) {
>>> +		clp = list_entry(pos, struct nfs4_client, cl_lru);
>>> +		unhash_client_locked(clp);
>>> +		list_add(&clp->cl_lru, &reaplist);
>>> +		count ++;
>>> +	}
>>> +	spin_unlock(&client_lock);
>>> +	list_for_each_safe(pos, next, &reaplist) {
>>> +		clp = list_entry(pos, struct nfs4_client, cl_lru);
>>> +		nfsd4_remove_clid_dir(clp);
>>> +		expire_client(clp);
>>> +	}
>>> +
>>> +	nfs4_unlock_state();
>>> +	printk(KERN_INFO "%s %s Forgot %d clients", __FILE__, __func__, count);
>>> +}
>>> +
>>> +void nfsd_forget_all_locks(void)
>>> +{
>>> +	struct nfs4_stateid *stp;
>>> +	struct nfs4_stateowner *sop;
>>> +	struct list_head reaplist;
>>> +	int count = 0;
>>> +	int i;
>>> +
>>> +	INIT_LIST_HEAD(&reaplist);
>>> +	nfs4_lock_state();
>>> +	for (i = 0; i < LOCK_HASH_SIZE; i++) {
>>> +		list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
>>> +			list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
>>> +				list_add(&sop->so_perclient, &reaplist);
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	while (!list_empty(&reaplist)) {
>>> +		sop = list_entry(reaplist.next, struct nfs4_stateowner, so_perclient);
>>> +		list_del(&sop->so_perclient);
>>> +		release_lockowner(sop);
>>> +		count ++;
>>> +	}
>>> +	nfs4_unlock_state();
>>> +
>>> +	printk(KERN_INFO "%s %s Forgot %d locks", __FILE__, __func__, count);
>>> +}
>>> +
>>> +void nfsd_forget_all_open_owners(void)
>>> +{
>>> +	struct nfs4_stateid *stp, *next;
>>> +	unsigned int i;
>>> +	int count = 0;
>>> +
>>> +	nfs4_lock_state();
>>> +	for (i = 0; i < STATEID_HASH_SIZE; i++) {
>>> +		list_for_each_entry_safe(stp, next, &stateid_hashtbl[i], st_hash) {
>>> +			if (stp->st_openstp == NULL) {
>>> +				release_openowner(stp->st_stateowner);
>>> +				count++;
>>> +			}
>>> +		}
>>> +	}
>>> +	nfs4_unlock_state();
>>> +	printk(KERN_INFO "%s %s Forgot %d open owners", __FILE__, __func__, count);
>>> +}
>>> +
>>> +void nfsd_forget_all_delegations(void)
>>> +{
>>> +	struct nfs4_file *fp;
>>> +	struct nfs4_delegation *dp;
>>> +	struct list_head *pos, *next, reaplist;
>>> +	unsigned int i;
>>> +	unsigned int count = 0;
>>> +
>>> +	INIT_LIST_HEAD(&reaplist);
>>> +
>>> +	nfs4_lock_state();
>>> +	spin_lock(&recall_lock);
>>> +	for (i = 0; i < FILE_HASH_SIZE; i++) {
>>> +		list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
>>> +			list_for_each(pos, &fp->fi_delegations) {
>>> +				dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
>>> +				list_del_init(&dp->dl_perclnt);
>>> +				list_move(&dp->dl_recall_lru, &reaplist);
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	spin_unlock(&recall_lock);
>>> +	list_for_each_safe(pos, next, &reaplist) {
>>> +		dp = list_entry(pos, struct nfs4_delegation, dl_recall_lru);
>>> +		list_del_init(&dp->dl_recall_lru);
>>> +		unhash_delegation(dp);
>>> +		count++;
>>> +	}
>>> +	nfs4_unlock_state();
>>> +
>>> +	printk(KERN_INFO "%s %s Forgot %d delegations", __FILE__, __func__, count);
>>> +}
>>> +
>>> +void nfsd_recall_all_delegations(void)
>>> +{
>>> +	struct nfs4_file *fp;
>>> +	struct nfs4_delegation *dp;
>>> +	struct list_head *pos;
>>> +	unsigned int i;
>>> +	unsigned int count = 0;
>>> +
>>> +	nfs4_lock_state();
>>> +	spin_lock(&recall_lock);
>>> +	for (i = 0; i < FILE_HASH_SIZE; i++) {
>>> +		list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
>>> +			list_for_each(pos, &fp->fi_delegations) {
>>> +				dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
>>> +				nfsd_break_one_deleg(dp);
>>> +				count++;
>>> +			}
>>> +		}
>>> +	}
>>> +	spin_unlock(&recall_lock);
>>> +	nfs4_unlock_state();
>>> +	printk(KERN_INFO "%s %s Recalled %d delegations", __FILE__, __func__, count);
>>> +}
>>> +
>>> +#endif /* CONFIG_NFSD_FAULT_INJECTION */
>>> +
>>> +
>>>  /* initialization to perform at module load time: */
>>>  
>>>  int
>>> diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
>>> index 1f5eae4..1eb3e92 100644
>>> --- a/fs/nfsd/nfsctl.c
>>> +++ b/fs/nfsd/nfsctl.c
>>> @@ -1481,6 +1481,9 @@ static int __init init_nfsd(void)
>>>  	retval = nfs4_state_init(); /* nfs4 locking state */
>>>  	if (retval)
>>>  		return retval;
>>> +	retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */
>>> +	if (retval)
>>> +		goto out_cleanup_fault_injection;
>>>  	nfsd_stat_init();	/* Statistics */
>>>  	retval = nfsd_reply_cache_init();
>>>  	if (retval)
>>> @@ -1512,6 +1515,8 @@ out_free_cache:
>>>  out_free_stat:
>>>  	nfsd_stat_shutdown();
>>>  	nfsd4_free_slabs();
>>> +out_cleanup_fault_injection:
>>> +	nfsd_cleanup_fault_inject();
>>>  	return retval;
>>>  }
>>>  
>>> @@ -1525,6 +1530,7 @@ static void __exit exit_nfsd(void)
>>>  	nfsd_lockd_shutdown();
>>>  	nfsd_idmap_shutdown();
>>>  	nfsd4_free_slabs();
>>> +	nfsd_cleanup_fault_inject();
>>>  	unregister_filesystem(&nfsd_fs_type);
>>>  }
>>>  
>>> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
>>> index 7ecfa24..4a6cded 100644
>>> --- a/fs/nfsd/nfsd.h
>>> +++ b/fs/nfsd/nfsd.h
>>> @@ -79,11 +79,18 @@ static inline int nfsd_v4client(struct svc_rqst *rq)
>>>  #ifdef CONFIG_NFSD_V4
>>>  extern unsigned int max_delegations;
>>>  int nfs4_state_init(void);
>>> +int nfsd_fault_inject_init(void);
>>> +void nfsd_cleanup_fault_inject(void);
>>>  void nfsd4_free_slabs(void);
>>>  int nfs4_state_start(void);
>>>  void nfs4_state_shutdown(void);
>>>  void nfs4_reset_lease(time_t leasetime);
>>>  int nfs4_reset_recoverydir(char *recdir);
>>> +void nfsd_forget_all_clients(void);
>>> +void nfsd_forget_all_locks(void);
>>> +void nfsd_forget_all_open_owners(void);
>>> +void nfsd_forget_all_delegations(void);
>>> +void nfsd_recall_all_delegations(void);
>>>  #else
>>>  static inline int nfs4_state_init(void) { return 0; }
>>>  static inline void nfsd4_free_slabs(void) { }
>>> @@ -91,6 +98,11 @@ static inline int nfs4_state_start(void) { return 0; }
>>>  static inline void nfs4_state_shutdown(void) { }
>>>  static inline void nfs4_reset_lease(time_t leasetime) { }
>>>  static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
>>> +static inline void nfsd_forget_all_clients(void) {};
>>> +static inline void nfsd_forget_all_locks(void) {};
>>> +static inline void nfsd_forget_all_open_owners(void) {};
>>> +static inline void nfsd_forget_all_delegations(void) {};
>>> +static inline void nfsd_recall_all_delegations(void) {};
>>>  #endif
>>>  
>>>  /*
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux