diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-01-27 01:05:20 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-01-27 01:05:20 +0000 |
commit | 546db14ee74118296f425f3b91634fb767d67290 (patch) | |
tree | 22b613a3da8d4bf663eec5e155af01b87fdf9094 /fs/nfs | |
parent | 1e25e41c4f5474e14452094492dbc169b800e4c8 (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.c | 144 | ||||
-rw-r--r-- | fs/nfs/inode.c | 226 | ||||
-rw-r--r-- | fs/nfs/nfs2xdr.c | 36 | ||||
-rw-r--r-- | fs/nfs/proc.c | 8 | ||||
-rw-r--r-- | fs/nfs/symlink.c | 7 |
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; |