patch-1.3.82 linux/fs/nfs/bio.c
Next file: linux/fs/nfs/cache.c
Previous file: linux/fs/nfs/README
Back to the patch index
Back to the overall index
- Lines: 165
- Date:
Sat Mar 30 23:54:01 1996
- Orig file:
v1.3.81/linux/fs/nfs/bio.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.81/linux/fs/nfs/bio.c linux/fs/nfs/bio.c
@@ -0,0 +1,164 @@
+/*
+ * linux/fs/nfs/bio.c
+ *
+ * Block I/O for NFS
+ *
+ * Partial copy of Linus' read cache modifications to fs/nfs/file.c
+ * modified for async RPC by okir@monad.swb.de
+ *
+ * We do an ugly hack here in order to return proper error codes to the
+ * user program when a read request failed. This is a huge problem because
+ * generic_file_read only checks the return value of inode->i_op->readpage()
+ * which is usually 0 for async RPC. To overcome this obstacle, we set
+ * the error bit of the page to 1 when an error occurs, and make nfs_readpage
+ * transmit requests synchronously when encountering this.
+ *
+ * Another possible solution to this problem may be to have a cache of recent
+ * RPC call results indexed by page pointer, or even a result code field
+ * in struct page.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfsiod.h>
+#include <linux/malloc.h>
+#include <linux/pagemap.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#undef DEBUG_BIO
+#ifdef DEBUG_BIO
+#define dprintk(args...) printk(## args)
+#else
+#define dprintk(args...) /* nothing */
+#endif
+
+static inline int
+do_read_nfs_sync(struct inode * inode, struct page * page)
+{
+ struct nfs_fattr fattr;
+ int result, refresh = 0;
+ int count = PAGE_SIZE;
+ int rsize = NFS_SERVER(inode)->rsize;
+ char *buf = (char *) page_address(page);
+ unsigned long pos = page->offset;
+
+ dprintk("NFS: do_read_nfs_sync(%p)\n", page);
+
+ page->locked = 1;
+ page->error = 0;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+ result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
+ pos, rsize, buf, &fattr);
+ dprintk("nfs_proc_read(%s, (%x,%lx), %ld, %d, %p) = %d\n",
+ NFS_SERVER(inode)->hostname,
+ inode->i_dev, inode->i_ino,
+ pos, rsize, buf, result);
+ if (result < 0)
+ break;
+ refresh = 1;
+ count -= result;
+ pos += result;
+ buf += result;
+ if (result < rsize)
+ break;
+ } while (count);
+
+ memset(buf, 0, count);
+ if (refresh) {
+ nfs_refresh_inode(inode, &fattr);
+ result = 0;
+ page->uptodate = 1;
+ }
+ page->locked = 0;
+ wake_up(&page->wait);
+ return result;
+}
+
+/*
+ * This is the callback from nfsiod telling us whether a reply was
+ * received or some error occurred (timeout or socket shutdown).
+ */
+static void
+nfs_read_cb(int result, struct nfsiod_req *req)
+{
+ struct page *page = (struct page *) req->rq_cdata;
+ static int succ = 0, fail = 0;
+
+ dprintk("BIO: received callback for page %p, result %d\n",
+ page, result);
+
+ if (result >= 0
+ && (result = nfs_proc_read_reply(&req->rq_rpcreq)) >= 0) {
+ succ++;
+ page->uptodate = 1;
+ } else {
+ fail++;
+ printk("BIO: %d successful reads, %d failures\n", succ, fail);
+ page->error = 1;
+ }
+ page->locked = 0;
+ wake_up(&page->wait);
+ free_page(page_address(page));
+}
+
+static inline int
+do_read_nfs_async(struct inode *inode, struct page *page)
+{
+ struct nfsiod_req *req;
+ int result = -1; /* totally arbitrary */
+
+ dprintk("NFS: do_read_nfs_async(%p)\n", page);
+
+ page->locked = 1;
+ page->error = 0;
+
+ if (!(req = nfsiod_reserve(NFS_SERVER(inode), nfs_read_cb)))
+ goto done;
+ result = nfs_proc_read_request(&req->rq_rpcreq,
+ NFS_SERVER(inode), NFS_FH(inode),
+ page->offset, PAGE_SIZE,
+ (__u32 *) page_address(page));
+ if (result >= 0) {
+ req->rq_cdata = page;
+ page->count++;
+ result = nfsiod_enqueue(req);
+ if (result >= 0)
+ dprintk("NFS: enqueued async READ request.\n");
+ }
+ if (result < 0) {
+ dprintk("NFS: deferring async READ request.\n");
+ nfsiod_release(req);
+ page->locked = 0;
+ wake_up(&page->wait);
+ }
+
+done:
+ return result < 0? result : 0;
+}
+
+int
+nfs_readpage(struct inode *inode, struct page *page)
+{
+ unsigned long address;
+ int error = -1;
+
+ dprintk("NFS: nfs_readpage %08lx\n", page_address(page));
+ address = page_address(page);
+ page->count++;
+ if (!page->error && NFS_SERVER(inode)->rsize >= PAGE_SIZE)
+ error = do_read_nfs_async(inode, page);
+ if (error < 0) /* couldn't enqueue */
+ error = do_read_nfs_sync(inode, page);
+ free_page(address);
+ return error;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this