struct list_head *curr;
unsigned int generation;
off_t skip;
+ rwlock_t proc_route_rwlock;
} kpr_read_routes_data;
/* nal2name support re-used from utils/portals.c */
{ "tcp", SOCKNAL},
{ "gm", GMNAL},
{ "ib", OPENIBNAL},
+ { "iib", IIBNAL},
+ { "lo", LONAL},
{ NULL, -1}
};
static int kpr_proc_routes_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- struct proc_route_data *prd = data;
- kpr_route_entry_t *re;
- kpr_gateway_entry_t *ge;
- int chunk_len = 0;
- int line_len = 0;
- int user_len = 0;
+ struct proc_route_data *prd = data;
+ kpr_route_entry_t *re;
+ kpr_gateway_entry_t *ge;
+ int chunk_len = 0;
+ int line_len = 0;
+ int user_len = 0;
+ int rc = 0;
*eof = 1;
*start = page;
+ write_lock(&(prd->proc_route_rwlock));
+
if (prd->curr == NULL) {
if (off != 0)
- return 0;
+ goto routes_read_exit;
/* First pass, initialize our private data */
prd->curr = kpr_routes.next;
/* Abort route list generation change */
if (prd->generation != kpr_routes_generation) {
prd->curr = NULL;
- return sprintf(page, "\nError: Routes Changed\n");
+ rc = sprintf(page, "\nError: Routes Changed\n");
+ goto routes_read_exit;
}
/* All the routes have been walked */
if (prd->curr == &kpr_routes) {
prd->curr = NULL;
- return 0;
+ goto routes_read_exit;
}
}
*start = page + prd->skip;
user_len = -prd->skip;
- for (; prd->curr != &kpr_routes; prd->curr = prd->curr->next) {
+ while ((prd->curr != NULL) && (prd->curr != &kpr_routes)) {
re = list_entry(prd->curr, kpr_route_entry_t, kpre_list);
ge = re->kpre_gateway;
chunk_len += line_len;
user_len += line_len;
- /* The route table will exceed one page */
- if ((chunk_len > (PAGE_SIZE - 80)) || (user_len > count)) {
- prd->curr = prd->curr->next;
- break;
+ /* Abort the route list changed */
+ if (prd->curr->next == NULL) {
+ prd->curr = NULL;
+ read_unlock(&kpr_rwlock);
+ rc = sprintf(page, "\nError: Routes Changed\n");
+ goto routes_read_exit;
}
+
+ prd->curr = prd->curr->next;
+
+ /* The route table will exceed one page, break the while loop
+ * so the function can be re-called with a new page.
+ */
+ if ((chunk_len > (PAGE_SIZE - 80)) || (user_len > count))
+ break;
}
*eof = 0;
prd->curr = prd->curr->prev;
prd->skip = line_len - (user_len - count);
read_unlock(&kpr_rwlock);
- return count;
+ rc = count;
+ goto routes_read_exit;
}
/* Not enough data to entirely satify callers request */
prd->skip = 0;
read_unlock(&kpr_rwlock);
- return user_len;
+ rc = user_len;
+
+routes_read_exit:
+ write_unlock(&(prd->proc_route_rwlock));
+ return rc;
}
static int kpr_proc_routes_write(struct file *file, const char *ubuffer,
kpr_read_routes_data.curr = NULL;
kpr_read_routes_data.generation = 0;
kpr_read_routes_data.skip = 0;
+ kpr_read_routes_data.proc_route_rwlock = RW_LOCK_UNLOCKED;
routes_entry->data = &kpr_read_routes_data;
routes_entry->read_proc = kpr_proc_routes_read;