From patchwork Tue Aug 17 17:27:24 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: jvrao X-Patchwork-Id: 119986 X-Patchwork-Delegate: ericvh@gmail.com Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o7HHK2vl010555 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 17 Aug 2010 17:20:40 GMT Received: from localhost ([127.0.0.1] helo=sfs-ml-3.v29.ch3.sourceforge.com) by sfs-ml-3.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1OlPpN-00049N-AD; Tue, 17 Aug 2010 17:19:57 +0000 Received: from sog-mx-1.v43.ch3.sourceforge.com ([172.29.43.191] helo=mx.sourceforge.net) by sfs-ml-3.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1OlPpL-00049G-RU for v9fs-developer@lists.sourceforge.net; Tue, 17 Aug 2010 17:19:55 +0000 X-ACL-Warn: Received: from e38.co.us.ibm.com ([32.97.110.159]) by sog-mx-1.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.69) id 1OlPpL-0006BO-0C for v9fs-developer@lists.sourceforge.net; Tue, 17 Aug 2010 17:19:55 +0000 Received: from d03relay03.boulder.ibm.com (d03relay03.boulder.ibm.com [9.17.195.228]) by e38.co.us.ibm.com (8.14.4/8.13.1) with ESMTP id o7HHCTRT027458 for ; Tue, 17 Aug 2010 11:12:29 -0600 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d03relay03.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o7HHJdIs071392 for ; Tue, 17 Aug 2010 11:19:39 -0600 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id o7HHJbN2002366 for ; Tue, 17 Aug 2010 11:19:37 -0600 Received: from localhost.localdomain (elm9m80.beaverton.ibm.com [9.47.81.80]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id o7HHJWRx001997; Tue, 17 Aug 2010 11:19:36 -0600 From: "Venkateswararao Jujjuri (JV)" To: v9fs-developer@lists.sourceforge.net Date: Tue, 17 Aug 2010 10:27:24 -0700 Message-Id: <1282066045-3945-5-git-send-email-jvrao@linux.vnet.ibm.com> X-Mailer: git-send-email 1.6.0.6 In-Reply-To: <1282066045-3945-1-git-send-email-jvrao@linux.vnet.ibm.com> References: <1282066045-3945-1-git-send-email-jvrao@linux.vnet.ibm.com> X-Spam-Score: -0.0 (/) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain X-Headers-End: 1OlPpL-0006BO-0C Cc: linux-fsdevel@vger.kernel.org, Badari Pulavarty Subject: [V9fs-developer] [PATCH 4/5] [net/9p] Achieve zero copy on write path. X-BeenThere: v9fs-developer@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: v9fs-developer-bounces@lists.sourceforge.net X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 17 Aug 2010 17:20:40 +0000 (UTC) diff --git a/net/9p/client.c b/net/9p/client.c index 5487896..7ce58fb 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "protocol.h" /* @@ -521,6 +522,25 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) } /** + * p9_release_req_pages - Release pages after the transaction. + * @req - Request buffer. + * + */ +static void +p9_release_req_pages(struct p9_req_t *req) +{ + int i = 0; + while (req->tc->pdata[i] && req->tc->pdata_mapped_pages--) { + put_page(req->tc->pdata[i]); + req->tc->pdata[i] = NULL; + i++; + } + req->tc->pdata_write_len = 0; + req->tc->pdata_read_len = 0; +} + + +/** * p9_client_rpc - issue a request and wait for a response * @c: client session * @type: type of request @@ -575,6 +595,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) err = c->trans_mod->request(c, req); if (err < 0) { c->status = Disconnected; + if (req->tc->pdata_write_len || req->tc->pdata_read_len) + p9_release_req_pages(req); goto reterr; } @@ -583,6 +605,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) req->status >= REQ_STATUS_RCVD); P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d\n", req->wq, tag, err); + if (req->tc->pdata_write_len || req->tc->pdata_read_len) + p9_release_req_pages(req); if (req->status == REQ_STATUS_ERROR) { P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); @@ -1331,9 +1355,15 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, if (data) req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, rsize, data); - else + else { + if (clnt->trans_mod->capability && + clnt->trans_mod->capability(P9_CAP_GET_MAX_SG_PAGES)) { + + rsize = count; + } req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, rsize, udata); + } if (IS_ERR(req)) { err = PTR_ERR(req); goto error; diff --git a/net/9p/protocol.c b/net/9p/protocol.c index ca63aff..97f313d 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -31,9 +31,12 @@ #include #include #include +#include #include #include #include "protocol.h" +#include +#include #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -110,6 +113,51 @@ static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) return size - len; } +static int +pdu_fill_pages(struct p9_fcall *pdu, const char __user *udata, size_t size, + int rw, int max_sg_pages) +{ + int nr_pages; + uint32_t first_page_bytes = 0; + int pdata_len; + + nr_pages = size >> PAGE_SHIFT; + pdu->pdata_off = (size_t)udata & (PAGE_SIZE-1); + if (pdu->pdata_off) + first_page_bytes = PAGE_SIZE - pdu->pdata_off; + if (size - (first_page_bytes + (nr_pages << PAGE_SHIFT))) { + /* trailing partial page */ + nr_pages++; + } + if (first_page_bytes) { + /* leading partial page */ + nr_pages++; + } + nr_pages = min(max_sg_pages, nr_pages); + pdu->pdata = (struct page **)(pdu->sdata + pdu->size); + pdu->pdata_write_len = 0; + pdu->pdata_read_len = 0; + pdu->pdata_mapped_pages = get_user_pages_fast((unsigned long)udata, + nr_pages, rw, pdu->pdata); + if (pdu->pdata_mapped_pages < 0) { + printk(KERN_WARNING "get_user_pages_fast failed:%d udata:%p" + "nr_pages:%d\n", pdu->pdata_mapped_pages, + udata, nr_pages); + pdu->pdata_mapped_pages = 0; + return -1; + } + if (pdu->pdata_off) { + pdata_len = first_page_bytes; + pdata_len += min((size - pdata_len), + ((size_t)pdu->pdata_mapped_pages - 1) << + PAGE_SHIFT); + } else { + pdata_len = min(size, (size_t)pdu->pdata_mapped_pages << + PAGE_SHIFT); + } + return pdata_len; +} + static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) { size_t len = MIN(pdu->capacity - pdu->size, size); @@ -119,15 +167,31 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) } static size_t -pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) +pdu_write_u(struct p9_fcall *pdu, struct p9_client *c, const char __user *udata, + size_t size) { - size_t len = MIN(pdu->capacity - pdu->size, size); - int err = copy_from_user(&pdu->sdata[pdu->size], udata, len); - if (err) - printk(KERN_WARNING "pdu_write_u returning: %d\n", err); + size_t len; + int err; + int max_req_sg_pages = 0; - pdu->size += len; - return size - len; + if (c->trans_mod->capability && + (udata && !segment_eq(get_fs(), KERNEL_DS))) { + max_req_sg_pages = + c->trans_mod->capability(P9_CAP_GET_MAX_SG_PAGES); + } + if (max_req_sg_pages) { + len = pdu_fill_pages(pdu, udata, size, 0, max_req_sg_pages); + if (len < 0) + return len; + pdu->pdata_write_len = len; + } else { + len = MIN(pdu->capacity - pdu->size, size); + err = copy_from_user(&pdu->sdata[pdu->size], udata, len); + if (err) + printk(KERN_WARNING "pdu_write_u returning: %d\n", err); + pdu->size += len; + } + return len; } /* @@ -467,7 +531,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, struct p9_client *c, const char *fmt, const char __user *udata = va_arg(ap, const void __user *); errcode = p9pdu_writef(pdu, c, "d", count); - if (!errcode && pdu_write_u(pdu, udata, count)) + if (!errcode && + pdu_write_u(pdu, c, udata, count) < 0) errcode = -EFAULT; } break;