patch-2.2.18 linux/fs/nfs/symlink.c
Next file: linux/fs/nfs/unlink.c
Previous file: linux/fs/nfs/read.c
Back to the patch index
Back to the overall index
- Lines: 160
- Date:
Fri Sep 15 22:10:44 2000
- Orig file:
v2.2.17/fs/nfs/symlink.c
- Orig date:
Fri Apr 21 12:46:44 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/fs/nfs/symlink.c linux/fs/nfs/symlink.c
@@ -5,13 +5,20 @@
*
* Optimization changes Copyright (C) 1994 Florian La Roche
*
+ * Jun 7 1999, cache symlink lookups in the page cache. -DaveM
+ *
* nfs symlink handling code
*/
+#define NFS_NEED_XDR_TYPES
#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs.h>
+#include <linux/pagemap.h>
#include <linux/stat.h>
+#include <asm/pgtable.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/string.h>
@@ -37,70 +44,85 @@
NULL, /* rename */
nfs_readlink, /* readlink */
nfs_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
+/* Symlink caching in the page cache is even more simplistic
+ * and straight-forward than readdir caching.
+ */
+static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
+{
+ struct inode *inode = dentry->d_inode;
+ struct nfs_fattr fattr;
+ void * buffer = (void *)page_address(page);
+ unsigned int error;
+
+ /* We place the length at the beginning of the page,
+ * in client byte order, followed by the string.
+ */
+ error = NFS_CALL(readlink, inode, (dentry, &fattr, buffer,
+ PAGE_CACHE_SIZE-sizeof(u32)-4));
+ nfs_refresh_inode(inode, &fattr);
+ if (error < 0)
+ goto error;
+ flush_dcache_page(page_address(page)); /* Is this correct? */
+ set_bit(PG_uptodate, &page->flags);
+ nfs_unlock_page(page);
+ return 0;
+error:
+ set_bit(PG_error, &page->flags);
+ nfs_unlock_page(page);
+ return -EIO;
+}
+
static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
- int error;
- unsigned int len;
- char *res;
- void *mem;
-
- dfprintk(VFS, "nfs: readlink(%s/%s)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
-
- error = nfs_proc_readlink(NFS_DSERVER(dentry), NFS_FH(dentry),
- &mem, &res, &len, NFS_MAXPATHLEN);
- if (! error) {
- if (len > buflen)
- len = buflen;
- copy_to_user(buffer, res, len);
- error = len;
- kfree(mem);
- }
- return error;
+ struct inode *inode = dentry->d_inode;
+ struct page *page;
+ u32 *p, len;
+
+ /* Caller revalidated the directory inode already. */
+ page = read_cache_page(inode, 0,
+ (filler_t *)nfs_symlink_filler, dentry);
+ if (IS_ERR(page))
+ goto read_failed;
+
+ p = (u32 *) page_address(page);
+ len = *p++;
+ if (len > buflen)
+ len = buflen;
+ copy_to_user(buffer, p, len);
+ page_cache_release(page);
+ return len;
+read_failed:
+ return PTR_ERR(page);
}
static struct dentry *
-nfs_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
+nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
{
- int error;
- unsigned int len;
- char *res;
- void *mem;
- char *path;
struct dentry *result;
-
- dfprintk(VFS, "nfs: follow_link(%s/%s)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
-
- error = nfs_proc_readlink(NFS_DSERVER(dentry), NFS_FH(dentry),
- &mem, &res, &len, NFS_MAXPATHLEN);
- result = ERR_PTR(error);
- if (error)
- goto out_dput;
-
- result = ERR_PTR(-ENOMEM);
- path = kmalloc(len + 1, GFP_KERNEL);
- if (!path)
- goto out_mem;
- memcpy(path, res, len);
- path[len] = 0;
- kfree(mem);
-
- result = lookup_dentry(path, base, follow);
- kfree(path);
-out:
+ struct inode *inode = dentry->d_inode;
+ struct page *page;
+ u32 *p;
+
+ /* Caller revalidated the directory inode already. */
+ page = read_cache_page(inode, 0,
+ (filler_t *)nfs_symlink_filler, dentry);
+ if (IS_ERR(page))
+ goto read_failed;
+
+ p = (u32 *) page_address(page);
+ result = lookup_dentry((char *) (p + 1), base, follow);
+ page_cache_release(page);
return result;
-
-out_mem:
- kfree(mem);
-out_dput:
- dput(base);
- goto out;
+read_failed:
+ return (struct dentry *)page;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)