[SSI] openssi/kernel/cluster/ssi/cfs proc.c, 1.25, 1.26 read.c, 1.24, 1.25 write.c, 1.45, 1.46

Roger Tsang <[email protected]> Mon, 25 Oct 2010 05:53:41 +0000
Newsgroups gmane.linux.cluster.ssic.cvs
Message-ID <[email protected]>
Update of /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/cfs
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv12379/cluster/ssi/cfs

Modified Files:
      Tag: OPENSSI-FC
	proc.c read.c write.c 
Log Message:
CFS_PROTO->write/read() avoid use of kmap pools. Remove contention when kmap pool limit is reached as the number of CFS threads grows.
- Pre-allocate pagevec during RPC setup only if the pages are not already physically mapped.
- Reduce default CFS_SERVER rsize/wsize from 1MB to 64KB.

 cluster/ssi/cfs/proc.c            |   54 ++++++++++++
 cluster/ssi/cfs/read.c            |   79 +++++++++++++++++-
 cluster/ssi/cfs/write.c           |  129 ++++++++++++++++++++++--------
 include/cluster/ssi/cfs/cfs_fs.h  |    6 +
 include/cluster/ssi/cfs/cfs_xdr.h |    4 
 5 files changed, 231 insertions(+), 41 deletions(-)


Index: proc.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/cfs/proc.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- proc.c	13 Mar 2010 10:02:41 -0000	1.25
+++ proc.c	25 Oct 2010 05:53:39 -0000	1.26
@@ -57,7 +57,7 @@
 #define CFS_ASYNC(_data) (_data->flags & RPC_TASK_ASYNC)
 
 /* _data argument is pointer to struct cfs_read_data or cfs_write_data */
-#define MAP_CFS_PAGEVEC(_data, _vec, _vlen) do { \
+#define KMAP_CFS_PAGEVEC(_data, _vec, _vlen) do { \
 	int i, len = (_data)->count; \
  \
 	(_vlen) = (_vlen) ? : \
@@ -88,7 +88,7 @@
 	BUG_ON(i != (_vlen)); \
 } while (0)
 
-#define UNMAP_CFS_PAGEVEC(_data, _vec, _vlen) do { \
+#define KUNMAP_CFS_PAGEVEC(_data, _vec, _vlen) do { \
 	int i; \
  \
 	for (i = 0; i < (_vlen); i++) \
@@ -96,6 +96,56 @@
 	kfree(_vec); \
 } while (0)
 
+#ifdef CFS_ASYNC_LOCAL_SYNC
+#define __MAP_CFS_PAGEVEC(_data, _vec, _vlen) do { \
+	int i, len = (_data)->count; \
+ \
+	(_vlen) = (_vlen) ? : \
+			((_data)->pgbase + (_data)->count + PAGE_SIZE - 1) \
+			>> PAGE_SHIFT; \
+ \
+	(_vec) = kmalloc((_vlen) * sizeof(struct kvec), GFP_NOFS|__GFP_NOFAIL); \
+ \
+	(_vec)[0].iov_base = page_address((_data)->pagevec[0]) + (_data)->pgbase; \
+	(_vec)[0].iov_len = min_t(typeof((_vec)[0].iov_len), \
+					len, PAGE_SIZE - (_data)->pgbase); \
+	len -= (PAGE_SIZE - (_data)->pgbase); \
+ \
+	i = 1; \
+	while (len > 0) { \
+		(_vec)[i].iov_base = page_address((_data)->pagevec[i]); \
+		(_vec)[i].iov_len = \
+			min_t(typeof((_vec)[0].iov_len), len, PAGE_SIZE); \
+		len -= PAGE_SIZE; \
+		i++; \
+	} \
+ \
+	BUG_ON(i != (_vlen)); \
+} while (0)
+
+#define __UNMAP_CFS_PAGEVEC(_data, _vec, _vlen) kfree(_vec)
+
+#define MAP_CFS_PAGEVEC(_data, _vec, _vlen) do { \
+	if (likely((_data)->is_local)) \
+		__MAP_CFS_PAGEVEC(_data, _vec, _vlen); \
+	else \
+		KMAP_CFS_PAGEVEC(_data, _vec, _vlen); \
+} while (0)
+
+#define UNMAP_CFS_PAGEVEC(_data, _vec, _vlen) do { \
+	if (likely((_data)->is_local)) \
+		__UNMAP_CFS_PAGEVEC(_data, _vec, _vlen); \
+	else \
+		KUNMAP_CFS_PAGEVEC(_data, _vec, _vlen); \
+} while (0)
+
+#else /* CFS_ASYNC_LOCAL_SYNC */
+#define MAP_CFS_PAGEVEC(_data, _vec, _vlen) \
+		KMAP_CFS_PAGEVEC(_data, _vec, _vlen)
+#define UNMAP_CFS_PAGEVEC(_data, _vec, _vlen) \
+		KUNMAP_CFS_PAGEVEC(_data, _vec, _vlen)
+#endif /* !CFS_ASYNC_LOCAL_SYNC */
+
 #ifndef ICS_OOL_STRUCT_PAGES
 #define CFS_PAGEVEC_MAP_BUFFER(_data, _buf, _vlen) do {			\
 	_vlen = _vlen ? : (_data->pgbase + _data->count + PAGE_SIZE - 1) \

