Anyway, here's the story in brief:
* Get linux-nfs-0.4.21.tar.gz from
ftp.mathematik.th-darmstadt.de/pub/linux/okir or
linux.nrao.edu/pub/people/okir
It contains all the utilities you need. It also contains a
copy of the code that's now in the kernel; just remove the
kernel target from Makefile.
* To use the NFS client fully, you need at least the patched mount
program. If you don't want to use file locking, mount all your
NFS volumes using -o no_lock.
* If you do want to test the file locking code, you must create
/var/lib/nfs/sm and install and run rpc.statd.
* To run nfsd, include nfsd in your kernel and run
the and rpc.mountd and rpc.nfsd included in the package.
rpc.kmountd
rpc.knfsd 4
kexports -va
will start four server threads. (By default, these will will
be installed with a leading `k' in order not to overwrite existing
programs--yet :).
* If something does not work, please send me bug reports. The utils
package contains a tool called rpcdebug, by which you can enable
and disable various logging features. Use
rpcdebug -m <module> <flags>
where module can be one of rpc, nfs, nfsd, and nlm (for lockd).
Each module supports a different set of flags; the easiest way
is to use `all'.
If you provide me with debug logs of how things go wrong, this
will help me a lot.
* Also, volunteers are welcome to participate in maintaining the
user utilities, write manpages etc. Of course, kernel patches
are also welcome.
Below I'm appending a kernel patch that lets you compile NFS as a module,
and enables the /proc files for NFS statistics (can be printed out using
knfsstat). Depending on your setup, you may also have to add one of the
ksyms patches posted to the list by other people.
Cheers
Olaf
-- Olaf Kirch | Why don't you try assert(__TUBORG__); ? okir@monad.swb.de | --Olaf Titz (no relation) ------------------------------------------------------------------ diff -ur v2.1.32/fs/Config.in linux/fs/Config.in --- v2.1.32/fs/Config.in Mon Apr 7 23:58:09 1997 +++ linux/fs/Config.in Mon Apr 7 20:56:51 1997 @@ -18,12 +18,23 @@ if [ "$CONFIG_INET" = "y" ]; then tristate 'NFS filesystem support' CONFIG_NFS_FS if [ "$CONFIG_NFS_FS" = "y" ]; then - define_bool CONFIG_SUNRPC y - define_bool CONFIG_LOCKD y bool ' Root file system on NFS' CONFIG_ROOT_NFS if [ "$CONFIG_ROOT_NFS" = "y" ]; then bool ' BOOTP support' CONFIG_RNFS_BOOTP bool ' RARP support' CONFIG_RNFS_RARP + fi + fi + tristate 'NFS server support' CONFIG_NFSD + if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then + define_bool CONFIG_SUNRPC y + define_bool CONFIG_LOCKD y + else + if [ "$CONFIG_NFS_FS" = "m" -o "$CONFIG_NFSD" = "m" ]; then + define_bool CONFIG_SUNRPC m + define_bool CONFIG_LOCKD m + else + define_bool CONFIG_SUNRPC n + define_bool CONFIG_LOCKD n fi fi tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS diff -ur v2.1.32/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c --- v2.1.32/fs/lockd/clntproc.c Mon Apr 7 23:58:11 1997 +++ linux/fs/lockd/clntproc.c Tue Apr 8 02:25:40 1997 @@ -322,7 +322,8 @@ int status; if (!host->h_monitored && nsm_monitor(host) < 0) { - printk(KERN_NOTICE "lockd: failed to monitor %s", host->h_name); + printk(KERN_NOTICE "lockd: failed to monitor %s\n", + host->h_name); return -ENOLCK; } @@ -496,10 +497,10 @@ /* Everything's good */ break; case NLM_LCK_DENIED_NOLOCKS: - dprintk("lockd: CANCEL failed (server has no locks)"); + dprintk("lockd: CANCEL failed (server has no locks)\n"); goto retry_cancel; default: - printk(KERN_NOTICE "lockd: weird return %d for CANCEL call", + printk(KERN_NOTICE "lockd: weird return %d for CANCEL call\n", req->a_res.status); } diff -ur v2.1.32/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.1.32/fs/nfs/inode.c Mon Apr 7 23:58:12 1997 +++ linux/fs/nfs/inode.c Mon Apr 7 18:35:48 1997 @@ -25,11 +25,12 @@ #include <linux/locks.h> #include <linux/unistd.h> #include <linux/sunrpc/clnt.h> +#include <linux/sunrpc/stats.h> #include <linux/nfs_fs.h> #include <linux/lockd/bind.h> #include <asm/system.h> -# include <asm/uaccess.h> +#include <asm/uaccess.h> #define NFSDBG_FACILITY NFSDBG_VFS @@ -50,6 +51,7 @@ NULL }; +struct rpc_stat nfs_rpcstat = { &nfs_program }; /* * The "read_inode" function doesn't actually do anything: @@ -438,7 +440,7 @@ init_nfs_fs(void) { #ifdef CONFIG_PROC_FS - rpcstat_register(&nfs_rpcstat); + rpc_proc_register(&nfs_rpcstat); #endif return register_filesystem(&nfs_fs_type); } @@ -462,7 +464,7 @@ cleanup_module(void) { #ifdef CONFIG_PROC_FS - rpcstat_unregister(&nfs_rpcstat); + rpc_proc_unregister("nfs"); #endif unregister_filesystem(&nfs_fs_type); nfs_free_dircache(); diff -ur v2.1.32/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c --- v2.1.32/fs/nfs/nfs2xdr.c Mon Apr 7 23:58:12 1997 +++ linux/fs/nfs/nfs2xdr.c Mon Apr 7 15:58:24 1997 @@ -625,25 +625,3 @@ nfs_version, &nfs_rpcstat, }; - -/* - * RPC stats support - */ -static int -nfs_get_info(char *buffer, char **start, off_t offset, int length, int dummy) -{ - return rpcstat_get_info(&nfs_rpcstat, buffer, start, offset, length); -} - -static struct proc_dir_entry proc_nfsclnt = { - 0, 3, "nfs", - S_IFREG | S_IRUGO, 1, 0, 0, - 6, &proc_net_inode_operations, - nfs_get_info -}; - -struct rpc_stat nfs_rpcstat = { - NULL, /* next */ - &proc_nfsclnt, /* /proc/net directory entry */ - &nfs_program, /* RPC program */ -}; diff -ur v2.1.32/fs/nfsd/stats.c linux/fs/nfsd/stats.c --- v2.1.32/fs/nfsd/stats.c Mon Apr 7 23:58:13 1997 +++ linux/fs/nfsd/stats.c Mon Apr 7 15:49:57 1997 @@ -1,18 +1,16 @@ /* - * nfsstat.c procfs-based user access to knfsd statistics + * linux/fs/nfsd/stats.c * - * /proc/net/nfssrv + * procfs-based user access to knfsd statistics + * + * /proc/net/rpc/nfsd + * * Format: - * net <packets> <udp> <tcp> <tcpconn> - * rpc <packets> <badfmt> <badclnt> - * auth <flavor> <creds> <upcalls> <badauth> <badverf> <authrej> - * fh <hits> <misses> <avg_util> <stale> <cksum> <badcksum> * rc <hits> <misses> <nocache> - * proto <version> <nrprocs> - * <calls> <time_msec> - * ... (for each procedure and protocol version) + * Statistsics for the reply cache + * plus generic RPC stats (see net/sunrpc/stats.c) * - * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> */ #include <linux/kernel.h> @@ -26,28 +24,13 @@ #include <linux/nfsd/stats.h> struct nfsd_stats nfsdstats; - -static int nfsd_get_info(char *, char **, off_t, int, int); +struct svc_stat nfsd_svcstats = { &nfsd_program, }; -#ifndef PROC_NET_NFSSRV -# define PROC_NET_NFSSRV 0 -#endif - -static struct proc_dir_entry proc_nfssrv = { - PROC_NET_NFSSRV, 4, "nfsd", - S_IFREG | S_IRUGO, 1, 0, 0, - 6, &proc_net_inode_operations, - nfsd_get_info -}; - -struct svc_stat nfsd_svcstats = { - NULL, &proc_nfssrv, &nfsd_program, -}; - static int -nfsd_get_info(char *buffer, char **start, off_t offset, int length, int dummy) +nfsd_proc_read(char *buffer, char **start, off_t offset, int count, + int *eof, void *data) { - int len; + int len; len = sprintf(buffer, "rc %d %d %d\n", @@ -55,38 +38,45 @@ nfsdstats.rcmisses, nfsdstats.rcnocache); + /* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */ + *eof = 0; + /* - * Append generic nfsd RPC statistics + * Append generic nfsd RPC statistics if there's room for it. */ - if (offset >= len) { - offset -= len; - len = svcstat_get_info(&nfsd_svcstats, buffer, start, - offset, length); -#if 0 - } else if (len < length) { - len = svcstat_get_info(&nfsd_svcstats, buffer + len, start, - offset - len, length - len); -#endif + if (len <= offset) { + len = svc_proc_read(buffer, start, offset - len, count, + eof, data); + return len; + } + + if (len < count) { + len += svc_proc_read(buffer + len, start, 0, count - len, + eof, data); } if (offset >= len) { *start = buffer; return 0; } + *start = buffer + offset; - if ((len -= offset) > length) - len = length; + if ((len -= offset) > count) + return count; return len; } void nfsd_stat_init(void) { - svcstat_register(&nfsd_svcstats); + struct proc_dir_entry *ent; + + if ((ent = svc_proc_register(&nfsd_svcstats)) != 0) + ent->read_proc = nfsd_proc_read; } void nfsd_stat_shutdown(void) { - svcstat_unregister(&nfsd_svcstats); + svc_proc_unregister("nfsd"); } diff -ur v2.1.32/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c --- v2.1.32/fs/proc/procfs_syms.c Mon Apr 7 23:56:37 1997 +++ linux/fs/proc/procfs_syms.c Mon Apr 7 23:50:17 1997 @@ -14,6 +14,8 @@ EXPORT_SYMBOL(proc_register); EXPORT_SYMBOL(proc_unregister); +EXPORT_SYMBOL(create_proc_entry); +EXPORT_SYMBOL(remove_proc_entry); EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_get_inode); EXPORT_SYMBOL(in_group_p); diff -ur v2.1.32/include/linux/sunrpc/stats.h linux/include/linux/sunrpc/stats.h --- v2.1.32/include/linux/sunrpc/stats.h Mon Apr 7 23:58:15 1997 +++ linux/include/linux/sunrpc/stats.h Mon Apr 7 21:01:57 1997 @@ -12,8 +12,6 @@ #include <linux/proc_fs.h> struct rpc_stat { - struct rpc_stat * next; - struct proc_dir_entry * entry; struct rpc_program * program; unsigned int netcnt, @@ -28,8 +26,6 @@ }; struct svc_stat { - struct svc_stat * next; - struct proc_dir_entry * entry; struct svc_program * program; unsigned int netcnt, @@ -42,18 +38,18 @@ rpcbadclnt; }; -void rpcstat_init(void); -void rpcstat_exit(void); +void rpc_proc_init(void); +void rpc_proc_exit(void); -void rpcstat_register(struct rpc_stat *); -void rpcstat_unregister(struct rpc_stat *); -int rpcstat_get_info(struct rpc_stat *, char *, char **, - off_t, int); -void rpcstat_zero_info(struct rpc_program *); -void svcstat_register(struct svc_stat *); -void svcstat_unregister(struct svc_stat *); -int svcstat_get_info(struct svc_stat *, char *, char **, - off_t, int); -void svcstat_zero_info(struct svc_program *); +struct proc_dir_entry * rpc_proc_register(struct rpc_stat *); +void rpc_proc_unregister(const char *); +int rpc_proc_read(char *, char **, off_t, int, + int *, void *); +void rpc_proc_zero(struct rpc_program *); +struct proc_dir_entry * svc_proc_register(struct svc_stat *); +void svc_proc_unregister(const char *); +int svc_proc_read(char *, char **, off_t, int, + int *, void *); +void svc_proc_zero(struct svc_program *); #endif /* _LINUX_SUNRPC_STATS_H */ diff -ur v2.1.32/kernel/printk.c linux/kernel/printk.c --- v2.1.32/kernel/printk.c Mon Apr 7 23:58:17 1997 +++ linux/kernel/printk.c Mon Apr 7 20:06:19 1997 @@ -218,7 +218,7 @@ struct console *c = console_drivers; while(c) { if (c->write) - c->write(msg, p - msg + 1); + c->write(msg, p - msg + (*p == '\n')); c = c->next; } } diff -ur v2.1.32/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c --- v2.1.32/net/sunrpc/clnt.c Mon Apr 7 23:58:18 1997 +++ linux/net/sunrpc/clnt.c Mon Apr 7 16:38:20 1997 @@ -746,7 +746,7 @@ #ifdef RPC_DEBUG rpc_register_sysctl(); #endif - rpcstat_init(); + rpc_proc_init(); return 0; } @@ -756,6 +756,6 @@ #ifdef RPC_DEBUG rpc_unregister_sysctl(); #endif - rpcstat_exit(); + rpc_proc_exit(); } #endif diff -ur v2.1.32/net/sunrpc/stats.c linux/net/sunrpc/stats.c --- v2.1.32/net/sunrpc/stats.c Mon Apr 7 23:58:18 1997 +++ linux/net/sunrpc/stats.c Mon Apr 7 23:48:30 1997 @@ -1,14 +1,15 @@ /* * linux/net/sunrpc/stats.c * - * procfs-based user access to RPC statistics + * procfs-based user access to generic RPC statistics. The stats files + * reside in /proc/net/rpc. * - * Everything is complicated by the fact that procfs doesn't pass the - * proc_dir_info struct in the call to get_info. We need our own - * inode_ops for /proc/net/rpc (we want to have a write op for zeroing - * the current stats, anyway). + * The read routines assume that the buffer passed in is just big enough. + * If you implement an RPC service that has its own stats routine which + * appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE + * limit. * - * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> */ #include <linux/kernel.h> @@ -19,83 +20,16 @@ #define RPCDBG_FACILITY RPCDBG_MISC -/* - * Generic stats object (same for clnt and svc stats). - * Must agree with first two fields of either. - */ -struct stats { - struct stats * next; - struct proc_dir_entry * entry; -}; - -/* Code disabled until updated to new dynamic /proc code */ -#if 0 - -static struct stats * rpc_stats = NULL; -static struct stats * svc_stats = NULL; - -static struct proc_dir_entry proc_rpc = { - 0, 3, "rpc", - S_IFDIR | S_IRUGO | S_IXUGO, 1, 0, 0, - 0, NULL, - NULL, NULL, - NULL, - NULL, NULL, -}; - -/* - * Register/unregister a stats file - */ -static void -stats_register(struct stats **q, struct stats *p) -{ - dprintk("RPC: registering /proc/net/rpc/%s\n", - p->entry->name); - /* return; */ - if (p->entry->low_ino) - return; - p->next = *q; - *q = p; - proc_register_dynamic(&proc_rpc, p->entry); -} +static struct proc_dir_entry *proc_net_rpc = 0; -static void -stats_unregister(struct stats **q, struct stats *p) -{ - dprintk("RPC: unregistering /proc/net/rpc/%s\n", - p->entry->name); - /* return; */ - if (!p->entry->low_ino) - return; - while (*q) { - if (*q == p) { - *q = p->next; - proc_unregister(&proc_rpc, p->entry->low_ino); - return; - } - q = &((*q)->next); - } -} - /* - * Client stats handling + * Get RPC client stats */ -void -rpcstat_register(struct rpc_stat *statp) -{ - stats_register(&rpc_stats, (struct stats *) statp); -} - -void -rpcstat_unregister(struct rpc_stat *statp) -{ - stats_unregister(&rpc_stats, (struct stats *) statp); -} - int -rpcstat_get_info(struct rpc_stat *statp, char *buffer, - char **start, off_t offset, int length) +rpc_proc_read(char *buffer, char **start, off_t offset, int count, + int *eof, void *data) { + struct rpc_stat *statp = (struct rpc_stat *) data; struct rpc_program *prog = statp->program; struct rpc_version *vers; int len, i, j; @@ -125,34 +59,24 @@ if (offset >= len) { *start = buffer; + *eof = 1; return 0; } *start = buffer + offset; - len -= offset; - if (len > length) - len = length; + if ((len -= offset) > count) + return count; + *eof = 1; return len; } /* - * Server stats handling + * Get RPC server stats */ -void -svcstat_register(struct svc_stat *statp) -{ - stats_register(&svc_stats, (struct stats *) statp); -} - -void -svcstat_unregister(struct svc_stat *statp) -{ - stats_unregister(&svc_stats, (struct stats *) statp); -} - int -svcstat_get_info(struct svc_stat *statp, char *buffer, - char **start, off_t offset, int length) +svc_proc_read(char *buffer, char **start, off_t offset, int count, + int *eof, void *data) { + struct svc_stat *statp = (struct svc_stat *) data; struct svc_program *prog = statp->program; struct svc_procedure *proc; struct svc_version *vers; @@ -183,85 +107,69 @@ if (offset >= len) { *start = buffer; + *eof = 1; return 0; } *start = buffer + offset; - if ((len -= offset) > length) - len = length; + if ((len -= offset) > count) + return count; + *eof = 1; return len; } /* - * Register /proc/net/rpc - */ -void -rpcstat_init(void) -{ - dprintk("RPC: registering /proc/net/rpc\n"); - proc_rpc.ops = proc_net.ops; /* cheat */ - proc_register_dynamic(&proc_net, &proc_rpc); -} - -/* - * Unregister /proc/net/rpc + * Register/unregister RPC proc files */ -void -rpcstat_exit(void) +static inline struct proc_dir_entry * +do_register(const char *name, void *data, int issvc) { - while (rpc_stats) - stats_unregister(&rpc_stats, rpc_stats); - while (svc_stats) - stats_unregister(&svc_stats, svc_stats); - dprintk("RPC: unregistering /proc/net/rpc\n"); - proc_unregister(&proc_net, proc_rpc.low_ino); -} + struct proc_dir_entry *ent; -#else + dprintk("RPC: registering /proc/net/rpc/%s\n", name); + ent = create_proc_entry(name, 0, proc_net_rpc); + ent->read_proc = issvc? svc_proc_read : rpc_proc_read; + ent->data = data; -/* Various dummy functions */ - -int -rpcstat_get_info(struct rpc_stat *statp, char *buffer, - char **start, off_t offset, int length) -{ - return 0; -} - -int -svcstat_get_info(struct svc_stat *statp, char *buffer, - char **start, off_t offset, int length) -{ - return 0; + return ent; } -void -rpcstat_register(struct rpc_stat *statp) +struct proc_dir_entry * +rpc_proc_register(struct rpc_stat *statp) { + return do_register(statp->program->name, statp, 0); } void -rpcstat_unregister(struct rpc_stat *statp) +rpc_proc_unregister(const char *name) { + remove_proc_entry(name, proc_net_rpc); } -void -svcstat_register(struct svc_stat *statp) +struct proc_dir_entry * +svc_proc_register(struct svc_stat *statp) { + return do_register(statp->program->pg_name, statp, 1); } void -svcstat_unregister(struct svc_stat *statp) +svc_proc_unregister(const char *name) { + remove_proc_entry(name, proc_net_rpc); } void -rpcstat_init(void) +rpc_proc_init(void) { + dprintk("RPC: registering /proc/net/rpc\n"); + if (!proc_net_rpc) + proc_net_rpc = create_proc_entry("net/rpc", S_IFDIR, 0); } void -rpcstat_exit(void) +rpc_proc_exit(void) { + dprintk("RPC: unregistering /proc/net/rpc\n"); + if (proc_net_rpc) + remove_proc_entry("net/rpc", 0); + proc_net_rpc = 0; } - -#endif diff -ur v2.1.32/net/sunrpc/sunrpc_syms.c linux/net/sunrpc/sunrpc_syms.c --- v2.1.32/net/sunrpc/sunrpc_syms.c Mon Apr 7 23:58:18 1997 +++ linux/net/sunrpc/sunrpc_syms.c Mon Apr 7 16:39:36 1997 @@ -10,8 +10,6 @@ #include <linux/config.h> #include <linux/module.h> -#ifdef CONFIG_MODULES - #include <linux/types.h> #include <linux/socket.h> #include <linux/sched.h> @@ -75,12 +73,12 @@ /* RPC statistics */ #ifdef CONFIG_PROC_FS -EXPORT_SYMBOL(rpcstat_register); -EXPORT_SYMBOL(rpcstat_unregister); -EXPORT_SYMBOL(rpcstat_get_info); -EXPORT_SYMBOL(svcstat_register); -EXPORT_SYMBOL(svcstat_unregister); -EXPORT_SYMBOL(svcstat_get_info); +EXPORT_SYMBOL(rpc_proc_register); +EXPORT_SYMBOL(rpc_proc_unregister); +EXPORT_SYMBOL(rpc_proc_read); +EXPORT_SYMBOL(svc_proc_register); +EXPORT_SYMBOL(svc_proc_unregister); +EXPORT_SYMBOL(svc_proc_read); #endif /* Generic XDR */ @@ -101,5 +99,3 @@ EXPORT_SYMBOL(nfs_debug); EXPORT_SYMBOL(nfsd_debug); EXPORT_SYMBOL(nlm_debug); - -#endif /* CONFIG_MODULES */ ----------------------- END OF PATCH ------------------------