diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/dir.c | 106 | ||||
-rw-r--r-- | fs/nfs/file.c | 5 | ||||
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/read.c | 19 | ||||
-rw-r--r-- | fs/nfs/symlink.c | 159 | ||||
-rw-r--r-- | fs/nfs/write.c | 8 |
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--; |