summaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c106
-rw-r--r--fs/nfs/file.c5
-rw-r--r--fs/nfs/inode.c2
-rw-r--r--fs/nfs/read.c19
-rw-r--r--fs/nfs/symlink.c159
-rw-r--r--fs/nfs/write.c8
6 files changed, 126 insertions, 173 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 149077fae..788307cc2 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -81,10 +81,8 @@ struct inode_operations nfs_dir_inode_operations = {
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL, /* smap */
nfs_revalidate, /* revalidate */
};
@@ -302,77 +300,80 @@ out_error:
* page-in of the RPC reply, nowhere else, this simplies
* things substantially.
*/
-static struct page *try_to_get_dirent_page(struct file *file, __u32 cookie, int refetch_ok)
+
+static int nfs_dir_filler(struct dentry *dentry, struct page *page)
{
struct nfs_readdirargs rd_args;
struct nfs_readdirres rd_res;
- struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
- struct page *page, **hash, *page_cache;
- long offset;
+ long offset = page->index;
__u32 *cookiep;
+ int err;
- page = NULL;
- page_cache = page_cache_alloc();
- if (!page_cache)
- goto out;
-
- if ((offset = nfs_readdir_offset(inode, cookie)) < 0) {
- if (!refetch_ok ||
- (offset = refetch_to_readdir_cookie(file, inode)) < 0) {
- page_cache_free(page_cache);
- goto out;
- }
- }
+ kmap(page);
+ err = -EIO;
cookiep = find_cookie(inode, offset);
- if (!cookiep) {
- /* Gross fatal error. */
- page_cache_free(page_cache);
- goto out;
- }
-
- hash = page_hash(&inode->i_data, offset);
-repeat:
- page = __find_lock_page(&inode->i_data, offset, hash);
- if (page) {
- page_cache_free(page_cache);
- goto unlock_out;
- }
-
- page = page_cache;
- if (add_to_page_cache_unique(page, &inode->i_data, offset, hash)) {
- page_cache_release(page);
- goto repeat;
- }
+ if (!cookiep)
+ goto fail;
rd_args.fh = NFS_FH(dentry);
- rd_res.buffer = (char *)page_address(page_cache);
+ rd_res.buffer = (char *)page_address(page);
rd_res.bufsiz = PAGE_CACHE_SIZE;
rd_res.cookie = *cookiep;
do {
rd_args.buffer = rd_res.buffer;
rd_args.bufsiz = rd_res.bufsiz;
rd_args.cookie = rd_res.cookie;
- if (rpc_call(NFS_CLIENT(inode),
- NFSPROC_READDIR, &rd_args, &rd_res, 0) < 0)
- goto error;
+ err = rpc_call(NFS_CLIENT(inode),
+ NFSPROC_READDIR, &rd_args, &rd_res, 0);
+ if (err < 0)
+ goto fail;
} while(rd_res.bufsiz > 0);
+ err = -EIO;
if (rd_res.bufsiz < 0)
NFS_DIREOF(inode) = rd_res.cookie;
else if (create_cookie(rd_res.cookie, offset, inode))
- goto error;
+ goto fail;
SetPageUptodate(page);
-unlock_out:
+ kunmap(page);
UnlockPage(page);
-out:
+ return 0;
+fail:
+ SetPageError(page);
+ kunmap(page);
+ UnlockPage(page);
+ return err;
+}
+
+static struct page *try_to_get_dirent_page(struct file *file, __u32 cookie, int refetch_ok)
+{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct page *page;
+ long offset;
+
+ if ((offset = nfs_readdir_offset(inode, cookie)) < 0) {
+ if (!refetch_ok ||
+ (offset = refetch_to_readdir_cookie(file, inode)) < 0) {
+ goto fail;
+ }
+ }
+
+ page = read_cache_page(&inode->i_data, offset,
+ (filler_t *)nfs_dir_filler, dentry);
+ if (IS_ERR(page))
+ goto fail;
+ if (!Page_Uptodate(page))
+ goto fail2;
return page;
-error:
- SetPageError(page);
- goto unlock_out;
+fail2:
+ page_cache_release(page);
+fail:
+ return NULL;
}
/* Seek up to dirent assosciated with the passed in cookie,
@@ -417,7 +418,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
- struct page *page, **hash;
+ struct page *page;
long offset;
int res;
@@ -431,15 +432,16 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if ((offset = nfs_readdir_offset(inode, filp->f_pos)) < 0)
goto no_dirent_page;
- hash = page_hash(&inode->i_data, offset);
- page = __find_get_page(&inode->i_data, offset, hash);
+ page = find_get_page(&inode->i_data, offset);
if (!page)
goto no_dirent_page;
if (!Page_Uptodate(page))
goto dirent_read_error;
success:
+ kmap(page);
filp->f_pos = nfs_do_filldir((__u32 *) page_address(page),
filp->f_pos, dirent, filldir);
+ kunmap(page);
page_cache_release(page);
return 0;
@@ -681,6 +683,7 @@ struct dentry_operations nfs_dentry_operations = {
NULL /* d_iput */
};
+#if 0 /* dead code */
#ifdef NFS_PARANOIA
/*
* Display all dentries holding the specified inode.
@@ -702,7 +705,8 @@ static void show_dentry(struct list_head * dlist)
unhashed);
}
}
-#endif
+#endif /* NFS_PARANOIA */
+#endif /* 0 */
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
{
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index ab9b22683..00279fc6a 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -74,10 +74,8 @@ struct inode_operations nfs_file_inode_operations = {
NULL, /* get_block */
nfs_readpage, /* readpage */
nfs_writepage, /* writepage */
- NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL, /* smap */
nfs_revalidate, /* revalidate */
};
@@ -171,7 +169,8 @@ static int nfs_write_one_page(struct file *file, struct page *page, unsigned lon
{
long status;
- bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
+ bytes -= copy_from_user((u8*)kmap(page) + offset, buf, bytes);
+ kunmap(page);
status = -EFAULT;
if (bytes) {
lock_kernel();
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 00b310e06..abf7f16f9 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -958,8 +958,6 @@ init_nfs_fs(void)
return err;
#ifdef CONFIG_PROC_FS
- rpc_register_sysctl();
- rpc_proc_init();
rpc_proc_register(&nfs_rpcstat);
#endif
return register_filesystem(&nfs_fs_type);
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 6b2e3d73a..37a8715cf 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -71,7 +71,7 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
{
struct nfs_rreq rqst;
unsigned long offset = page->index << PAGE_CACHE_SHIFT;
- char *buffer = (char *) page_address(page);
+ char *buffer;
int rsize = NFS_SERVER(inode)->rsize;
int result, refresh = 0;
int count = PAGE_SIZE;
@@ -79,6 +79,12 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
dprintk("NFS: nfs_readpage_sync(%p)\n", page);
+ /*
+ * This works now because the socket layer never tries to DMA
+ * into this buffer directly.
+ */
+ buffer = (char *) kmap(page);
+
do {
if (count < rsize)
rsize = count;
@@ -116,6 +122,7 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
result = 0;
io_error:
+ kunmap(page);
UnlockPage(page);
/* Note: we don't refresh if the call returned error */
if (refresh && result >= 0)
@@ -152,6 +159,7 @@ nfs_readpage_result(struct rpc_task *task)
fail++;
dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
}
+ kunmap(page);
UnlockPage(page);
free_page(address);
@@ -163,7 +171,7 @@ static inline int
nfs_readpage_async(struct dentry *dentry, struct inode *inode,
struct page *page)
{
- unsigned long address = page_address(page);
+ unsigned long address;
struct nfs_rreq *req;
int result = -1, flags;
@@ -177,6 +185,7 @@ nfs_readpage_async(struct dentry *dentry, struct inode *inode,
if (!req)
goto out_defer;
+ address = kmap(page);
/* Initialize request */
/* N.B. Will the dentry remain valid for life of request? */
nfs_readreq_setup(req, NFS_FH(dentry), page->index << PAGE_CACHE_SHIFT,
@@ -200,6 +209,7 @@ out_defer:
goto out;
out_free:
dprintk("NFS: failed to enqueue async READ request.\n");
+ kunmap(page);
kfree(req);
goto out;
}
@@ -217,9 +227,8 @@ out_free:
* - The server is congested.
*/
int
-nfs_readpage(struct file *file, struct page *page)
+nfs_readpage(struct dentry *dentry, struct page *page)
{
- struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
int error;
@@ -254,7 +263,7 @@ nfs_readpage(struct file *file, struct page *page)
out_error:
UnlockPage(page);
out_free:
- free_page(page_address(page));
+ __free_page(page);
out:
unlock_kernel();
return error;
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,
+};
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index abc048dc2..9f58b4171 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -99,7 +99,7 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
dentry->d_parent->d_name.name, dentry->d_name.name,
count, page->index, offset);
- buffer = (u8 *) page_address(page) + offset;
+ buffer = (u8 *) kmap(page) + offset;
offset += page->index << PAGE_CACHE_SHIFT;
do {
@@ -132,6 +132,7 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
} while (count);
io_error:
+ kunmap(page);
/* Note: we don't refresh if the call failed (fattr invalid) */
if (refresh && result >= 0) {
/* See comments in nfs_wback_result */
@@ -314,6 +315,7 @@ create_write_request(struct file * file, struct page *page, unsigned int offset,
wreq->wb_bytes = bytes;
wreq->wb_count = 2; /* One for the IO, one for us */
+ kmap(page);
append_write_request(&NFS_WRITEBACK(inode), wreq);
if (nr_write_requests++ > NFS_WRITEBACK_MAX*3/4)
@@ -412,9 +414,8 @@ wait_on_write_request(struct nfs_wreq *req)
* (for now), and we currently do this synchronously only.
*/
int
-nfs_writepage(struct file * file, struct page *page)
+nfs_writepage(struct dentry * dentry, struct page *page)
{
- struct dentry *dentry = file->f_dentry;
return nfs_writepage_sync(dentry, dentry->d_inode, page, 0, PAGE_SIZE);
}
@@ -687,6 +688,7 @@ nfs_wback_result(struct rpc_task *task)
if (WB_INVALIDATE(req))
ClearPageUptodate(page);
+ kunmap(page);
__free_page(page);
remove_write_request(&NFS_WRITEBACK(inode), req);
nr_write_requests--;