patch-2.2.18 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: 1405
- Date:
Sun Oct 15 21:15:17 2000
- Orig file:
v2.2.17/fs/nfs/inode.c
- Orig date:
Sun Jun 11 21:44:19 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/fs/nfs/inode.c linux/fs/nfs/inode.c
@@ -24,11 +24,19 @@
#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/unistd.h>
+#include <linux/major.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/stats.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs_flushd.h>
#include <linux/lockd/bind.h>
+#include <asm/spinlock.h>
+
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -37,16 +45,16 @@
#define NFS_PARANOIA 1
static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
-static void nfs_zap_caches(struct inode *);
-static void nfs_invalidate_inode(struct inode *);
static void nfs_read_inode(struct inode *);
static void nfs_put_inode(struct inode *);
static void nfs_delete_inode(struct inode *);
static int nfs_notify_change(struct dentry *, struct iattr *);
static void nfs_put_super(struct super_block *);
-static void nfs_umount_begin(struct super_block *);
static int nfs_statfs(struct super_block *, struct statfs *, int);
+static void nfs_umount_begin(struct super_block *);
+static struct nfs_file *nfs_file_alloc(void);
+static void nfs_file_free(struct nfs_file *p);
static struct super_operations nfs_sops = {
nfs_read_inode, /* read inode */
@@ -57,12 +65,44 @@
nfs_put_super, /* put superblock */
NULL, /* write superblock */
nfs_statfs, /* stat filesystem */
- NULL, /* no remount */
- NULL, /* no clear inode */
+ NULL, /* remount */
+ NULL, /* clear inode */
nfs_umount_begin /* umount attempt begin */
};
-struct rpc_stat nfs_rpcstat = { &nfs_program };
+
+/*
+ * RPC crutft for NFS
+ */
+static 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);
+}
+
+/*
+ * We don't keep the file handle in the inode anymore to avoid bloating
+ * struct inode and use a pointer to external memory instead.
+ */
+#define NFS_SB_FHSIZE(sb) ((sb)->u.nfs_sb.s_fhsize)
/*
* The "read_inode" function doesn't actually do anything:
@@ -78,8 +118,19 @@
inode->i_mode = 0;
inode->i_rdev = 0;
inode->i_op = NULL;
+ NFS_FILEID(inode) = 0;
+ NFS_FSID(inode) = 0;
+ INIT_LIST_HEAD(&inode->u.nfs_i.read);
+ INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
+ INIT_LIST_HEAD(&inode->u.nfs_i.commit);
+ INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
+ inode->u.nfs_i.nread = 0;
+ inode->u.nfs_i.ndirty = 0;
+ inode->u.nfs_i.ncommit = 0;
+ inode->u.nfs_i.npages = 0;
NFS_CACHEINV(inode);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
static void
@@ -96,32 +147,15 @@
static void
nfs_delete_inode(struct inode * inode)
{
- int failed;
-
dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+#ifdef NFS_DEBUG_VERBOSE
/*
* Flush out any pending write requests ...
*/
- if (NFS_WRITEBACK(inode) != NULL) {
- unsigned long timeout = jiffies + 5*HZ;
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
-#endif
- nfs_inval(inode);
- while (NFS_WRITEBACK(inode) != NULL &&
- time_before(jiffies, timeout)) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/10);
- }
- current->state = TASK_RUNNING;
- if (NFS_WRITEBACK(inode) != NULL)
- printk("NFS: Arghhh, stuck RPC requests!\n");
+ if (nfs_have_writebacks(inode) || nfs_have_read(inode)) {
+ printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
}
-
- failed = nfs_check_failed_request(inode);
- if (failed)
- printk("NFS: inode %ld had %d failed requests\n",
- inode->i_ino, failed);
+#endif
clear_inode(inode);
}
@@ -131,18 +165,22 @@
struct nfs_server *server = &sb->u.nfs_sb.s_server;
struct rpc_clnt *rpc;
+ /*
+ * First get rid of the request flushing daemon.
+ * Relies on rpc_shutdown_client() waiting on all
+ * client tasks to finish.
+ */
+ nfs_reqlist_exit(server);
+
if ((rpc = server->client) != NULL)
rpc_shutdown_client(rpc);
-#if 0
+ nfs_reqlist_free(server);
+
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_down(); /* release rpc.lockd */
-#endif
+
rpciod_down(); /* release rpciod */
- /*
- * Invalidate the dircache for this superblock.
- */
- nfs_invalidate_dircache_sb(sb);
kfree(server->hostname);
@@ -160,17 +198,10 @@
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;
@@ -180,14 +211,56 @@
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)
+{
+ off_t used = nfs_size_to_off_t(tsize);
+ return (used + 511) >> 9;
+}
+
+/*
+ * 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;
+}
+
+/*
* The way this works is that the mount process passes a structure
* in the data argument which contains the server's IP address
* and the root file handle obtained from the server's mount
@@ -198,38 +271,47 @@
{
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 = 0;
+ struct rpc_clnt *clnt = 0;
+ struct nfs_fh *root_fh = NULL,
+ *root = &data->root,
+ 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;
MOD_INC_USE_COUNT;
- if (!data)
- goto out_miss_args;
+ memset(&sb->u.nfs_sb, 0, sizeof(sb->u.nfs_sb));
+ if (!data) {
+ printk(KERN_NOTICE "nfs_read_super: missing data argument\n");
+ goto failure;
+ }
- /* No NFS V3. */
- if (data->flags & NFS_MOUNT_VER3)
- goto out_fail;
-
- /* Don't complain if "mount" is newer. */
- if (data->version < NFS_MOUNT_VERSION) {
- printk("nfs warning: mount version %s than kernel\n",
+ memset(&fh, 0, sizeof(fh));
+ if (data->version != NFS_MOUNT_VERSION) {
+ printk(KERN_WARNING "nfs warning: mount version %s than kernel\n",
data->version < NFS_MOUNT_VERSION ? "older" : "newer");
if (data->version < 2)
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 */
memcpy(&srvaddr, &data->addr, sizeof(srvaddr));
- if (srvaddr.sin_addr.s_addr == INADDR_ANY)
- goto out_no_remote;
+ if (srvaddr.sin_addr.s_addr == INADDR_ANY) {
+ printk(KERN_WARNING "NFS: mount program didn't pass remote address!\n");
+ goto failure;
+ }
lock_super(sb);
@@ -237,12 +319,16 @@
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_op = &nfs_sops;
- sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
- sb->u.nfs_sb.s_root = data->root;
+
+ sb->s_blocksize_bits = 0;
+ sb->s_blocksize = nfs_block_bits(data->bsize, &sb->s_blocksize_bits);
+
server = &sb->u.nfs_sb.s_server;
+ memset(server, 0, sizeof(*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;
@@ -253,11 +339,34 @@
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;
+ goto failure_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;
+ NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS3_FHSIZE;
+ version = 3;
+ if (data->version < 4) {
+ printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
+ goto failure_unlock;
+ }
+#else
+ printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
+ goto failure_unlock;
+#endif
+ } else {
+ server->rpc_ops = &nfs_v2_clientops;
+ NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS2_FHSIZE;
+ version = 2;
+ }
+
/* Which protocol do we use? */
tcp = (data->flags & NFS_MOUNT_TCP);
@@ -267,11 +376,18 @@
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);
- if (xprt == NULL)
- goto out_no_xprt;
+ if (xprt == NULL) {
+ printk(KERN_NOTICE "NFS: cannot create RPC transport. \n");
+ goto failure_unlock;
+ }
/* Choose authentication flavor */
authflavor = RPC_AUTH_UNIX;
@@ -281,92 +397,145 @@
authflavor = RPC_AUTH_KRB;
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
- NFS_VERSION, authflavor);
- if (clnt == NULL)
- goto out_no_client;
+ version, authflavor);
+ if (clnt == NULL) {
+ printk(KERN_NOTICE "NFS: cannot create RPC client \n");
+ goto failure_unlock;
+ }
clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
+ clnt->cl_droppriv = (data->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
clnt->cl_chatty = 1;
server->client = clnt;
/* Fire up rpciod if not yet running */
- if (rpciod_up() != 0)
- goto out_no_iod;
+ if (rpciod_up() != 0) {
+ printk(KERN_NOTICE "NFS: cannot start rpciod!\n");
+ goto failure_unlock;
+ }
/*
* Keep the super block locked while we try to get
* the root fh attributes.
*/
- root_fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
+ root_fh = nfs_fh_alloc();
if (!root_fh)
goto out_no_fh;
- *root_fh = data->root;
-
- if (nfs_proc_getattr(server, root_fh, &fattr) != 0)
- goto out_no_fattr;
+ memcpy((u8*)root_fh, (u8*)root, sizeof(*root_fh));
- root_inode = __nfs_fhget(sb, &fattr);
+ /* Did getting the root inode fail? */
+ if ((root->size > NFS_SB_FHSIZE(sb)
+ || ! (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;
+ }
if (!root_inode)
- goto out_no_root;
- sb->s_root = d_alloc_root(root_inode, NULL);
- if (!sb->s_root)
- goto out_no_root;
+ goto failure_put_root;
+
+ if (! (sb->s_root = d_alloc_root(root_inode, NULL)))
+ goto failure_put_root;
+
sb->s_root->d_op = &nfs_dentry_operations;
sb->s_root->d_fsdata = root_fh;
+ sb->u.nfs_sb.s_root = 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 failure_put_root;
+ }
+
+ /* Fire up the writeback cache */
+ if (nfs_reqlist_alloc(server) < 0) {
+ printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
+ goto failure_kill_reqlist;
+ }
+
+ if (data->rsize == 0 && tcp)
+ server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+ if (data->wsize == 0 && tcp)
+ server->wsize = nfs_block_size(fsinfo.wtpref, 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;
+ server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (server->rpages > NFS_READ_MAXIOV) {
+ server->rpages = NFS_READ_MAXIOV;
+ server->rsize = server->rpages << PAGE_CACHE_SHIFT;
+ }
+
+ if (server->wsize > fsinfo.wtmax)
+ server->wsize = fsinfo.wtmax;
+ server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (server->wpages > NFS_WRITE_MAXIOV) {
+ server->wpages = NFS_WRITE_MAXIOV;
+ server->wsize = server->wpages << PAGE_CACHE_SHIFT;
+ }
+
+ server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+ if (server->dtsize > PAGE_CACHE_SIZE)
+ server->dtsize = PAGE_CACHE_SIZE;
+ if (server->dtsize > server->rsize)
+ server->dtsize = server->rsize;
+
+ maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
+
+ if (server->namelen == 0 || server->namelen > maxlen)
+ server->namelen = maxlen;
/* We're airborne */
unlock_super(sb);
-#if 0
/* Check whether to start the lockd process */
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_up();
-#endif
+
return sb;
/* Yargs. It didn't work out. */
-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:
- kfree(root_fh);
-out_no_fh:
+ failure_kill_reqlist:
+ nfs_reqlist_exit(server);
+ failure_put_root:
+ if (root_inode)
+ iput(root_inode);
+ if (root_fh)
+ nfs_fh_free(root_fh);
+ out_no_fh:
rpciod_down();
- goto out_shutdown;
-
-out_no_iod:
- printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
-out_shutdown:
- rpc_shutdown_client(server->client);
- goto out_free_host;
-
-out_no_client:
- printk(KERN_WARNING "NFS: cannot create RPC client.\n");
- xprt_destroy(xprt);
- goto out_free_host;
-out_no_xprt:
- printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
-
-out_free_host:
- kfree(server->hostname);
-out_unlock:
+ failure_unlock:
+ /* Yargs. It didn't work out. */
+ if (clnt)
+ rpc_shutdown_client(server->client);
+ else if (xprt)
+ xprt_destroy(xprt);
unlock_super(sb);
- goto out_fail;
-
-out_no_remote:
- printk("NFS: mount program didn't pass remote address!\n");
- goto out_fail;
-
-out_miss_args:
- printk("nfs_read_super: missing data argument\n");
+ nfs_reqlist_free(server);
+ if (server->hostname)
+ kfree(server->hostname);
+ printk(KERN_NOTICE "NFS: cannot create RPC transport.\n");
-out_fail:
+failure:
sb->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
@@ -375,27 +544,51 @@
static int
nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
- int error;
- struct nfs_fsinfo res;
- struct statfs tmp;
+ struct nfs_sb_info *si = &sb->u.nfs_sb;
+ struct nfs_server *server = &si->s_server;
+ unsigned char blockbits;
+ unsigned long blockres;
+ int error;
+ struct nfs_fsinfo res;
+ struct statfs tmp;
- error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
- &res);
+ error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
if (error) {
- printk("nfs_statfs: statfs error = %d\n", -error);
- res.bsize = res.blocks = res.bfree = res.bavail = 0;
+ printk(KERN_NOTICE "nfs_statfs: statfs error = %d\n", -error);
+ memset(&res, 0, sizeof(res));
}
tmp.f_type = NFS_SUPER_MAGIC;
- tmp.f_bsize = res.bsize;
- tmp.f_blocks = res.blocks;
- tmp.f_bfree = res.bfree;
- tmp.f_bavail = res.bavail;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
+ if (res.bsize == 0)
+ res.bsize = sb->s_blocksize;
+ if (res.namelen == 0)
+ res.namelen = server->namelen;
+ tmp.f_bsize = nfs_block_bits(res.bsize, &blockbits);
+ blockres = (1 << blockbits) - 1;
+ tmp.f_blocks = (res.tbytes + blockres) >> blockbits;
+ tmp.f_bfree = (res.fbytes + blockres) >> blockbits;
+ tmp.f_bavail = (res.abytes + blockres) >> blockbits;
+ tmp.f_files = res.tfiles;
+ tmp.f_ffree = res.ffiles;
+ tmp.f_namelen = res.namelen;
return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
+#if 0
+int nfs_remountfs(struct super_block *sb, int *flags, char *data)
+{
+ struct nfs_server *server = &sb->u.nfs_sb.s_server;
+
+ if (*flags & ~(NFS_MOUNT_NONLM|MS_RDONLY))
+ return -EINVAL;
+
+ if (*flags & ~NFS_MOUNT_NONLM)
+ return 0;
+
+ if ((*flags & NFS_MOUNT_NONLM) == (server->flags & NFS_MOUNT_NONLM))
+ return 0;
+}
+#endif
+
/*
* Free all unused dentries in an inode's alias list.
*
@@ -437,23 +630,19 @@
}
/*
- * Invalidate the local caches
+ * Zap the caches.
*/
-static void
-nfs_zap_caches(struct inode *inode)
+void 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_invalidate_dircache(inode);
- else
- invalidate_inode_pages(inode);
+ memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+ NFS_CACHEINV(inode);
}
-/*
- * Invalidate, but do not unhash, the inode
- */
static void
nfs_invalidate_inode(struct inode *inode)
{
@@ -461,7 +650,6 @@
make_bad_inode(inode);
inode->i_mode = save_mode;
- nfs_inval(inode);
nfs_zap_caches(inode);
}
@@ -476,6 +664,8 @@
* do this once. (We don't allow inodes to change types.)
*/
if (inode->i_mode == 0) {
+ NFS_FILEID(inode) = fattr->fileid;
+ NFS_FSID(inode) = fattr->fsid;
inode->i_mode = fattr->mode;
if (S_ISREG(inode->i_mode))
inode->i_op = &nfs_file_inode_operations;
@@ -496,26 +686,62 @@
/*
* 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_off_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);
}
+static struct inode *
+nfs_make_new_inode(struct super_block *sb, struct nfs_fattr *fattr)
+{
+ struct inode *inode = get_empty_inode();
+
+ if (!inode)
+ return NULL;
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_flags = 0;
+ inode->i_ino = nfs_fattr_to_ino_t(fattr);
+ nfs_read_inode(inode);
+ nfs_fill_inode(inode, fattr);
+ return inode;
+}
+
/*
- * The following may seem pretty minimal, but the stateless nature
- * of NFS means that we can't do too much more. Previous attempts to use
- * fattr->nlink to determine how well the cached state matches the
- * server suffer from races with stale dentries. You also risk killing
- * off processes by just doing 'mv file newdir' on the server.
- *
- * FIXME: Of course, if 2 exported files have the same fileid (but
- * different fsid which makes it legal) you're still buggered...
- * Trond, August 1999.
+ * In NFSv3 we can have 64bit inode numbers. In order to support
+ * this, and re-exported directories (also seen in NFSv2)
+ * we are forced to allow 2 different inodes to have the same
+ * i_ino.
*/
static int
+nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
+{
+ struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+ if (NFS_FSID(inode) != fattr->fsid)
+ return 0;
+ if (NFS_FILEID(inode) != fattr->fileid)
+ return 0;
+ if (inode->i_mode &&
+ (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+ return 0;
+ if (is_bad_inode(inode))
+ return 0;
+ if (NFS_FLAGS(inode) & NFS_INO_STALE)
+ return 0;
+ return 1;
+}
+
+static int
nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
{
int unhashed;
@@ -529,16 +755,16 @@
is_stale = 1;
/*
- * Free up unused cached dentries to see if it's wise to unhash
- * the inode (which we can do if all the dentries have been unhashed).
+ * If the inode seems stale, free up cached dentries.
*/
unhashed = nfs_free_dentries(inode);
- /* Assume we're holding 1 lock on the inode from 'iget'
+ /* Assume we're holding an i_count
*
* NB: sockets sometimes have volatile file handles
* don't invalidate their inodes even if all dentries are
- * unhashed. */
+ * unhashed.
+ */
if (unhashed && inode->i_count == unhashed + 1
&& !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
is_stale = 1;
@@ -561,12 +787,12 @@
{
struct super_block *sb = dentry->d_sb;
- dprintk("NFS: nfs_fhget(%s/%s fileid=%d)\n",
+ dprintk("NFS: nfs_fhget(%s/%s fileid=%Lu)\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;
+ memcpy(NFS_FH(dentry), (u8*)fhandle, sizeof(*fhandle));
#ifdef CONFIG_NFS_SNAPSHOT
/*
@@ -576,15 +802,9 @@
if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
(dentry->d_name.len == 9 &&
memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
- struct inode *inode = get_empty_inode();
+ struct inode *inode = nfs_make_new_inode(sb, fattr);
if (!inode)
- goto out;
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
- inode->i_flags = 0;
- inode->i_ino = fattr->fileid;
- nfs_read_inode(inode);
- nfs_fill_inode(inode, fattr);
+ goto out;
inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino);
out:
@@ -605,27 +825,39 @@
static struct inode *
__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
{
- struct inode *inode = NULL;
+ struct inode *inode = NULL;
+ unsigned long ino;
- if (!fattr)
+ if ((fattr->valid & NFS_ATTR_FATTR) == 0)
goto out_no_inode;
- while (!inode) {
- inode = iget(sb, fattr->fileid);
- if (!inode)
- goto out_no_inode;
- /* N.B. This should be impossible ... */
- if (inode->i_ino != fattr->fileid)
- goto out_bad_id;
+ ino = nfs_fattr_to_ino_t(fattr);
+
+ while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
+ /*
+ * Check for busy inodes, and attempt to get rid of any
+ * unused local references. If successful, we release the
+ * inode and try again.
+ *
+ * Note that the busy test uses the values in the fattr,
+ * as the inode may have become a different object.
+ * (We can probably handle modes changes here, too.)
+ */
if (!nfs_inode_is_stale(inode,fattr))
break;
- remove_inode_hash(inode);
- nfs_invalidate_inode(inode);
+ dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
+ inode->i_ino, inode->i_count);
+ /* Mark the inode as being stale */
+ NFS_FLAGS(inode) |= NFS_INO_STALE;
+ nfs_zap_caches(inode);
iput(inode);
- inode = NULL;
}
+
+ if (!inode)
+ goto out_no_inode;
+
nfs_fill_inode(inode, fattr);
dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino, inode->i_count);
@@ -634,10 +866,7 @@
return inode;
out_no_inode:
- printk("__nfs_fhget: iget failed\n");
- goto out;
-out_bad_id:
- printk("__nfs_fhget: unexpected inode from iget\n");
+ printk(KERN_NOTICE "__nfs_fhget: iget failed\n");
goto out;
}
@@ -645,9 +874,8 @@
nfs_notify_change(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
- int error;
- struct nfs_sattr sattr;
struct nfs_fattr fattr;
+ int error;
/*
* Make sure the inode is up-to-date.
@@ -655,87 +883,123 @@
error = nfs_revalidate(dentry);
if (error) {
#ifdef NFS_PARANOIA
-printk("nfs_notify_change: revalidate failed, error=%d\n", error);
+ printk(KERN_DEBUG "nfs_notify_change: revalidate failed, error=%d\n", error);
#endif
goto out;
}
- sattr.mode = (u32) -1;
- if (attr->ia_valid & ATTR_MODE)
- sattr.mode = attr->ia_mode;
-
- sattr.uid = (u32) -1;
- if (attr->ia_valid & ATTR_UID)
- sattr.uid = attr->ia_uid;
-
- sattr.gid = (u32) -1;
- if (attr->ia_valid & ATTR_GID)
- sattr.gid = attr->ia_gid;
-
- sattr.size = (u32) -1;
- if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode))
- sattr.size = attr->ia_size;
-
- sattr.mtime.seconds = sattr.mtime.useconds = (u32) -1;
- if (attr->ia_valid & ATTR_MTIME) {
- sattr.mtime.seconds = attr->ia_mtime;
- sattr.mtime.useconds = 0;
- }
-
- sattr.atime.seconds = sattr.atime.useconds = (u32) -1;
- if (attr->ia_valid & ATTR_ATIME) {
- sattr.atime.seconds = attr->ia_atime;
- sattr.atime.useconds = 0;
- }
+ if (!S_ISREG(inode->i_mode))
+ attr->ia_valid &= ~ATTR_SIZE;
error = nfs_wb_all(inode);
- if (error)
+ if (error < 0)
goto out;
- error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
- &sattr, &fattr);
- if (error)
+ /* Now perform the setattr call */
+ error = NFS_CALL(setattr, inode, (dentry, &fattr, attr));
+ if (error || !(fattr.valid & NFS_ATTR_FATTR)) {
+ nfs_zap_caches(inode);
goto out;
+ }
/*
* If we changed the size or mtime, update the inode
* now to avoid invalidating the page cache.
*/
- if (sattr.size != (u32) -1) {
- if (sattr.size != fattr.size)
- printk("nfs_notify_change: sattr=%d, fattr=%d??\n",
- sattr.size, fattr.size);
- inode->i_size = sattr.size;
- inode->i_mtime = fattr.mtime.seconds;
+ 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;
}
- if (sattr.mtime.seconds != (u32) -1)
- inode->i_mtime = fattr.mtime.seconds;
error = nfs_refresh_inode(inode, &fattr);
out:
return error;
}
+int
+nfs_update_atime(struct dentry *dentry)
+{
+ struct iattr attr;
+ struct inode *inode = dentry->d_inode;
+
+ nfs_revalidate(dentry);
+ if (!inode || time_before(inode->i_atime,nfs_time_to_secs(NFS_CACHE_ATIME(inode))))
+ return 0;
+
+ attr.ia_valid = ATTR_ATIME|ATTR_ATIME_SET;
+ attr.ia_atime = inode->i_atime;
+ return nfs_notify_change(dentry, &attr);
+}
+
/*
- * Externally visible revalidation function
+ * Wait for the inode to get unlocked.
+ * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
*/
int
-nfs_revalidate(struct dentry *dentry)
+nfs_wait_on_inode(struct inode *inode, int flag)
{
- return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ 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;
}
/*
- * These are probably going to contain hooks for
- * allocating and releasing RPC credentials for
- * the file. I'll have to think about Tronds patch
- * a bit more..
+ * Externally visible revalidation function
*/
+int
+nfs_revalidate(struct dentry *dentry)
+{
+ return nfs_revalidate_inode(dentry);
+}
+
+static __inline__ struct nfs_file *nfs_file_alloc(void)
+{
+ struct nfs_file *p;
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (p) {
+ memset(p, 0, sizeof(*p));
+ p->magic = NFS_FILE_MAGIC;
+ }
+ return p;
+}
+
+static __inline__ void nfs_file_free(struct nfs_file *p)
+{
+ if (p->magic == NFS_FILE_MAGIC) {
+ p->magic = 0;
+ kfree(p);
+ } else
+ printk(KERN_ERR "NFS: extra file info corrupted!\n");
+}
+
int nfs_open(struct inode *inode, struct file *filp)
{
+ struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth;
+ struct nfs_file *data;
+
+ data = nfs_file_alloc();
+ if (!data)
+ return -ENOMEM;
+ data->cred = rpcauth_lookupcred(auth, 0);
+ filp->private_data = data;
return 0;
}
int nfs_release(struct inode *inode, struct file *filp)
{
+ struct nfs_file *data = NFS_FILE(filp);
+ struct rpc_auth *auth = NFS_CLIENT(inode)->cl_auth;
+ struct rpc_cred *cred;
+
+ cred = nfs_file_cred(filp);
+ if (cred)
+ rpcauth_releasecred(auth, cred);
+ nfs_file_free(data);
return 0;
}
@@ -744,25 +1008,44 @@
* the cached attributes have to be refreshed.
*/
int
-_nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+__nfs_revalidate_inode(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- int status = 0;
struct nfs_fattr fattr;
+ int status = 0;
dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_ino);
- status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
+
+ if (!inode || is_bad_inode(inode))
+ return -ESTALE;
+
+ while (NFS_REVALIDATING(inode)) {
+ status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
+ if (status < 0)
+ return status;
+ if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
+ return 0;
+ }
+ NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
+
+ status = NFS_CALL(getattr, inode, (dentry, &fattr));
if (status) {
int error;
u32 *fh;
+ struct dentry *dir = dentry->d_parent;
struct nfs_fh fhandle;
+ struct nfs_fattr dir_attr;
+
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);
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ inode->i_ino, status);
+ nfs_zap_caches(inode);
+
if (status != -ESTALE)
goto out;
+
/*
* A "stale filehandle" error ... show the current fh
* and find out what the filehandle should be.
@@ -770,8 +1053,9 @@
fh = (u32 *) NFS_FH(dentry);
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_CALL(lookup, dir->d_inode, (dir, &dir_attr,
+ &dentry->d_name, &fhandle, &fattr));
+ nfs_refresh_inode(dir->d_inode, &dir_attr);
if (error) {
dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
goto out;
@@ -787,13 +1071,16 @@
status = nfs_refresh_inode(inode, &fattr);
if (status) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name, inode->i_ino, status);
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ inode->i_ino, status);
goto out;
}
+
dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
out:
+ NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
+ wake_up(&inode->i_wait);
return status;
}
@@ -802,29 +1089,54 @@
* an operation. Here we update the inode to reflect the state
* of the server's inode.
*
- * This is a bit tricky because we have to make sure all dirty pages
- * have been sent off to the server before calling invalidate_inode_pages.
- * To make sure no other process adds more write requests while we try
- * our best to flush them, we make them sleep during the attribute refresh.
+ * If we have reason to believe that any data we cached has become
+ * invalid, we schedule it to be flushed on the next occasion
+ * (i.e. when nfs_revalidate_inode is called).
*
- * A very similar scenario holds for the dir cache.
+ * The reason we don't do it here is because nfs_refresh_inode can
+ * be called outside of the process context, e.g. from nfs_readpage_result,
+ * which is invoked by rpciod.
*/
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);
+ off_t new_size, new_isize;
+ __u64 new_mtime;
+ 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%08lx/0x%lx%08lx), got (0x%lx%08lx/0x%lx%08lx)\n",
+ (unsigned long) (NFS_FSID(inode)>>32),
+ (unsigned long) (NFS_FSID(inode) & 0xFFFFFFFFUL),
+ (unsigned long) (NFS_FILEID(inode)>>32),
+ (unsigned long) (NFS_FILEID(inode) & 0xFFFFFFFFUL),
+ (unsigned long) (fattr->fsid >> 32),
+ (unsigned long) (fattr->fsid & 0xFFFFFFFFUL),
+ (unsigned long) (fattr->fileid >> 32),
+ (unsigned long) (fattr->fileid & 0xFFFFFFFFUL));
goto out;
}
@@ -834,54 +1146,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_off_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_WRITEBACK(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;
@@ -891,22 +1250,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;
}
/*
@@ -926,8 +1279,6 @@
init_nfs_fs(void)
{
#ifdef CONFIG_PROC_FS
- rpc_register_sysctl();
- rpc_proc_init();
rpc_proc_register(&nfs_rpcstat);
#endif
return register_filesystem(&nfs_fs_type);
@@ -955,6 +1306,5 @@
rpc_proc_unregister("nfs");
#endif
unregister_filesystem(&nfs_fs_type);
- nfs_free_dircache();
}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)