summaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-01-27 01:05:20 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-01-27 01:05:20 +0000
commit546db14ee74118296f425f3b91634fb767d67290 (patch)
tree22b613a3da8d4bf663eec5e155af01b87fdf9094 /fs/nfs
parent1e25e41c4f5474e14452094492dbc169b800e4c8 (diff)
Merge with Linux 2.3.23. The new bootmem stuff has broken various
platforms. At this time I've only verified that IP22 support compiles and IP27 actually works.
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c144
-rw-r--r--fs/nfs/inode.c226
-rw-r--r--fs/nfs/nfs2xdr.c36
-rw-r--r--fs/nfs/proc.c8
-rw-r--r--fs/nfs/symlink.c7
5 files changed, 219 insertions, 202 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 6b52b2d54..b7ec225ac 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -308,8 +308,7 @@ static struct page *try_to_get_dirent_page(struct file *file, __u32 cookie, int
struct nfs_readdirres rd_res;
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
- struct page *page, **hash;
- unsigned long page_cache;
+ struct page *page, **hash, *page_cache;
long offset;
__u32 *cookiep;
@@ -341,14 +340,14 @@ repeat:
goto unlock_out;
}
- page = page_cache_entry(page_cache);
+ page = page_cache;
if (add_to_page_cache_unique(page, inode, offset, hash)) {
page_cache_release(page);
goto repeat;
}
rd_args.fh = NFS_FH(dentry);
- rd_res.buffer = (char *)page_cache;
+ rd_res.buffer = (char *)page_address(page_cache);
rd_res.bufsiz = PAGE_CACHE_SIZE;
rd_res.cookie = *cookiep;
do {
@@ -533,13 +532,15 @@ static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags)
* If mtime is close to present time, we revalidate
* more often.
*/
+#define NFS_REVALIDATE_NEGATIVE (1 * HZ)
static inline int nfs_neg_need_reval(struct dentry *dentry)
{
- unsigned long timeout = 30 * HZ;
- long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+ struct inode *dir = dentry->d_parent->d_inode;
+ unsigned long timeout = NFS_ATTRTIMEO(dir);
+ long diff = CURRENT_TIME - dir->i_mtime;
- if (diff < 5*60)
- timeout = 1 * HZ;
+ if (diff < 5*60 && timeout > NFS_REVALIDATE_NEGATIVE)
+ timeout = NFS_REVALIDATE_NEGATIVE;
return time_after(jiffies, dentry->d_time + timeout);
}
@@ -581,12 +582,14 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
goto out_bad;
}
- if (IS_ROOT(dentry))
- goto out_valid;
-
if (!nfs_dentry_force_reval(dentry, flags))
goto out_valid;
+ if (IS_ROOT(dentry)) {
+ __nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+ goto out_valid_renew;
+ }
+
/*
* Do a new lookup and check the dentry attributes.
*/
@@ -596,32 +599,29 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
goto out_bad;
/* Inode number matches? */
- if (fattr.fileid != inode->i_ino)
+ if (NFS_FSID(inode) != fattr.fsid ||
+ NFS_FILEID(inode) != fattr.fileid)
goto out_bad;
/* Filehandle matches? */
- if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
- if (!list_empty(&dentry->d_subdirs))
- shrink_dcache_parent(dentry);
- if (dentry->d_count < 2)
- goto out_bad;
- }
+ if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
+ goto out_bad;
/* Ok, remeber that we successfully checked it.. */
- nfs_renew_times(dentry);
nfs_refresh_inode(inode, &fattr);
+ out_valid_renew:
+ nfs_renew_times(dentry);
out_valid:
return 1;
out_bad:
+ d_drop(dentry);
+ if (!list_empty(&dentry->d_subdirs))
+ shrink_dcache_parent(dentry);
/* Purge readdir caches. */
if (dentry->d_parent->d_inode) {
- invalidate_inode_pages(dentry->d_parent->d_inode);
- nfs_flush_dircache(dentry->d_parent->d_inode);
- }
- if (inode && S_ISDIR(inode->i_mode)) {
- invalidate_inode_pages(inode);
- nfs_flush_dircache(inode);
+ nfs_zap_caches(dentry->d_parent->d_inode);
+ NFS_CACHEINV(dentry->d_parent->d_inode);
}
return 0;
}
@@ -649,21 +649,6 @@ static void nfs_dentry_delete(struct dentry *dentry)
dentry->d_name.name, error);
}
-#ifdef NFS_PARANOIA
- /*
- * Sanity check: if the dentry has been unhashed and the
- * inode still has users, we could have problems ...
- */
- if (list_empty(&dentry->d_hash) && dentry->d_inode) {
- struct inode *inode = dentry->d_inode;
- int max_count = (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink);
- if (inode->i_count > max_count) {
-printk("nfs_dentry_delete: %s/%s: ino=%ld, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
- }
- }
-#endif
}
static kmem_cache_t *nfs_fh_cachep;
@@ -750,14 +735,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
error = -EACCES;
inode = nfs_fhget(dentry, &fhandle, &fattr);
if (inode) {
-#ifdef NFS_PARANOIA
-if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) {
-printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
-show_dentry(&inode->i_dentry);
-}
-#endif
no_entry:
d_add(dentry, inode);
nfs_renew_times(dentry);
@@ -779,14 +756,6 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
inode = nfs_fhget(dentry, fhandle, fattr);
if (inode) {
-#ifdef NFS_PARANOIA
-if (inode->i_count > (S_ISDIR(inode->i_mode) ? 1 : inode->i_nlink)) {
-printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_ino, inode->i_count, inode->i_nlink);
-show_dentry(&inode->i_dentry);
-}
-#endif
d_instantiate(dentry, inode);
nfs_renew_times(dentry);
error = 0;
@@ -803,16 +772,15 @@ show_dentry(&inode->i_dentry);
static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
- struct nfs_sattr sattr;
+ struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- sattr.mode = mode;
- sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
- sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ attr.ia_mode = mode;
+ attr.ia_valid = ATTR_MODE;
/*
* Invalidate the dir cache before the operation to avoid a race.
@@ -820,7 +788,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
+ dentry->d_name.name, &attr, &fhandle, &fattr);
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error)
@@ -834,23 +802,25 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
int error;
- struct nfs_sattr sattr;
+ struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- sattr.mode = mode;
- sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
- if (S_ISCHR(mode) || S_ISBLK(mode))
- sattr.size = rdev; /* get out your barf bag */
- sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ attr.ia_mode = mode;
+ attr.ia_valid = ATTR_MODE;
+ /* FIXME: move this to a special nfs_proc_mknod() */
+ if (S_ISCHR(mode) || S_ISBLK(mode)) {
+ attr.ia_size = rdev; /* get out your barf bag */
+ attr.ia_valid |= ATTR_SIZE;
+ }
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
+ dentry->d_name.name, &attr, &fhandle, &fattr);
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error)
@@ -864,16 +834,15 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
- struct nfs_sattr sattr;
+ struct iattr attr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
- sattr.mode = mode | S_IFDIR;
- sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
- sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ attr.ia_valid = ATTR_MODE;
+ attr.ia_mode = mode | S_IFDIR;
/*
* Always drop the dentry, we can't always depend on
@@ -885,7 +854,7 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
+ dentry->d_name.name, &attr, &fhandle, &fattr);
if (!error)
dir->i_nlink++;
return error;
@@ -898,13 +867,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
-#ifdef NFS_PARANOIA
-if (dentry->d_inode->i_count > 1)
-printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-dentry->d_inode->i_count, dentry->d_inode->i_nlink);
-#endif
-
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
@@ -1082,12 +1044,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
#endif
goto out;
}
-#ifdef NFS_PARANOIA
-if (inode && inode->i_count > inode->i_nlink)
-printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-inode->i_count, inode->i_nlink);
-#endif
/*
* Unhash the dentry while we remove the file ...
*/
@@ -1141,7 +1097,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
static int
nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
- struct nfs_sattr sattr;
+ struct iattr attr;
int error;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
@@ -1160,9 +1116,8 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
* Fill in the sattr for the call.
* Note: SunOS 4.1.2 crashes if the mode isn't initialized!
*/
- sattr.mode = S_IFLNK | S_IRWXUGO;
- sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
- sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ attr.ia_valid = ATTR_MODE;
+ attr.ia_mode = S_IFLNK | S_IRWXUGO;
/*
* Drop the dentry in advance to force a new lookup.
@@ -1173,7 +1128,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
invalidate_inode_pages(dir);
nfs_flush_dircache(dir);
error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
- dentry->d_name.name, symname, &sattr);
+ dentry->d_name.name, symname, &attr);
if (!error) {
nfs_renew_times(dentry->d_parent);
} else if (error == -EEXIST) {
@@ -1332,13 +1287,6 @@ do_rename:
* To prevent any new references to the target during the rename,
* we unhash the dentry and free the inode in advance.
*/
-#ifdef NFS_PARANOIA
-if (new_inode &&
- new_inode->i_count > (S_ISDIR(new_inode->i_mode) ? 1 : new_inode->i_nlink))
-printk("nfs_rename: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_inode->i_count, new_inode->i_nlink);
-#endif
if (!list_empty(&new_dentry->d_hash)) {
d_drop(new_dentry);
rehash = update;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5421cebf9..ab1e51485 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -37,7 +37,7 @@
#define NFS_PARANOIA 1
static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
-static void nfs_zap_caches(struct inode *);
+void nfs_zap_caches(struct inode *);
static void nfs_invalidate_inode(struct inode *);
static void nfs_read_inode(struct inode *);
@@ -78,6 +78,8 @@ nfs_read_inode(struct inode * inode)
inode->i_mode = 0;
inode->i_rdev = 0;
inode->i_op = NULL;
+ NFS_FILEID(inode) = 0;
+ NFS_FSID(inode) = 0;
NFS_CACHEINV(inode);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
}
@@ -415,13 +417,15 @@ restart:
dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_count, !list_empty(&dentry->d_hash));
+ if (!list_empty(&dentry->d_subdirs))
+ shrink_dcache_parent(dentry);
if (!dentry->d_count) {
dget(dentry);
d_drop(dentry);
dput(dentry);
goto restart;
}
- if (!list_empty(&dentry->d_hash))
+ if (list_empty(&dentry->d_hash))
unhashed++;
}
return unhashed;
@@ -430,7 +434,7 @@ restart:
/*
* Invalidate the local caches
*/
-static void
+void
nfs_zap_caches(struct inode *inode)
{
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
@@ -466,6 +470,8 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
* 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;
@@ -487,6 +493,54 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
}
/*
+ * 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;
+ return 1;
+}
+
+static int
+nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
+{
+ int unhashed;
+ int is_stale = 0;
+
+ if (inode->i_mode &&
+ (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+ is_stale = 1;
+
+ if (is_bad_inode(inode))
+ is_stale = 1;
+
+ /*
+ * If the inode seems stale, free up cached dentries.
+ */
+ unhashed = nfs_free_dentries(inode);
+
+ /* 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.
+ */
+ if (unhashed && inode->i_count == unhashed + 1
+ && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
+ is_stale = 1;
+
+ return is_stale;
+}
+
+/*
* This is our own version of iget that looks up inodes by file handle
* instead of inode number. We use this technique instead of using
* the vfs read_inode function because there is no way to pass the
@@ -545,54 +599,40 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
static struct inode *
__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
{
- struct inode *inode;
- int max_count, stale_inode, unhashed = 0;
+ struct inode *inode = NULL;
+ unsigned long ino;
-retry:
- inode = iget(sb, fattr->fileid);
- if (!inode)
+ if (!fattr->nlink) {
+ printk("NFS: Buggy server - nlink == 0!\n");
goto out_no_inode;
- /* N.B. This should be impossible ... */
- if (inode->i_ino != fattr->fileid)
- goto out_bad_id;
+ }
- /*
- * 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.)
- */
- stale_inode = inode->i_mode &&
- ((fattr->mode ^ inode->i_mode) & S_IFMT);
- stale_inode |= inode->i_count && inode->i_count == unhashed;
- max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
- if (stale_inode || inode->i_count > max_count + unhashed) {
- dprintk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
- inode->i_ino, inode->i_count, inode->i_nlink);
- unhashed = nfs_free_dentries(inode);
- if (stale_inode || inode->i_count > max_count + unhashed) {
- printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
- inode->i_ino, inode->i_count);
- if (!list_empty(&inode->i_dentry)) {
- struct dentry *dentry;
- dentry = list_entry(inode->i_dentry.next,
- struct dentry, d_alias);
- printk("__nfs_fhget: killing %s/%s filehandle\n",
- dentry->d_parent->d_name.name,
- dentry->d_name.name);
- memset(dentry->d_fsdata, 0,
- sizeof(struct nfs_fh));
- }
- remove_inode_hash(inode);
- nfs_invalidate_inode(inode);
- unhashed = 0;
- }
+ ino = fattr->fileid;
+
+ 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;
+
+ dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
+ inode->i_ino, inode->i_count);
+ nfs_zap_caches(inode);
+ remove_inode_hash(inode);
iput(inode);
- goto retry;
}
+
+ 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);
@@ -603,18 +643,14 @@ out:
out_no_inode:
printk("__nfs_fhget: iget failed\n");
goto out;
-out_bad_id:
- printk("__nfs_fhget: unexpected inode from iget\n");
- goto out;
}
int
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.
@@ -627,54 +663,29 @@ printk("nfs_notify_change: revalidate failed, error=%d\n", error);
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)
goto out;
error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
- &sattr, &fattr);
+ &fattr, attr);
if (error)
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;
+ if (attr->ia_valid & ATTR_SIZE) {
+ if (attr->ia_size != fattr.size)
+ printk("nfs_notify_change: attr=%ld, fattr=%d??\n",
+ attr->ia_size, fattr.size);
+ inode->i_size = attr->ia_size;
inode->i_mtime = fattr.mtime.seconds;
}
- if (sattr.mtime.seconds != (u32) -1)
+ if (attr->ia_valid & ATTR_MTIME)
inode->i_mtime = fattr.mtime.seconds;
error = nfs_refresh_inode(inode, &fattr);
out:
@@ -682,6 +693,34 @@ out:
}
/*
+ * Wait for the inode to get unlocked.
+ * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
+ */
+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);
+ return error;
+}
+
+/*
* Externally visible revalidation function
*/
int
@@ -711,7 +750,7 @@ int nfs_release(struct inode *inode, struct file *filp)
* the cached attributes have to be refreshed.
*/
int
-_nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+__nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
int status = 0;
@@ -720,6 +759,19 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
inode->i_ino);
+
+ 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_proc_getattr(server, NFS_FH(dentry), &fattr);
if (status) {
int error;
@@ -759,6 +811,8 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
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;
}
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 1bc7d3d37..a7e53e6db 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -118,19 +118,35 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
return p;
}
+
+#define SATTR(p, attr, flag, field) \
+ *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
static inline u32 *
-xdr_encode_sattr(u32 *p, struct nfs_sattr *sattr)
+xdr_encode_sattr(u32 *p, struct iattr *attr)
{
- *p++ = htonl(sattr->mode);
- *p++ = htonl(sattr->uid);
- *p++ = htonl(sattr->gid);
- *p++ = htonl(sattr->size);
- *p++ = htonl(sattr->atime.seconds);
- *p++ = htonl(sattr->atime.useconds);
- *p++ = htonl(sattr->mtime.seconds);
- *p++ = htonl(sattr->mtime.useconds);
- return p;
+ SATTR(p, attr, ATTR_MODE, ia_mode);
+ SATTR(p, attr, ATTR_UID, ia_uid);
+ SATTR(p, attr, ATTR_GID, ia_gid);
+ SATTR(p, attr, ATTR_SIZE, ia_size);
+
+ if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
+ *p++ = htonl(attr->ia_atime);
+ *p++ = 0;
+ } else {
+ *p++ = ~(u32) 0;
+ *p++ = ~(u32) 0;
+ }
+
+ if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
+ *p++ = htonl(attr->ia_mtime);
+ *p++ = 0;
+ } else {
+ *p++ = ~(u32) 0;
+ *p++ = ~(u32) 0;
+ }
+ return p;
}
+#undef SATTR
/*
* NFS encode functions
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 3b48b326a..bb55ce6d6 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -65,7 +65,7 @@ nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
int
nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_sattr *sattr, struct nfs_fattr *fattr)
+ struct nfs_fattr *fattr, struct iattr *sattr)
{
struct nfs_sattrargs arg = { fhandle, sattr };
int status;
@@ -123,7 +123,7 @@ nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, int swap,
int
nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct nfs_sattr *sattr,
+ const char *name, struct iattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_createargs arg = { dir, name, sattr };
@@ -178,7 +178,7 @@ nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
int
nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
const char *name, const char *path,
- struct nfs_sattr *sattr)
+ struct iattr *sattr)
{
struct nfs_symlinkargs arg = { dir, name, path, sattr };
int status;
@@ -191,7 +191,7 @@ nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
int
nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, struct nfs_sattr *sattr,
+ const char *name, struct iattr *sattr,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
struct nfs_createargs arg = { dir, name, sattr };
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 6cd892740..6b0d0f05b 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -59,8 +59,7 @@ struct inode_operations nfs_symlink_inode_operations = {
static struct page *try_to_get_symlink_page(struct dentry *dentry, struct inode *inode)
{
struct nfs_readlinkargs rl_args;
- struct page *page, **hash;
- unsigned long page_cache;
+ struct page *page, **hash, *page_cache;
page = NULL;
page_cache = page_cache_alloc();
@@ -75,7 +74,7 @@ repeat:
goto unlock_out;
}
- page = page_cache_entry(page_cache);
+ page = page_cache;
if (add_to_page_cache_unique(page, inode, 0, hash)) {
page_cache_release(page);
goto repeat;
@@ -86,7 +85,7 @@ repeat:
* XDR response verification will NULL terminate it.
*/
rl_args.fh = NFS_FH(dentry);
- rl_args.buffer = (const void *)page_cache;
+ rl_args.buffer = (const void *)page_address(page_cache);
if (rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
&rl_args, NULL, 0) < 0)
goto error;