[SSI] openssi/kernel/cluster/ssi/vproc procfs_subr.c,1.19,1.20
Roger Tsang <[email protected]> Mon, 25 Oct 2010 05:24:45 +0000
| Newsgroups | gmane.linux.cluster.ssic.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/vproc
In directory sfp-cvsdas-3.v30.ch3.sourceforge.com:/tmp/cvs-serv6902/cluster/ssi/vproc
Modified Files:
Tag: OPENSSI-FC
procfs_subr.c
Log Message:
VPROC (#ifdef PROC_LARGE_MAXPIDS):
- Refactor ssi_get_tgid_list() to do concurrent async requests and buffer the PIDs list for each node in the cluster.
- Revert PROC_MAXPIDS value to 20 (the default in Linux base). filldir() in proc_pid_readdir() stops at around 20 entries.
- Reduce VPROC_MAXPIDS value so that internal pid_list[] cache and related proc_readdir_cookie structure fit within one memory page. Reduce memory pressure. Remove large kmalloc() call in proc_pid_readdir().
- Fix ssi_get_tgid_list() skips remaining nodes in the cluster if "start_node" in struct proc_root_readdir_cookie is not found in CLMS node list. This can happen when the next node ("start_node") goes down while the system is reading the list of PIDs. Affects userspace accessing procfs and is not in localview mode.
cluster/ssi/vproc/procfs_subr.c | 285 ++++++++++++++++++++++++++++----
fs/proc/base.c | 31 +--
2 files changed, 267 insertions(+), 49 deletions(-)
Index: procfs_subr.c
===================================================================
RCS file: /cvsroot/ssic-linux/openssi/kernel/cluster/ssi/vproc/procfs_subr.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- procfs_subr.c 25 Oct 2010 05:08:56 -0000 1.19
+++ procfs_subr.c 25 Oct 2010 05:24:43 -0000 1.20
@@ -4,6 +4,7 @@
#include <linux/fs.h>
#include <linux/tty.h>
+#include <cluster/async.h>
#include <cluster/clms.h>
#include <cluster/config.h>
#include <cluster/nodelist.h>
@@ -12,19 +13,39 @@
#include <cluster/gen/reopen.h>
#ifdef PROC_LARGE_MAXPIDS
-#define PROC_MAXPIDS VPROC_MAXPIDS
-#else
-#define PROC_MAXPIDS 20
-#endif
+struct proc_readdir_cookie {
+ struct list_head d_list;
+ int pids_done;
+ int pids_size; /* size of pid_list[] */
+ int pids_read; /* # of pids read into pids[] */
+ clusternode_t node;
+ int h_index; /* vproc hash */
+ int v_index; /* vproc list */
+ unsigned int *pid_list; /* pid_list[] */
+};
+#define MAX_PROC_READDIR_COOKIES 2 /* default: 2 */
+
+#define VPROC_MAXPIDS \
+ ((PAGE_SIZE-sizeof(struct proc_readdir_cookie)) / sizeof(unsigned int))
struct proc_root_readdir_cookie {
unsigned int start_index;
unsigned int cur_index;
clusternode_t start_node;
+ struct proc_readdir_cookie *cur_cookie;
+ struct list_head cp_list; /* proc_readdir_cookie's */
+ unsigned int pid_list[PROC_MAXPIDS]; /* cache for short read */
+};
+#else /* PROC_LARGE_MAXPIDS */
+struct proc_root_readdir_cookie {
+ unsigned int start_index;
+ unsigned int cur_index;
+ clusternode_t start_node;
int h_index;
int v_index;
unsigned int pid_list[PROC_MAXPIDS];
};
+#endif /* !PROC_LARGE_MAXPIDS */
int ssi_proc_root_open(struct inode *inode, struct file *file)
{
@@ -37,17 +58,17 @@
return 0;
#ifdef PROC_LARGE_MAXPIDS
cp = kmalloc(sizeof(*cp), GFP_KERNEL);
-#else
- cp = kzmalloc(sizeof(*cp), GFP_KERNEL);
-#endif
if (cp == NULL)
return -ENOMEM;
-#ifdef PROC_LARGE_MAXPIDS
cp->start_index = 0;
cp->cur_index = 0;
cp->start_node = 0;
- cp->h_index = 0;
- cp->v_index = 0;
+ cp->cur_cookie = NULL;
+ INIT_LIST_HEAD(&cp->cp_list);
+#else
+ cp = kzmalloc(sizeof(*cp), GFP_KERNEL);
+ if (cp == NULL)
+ return -ENOMEM;
#endif
file->private_data = cp;
return 0;
@@ -55,14 +76,53 @@
int ssi_proc_root_release(struct inode *inode, struct file *file)
{
+#ifdef PROC_LARGE_MAXPIDS
+ struct proc_root_readdir_cookie *cp;
+ struct proc_readdir_cookie *data, *tmp;
+
+ (void)inode;
+ if (PVP(current->p_vproc)->pvp_localview)
+ return 0;
+
+ cp = file->private_data;
+retry:
+ list_for_each_entry_safe(data, tmp, &cp->cp_list, d_list) {
+ if (!data->pids_done)
+ continue;
+ list_del(&data->d_list);
+ free_page((unsigned long)data);
+ }
+ if (unlikely(!list_empty(&cp->cp_list))) {
+ idelay((HZ+99)/100);
+ goto retry;
+ }
+#else
(void)inode;
if (PVP(current->p_vproc)->pvp_localview)
return 0;
+#endif /* !PROC_LARGE_MAXPIDS */
kfree(file->private_data);
file->private_data = NULL;
return 0;
}
+#ifdef PROC_LARGE_MAXPIDS
+void
+ssi_get_tgid_list_async_handler(void *data)
+{
+ struct proc_readdir_cookie *cp = (struct proc_readdir_cookie *) data;
+ u_int *pidsp = cp->pid_list;
+
+ if (PVPSOP_GET_TGID_LIST(cp->node, &pidsp,
+ &cp->pids_size, &cp->h_index, &cp->v_index)) {
+ cp->pids_size = 0;
+ }
+ cp->pids_done = 1;
+ smp_mb();
+}
+#endif
+
+/* Caller holds inode->i_sem */
int
ssi_get_tgid_list(struct file *file, unsigned int index, unsigned int *pids)
{
@@ -70,25 +130,193 @@
nsc_nodelist_t *nodelist;
nsc_nlcookie_t cookie;
clusternode_t node;
- u_int *pidsp;
- int pids_size, nr_pids = 0;
- unsigned int out_index;
- int pids_off;
+#ifdef PROC_LARGE_MAXPIDS
+ struct proc_readdir_cookie *data;
+ struct list_head *pos;
+ int count, nr_pids = 0;
+ /* Use the saved starting position. */
+ if (cp->start_index && index >= cp->start_index) {
+ /* short read, fill pids[] from cache */
+ if (index < cp->cur_index) {
+ nr_pids = cp->cur_index - index;
+ memcpy(pids, cp->pid_list + index - cp->start_index,
+ nr_pids * sizeof(unsigned int));
+ index = cp->cur_index - nr_pids;
+ if (unlikely(nr_pids == PROC_MAXPIDS)) {
+ cp->start_index = index;
+ return nr_pids;
+ }
+ }
+ if (cp->start_node == CLUSTERNODE_INVAL) {
+ node = cp->start_node;
+ goto wait_for_pids;
+ }
+ } else
+ BUG_ON(index < cp->start_index);
+
+ /* Limit number of queued requests */
+ count = 0;
+ list_for_each(pos, &cp->cp_list) {
+ if (++count == MAX_PROC_READDIR_COOKIES) {
+ node = cp->start_node;
+ goto wait_for_pids;
+ }
+ }
+
+queue_requests:
+ /* get node list */
+ nodelist = clms_get_nsc_nodelist(CLMS_NODE_UP
+ |CLMS_NODE_HALF_UP
+ |CLMS_NODE_HALF_DOWN);
+ NSC_NLCOOKIE_INIT(&cookie);
+ if (likely(NSC_NODELIST_TEST1(nodelist, this_node))) {
+ do {
+ node = NSC_NODELIST_GET_NEXT(&cookie, nodelist);
+ if (node == CLUSTERNODE_INVAL) {
+ NSC_NODELIST_FREE(nodelist);
+ goto wait_for_pids;
+ }
+ } while (node < cp->start_node);
+ } else {
+ /* If this node not in the list, then it must be coming
+ * up or going down, so clear the list and only process
+ * this node.
+ */
+ NSC_NODELIST_CLRALL(nodelist);
+ node = this_node;
+ }
+
+ for (;;) {
+ data = (void *) __get_free_page(GFP_KERNEL);
+ if (!data)
+ break;
+
+ INIT_LIST_HEAD(&data->d_list);
+ data->pids_done = 0;
+ data->pids_size = VPROC_MAXPIDS;
+ data->pids_read = 0;
+ data->node = node;
+ data->h_index = 0;
+ data->v_index = 0;
+ data->pid_list = (void *)((char *)data + sizeof(*data));
+
+ list_add_tail(&data->d_list, &cp->cp_list);
+
+ if (nsc_async_queue(nsc_generic_async_queue,
+ ssi_get_tgid_list_async_handler,
+ (void *)data, sizeof(*data), 0)) {
+ list_del(&data->d_list);
+ free_page((unsigned long)data);
+ break;
+ }
+
+ node = NSC_NODELIST_GET_NEXT(&cookie, nodelist);
+ if (node == CLUSTERNODE_INVAL)
+ break;
+ if (++count == MAX_PROC_READDIR_COOKIES)
+ break;
+ }
+ NSC_NODELIST_FREE(nodelist);
+
+wait_for_pids:
+ do {
+ struct proc_readdir_cookie *tmp;
+
+ count = 0;
+ if (cp->cur_cookie && cp->cur_cookie->pids_done) {
+ data = cp->cur_cookie;
+ cp->cur_cookie = NULL;
+ goto resume;
+ }
+ list_for_each_entry(data, &cp->cp_list, d_list) {
+ int __nr_pids, avail_pids;
+resume:
+ count++;
+ if (!data->pids_done || !data->pids_size)
+ continue;
+ cp->cur_cookie = data;
+
+ /* Populate pids[] */
+ __nr_pids = PROC_MAXPIDS - nr_pids;
+ avail_pids = data->pids_size - data->pids_read;
+
+ if (avail_pids < __nr_pids)
+ __nr_pids = avail_pids;
+ memcpy(pids + nr_pids,
+ data->pid_list + data->pids_read,
+ __nr_pids * sizeof(unsigned int));
+
+ nr_pids += __nr_pids;
+ data->pids_read += __nr_pids;
+
+ if (data->pids_size != data->pids_read) {
+ SSI_ASSERT(nr_pids == PROC_MAXPIDS);
+ break;
+ }
+
+ /* Reached end of vproc list */
+ if (!data->v_index) {
+ data->pids_size = 0;
+ cp->cur_cookie = NULL;
+ goto next;
+ }
+
+ /* More vproc pids to read */
+ data->pids_done = 0;
+ data->pids_size = VPROC_MAXPIDS;
+ data->pids_read = 0;
+ if (nsc_async_queue(nsc_generic_async_queue,
+ ssi_get_tgid_list_async_handler,
+ (void *)data, sizeof(*data), 0)) {
+ data->pids_size = 0;
+ break;
+ }
+next:
+ if (nr_pids == PROC_MAXPIDS)
+ break;
+ }
+ if (!count)
+ break;
+
+ list_for_each_entry_safe(data, tmp, &cp->cp_list, d_list) {
+ if (!data->pids_done || data->pids_size)
+ continue;
+ list_del(&data->d_list);
+ free_page((unsigned long)data);
+ }
+
+ if (nr_pids == 0)
+ idelay((HZ+99)/100);
+ } while (nr_pids == 0);
+
+ /* Try harder to fill pids[] */
+ if (nr_pids != PROC_MAXPIDS && node != CLUSTERNODE_INVAL &&
+ count < MAX_PROC_READDIR_COOKIES)
+ goto queue_requests;
+
+ cp->start_index = index;
+ cp->cur_index = index + nr_pids;
+ cp->start_node = node;
+ if (count)
+ memcpy(cp->pid_list, pids, nr_pids * sizeof(unsigned int));
+
+ return nr_pids;
+#else /* PROC_LARGE_MAXPIDS */
+ unsigned int out_index, start_index;
+ int pids_off, nr_pids = 0;
+
+ start_index = index;
if (cp->start_index && index >= cp->start_index) {
/* Use the saved starting position. */
out_index = cp->cur_index;
- /* If caller truncated read, fill-in pids from previous read */
- if (unlikely(index < cp->cur_index)) {
+ if (index < cp->cur_index) {
nr_pids = cp->cur_index - index;
- BUG_ON(nr_pids > PROC_MAXPIDS);
memcpy(pids, cp->pid_list + index - cp->start_index,
nr_pids * sizeof(unsigned int));
index = cp->cur_index;
}
- BUG_ON(index > cp->cur_index);
} else {
- /* Reset the saved starting position. */
cp->start_node = 0;
cp->h_index = 0;
cp->v_index = 0;
@@ -102,12 +330,10 @@
NSC_NLCOOKIE_INIT(&cookie);
if (NSC_NODELIST_TEST1(nodelist, this_node)) {
node = NSC_NODELIST_GET_NEXT(&cookie,nodelist);
- if (cp->start_node) {
- while (node != cp->start_node) {
- node = NSC_NODELIST_GET_NEXT(&cookie,nodelist);
- if (node == CLUSTERNODE_INVAL)
- goto out;
- }
+ while (cp->start_node && node != cp->start_node) {
+ node = NSC_NODELIST_GET_NEXT(&cookie,nodelist);
+ if (node == CLUSTERNODE_INVAL)
+ goto out;
}
}
else {
@@ -119,7 +345,11 @@
NSC_NODELIST_CLRALL(nodelist);
}
+
for (;;) {
+ u_int *pidsp;
+ int pids_size;
+
pids_size = PROC_MAXPIDS - nr_pids;
pidsp = pids + nr_pids;
if (PVPSOP_GET_TGID_LIST(node, &pidsp,
@@ -154,12 +384,13 @@
}
out:
NSC_NODELIST_FREE(nodelist);
- cp->start_index = index;
- cp->cur_index = index + nr_pids;
+ cp->start_index = start_index;
+ cp->cur_index = start_index + nr_pids;
cp->start_node = node;
memcpy(cp->pid_list, pids, nr_pids * sizeof(unsigned int));
return nr_pids;
+#endif /* !PROC_LARGE_MAXPIDS */
}
------------------------------------------------------------------------------
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