diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/nfs/symlink.c | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/nfs/symlink.c')
-rw-r--r-- | fs/nfs/symlink.c | 159 |
1 files changed, 50 insertions, 109 deletions
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 1b1705ef2..ab0ebf145 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -22,145 +22,86 @@ #include <linux/malloc.h> #include <linux/string.h> -#include <asm/uaccess.h> - -static int nfs_readlink(struct dentry *, char *, int); -static struct dentry *nfs_follow_link(struct dentry *, struct dentry *, unsigned int); - -/* - * symlinks can't do much... - */ -struct inode_operations nfs_symlink_inode_operations = { - NULL, /* no file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - nfs_readlink, /* readlink */ - nfs_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* flushpage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL /* revalidate */ -}; - /* Symlink caching in the page cache is even more simplistic * and straight-forward than readdir caching. */ -static struct page *try_to_get_symlink_page(struct dentry *dentry, struct inode *inode) +static int nfs_symlink_filler(struct dentry *dentry, struct page *page) { struct nfs_readlinkargs rl_args; - struct page *page, **hash, *page_cache; - - page = NULL; - page_cache = page_cache_alloc(); - if (!page_cache) - goto out; - - hash = page_hash(&inode->i_data, 0); -repeat: - page = __find_lock_page(&inode->i_data, 0, hash); - if (page) { - page_cache_free(page_cache); - goto unlock_out; - } - - page = page_cache; - if (add_to_page_cache_unique(page, &inode->i_data, 0, hash)) { - page_cache_release(page); - goto repeat; - } - + kmap(page); /* We place the length at the beginning of the page, * in host byte order, followed by the string. The * XDR response verification will NULL terminate it. */ rl_args.fh = NFS_FH(dentry); - rl_args.buffer = (const void *)page_address(page_cache); - if (rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, + rl_args.buffer = (const void *)page_address(page); + if (rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK, &rl_args, NULL, 0) < 0) goto error; SetPageUptodate(page); -unlock_out: + kunmap(page); UnlockPage(page); -out: - return page; + return 0; error: SetPageError(page); - goto unlock_out; + kunmap(page); + UnlockPage(page); + return -EIO; } -static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen) +static char *nfs_getlink(struct dentry *dentry, struct page **ppage) { struct inode *inode = dentry->d_inode; struct page *page; - u32 *p, len; + u32 *p; /* Caller revalidated the directory inode already. */ - page = find_get_page(&inode->i_data, 0); - if (!page) - goto no_readlink_page; + page = read_cache_page(&inode->i_data, 0, + (filler_t *)nfs_symlink_filler, dentry); + if (IS_ERR(page)) + goto read_failed; if (!Page_Uptodate(page)) - goto readlink_read_error; -success: - p = (u32 *) page_address(page); - len = *p++; - if (len > buflen) - len = buflen; - copy_to_user(buffer, p, len); + goto getlink_read_error; + *ppage = page; + p = (u32 *) kmap(page); + return (char*)(p+1); + +getlink_read_error: page_cache_release(page); - return len; + return ERR_PTR(-EIO); +read_failed: + return (char*)page; +} -no_readlink_page: - page = try_to_get_symlink_page(dentry, inode); - if (!page) - goto no_page; - if (Page_Uptodate(page)) - goto success; -readlink_read_error: - page_cache_release(page); -no_page: - return -EIO; +static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct page *page = NULL; + int res = vfs_readlink(dentry,buffer,buflen,nfs_getlink(dentry,&page)); + if (page) { + kunmap(page); + page_cache_release(page); + } + return res; } static struct dentry * nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) { - struct dentry *result; - struct inode *inode = dentry->d_inode; - struct page *page; - u32 *p; - - /* Caller revalidated the directory inode already. */ - page = find_get_page(&inode->i_data, 0); - if (!page) - goto no_followlink_page; - if (!Page_Uptodate(page)) - goto followlink_read_error; -success: - p = (u32 *) page_address(page); - result = lookup_dentry((char *) (p + 1), base, follow); - page_cache_release(page); - return result; - -no_followlink_page: - page = try_to_get_symlink_page(dentry, inode); - if (!page) - goto no_page; - if (Page_Uptodate(page)) - goto success; -followlink_read_error: - page_cache_release(page); -no_page: - return ERR_PTR(-EIO); + struct page *page = NULL; + struct dentry *res = vfs_follow_link(dentry, base, follow, + nfs_getlink(dentry, &page)); + if (page) { + kunmap(page); + page_cache_release(page); + } + return res; } + +/* + * symlinks can't do much... + */ +struct inode_operations nfs_symlink_inode_operations = { + readlink: nfs_readlink, + follow_link: nfs_follow_link, +}; |