diff -ruN linux/fs/nfs/Makefile.noac-timeout linux/fs/nfs/Makefile --- linux/fs/nfs/Makefile.noac-timeout Fri Nov 23 15:27:25 2001 +++ linux/fs/nfs/Makefile Tue Aug 6 22:40:28 2002 @@ -14,6 +14,7 @@ obj-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o obj-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o +obj-$(CONFIG_SYSCTL) += sysctl_net_nfs.o obj-m := $(O_TARGET) diff -ruN linux/fs/nfs/dir.c.noac-timeout linux/fs/nfs/dir.c --- linux/fs/nfs/dir.c.noac-timeout Tue Aug 6 22:27:49 2002 +++ linux/fs/nfs/dir.c Tue Aug 6 22:40:28 2002 @@ -409,6 +409,8 @@ static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry) { + if (NFS_NOAC_TIMEOUT(dir)) + return 0; if (IS_ROOT(dentry)) return 1; if (nfs_revalidate_inode(NFS_SERVER(dir), dir)) diff -ruN linux/fs/nfs/inode.c.noac-timeout linux/fs/nfs/inode.c --- linux/fs/nfs/inode.c.noac-timeout Tue Aug 6 22:27:49 2002 +++ linux/fs/nfs/inode.c Tue Aug 6 22:40:28 2002 @@ -114,6 +114,7 @@ NFS_CACHEINV(inode); NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; + NFS_NOAC_TIMEOUT(inode) = 0; } static void @@ -600,7 +601,8 @@ void nfs_zap_caches(struct inode *inode) { - NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); + if (!NFS_NOAC_TIMEOUT(inode)) + NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; invalidate_inode_pages(inode); @@ -1101,6 +1103,16 @@ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) inode->i_rdev = to_kdev_t(fattr->rdev); + /* check for attribute cache reactivation */ + if ( NFS_NOAC_TIMEOUT(inode) + && NFS_ATTRTIMEO(inode) == 0 + && time_after(jiffies, NFS_NOAC_TIMEOUT(inode)) + ) + { + NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); + NFS_NOAC_TIMEOUT(inode) = 0; + } + /* Update attrtimeo value */ if (invalid) { NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); @@ -1170,6 +1182,9 @@ #ifdef CONFIG_PROC_FS rpc_proc_register(&nfs_rpcstat); #endif +#ifdef CONFIG_SYSCTL + nfs_sysctl_register(); +#endif return register_filesystem(&nfs_fs_type); } @@ -1181,6 +1196,9 @@ #ifdef CONFIG_PROC_FS rpc_proc_unregister("nfs"); #endif +#ifdef CONFIG_SYSCTL + nfs_sysctl_unregister(); +#endif unregister_filesystem(&nfs_fs_type); } diff -ruN /dev/null linux/fs/nfs/sysctl_net_nfs.c --- /dev/null Thu Aug 30 22:30:55 2001 +++ linux/fs/nfs/sysctl_net_nfs.c Tue Aug 6 22:43:14 2002 @@ -0,0 +1,82 @@ +/* + * Sysctl interface to NFS. + * + * Copyright (C) 2001-2004, Frank van Maarseveen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * + * /proc/sys/net/nfs/noac-timeout + * When a nonzero value is written, suspend atribute caching for the current + * working directory and one level of files inside for the specified number + * of seconds. Attribute caching will automatically be enabled when the time + * elapses. Writing a zero re-enables attribute caching as well. Reading + * yields the number of remaining seconds attribute caching will be disabled. + * + * Notes: + * - sys_sysctl() not supported, only /proc/sys + */ + +#include +#include +#include + +static int sysctl_noac_timeout; /* not used */ +static struct ctl_table_header * nfs_sysctl_header; + +static int proc_noac_timeout(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int noac_timeout, error; + struct inode *inode; + struct ctl_table ctl; + + inode = current->fs->pwd->d_inode; + if (inode->i_sb->s_magic != NFS_SUPER_MAGIC) + return -ENOSYS; + + ctl = *table; + ctl.data = &noac_timeout; + noac_timeout = NFS_NOAC_TIMEOUT(inode); + if (noac_timeout) + noac_timeout -= jiffies; + error = proc_dointvec_jiffies(&ctl, write, filp, buffer, lenp); + if (write && !error) { + if (noac_timeout) { + NFS_NOAC_TIMEOUT(inode) = jiffies + noac_timeout; + NFS_ATTRTIMEO(inode) = 0; + } else { + NFS_NOAC_TIMEOUT(inode) = 0; + NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); + } + } + return error; +} + +static ctl_table nfs_table[] = { + {NET_NFS_NOAC_TIMEOUT, "noac-timeout", &sysctl_noac_timeout, sizeof(int), 0666, NULL, &proc_noac_timeout}, + {0} +}; + +static ctl_table nfs_net_table[] = { + {NET_NFS, "nfs", NULL, 0, 0555, nfs_table}, + {0} +}; + +static ctl_table nfs_root_table[] = { + {CTL_NET, "net", NULL, 0, 0555, nfs_net_table}, + {0} +}; + +void nfs_sysctl_register(void) +{ + nfs_sysctl_header = register_sysctl_table(nfs_root_table, 0); +} + +void nfs_sysctl_unregister(void) +{ + unregister_sysctl_table(nfs_sysctl_header); +} diff -ruN linux/include/linux/nfs_fs.h.noac-timeout linux/include/linux/nfs_fs.h --- linux/include/linux/nfs_fs.h.noac-timeout Tue Aug 6 22:27:48 2002 +++ linux/include/linux/nfs_fs.h Tue Aug 6 22:40:28 2002 @@ -95,6 +95,7 @@ (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \ : NFS_SERVER(inode)->acregmax) #define NFS_ATTRTIMEO_UPDATE(inode) ((inode)->u.nfs_i.attrtimeo_timestamp) +#define NFS_NOAC_TIMEOUT(inode) ((inode)->u.nfs_i.noac_timeout) #define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags) #define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING) @@ -276,6 +277,12 @@ extern int nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *); extern int nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *); +/* + * linux/fs/nfs/sysctl_net_nfs.c + */ +extern void nfs_sysctl_register(void); +extern void nfs_sysctl_unregister(void); + /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ extern u32 root_nfs_parse_addr(char *name); /*__init*/ diff -ruN linux/include/linux/nfs_fs_i.h.noac-timeout linux/include/linux/nfs_fs_i.h --- linux/include/linux/nfs_fs_i.h.noac-timeout Tue Aug 6 22:27:48 2002 +++ linux/include/linux/nfs_fs_i.h Tue Aug 6 22:40:28 2002 @@ -55,6 +55,13 @@ unsigned long cache_mtime_jiffies; /* + * attribute caching can selectively be suspended by clearing + * attrtimeo. When jiffies > noac_timeout then attribute + * caching will be reactivated. + */ + unsigned long noac_timeout; + + /* * This is the cookie verifier used for NFSv3 readdir * operations */ diff -ruN linux/include/linux/sysctl.h.noac-timeout linux/include/linux/sysctl.h --- linux/include/linux/sysctl.h.noac-timeout Tue Aug 6 22:27:48 2002 +++ linux/include/linux/sysctl.h Tue Aug 6 22:40:28 2002 @@ -165,7 +165,8 @@ NET_TR=14, NET_DECNET=15, NET_ECONET=16, - NET_KHTTPD=17 + NET_KHTTPD=17, + NET_NFS=18 }; /* /proc/sys/kernel/random */ @@ -503,6 +504,11 @@ NET_KHTTPD_MAXCONNECT = 13 }; +/* /proc/sys/net/nfs/ */ +enum { + NET_NFS_NOAC_TIMEOUT = 1 +}; + /* /proc/sys/net/decnet/conf/ */ enum { NET_DECNET_CONF_LOOPBACK = -2,