* [PATCH] Support for cached lookups via readdirplus [4/6]
@ 2002-07-28 15:26 Trond Myklebust
0 siblings, 0 replies; only message in thread
From: Trond Myklebust @ 2002-07-28 15:26 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Linux Kernel, NFS maillist
Add support for positive lookups using the READDIRPLUS cached
information. Both new lookups and lookup revalidation is supported.
Use READDIRPLUS instead of READDIR on NFSv3 directories with lengths
shorter than 8*PAGE_SIZE.
Note that inode attribute information is only updated if it is seen to
be more recent than any existing cached information.
Cheers,
Trond
diff -u --recursive --new-file linux-2.5.29-rdplus3/fs/nfs/dir.c linux-2.5.29-rdplus4/fs/nfs/dir.c
--- linux-2.5.29-rdplus3/fs/nfs/dir.c Sat Jul 27 18:58:30 2002
+++ linux-2.5.29-rdplus4/fs/nfs/dir.c Sat Jul 27 19:15:50 2002
@@ -37,6 +37,8 @@
static int nfs_readdir(struct file *, void *, filldir_t);
static struct dentry *nfs_lookup(struct inode *, struct dentry *);
+static int nfs_cached_lookup(struct inode *, struct dentry *,
+ struct nfs_fh *, struct nfs_fattr *);
static int nfs_create(struct inode *, struct dentry *, int);
static int nfs_mkdir(struct inode *, struct dentry *, int);
static int nfs_rmdir(struct inode *, struct dentry *);
@@ -504,6 +506,15 @@
goto out_valid;
}
+ error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);
+ if (!error) {
+ if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
+ goto out_bad;
+ if (nfs_lookup_verify_inode(inode))
+ goto out_bad;
+ goto out_valid_renew;
+ }
+
if (NFS_STALE(inode))
goto out_bad;
@@ -515,6 +526,7 @@
if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
goto out_bad;
+ out_valid_renew:
nfs_renew_times(dentry);
out_valid:
unlock_kernel();
@@ -578,7 +590,7 @@
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
{
- struct inode *inode;
+ struct inode *inode = NULL;
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
@@ -594,8 +606,19 @@
dentry->d_op = &nfs_dentry_operations;
lock_kernel();
+ error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);
+ if (!error) {
+ error = -EACCES;
+ inode = nfs_fhget(dentry, &fhandle, &fattr);
+ if (inode) {
+ d_add(dentry, inode);
+ nfs_renew_times(dentry);
+ error = 0;
+ }
+ goto out;
+ }
+
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
- inode = NULL;
if (error == -ENOENT)
goto no_entry;
if (!error) {
@@ -613,6 +636,79 @@
return ERR_PTR(error);
}
+static inline
+int find_dirent_name(nfs_readdir_descriptor_t *desc, struct page *page, struct dentry *dentry)
+{
+ struct nfs_entry *entry = desc->entry;
+ int status;
+
+ while((status = dir_decode(desc)) == 0) {
+ if (entry->len != dentry->d_name.len)
+ continue;
+ if (memcmp(entry->name, dentry->d_name.name, entry->len))
+ continue;
+ if (!(entry->fattr->valid & NFS_ATTR_FATTR))
+ continue;
+ break;
+ }
+ return status;
+}
+
+/*
+ * Use the cached Readdirplus results in order to avoid a LOOKUP call
+ * whenever we believe that the parent directory has not changed.
+ *
+ * We assume that any file creation/rename changes the directory mtime.
+ * As this results in a page cache invalidation whenever it occurs,
+ * we don't require any other tests for cache coherency.
+ */
+static
+int nfs_cached_lookup(struct inode *dir, struct dentry *dentry,
+ struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+ nfs_readdir_descriptor_t desc;
+ struct nfs_server *server;
+ struct nfs_entry entry;
+ struct page *page;
+ unsigned long timestamp = NFS_MTIME_UPDATE(dir);
+ int res;
+
+ if (!NFS_USE_READDIRPLUS(dir))
+ return -ENOENT;
+ server = NFS_SERVER(dir);
+ if (server->flags & NFS_MOUNT_NOAC)
+ return -ENOENT;
+ nfs_revalidate_inode(server, dir);
+
+ entry.fh = fh;
+ entry.fattr = fattr;
+
+ desc.decode = NFS_PROTO(dir)->decode_dirent;
+ desc.entry = &entry;
+ desc.page_index = 0;
+ desc.plus = 1;
+
+ for(;(page = find_get_page(&dir->i_data, desc.page_index)); desc.page_index++) {
+
+ res = -EIO;
+ if (PageUptodate(page)) {
+ desc.ptr = kmap(page);
+ res = find_dirent_name(&desc, page, dentry);
+ kunmap(page);
+ }
+ page_cache_release(page);
+
+ if (res == 0)
+ goto out_found;
+ if (res != -EAGAIN)
+ break;
+ }
+ return -ENOENT;
+ out_found:
+ fattr->timestamp = timestamp;
+ return 0;
+}
+
/*
* Code common to create, mkdir, and mknod.
*/
diff -u --recursive --new-file linux-2.5.29-rdplus3/fs/nfs/inode.c linux-2.5.29-rdplus4/fs/nfs/inode.c
--- linux-2.5.29-rdplus3/fs/nfs/inode.c Sat Jul 27 18:53:18 2002
+++ linux-2.5.29-rdplus4/fs/nfs/inode.c Sat Jul 27 19:03:43 2002
@@ -644,6 +644,9 @@
return __nfs_fhget(sb, fhandle, fattr);
}
+/* Don't use READDIRPLUS on directories that we believe are too large */
+#define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
+
/*
* Look up the inode by super block and fattr->fileid.
*/
@@ -692,6 +695,9 @@
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &nfs_dir_inode_operations;
inode->i_fop = &nfs_dir_operations;
+ if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
+ && fattr->size <= NFS_LIMIT_READDIRPLUS)
+ NFS_FLAGS(inode) |= NFS_INO_ADVISE_RDPLUS;
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
else
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2002-07-28 15:24 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-07-28 15:26 [PATCH] Support for cached lookups via readdirplus [4/6] Trond Myklebust
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®