patch-2.3.99-pre4 linux/fs/nfs/inode.c
Next file: linux/fs/nfs/mount_clnt.c
Previous file: linux/fs/nfs/flushd.c
Back to the patch index
Back to the overall index
- Lines: 796
- Date:
Sun Apr 2 15:31:32 2000
- Orig file:
v2.3.99-pre3/linux/fs/nfs/inode.c
- Orig date:
Mon Mar 27 08:08:29 2000
diff -u --recursive --new-file v2.3.99-pre3/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
@@ -27,6 +27,7 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
#include <linux/nfs_flushd.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
@@ -58,7 +59,32 @@
umount_begin: nfs_umount_begin,
};
+/*
+ * RPC cruft for NFS
+ */
struct rpc_stat nfs_rpcstat = { &nfs_program };
+static struct rpc_version * nfs_version[] = {
+ NULL,
+ NULL,
+ &nfs_version2,
+#ifdef CONFIG_NFS_V3
+ &nfs_version3,
+#endif
+};
+
+struct rpc_program nfs_program = {
+ "nfs",
+ NFS_PROGRAM,
+ sizeof(nfs_version) / sizeof(nfs_version[0]),
+ nfs_version,
+ &nfs_rpcstat,
+};
+
+static inline unsigned long
+nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
+{
+ return nfs_fileid_to_ino_t(fattr->fileid);
+}
/*
* The "read_inode" function doesn't actually do anything:
@@ -83,6 +109,7 @@
inode->u.nfs_i.npages = 0;
NFS_CACHEINV(inode);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
static void
@@ -101,18 +128,12 @@
{
dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
- lock_kernel();
- if (S_ISDIR(inode->i_mode)) {
- nfs_free_dircache(inode);
- } else {
- /*
- * The following can never actually happen...
- */
- if (nfs_have_writebacks(inode)) {
- printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
- }
+ /*
+ * The following can never actually happen...
+ */
+ if (nfs_have_writebacks(inode)) {
+ printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
}
- unlock_kernel();
clear_inode(inode);
}
@@ -153,33 +174,68 @@
rpc_killall_tasks(rpc);
}
-/*
- * Compute and set NFS server blocksize
- */
-static unsigned int
-nfs_block_size(unsigned int bsize, unsigned char *nrbitsp)
-{
- if (bsize < 1024)
- bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
- else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
- bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+static inline unsigned long
+nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
+{
/* make sure blocksize is a power of two */
if ((bsize & (bsize - 1)) || nrbitsp) {
- unsigned int nrbits;
+ unsigned char nrbits;
for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
;
bsize = 1 << nrbits;
if (nrbitsp)
*nrbitsp = nrbits;
- if (bsize < NFS_DEF_FILE_IO_BUFFER_SIZE)
- bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
}
return bsize;
}
+/*
+ * Calculate the number of 512byte blocks used.
+ */
+static inline unsigned long
+nfs_calc_block_size(u64 tsize)
+{
+ loff_t used = (tsize + 511) / 512;
+ return (used > ULONG_MAX) ? ULONG_MAX : used;
+}
+
+/*
+ * Compute and set NFS server blocksize
+ */
+static inline unsigned long
+nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
+{
+ if (bsize < 1024)
+ bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
+ else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
+ bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+
+ return nfs_block_bits(bsize, nrbitsp);
+}
+
+/*
+ * Obtain the root inode of the file system.
+ */
+static struct inode *
+nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh)
+{
+ struct nfs_server *server = &sb->u.nfs_sb.s_server;
+ struct nfs_fattr fattr;
+ struct inode *inode;
+ int error;
+
+ if ((error = server->rpc_ops->getroot(server, rootfh, &fattr)) < 0) {
+ printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
+ return NULL;
+ }
+
+ inode = __nfs_fhget(sb, &fattr);
+ return inode;
+}
+
extern struct nfs_fh *nfs_fh_alloc(void);
extern void nfs_fh_free(struct nfs_fh *p);
@@ -194,19 +250,20 @@
{
struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data;
struct nfs_server *server;
- struct rpc_xprt *xprt;
- struct rpc_clnt *clnt;
- struct nfs_fh *root_fh;
- struct inode *root_inode;
+ struct rpc_xprt *xprt = NULL;
+ struct rpc_clnt *clnt = NULL;
+ struct nfs_fh *root = &data->root, *root_fh, fh;
+ struct inode *root_inode = NULL;
unsigned int authflavor;
- int tcp;
struct sockaddr_in srvaddr;
struct rpc_timeout timeparms;
- struct nfs_fattr fattr;
+ struct nfs_fsinfo fsinfo;
+ int tcp, version, maxlen;
if (!data)
goto out_miss_args;
+ memset(&fh, 0, sizeof(fh));
if (data->version != NFS_MOUNT_VERSION) {
printk("nfs warning: mount version %s than kernel\n",
data->version < NFS_MOUNT_VERSION ? "older" : "newer");
@@ -214,6 +271,12 @@
data->namlen = 0;
if (data->version < 3)
data->bsize = 0;
+ if (data->version < 4) {
+ data->flags &= ~NFS_MOUNT_VER3;
+ root = &fh;
+ root->size = NFS2_FHSIZE;
+ memcpy(root->data, data->old_root.data, NFS2_FHSIZE);
+ }
}
/* We now require that the mount process passes the remote address */
@@ -225,12 +288,12 @@
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_op = &nfs_sops;
+ sb->s_blocksize_bits = 0;
sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
- sb->u.nfs_sb.s_root = data->root;
server = &sb->u.nfs_sb.s_server;
server->rsize = nfs_block_size(data->rsize, NULL);
server->wsize = nfs_block_size(data->wsize, NULL);
- server->flags = data->flags;
+ server->flags = data->flags & NFS_MOUNT_FLAGMASK;
if (data->flags & NFS_MOUNT_NOAC) {
data->acregmin = data->acregmax = 0;
@@ -241,11 +304,32 @@
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
+ server->namelen = data->namlen;
server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
if (!server->hostname)
goto out_unlock;
strcpy(server->hostname, data->hostname);
+ nfsv3_try_again:
+ /* Check NFS protocol revision and initialize RPC op vector
+ * and file handle pool. */
+ if (data->flags & NFS_MOUNT_VER3) {
+#ifdef CONFIG_NFS_V3
+ server->rpc_ops = &nfs_v3_clientops;
+ version = 3;
+ if (data->version < 4) {
+ printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
+ goto out_unlock;
+ }
+#else
+ printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
+ goto out_unlock;
+#endif
+ } else {
+ server->rpc_ops = &nfs_v2_clientops;
+ version = 2;
+ }
+
/* Which protocol do we use? */
tcp = (data->flags & NFS_MOUNT_TCP);
@@ -255,6 +339,11 @@
timeparms.to_maxval = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
timeparms.to_exponential = 1;
+ if (!timeparms.to_initval)
+ timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10;
+ if (!timeparms.to_retries)
+ timeparms.to_retries = 5;
+
/* Now create transport and client */
xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
&srvaddr, &timeparms);
@@ -269,7 +358,7 @@
authflavor = RPC_AUTH_KRB;
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
- NFS_VERSION, authflavor);
+ version, authflavor);
if (clnt == NULL)
goto out_no_client;
@@ -289,20 +378,68 @@
root_fh = nfs_fh_alloc();
if (!root_fh)
goto out_no_fh;
- *root_fh = data->root;
+ memcpy((u8*)root_fh, (u8*)root, sizeof(*root));
- if (nfs_proc_getattr(server, root_fh, &fattr) != 0)
- goto out_no_fattr;
+ /* Did getting the root inode fail? */
+ if (!(root_inode = nfs_get_root(sb, root))
+ && (data->flags & NFS_MOUNT_VER3)) {
+ data->flags &= ~NFS_MOUNT_VER3;
+ nfs_fh_free(root_fh);
+ rpciod_down();
+ rpc_shutdown_client(server->client);
+ goto nfsv3_try_again;
+ }
- root_inode = __nfs_fhget(sb, &fattr);
if (!root_inode)
goto out_no_root;
sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root)
goto out_no_root;
+
sb->s_root->d_op = &nfs_dentry_operations;
sb->s_root->d_fsdata = root_fh;
+ /* Get some general file system info */
+ if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
+ if (server->namelen == 0)
+ server->namelen = fsinfo.namelen;
+ } else {
+ printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
+ goto out_no_root;
+ }
+
+ /* Work out a lot of parameters */
+ if (data->rsize == 0)
+ server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+ if (data->wsize == 0)
+ server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+ server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+ /* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
+ if (!fsinfo.bsize)
+ fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
+ /* Also make sure we don't go below rsize/wsize since
+ * RPC calls are expensive */
+ if (fsinfo.bsize < server->rsize)
+ fsinfo.bsize = server->rsize;
+ if (fsinfo.bsize < server->wsize)
+ fsinfo.bsize = server->wsize;
+
+ if (data->bsize == 0)
+ sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
+ if (server->rsize > fsinfo.rtmax)
+ server->rsize = fsinfo.rtmax;
+ if (server->rsize > PAGE_CACHE_SIZE)
+ server->rsize = PAGE_CACHE_SIZE;
+ if (server->wsize > fsinfo.wtmax)
+ server->wsize = fsinfo.wtmax;
+ if (server->wsize > NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT)
+ server->wsize = NFS_WRITE_MAXIOV << PAGE_CACHE_SHIFT;
+
+ maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
+
+ if (server->namelen == 0 || server->namelen > maxlen)
+ server->namelen = maxlen;
+
/* Fire up the writeback cache */
if (nfs_reqlist_alloc(server) < 0) {
printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
@@ -322,11 +459,6 @@
out_no_root:
printk("nfs_read_super: get root inode failed\n");
iput(root_inode);
- goto out_free_fh;
-
-out_no_fattr:
- printk("nfs_read_super: get root fattr failed\n");
-out_free_fh:
nfs_fh_free(root_fh);
out_no_fh:
rpciod_down();
@@ -366,21 +498,33 @@
static int
nfs_statfs(struct super_block *sb, struct statfs *buf)
{
- int error;
+ struct nfs_server *server = &sb->u.nfs_sb.s_server;
+ unsigned char blockbits;
+ unsigned long blockres;
struct nfs_fsinfo res;
+ int error;
- error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
- &res);
- if (error) {
- printk("nfs_statfs: statfs error = %d\n", -error);
- res.bsize = res.blocks = res.bfree = res.bavail = -1;
- }
+ error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
buf->f_type = NFS_SUPER_MAGIC;
- buf->f_bsize = res.bsize;
- buf->f_blocks = res.blocks;
- buf->f_bfree = res.bfree;
- buf->f_bavail = res.bavail;
- buf->f_namelen = NAME_MAX;
+ if (error < 0)
+ goto out_err;
+
+ if (res.bsize == 0)
+ res.bsize = sb->s_blocksize;
+ buf->f_bsize = nfs_block_bits(res.bsize, &blockbits);
+ blockres = (1 << blockbits) - 1;
+ buf->f_blocks = (res.tbytes + blockres) >> blockbits;
+ buf->f_bfree = (res.fbytes + blockres) >> blockbits;
+ buf->f_bavail = (res.abytes + blockres) >> blockbits;
+ buf->f_files = res.tfiles;
+ buf->f_ffree = res.afiles;
+ if (res.namelen == 0 || res.namelen > server->namelen)
+ res.namelen = server->namelen;
+ buf->f_namelen = res.namelen;
+ return 0;
+ out_err:
+ printk("nfs_statfs: statfs error = %d\n", -error);
+ buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
return 0;
}
@@ -429,11 +573,12 @@
nfs_zap_caches(struct inode *inode)
{
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
- NFS_CACHEINV(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
invalidate_inode_pages(inode);
- if (S_ISDIR(inode->i_mode))
- nfs_flush_dircache(inode);
+
+ memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+ NFS_CACHEINV(inode);
}
/*
@@ -481,9 +626,16 @@
* Preset the size and mtime, as there's no need
* to invalidate the caches.
*/
- inode->i_size = fattr->size;
- inode->i_mtime = fattr->mtime.seconds;
- NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+ inode->i_size = nfs_size_to_loff_t(fattr->size);
+ inode->i_mtime = nfs_time_to_secs(fattr->mtime);
+ inode->i_atime = nfs_time_to_secs(fattr->atime);
+ inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+ NFS_CACHE_CTIME(inode) = fattr->ctime;
+ NFS_CACHE_MTIME(inode) = fattr->mtime;
+ NFS_CACHE_ATIME(inode) = fattr->atime;
+ NFS_CACHE_ISIZE(inode) = fattr->size;
+ NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
nfs_refresh_inode(inode, fattr);
}
@@ -551,9 +703,9 @@
{
struct super_block *sb = dentry->d_sb;
- dprintk("NFS: nfs_fhget(%s/%s fileid=%d)\n",
+ dprintk("NFS: nfs_fhget(%s/%s fileid=%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- fattr->fileid);
+ (long long)fattr->fileid);
/* Install the file handle in the dentry */
*((struct nfs_fh *) dentry->d_fsdata) = *fhandle;
@@ -572,7 +724,7 @@
inode->i_sb = sb;
inode->i_dev = sb->s_dev;
inode->i_flags = 0;
- inode->i_ino = fattr->fileid;
+ inode->i_ino = nfs_fattr_to_ino_t(fattr);
nfs_read_inode(inode);
nfs_fill_inode(inode, fattr);
inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
@@ -598,12 +750,15 @@
struct inode *inode = NULL;
unsigned long ino;
+ if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+ goto out_no_inode;
+
if (!fattr->nlink) {
printk("NFS: Buggy server - nlink == 0!\n");
goto out_no_inode;
}
- ino = fattr->fileid;
+ ino = nfs_fattr_to_ino_t(fattr);
while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
@@ -666,8 +821,7 @@
if (error)
goto out;
- error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
- &fattr, attr);
+ error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
if (error)
goto out;
/*
@@ -676,13 +830,21 @@
*/
if (attr->ia_valid & ATTR_SIZE) {
if (attr->ia_size != fattr.size)
- printk("nfs_notify_change: attr=%Ld, fattr=%d??\n",
- (long long) attr->ia_size, fattr.size);
- inode->i_mtime = fattr.mtime.seconds;
+ printk("nfs_notify_change: attr=%Ld, fattr=%Ld??\n",
+ (long long) attr->ia_size, (long long)fattr.size);
vmtruncate(inode, attr->ia_size);
}
- if (attr->ia_valid & ATTR_MTIME)
- inode->i_mtime = fattr.mtime.seconds;
+
+ /*
+ * If we changed the size or mtime, update the inode
+ * now to avoid invalidating the page cache.
+ */
+ if (!(fattr.valid & NFS_ATTR_WCC)) {
+ fattr.pre_size = NFS_CACHE_ISIZE(inode);
+ fattr.pre_mtime = NFS_CACHE_MTIME(inode);
+ fattr.pre_ctime = NFS_CACHE_CTIME(inode);
+ fattr.valid |= NFS_ATTR_WCC;
+ }
error = nfs_refresh_inode(inode, &fattr);
out:
return error;
@@ -695,24 +857,13 @@
int
nfs_wait_on_inode(struct inode *inode, int flag)
{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
- int intr, error = 0;
-
- intr = NFS_SERVER(inode)->flags & NFS_MOUNT_INTR;
- add_wait_queue(&inode->i_wait, &wait);
- for (;;) {
- set_task_state(tsk, (intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE));
- error = 0;
- if (!(NFS_FLAGS(inode) & flag))
- break;
- error = -ERESTARTSYS;
- if (intr && signalled())
- break;
- schedule();
- }
- set_task_state(tsk, TASK_RUNNING);
- remove_wait_queue(&inode->i_wait, &wait);
+ struct rpc_clnt *clnt = NFS_CLIENT(inode);
+ int error;
+ if (!(NFS_FLAGS(inode) & flag))
+ return 0;
+ inode->i_count++;
+ error = nfs_wait_event(clnt, inode->i_wait, !(NFS_FLAGS(inode) & flag));
+ iput(inode);
return error;
}
@@ -768,30 +919,32 @@
}
NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
- status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
+ status = NFS_PROTO(inode)->getattr(dentry, &fattr);
if (status) {
+ struct dentry *dir = dentry->d_parent;
+ struct inode *dir_i = dir->d_inode;
int error;
u32 *fh;
struct nfs_fh fhandle;
dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name, inode->i_ino, status);
+ dir->d_name.name, dentry->d_name.name,
+ inode->i_ino, status);
if (status != -ESTALE)
goto out;
/*
* A "stale filehandle" error ... show the current fh
* and find out what the filehandle should be.
*/
- fh = (u32 *) NFS_FH(dentry);
+ fh = (u32 *) NFS_FH(dentry)->data;
dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
- error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent),
- dentry->d_name.name, &fhandle, &fattr);
+ error = NFS_PROTO(dir_i)->lookup(dir, &dentry->d_name,
+ &fhandle, &fattr);
if (error) {
dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
goto out;
}
- fh = (u32 *) &fhandle;
+ fh = (u32 *) fhandle.data;
dfprintk(PAGECACHE, " %08x%08x%08x%08x%08x%08x%08x%08x\n",
fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
goto out;
@@ -827,19 +980,37 @@
int
nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
- int invalid = 0;
- int error = -EIO;
-
- dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino, inode->i_count);
+ __u64 new_size, new_mtime;
+ loff_t new_isize;
+ int invalid = 0;
+ int error = -EIO;
if (!inode || !fattr) {
- printk("nfs_refresh_inode: inode or fattr is NULL\n");
+ printk(KERN_ERR "nfs_refresh_inode: inode or fattr is NULL\n");
+ goto out;
+ }
+ if (inode->i_mode == 0) {
+ printk(KERN_ERR "nfs_refresh_inode: empty inode\n");
goto out;
}
- if (inode->i_ino != fattr->fileid) {
- printk("nfs_refresh_inode: mismatch, ino=%ld, fattr=%d\n",
- inode->i_ino, fattr->fileid);
+
+ if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+ goto out;
+
+ if (is_bad_inode(inode))
+ goto out;
+
+ dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n",
+ inode->i_dev, inode->i_ino, inode->i_count,
+ fattr->valid);
+
+
+ if (NFS_FSID(inode) != fattr->fsid ||
+ NFS_FILEID(inode) != fattr->fileid) {
+ printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
+ "expected (0x%Lx/0x%Lx), got (0x%Lx/0x%Lx)\n",
+ (long long)NFS_FSID(inode), (long long)NFS_FILEID(inode),
+ (long long)fattr->fsid, (long long)fattr->fileid);
goto out;
}
@@ -849,54 +1020,101 @@
if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
goto out_changed;
- inode->i_mode = fattr->mode;
- inode->i_nlink = fattr->nlink;
- inode->i_uid = fattr->uid;
- inode->i_gid = fattr->gid;
+ new_mtime = fattr->mtime;
+ new_size = fattr->size;
+ new_isize = nfs_size_to_loff_t(fattr->size);
- inode->i_blocks = fattr->blocks;
- inode->i_atime = fattr->atime.seconds;
- inode->i_ctime = fattr->ctime.seconds;
+ error = 0;
/*
* Update the read time so we don't revalidate too often.
*/
NFS_READTIME(inode) = jiffies;
- error = 0;
/*
- * If we have pending write-back entries, we don't want
- * to look at the size or the mtime the server sends us
- * too closely, as we're in the middle of modifying them.
+ * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
+ * NOT inode->i_size!!!
*/
- if (nfs_have_writebacks(inode))
- goto out;
-
- if (inode->i_size != fattr->size) {
+ if (NFS_CACHE_ISIZE(inode) != new_size) {
#ifdef NFS_DEBUG_VERBOSE
-printk("NFS: size change on %x/%ld\n", inode->i_dev, inode->i_ino);
+ printk(KERN_DEBUG "NFS: isize change on %x/%ld\n", inode->i_dev, inode->i_ino);
#endif
- inode->i_size = fattr->size;
invalid = 1;
}
- if (inode->i_mtime != fattr->mtime.seconds) {
+ /*
+ * Note: we don't check inode->i_mtime since pipes etc.
+ * can change this value in VFS without requiring a
+ * cache revalidation.
+ */
+ if (NFS_CACHE_MTIME(inode) != new_mtime) {
#ifdef NFS_DEBUG_VERBOSE
-printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
+ printk(KERN_DEBUG "NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
#endif
- inode->i_mtime = fattr->mtime.seconds;
invalid = 1;
}
- if (invalid)
- goto out_invalid;
+ /* Check Weak Cache Consistency data.
+ * If size and mtime match the pre-operation values, we can
+ * assume that any attribute changes were caused by our NFS
+ * operation, so there's no need to invalidate the caches.
+ */
+ if ((fattr->valid & NFS_ATTR_WCC)
+ && NFS_CACHE_ISIZE(inode) == fattr->pre_size
+ && NFS_CACHE_MTIME(inode) == fattr->pre_mtime) {
+ invalid = 0;
+ }
+
+ /*
+ * If we have pending writebacks, things can get
+ * messy.
+ */
+ if (nfs_have_writebacks(inode) && new_isize < inode->i_size)
+ new_isize = inode->i_size;
+
+ NFS_CACHE_CTIME(inode) = fattr->ctime;
+ inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+ /* If we've been messing around with atime, don't
+ * update it. Save the server value in NFS_CACHE_ATIME.
+ */
+ NFS_CACHE_ATIME(inode) = fattr->atime;
+ if (time_before(inode->i_atime, nfs_time_to_secs(fattr->atime)))
+ inode->i_atime = nfs_time_to_secs(fattr->atime);
+ NFS_CACHE_MTIME(inode) = new_mtime;
+ inode->i_mtime = nfs_time_to_secs(new_mtime);
+
+ NFS_CACHE_ISIZE(inode) = new_size;
+ inode->i_size = new_isize;
+
+ inode->i_mode = fattr->mode;
+ inode->i_nlink = fattr->nlink;
+ inode->i_uid = fattr->uid;
+ inode->i_gid = fattr->gid;
+
+ if (fattr->valid & NFS_ATTR_FATTR_V3) {
+ /*
+ * report the blocks in 512byte units
+ */
+ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
+ inode->i_blksize = inode->i_sb->s_blocksize;
+ } else {
+ inode->i_blocks = fattr->du.nfs2.blocks;
+ inode->i_blksize = fattr->du.nfs2.blocksize;
+ }
+ inode->i_rdev = 0;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_rdev = to_kdev_t(fattr->rdev);
+
/* Update attrtimeo value */
- if (fattr->mtime.seconds == NFS_OLDMTIME(inode)) {
+ if (!invalid && time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) {
if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
- NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+
+ if (invalid)
+ nfs_zap_caches(inode);
out:
return error;
@@ -906,22 +1124,16 @@
* Big trouble! The inode has become a different object.
*/
#ifdef NFS_PARANOIA
-printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
-inode->i_ino, inode->i_mode, fattr->mode);
+ printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
+ inode->i_ino, inode->i_mode, fattr->mode);
#endif
/*
* No need to worry about unhashing the dentry, as the
* lookup validation will know that the inode is bad.
+ * (But we fall through to invalidate the caches.)
*/
nfs_invalidate_inode(inode);
goto out;
-
-out_invalid:
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
-#endif
- nfs_zap_caches(inode);
- goto out;
}
/*
@@ -930,7 +1142,9 @@
static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, 0);
extern int nfs_init_fhcache(void);
+extern void nfs_destroy_fhcache(void);
extern int nfs_init_nfspagecache(void);
+extern void nfs_destroy_nfspagecache(void);
/*
* Initialize NFS
@@ -972,6 +1186,8 @@
void
cleanup_module(void)
{
+ nfs_destroy_nfspagecache();
+ nfs_destroy_fhcache();
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)