Index: read.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/cfs/read.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- read.c	5 Mar 2010 05:23:57 -0000	1.24
+++ read.c	25 Oct 2010 05:53:39 -0000	1.25
@@ -90,6 +90,7 @@
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
 #ifdef CFS_PAGEVEC
+		p->npages = pages;
 		if (pages <= CFS_PAGEVEC_SIZE)
 			p->pagevec = &p->page_array[0];
 		else {
@@ -108,6 +109,12 @@
 static inline void cfs_readdata_free(struct cfs_read_data *p)
 {
 #ifdef CFS_PAGEVEC
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	while (p->is_local && p->npages--) {
+		if (p->pagevec[p->npages])
+			__free_page(p->pagevec[p->npages]);
+	}
+#endif
 	if (p && (p->pagevec != &p->page_array[0]))
 		kfree(p->pagevec);
 #endif
@@ -338,10 +345,19 @@
 /*
  * Set up the CFS read request struct
  */
+#ifdef CFS_ASYNC_LOCAL_SYNC
+static int
+cfs_read_rpcsetup(struct list_head *head, struct cfs_read_data *data,
+		unsigned int count, unsigned int offset, unsigned npages)
+#else
 static void
 cfs_read_rpcsetup(struct cfs_page *req, struct cfs_read_data *data,
 		unsigned int count, unsigned int offset)
+#endif /* !CFS_ASYNC_LOCAL_SYNC */
 {
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	struct cfs_page *req = cfs_list_entry(head->next);
+#endif
 #ifdef CFS_PARANOIA
 	if (offset || req->wb_offset)
 		BUG();
@@ -355,15 +371,40 @@
 	data->offset	  = req_offset(req) + offset;
 
 #ifdef CFS_ASYNC_LOCAL_SYNC
-	if (!CFS_AT_SERVER(data->inode) || !CFS_SB_UP_MIP(itocmi(data->inode))) {
+	data->is_local = CFS_AT_SERVER(data->inode);
+	if (!data->is_local || !CFS_SB_UP_MIP(itocmi(data->inode))) {
 		data->flags = RPC_TASK_ASYNC;
 		if (IS_SWAPFILE(req->wb_inode))
 			data->flags |= CFS_RPC_SWAPFLAGS;
 	}
+
+	if (data->is_local) {
+		struct cfs_page *cp;
+		/* Unset is_local, do zero-copy if page cache is not virtual */
+		list_for_each_entry(cp, head, wb_list) {
+			if (PageHighMem(cp->wb_page)) {
+				data->is_local = -1;
+				break;
+			}
+		}
+		if (data->is_local == -1) {
+			int count;
+			for (count = 0; count < npages; count++) {
+				data->pagevec[count] = alloc_page(GFP_NOFS);
+				if (!data->pagevec[count])
+					break;
+			}
+			if (count != npages) {
+				cfs_readdata_free(data);
+				return -ENOMEM;
+			}
+		} else
+			data->is_local = 0;
+	}
 #else
 	/* N.B. Do we need to test? Never called for swapfile inode */
 	data->flags = RPC_TASK_ASYNC | (IS_SWAPFILE(req->wb_inode)? CFS_RPC_SWAPFLAGS : 0);
-#endif
+#endif /* !CFS_ASYNC_LOCAL_SYNC */
 #ifdef SKIP
 	/* This is derived from nfs3_proc_read_setup() */
 	/* N.B. Do we need to test? Never called for swapfile inode */
@@ -375,6 +416,9 @@
 	dprintk("CFS: %8d initiated read call (req %x/%lu)\n",
 		current->pid,
 		data->inode->i_sb->s_dev, data->inode->i_ino);
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	return 0;
+#endif
 }
 
 static void
@@ -396,6 +440,9 @@
 	struct cfs_page *req;
 	struct page *page;
 	unsigned int count = (ssize_t)data->res_count;
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	int i = 0;
+#endif
 
 	dprintk("CFS: read (%x/%ld %d@%Ld)\n",
 		data->inode->i_sb->s_dev,
@@ -410,6 +457,12 @@
 		cfs_list_remove_request(req);
 
 		if (status >= 0) {
+#ifdef CFS_ASYNC_LOCAL_SYNC
+			if (data->is_local) {
+				copy_highpage(page, data->pagevec[i]);
+				i++;
+			}
+#endif
 			if (count < PAGE_CACHE_SIZE) {
 				if (count < req->wb_bytes)
 					memclear_highpage_flush(page,
@@ -502,9 +555,12 @@
 #ifndef CFS_CHARD_RACE_FIX
 #error not supported
 #endif
-	do {
+	for (;;) {
 		status = CFS_PROTO(data->inode)->read(data);
-	} while (cfs_readpage_result(data, status) == -EAGAIN);
+		if (cfs_readpage_result(data, status) != -EAGAIN)
+			break;
+		cond_resched();
+	}
 #else /* CFS_PAGEVEC */
 #ifdef CFS_CHARD_RACE_FIX
 #warning deprecated
@@ -664,6 +720,10 @@
 		goto out_bad;
 
 #ifdef CFS_PAGEVEC
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	if (cfs_read_rpcsetup(head, data, 0, 0, npages))
+		goto out_bad;
+#endif
 	pages = data->pagevec;
 #endif
 	count = 0;
@@ -673,13 +733,22 @@
 		cfs_list_add_request(req, &data->pages);
 		ClearPageError(req->wb_page);
 #ifdef CFS_PAGEVEC
+#ifdef CFS_ASYNC_LOCAL_SYNC
+		if (data->is_local)
+			copy_highpage(*pages++, req->wb_page);
+		else
+#endif
 		*pages++ = req->wb_page;
 #endif
 		count += req->wb_bytes;
 	}
-	req = cfs_list_entry(data->pages.next);
 
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	data->count = count;
+#else
+	req = cfs_list_entry(data->pages.next);
 	cfs_read_rpcsetup(req, data, count, 0);
+#endif
 
 	return cfs_execute_read(data);
 

Index: write.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/cfs/write.c,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -d -r1.45 -r1.46
--- write.c	2 Apr 2010 20:53:20 -0000	1.45
+++ write.c	25 Oct 2010 05:53:39 -0000	1.46
@@ -142,6 +142,7 @@
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
 #ifdef CFS_PAGEVEC
+		p->npages = pages;
 		if (pages <= CFS_PAGEVEC_SIZE)
 			p->pagevec = &p->page_array[0];
 		else {
@@ -160,6 +161,12 @@
 static __inline__ void cfs_writedata_free(struct cfs_write_data *p)
 {
 #ifdef CFS_PAGEVEC
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	while (p->is_local && p->npages--) {
+		if (p->pagevec[p->npages])
+			__free_page(p->pagevec[p->npages]);
+	}
+#endif
 	if (p && (p->pagevec != &p->page_array[0]))
 		kfree(p->pagevec);
 #endif
@@ -1242,7 +1249,7 @@
 #endif
 	int status;
 #ifdef CFS_PAGEVEC
-	int prio = 0;
+	u_char prio = 0;
 #else
 	struct inode		*inode = data->inode;
 	int stable = data->stable;
@@ -1254,27 +1261,28 @@
 #ifndef CFS_CHARD_RACE_FIX
 #warning not supported
 #endif
-	do {
 #ifdef CFS_ASYNC_QUEUE
-		if (data->priority == RPC_PRIORITY_HIGH) {
+	if (data->priority == RPC_PRIORITY_HIGH) {
 #else
-		if (data->ics_prio) {
+	if (data->ics_prio) {
 #endif
-			prio = ics_getpriority();
-			if (prio < ICS_MAX_PRIO)
-				ics_setpriority(prio + 1);
-		}
+		prio = ics_getpriority();
+		if (prio < ICS_MAX_PRIO)
+			ics_setpriority(prio + 1);
+	}
 
+	for (;;) {
 		status = CFS_PROTO(data->inode)->write(data);
-
+		if (cfs_writeback_done(data, status) != -EAGAIN)
+			break;
+		cond_resched();
+	}
 #ifdef CFS_ASYNC_QUEUE
-		if (data->priority == RPC_PRIORITY_HIGH)
+	if (data->priority == RPC_PRIORITY_HIGH)
 #else
-		if (data->ics_prio)
+	if (data->ics_prio)
 #endif
-			ics_setpriority(prio);
-
-	} while (cfs_writeback_done(data, status) == -EAGAIN);
+		ics_setpriority(prio);
 #else /* CFS_PAGEVEC */
 #ifdef CFS_CHARD_RACE_FIX
 #warning deprecated
@@ -1459,11 +1467,21 @@
 /*
  * Set up the argument/result storage required for the RPC call.
  */
+#ifdef CFS_ASYNC_LOCAL_SYNC
+static int cfs_write_rpcsetup(struct list_head *head,
+		struct cfs_write_data *data,
+		unsigned int count, unsigned int offset,
+		int how, unsigned npages)
+#else
 static void cfs_write_rpcsetup(struct cfs_page *req,
 		struct cfs_write_data *data,
 		unsigned int count, unsigned int offset,
 		int how)
+#endif /* !CFS_ASYNC_LOCAL_SYNC */
 {
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	struct cfs_page *req = cfs_list_entry(head->next);
+#endif
 	struct inode		*inode;
 	int stable;
 
@@ -1482,13 +1500,38 @@
 	 * See related [ ssic-linux-Bugs-686748 ]
 	 *	-Roger
 	 */
+	data->is_local = CFS_AT_SERVER(inode);
 	if (!(how & FLUSH_SYNC) &&
-	    (!CFS_AT_SERVER(inode) || !CFS_SB_UP_SB(inode->i_sb)))
+	    (!data->is_local || !CFS_SB_UP_SB(inode->i_sb)))
 		data->flags = RPC_TASK_ASYNC;
+
+	if (data->is_local) {
+		struct cfs_page *cp;
+		/* Unset is_local, do zero-copy if page cache is not virtual */
+		list_for_each_entry(cp, head, wb_list) {
+			if (PageHighMem(cp->wb_page)) {
+				data->is_local = -1;
+				break;
+			}
+		}
+		if (data->is_local == -1) {
+			int count;
+			for (count = 0; count < npages; count++) {
+				data->pagevec[count] = alloc_page(GFP_NOFS);
+				if (!data->pagevec[count])
+					break;
+			}
+			if (count != npages) {
+				cfs_writedata_free(data);
+				return -ENOMEM;
+			}
+		} else
+			data->is_local = 0;
+	}
 #else
 	/* Set the initial flags for the task.  */
 	data->flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
-#endif
+#endif /* !CFS_ASYNC_LOCAL_SYNC */
 #endif /* CFS_PAGEVEC */
 	/* This is derived from nfs3_proc_write_setup() */
 #ifdef CFS_ONLY_REMOTE_IS_CHARD
@@ -1526,6 +1569,9 @@
 		count,
 		(unsigned long long)data->offset);
 
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	return 0;
+#endif
 #ifdef SSI_SKIP	/* Don't delete this, keeps fs/nfs/write.c comparison */
 	/* Set up the RPC argument and reply structs
 	 * NB: take care not to mess about with data->commit et al. */
@@ -1593,6 +1639,10 @@
 		goto out_bad;
 
 #ifdef CFS_PAGEVEC
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	if (cfs_write_rpcsetup(head, data, 0, 0, how, npages))
+		goto out_bad;
+#endif
 	pages = data->pagevec;
 #endif
 	count = 0;
@@ -1607,14 +1657,23 @@
 		SetPageWriteback(req->wb_page);
 #endif
 #ifdef CFS_PAGEVEC
+#ifdef CFS_ASYNC_LOCAL_SYNC
+		if (data->is_local)
+			copy_highpage(*pages++, req->wb_page);
+		else
+#endif
 		*pages++ = req->wb_page;
 #endif
 		count += req->wb_bytes;
 	}
-	req = cfs_list_entry(data->pages.next);
 
+#ifdef CFS_ASYNC_LOCAL_SYNC
+	data->count = count;
+#else
+	req = cfs_list_entry(data->pages.next);
 	/* Set up the argument struct */
 	cfs_write_rpcsetup(req, data, count, 0, how);
+#endif
 
 	return cfs_execute_write(data);
 
@@ -1797,38 +1856,42 @@
 	int status = 0;
 #ifndef CFS_PAGEVEC
 	unsigned int res = 0;
+#else
+	u_char prio = 0;
 #endif
 
 #ifdef CFSD_COMMIT
-	if (CFS_SB_HARD_MIP(itocmi(data->inode)))
+	if (CFS_SB_HARD_MIP(itocmi(data->inode))) {
 #endif
 #ifdef CFS_PAGEVEC
 #ifndef CFS_CHARD_RACE_FIX
 #error not supported
 #endif
-	do {
-		u_char prio = 0;
-
 #ifdef CFS_ASYNC_QUEUE
-		if (data->priority == RPC_PRIORITY_HIGH) {
+	if (data->priority == RPC_PRIORITY_HIGH) {
 #else
-		if (data->ics_prio) {
+	if (data->ics_prio) {
 #endif
-			prio = ics_getpriority();
-			if (prio < ICS_MAX_PRIO)
-				ics_setpriority(prio + 1);
-		}
+		prio = ics_getpriority();
+		if (prio < ICS_MAX_PRIO)
+			ics_setpriority(prio + 1);
+	}
 
+	for (;;) {
 		status = CFS_PROTO(data->inode)->commit(data);
-
+		if (cfs_commit_result(data, status) != -EAGAIN)
+			break;
+		cond_resched();
+	}
 #ifdef CFS_ASYNC_QUEUE
-		if (data->priority == RPC_PRIORITY_HIGH)
+	if (data->priority == RPC_PRIORITY_HIGH)
 #else
-		if (data->ics_prio)
+	if (data->ics_prio)
+#endif
+		ics_setpriority(prio);
+#ifdef CFSD_COMMIT
+	}
 #endif
-			ics_setpriority(prio);
-
-	} while (cfs_commit_result(data, status) == -EAGAIN);
 #else /* CFS_PAGEVEC */
 #ifdef CFS_CHARD_RACE_FIX
 #warning deprecated


------------------------------------------------------------------------------
Nokia and AT&T present the 2010 Calling All Innovators-North America contest
Create new apps & games for the Nokia N8 for consumers in  U.S. and Canada
$10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing
Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store 
http://p.sf.net/sfu/nokia-dev2dev