All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] smbfs async readpage
@ 2002-08-07  0:15 Urban Widmark
  2002-08-07  4:57 ` Andrew Morton
  0 siblings, 1 reply; 5+ messages in thread
From: Urban Widmark @ 2002-08-07  0:15 UTC (permalink / raw)
  To: linux-fsdevel


This patch implements async readpage for smbfs. It seems to generate
readahead judging from the network traffic and profile_readahead output
from 2.4.

In case someone cares to read it, the changes to file.c are inspired from
what nfs does in read.c.


A simple test using 'time md5sum /mnt/smb/sp6i386.exe' to an old and slow
test-server over 100Mbps eth gives

sync:   2.309u 0.632s 0:15.55 18.8%
async:  2.275u 0.460s 0:12.41 21.9%

Which is about 20% faster wall clock. A plain cp of the same file has a
smaller gain (lost the numbers, 13 vs 12 seconds or so).

/Urban


diff -urN -X exclude linux-2.5.30-orig/fs/smbfs/file.c linux-2.5.30-smbfs/fs/smbfs/file.c
--- linux-2.5.30-orig/fs/smbfs/file.c	Tue Aug  6 20:34:22 2002
+++ linux-2.5.30-smbfs/fs/smbfs/file.c	Wed Aug  7 00:47:37 2002
@@ -25,6 +25,7 @@
 
 #include "smb_debug.h"
 #include "proto.h"
+#include "request.h"
 
 static int
 smb_fsync(struct file *file, struct dentry * dentry, int datasync)
@@ -96,6 +97,58 @@
 	return result;
 }
 
+static void
+smb_readpage_result(struct smb_request *req)
+{
+	struct page *page = req->rq_page;
+	int result = req->rq_errno;
+
+	VERBOSE("result: %d  page: %p\n", result, page);
+
+	/* FIXME: anyone not using smb_request_ok should probably be using
+	   somthing like smb_valid_packet and smb_verify. */
+
+	if (result >= 0) {
+		result = WVAL(req->rq_header, smb_vwv5);
+		VERBOSE("count: %d\n", result);
+		if (result < PAGE_CACHE_SIZE) {
+			char *buffer = req->rq_pagemap;
+			memset(buffer + result, 0, PAGE_CACHE_SIZE - result);
+		}
+		SetPageUptodate(page);
+	} else {
+		SetPageError(page);
+	}
+
+	flush_dcache_page(page);
+	kunmap(page);
+	unlock_page(page);
+	page_cache_release(page);
+	smb_rput(req);
+}
+
+static int
+smb_readpage_async(struct dentry *dentry, struct page *page)
+{
+	struct smb_sb_info *server = server_from_dentry(dentry);
+	int result;
+	struct smb_request *req;
+
+	VERBOSE("page: %p\n", page);
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 0)))
+		goto out;
+
+	req->rq_page = page;		/* One page per request to begin with */
+	page_cache_get(page);
+	req->rq_completion = smb_readpage_result;
+	result = server->ops->reada(dentry->d_inode, req);
+
+	/* FIXME: nfs checks the number of read requests for this inode here */
+out:
+	return result;
+}
+
 /*
  * We are called with the page locked and we unlock it when done.
  */
@@ -104,10 +157,20 @@
 {
 	int		error;
 	struct dentry  *dentry = file->f_dentry;
+	struct smb_sb_info *server = server_from_dentry(dentry);
+
+	VERBOSE("\n");
+
+	if (server->ops->reada &&
+	    !PageError(page) && smb_get_rsize(server) > PAGE_CACHE_SIZE) {
+		error = smb_readpage_async(dentry, page);
+		goto out;
+	}
 
 	page_cache_get(page);
 	error = smb_readpage_sync(dentry, page);
 	page_cache_release(page);
+out:
 	return error;
 }
 
diff -urN -X exclude linux-2.5.30-orig/fs/smbfs/proc.c linux-2.5.30-smbfs/fs/smbfs/proc.c
--- linux-2.5.30-orig/fs/smbfs/proc.c	Tue Aug  6 20:34:10 2002
+++ linux-2.5.30-smbfs/fs/smbfs/proc.c	Tue Aug  6 22:31:39 2002
@@ -1252,7 +1252,7 @@
 	req->rq_iov[0].iov_base = req->rq_buffer;
 	req->rq_iov[0].iov_len  = 3;
 
-	req->rq_iov[1].iov_base = req->rq_page;
+	req->rq_iov[1].iov_base = req->rq_pagemap;
 	req->rq_iov[1].iov_len  = req->rq_rsize;
 	req->rq_iovlen = 2;
 
@@ -1280,7 +1280,7 @@
 	DSET(buf, smb_vwv2, offset);
 	WSET(buf, smb_vwv4, 0);
 
-	req->rq_page = data;
+	req->rq_pagemap = data;		/* FIXME: should work on the page */
 	req->rq_rsize = count;
 	req->rq_callback = smb_proc_read_data;
 	req->rq_buffer = rbuf;
@@ -1375,7 +1375,7 @@
 	req->rq_iov[0].iov_base = req->rq_buffer;
 	req->rq_iov[0].iov_len  = data_off;
 
-	req->rq_iov[1].iov_base = req->rq_page;
+	req->rq_iov[1].iov_base = req->rq_pagemap;
 	req->rq_iov[1].iov_len  = req->rq_rsize;
 	req->rq_iovlen = 2;
 
@@ -1408,7 +1408,7 @@
 	DSET(buf, smb_vwv10, (u32)(offset >> 32));      /* high 32 bits */
 	WSET(buf, smb_vwv11, 0);
 
-	req->rq_page = data;
+	req->rq_pagemap = data;
 	req->rq_rsize = count;
 	req->rq_callback = smb_proc_readX_data;
 	req->rq_buffer = pad;
@@ -1429,6 +1429,39 @@
 }
 
 static int
+smb_proc_readaX(struct inode *inode, struct smb_request *req)
+{
+	struct page *page = req->rq_page;
+	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+	unsigned int count = PAGE_SIZE;
+	unsigned char *buf;
+	static char pad[SMB_READX_MAX_PAD];
+
+	smb_setup_header(req, SMBreadX, 12, 0);
+	buf = req->rq_header;
+	WSET(buf, smb_vwv0, 0x00ff);
+	WSET(buf, smb_vwv1, 0);
+	WSET(buf, smb_vwv2, SMB_I(inode)->fileid);
+	DSET(buf, smb_vwv3, (u32)offset);               /* low 32 bits */
+	WSET(buf, smb_vwv5, count);
+	WSET(buf, smb_vwv6, 0);
+	DSET(buf, smb_vwv7, 0);
+	WSET(buf, smb_vwv9, 0);
+	DSET(buf, smb_vwv10, (u32)(offset >> 32));      /* high 32 bits */
+	WSET(buf, smb_vwv11, 0);
+
+	req->rq_pagemap = kmap(page);
+	req->rq_rsize = count;
+	req->rq_callback = smb_proc_readX_data;
+	req->rq_buffer = pad;
+	req->rq_bufsize = SMB_READX_MAX_PAD;
+	req->rq_flags |= SMB_REQ_STATIC | SMB_REQ_NORETRY | SMB_REQ_NORECEIVER;
+	req->rq_resp_wct = 12;
+	req->rq_resp_bcc = -1;
+	return smb_add_request(req);
+}
+
+static int
 smb_proc_writeX(struct inode *inode, loff_t offset, int count, const char *data)
 {
 	struct smb_sb_info *server = server_from_inode(inode);
@@ -2948,6 +2981,7 @@
 static struct smb_ops smb_ops_winNT =
 {
 	read:		smb_proc_readX,
+	reada:		smb_proc_readaX,
 	write:		smb_proc_writeX,
 	readdir:	smb_proc_readdir_long,
 	getattr:	smb_proc_getattr_trans2_all,
diff -urN -X exclude linux-2.5.30-orig/fs/smbfs/request.c linux-2.5.30-smbfs/fs/smbfs/request.c
--- linux-2.5.30-orig/fs/smbfs/request.c	Tue Aug  6 20:34:10 2002
+++ linux-2.5.30-smbfs/fs/smbfs/request.c	Wed Aug  7 00:14:01 2002
@@ -332,6 +332,9 @@
 
 	smbiod_wake_up();
 
+	if (req->rq_flags & SMB_REQ_NORECEIVER)
+		return 0;
+
 	/* FIXME: replace with a timeout-able wake_event_interruptible */
 	timeleft = interruptible_sleep_on_timeout(&req->rq_wait, 30*HZ);
 	if (!timeleft || signal_pending(current)) {
@@ -346,7 +349,7 @@
 		}
 		smb_unlock_server(server);
 	}
-		
+
 	if (!timeleft) {
 		PARANOIA("request [%p, mid=%d] timed out!\n",
 			 req, req->rq_mid);
@@ -391,8 +394,14 @@
 	if (!(req->rq_flags & SMB_REQ_TRANSMITTED))
 		goto out;
 
-	list_del_init(&req->rq_queue);
-	list_add_tail(&req->rq_queue, &server->recvq);
+	if (req->rq_flags & SMB_REQ_NOREPLY) {
+		if (!(req->rq_flags & SMB_REQ_NORECEIVER))
+			wake_up_interruptible(&req->rq_wait);
+		smb_rput(req);
+	} else {
+		list_del_init(&req->rq_queue);
+		list_add_tail(&req->rq_queue, &server->recvq);
+	}
 	result = 1;
 out:
 	return result;
@@ -789,8 +798,11 @@
 	if (!result) {
 		list_del_init(&req->rq_queue);
 		req->rq_flags |= SMB_REQ_RECEIVED;
+		if (req->rq_completion)
+			req->rq_completion(req);
+		if (!(req->rq_flags & SMB_REQ_NORECEIVER))
+			wake_up_interruptible(&req->rq_wait);
 		smb_rput(req);
-		wake_up_interruptible(&req->rq_wait);
 	}
 	return 0;
 }
diff -urN -X exclude linux-2.5.30-orig/fs/smbfs/request.h linux-2.5.30-smbfs/fs/smbfs/request.h
--- linux-2.5.30-orig/fs/smbfs/request.h	Tue Aug  6 20:34:10 2002
+++ linux-2.5.30-smbfs/fs/smbfs/request.h	Tue Aug  6 20:55:42 2002
@@ -19,8 +19,11 @@
 	int rq_bufsize;
 	unsigned char *rq_buffer;
 
+	/* FIXME: union to save space. This is never done with a trans2
+	   request. */
 	/* FIXME: this is not good enough for merging IO requests. */
-	unsigned char *rq_page;
+	struct page *rq_page;
+	unsigned char *rq_pagemap;
 	int rq_rsize;
 
 	int rq_resp_wct;
@@ -37,6 +40,7 @@
 
 	int (*rq_setup_read) (struct smb_request *);
 	void (*rq_callback) (struct smb_request *);
+	void (*rq_completion) (struct smb_request *);
 
 	/* ------ trans2 stuff ------ */
 
@@ -61,9 +65,8 @@
 
 #define SMB_REQ_STATIC		0x0001	/* rq_buffer is static */
 #define SMB_REQ_NORETRY		0x0002	/* request is invalid after retry */
+#define SMB_REQ_NOREPLY		0x0004	/* we don't want the reply (if any) */
+#define SMB_REQ_NORECEIVER	0x0008	/* caller doesn't wait for response */
 
 #define SMB_REQ_TRANSMITTED	0x4000	/* all data has been sent */
 #define SMB_REQ_RECEIVED	0x8000	/* reply received, smbiod is done */
-
-#define xSMB_REQ_NOREPLY	0x0004	/* we don't want the reply (if any) */
-#define xSMB_REQ_NORECEIVER	0x0008	/* caller doesn't wait for response */
diff -urN -X exclude linux-2.5.30-orig/fs/smbfs/smbiod.c linux-2.5.30-smbfs/fs/smbfs/smbiod.c
--- linux-2.5.30-orig/fs/smbfs/smbiod.c	Tue Aug  6 20:34:22 2002
+++ linux-2.5.30-smbfs/fs/smbfs/smbiod.c	Tue Aug  6 21:01:18 2002
@@ -110,15 +110,17 @@
 		req = list_entry(tmp, struct smb_request, rq_queue);
 		req->rq_errno = -EIO;
 		list_del_init(&req->rq_queue);
+		if (!(req->rq_flags & SMB_REQ_NORECEIVER))
+			wake_up_interruptible(&req->rq_wait);
 		smb_rput(req);
-		wake_up_interruptible(&req->rq_wait);
 	}
 	list_for_each_safe(tmp, n, &server->recvq) {
 		req = list_entry(tmp, struct smb_request, rq_queue);
 		req->rq_errno = -EIO;
 		list_del_init(&req->rq_queue);
+		if (!(req->rq_flags & SMB_REQ_NORECEIVER))
+			wake_up_interruptible(&req->rq_wait);
 		smb_rput(req);
-		wake_up_interruptible(&req->rq_wait);
 	}
 }
 
@@ -154,8 +156,9 @@
 			VERBOSE("aborting request %p on xmitq\n", req);
 			req->rq_errno = -EIO;
 			list_del_init(&req->rq_queue);
+			if (!(req->rq_flags & SMB_REQ_NORECEIVER))
+				wake_up_interruptible(&req->rq_wait);
 			smb_rput(req);
-			wake_up_interruptible(&req->rq_wait);
 		}
 	}
 
@@ -180,8 +183,9 @@
 		/* req->rq_rcls = ???; */ /* FIXME: set smb error code too? */
 		req->rq_errno = -EIO;
 		list_del_init(&req->rq_queue);
+		if (!(req->rq_flags & SMB_REQ_NORECEIVER))
+			wake_up_interruptible(&req->rq_wait);
 		smb_rput(req);
-		wake_up_interruptible(&req->rq_wait);
 	}
 
 	smb_close_socket(server);
diff -urN -X exclude linux-2.5.30-orig/include/linux/smb_fs.h linux-2.5.30-smbfs/include/linux/smb_fs.h
--- linux-2.5.30-orig/include/linux/smb_fs.h	Tue Aug  6 20:34:18 2002
+++ linux-2.5.30-smbfs/include/linux/smb_fs.h	Tue Aug  6 22:02:19 2002
@@ -167,10 +167,13 @@
 	int				filled, valid, idx;
 };
 
+struct smb_request;
+
 #define SMB_OPS_NUM_STATIC	5
 struct smb_ops {
 	int (*read)(struct inode *inode, loff_t offset, int count,
 		    char *data);
+	int (*reada) (struct inode *inode, struct smb_request *req);
 	int (*write)(struct inode *inode, loff_t offset, int count, const
 		     char *data);
 	int (*readdir)(struct file *filp, void *dirent, filldir_t filldir,


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2002-08-07 22:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-08-07  0:15 [PATCH] smbfs async readpage Urban Widmark
2002-08-07  4:57 ` Andrew Morton
2002-08-07 13:04   ` Urban Widmark
2002-08-07 17:34     ` Andrew Morton
2002-08-07 22:05       ` Urban Widmark

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.