diff -puN fs/nfsd/export.c~nfs_suspend fs/nfsd/export.c --- linux-2.6.21.1/fs/nfsd/export.c~nfs_suspend 2007-07-19 16:51:00.000000000 -0700 +++ linux-2.6.21.1-root/fs/nfsd/export.c 2007-07-19 16:51:00.000000000 -0700 @@ -874,7 +874,7 @@ exp_readlock(void) down_read(&hash_sem); } -static inline void +void exp_writelock(void) { down_write(&hash_sem); @@ -886,7 +886,7 @@ exp_readunlock(void) up_read(&hash_sem); } -static inline void +void exp_writeunlock(void) { up_write(&hash_sem); @@ -1444,6 +1444,17 @@ exp_verify_string(char *cp, int max) } /* + * Flush exports table without calling RW semaphore. + * The caller is required to lock and unlock the export table. + */ +void +export_purge(void) +{ + cache_purge(&svc_expkey_cache); + cache_purge(&svc_export_cache); +} + +/* * Initialize the exports module. */ void diff -puN fs/nfsd/nfsctl.c~nfs_suspend fs/nfsd/nfsctl.c --- linux-2.6.21.1/fs/nfsd/nfsctl.c~nfs_suspend 2007-07-19 16:51:00.000000000 -0700 +++ linux-2.6.21.1-root/fs/nfsd/nfsctl.c 2007-07-19 16:51:00.000000000 -0700 @@ -40,7 +40,7 @@ #include /* - * We have a single directory with 9 nodes in it. + * We have a single directory with several nodes in it. */ enum { NFSD_Root = 1, @@ -58,6 +58,7 @@ enum { NFSD_Versions, NFSD_Ports, NFSD_MaxBlkSize, + NFSD_Suspend, /* * The below MUST come last. Otherwise we leave a hole in nfsd_files[] * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops @@ -150,6 +151,26 @@ static const struct file_operations tran .release = simple_transaction_release, }; +static ssize_t nfsctl_suspend_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) +{ + printk("Suspending NFS transactions!\n"); + exp_writelock(); + export_purge(); + return size; +} + +static ssize_t nfsctl_suspend_read(struct file *file, char __user *buf, size_t size, loff_t *pos) +{ + printk("Resuming NFS transactions!\n"); + exp_writeunlock(); + return 0; +} + +static struct file_operations suspend_ops = { + .write = nfsctl_suspend_write, + .read = nfsctl_suspend_read, +}; + extern struct seq_operations nfs_exports_op; static int exports_open(struct inode *inode, struct file *file) { @@ -653,6 +674,7 @@ static int nfsd_fill_super(struct super_ [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, + [NFSD_Suspend] = {"suspend", &suspend_ops, S_IWUSR|S_IRUSR}, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, diff -puN include/linux/nfsd/export.h~nfs_suspend include/linux/nfsd/export.h --- linux-2.6.21.1/include/linux/nfsd/export.h~nfs_suspend 2007-07-19 16:51:00.000000000 -0700 +++ linux-2.6.21.1-root/include/linux/nfsd/export.h 2007-07-19 16:51:00.000000000 -0700 @@ -106,6 +106,9 @@ struct svc_expkey { void nfsd_export_init(void); void nfsd_export_shutdown(void); void nfsd_export_flush(void); +void export_purge(void); +void exp_writelock(void); +void exp_writeunlock(void); void exp_readlock(void); void exp_readunlock(void); struct svc_export * exp_get_by_name(struct auth_domain *clp,