Whamcloud - gitweb
- landing of b_hd_cleanup_merge to HEAD.
[fs/lustre-release.git] / lnet / router / proc.c
index dd65b34..0fe3b90 100644 (file)
 #include "router.h"
 
 #define KPR_PROC_ROUTER "sys/portals/router"
+#define KPR_PROC_ROUTES "sys/portals/routes"
 
-int
-kpr_proc_read (char *page, char **start, off_t off, int count, int *eof, void *data)
+/* Used for multi-page route list book keeping */
+struct proc_route_data {
+        struct list_head *curr;
+        unsigned int generation;
+        off_t skip;
+} kpr_read_routes_data;
+
+/* nal2name support re-used from utils/portals.c */
+struct name2num {
+        char *name;
+        int   num;
+} nalnames[] = {
+        { "any",         0},
+        { "elan",        QSWNAL},
+        { "tcp",         SOCKNAL},
+        { "gm",          GMNAL},
+        { "ib",          OPENIBNAL},
+        { NULL,          -1}
+};
+
+static struct name2num *name2num_lookup_num(struct name2num *table, int num)
+{
+        while (table->name != NULL)
+                if (num == table->num)
+                        return (table);
+                else
+                        table++;
+        return (NULL);
+}
+
+static char *nal2name(int nal)
 {
-       unsigned long long bytes = kpr_fwd_bytes;
-       unsigned long      packets = kpr_fwd_packets;
-       unsigned long      errors = kpr_fwd_errors;
+        struct name2num *e = name2num_lookup_num(nalnames, nal);
+        return ((e == NULL) ? "???" : e->name);
+}
+
+
+static int kpr_proc_router_read(char *page, char **start, off_t off,
+                                int count, int *eof, void *data)
+{
+        unsigned long long bytes = kpr_fwd_bytes;
+        unsigned long      packets = kpr_fwd_packets;
+        unsigned long      errors = kpr_fwd_errors;
         unsigned int       qdepth = atomic_read (&kpr_queue_depth);
-       int                len;
-       
-       *eof = 1;
-       if (off != 0)
-               return (0);
-       
-       len = sprintf (page, "%Ld %ld %ld %d\n", bytes, packets, errors, qdepth);
-       
-       *start = page;
-       return (len);
+        int                len;
+
+        *eof = 1;
+        if (off != 0)
+                return (0);
+
+        len = sprintf(page, "%Ld %ld %ld %d\n", bytes, packets, errors, qdepth);
+
+        *start = page;
+        return (len);
 }
 
-int
-kpr_proc_write (struct file *file, const char *ubuffer, unsigned long count, void *data)
+static int kpr_proc_router_write(struct file *file, const char *ubuffer,
+                                 unsigned long count, void *data)
 {
-       /* Ignore what we've been asked to write, and just zero the stats counters */
-       kpr_fwd_bytes = 0;
-       kpr_fwd_packets = 0;
-       kpr_fwd_errors = 0;
+        /* Ignore what we've been asked to write, and just zero the stats */
+        kpr_fwd_bytes = 0;
+        kpr_fwd_packets = 0;
+        kpr_fwd_errors = 0;
 
-       return (count);
+        return (count);
 }
 
-void
-kpr_proc_init(void)
+static int kpr_proc_routes_read(char *page, char **start, off_t off,
+                                int count, int *eof, void *data)
 {
-        struct proc_dir_entry *entry = create_proc_entry (KPR_PROC_ROUTER, S_IFREG | S_IRUGO | S_IWUSR, NULL);
+        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;
+
+        *eof = 1;
+        *start = page;
+
+        if (prd->curr == NULL) {
+                if (off != 0)
+                        return 0;
+
+                /* First pass, initialize our private data */
+                prd->curr = kpr_routes.next;
+                prd->generation = kpr_routes_generation;
+                prd->skip = 0;
+        } else {
+                /* Abort route list generation change */
+                if (prd->generation != kpr_routes_generation) {
+                        prd->curr = NULL;
+                        return sprintf(page, "\nError: Routes Changed\n");
+                }
+
+                /* All the routes have been walked */
+                if (prd->curr == &kpr_routes) {
+                        prd->curr = NULL;
+                        return 0;
+                }
+        }
+
+        read_lock(&kpr_rwlock);
+        *start = page + prd->skip;
+        user_len = -prd->skip;
+
+        for (; prd->curr != &kpr_routes; prd->curr = prd->curr->next) {
+                re = list_entry(prd->curr, kpr_route_entry_t, kpre_list);
+                ge = re->kpre_gateway;
+
+                line_len = sprintf(page + chunk_len,
+                        "%12s  "LPX64" : "LPX64" - "LPX64", %s\n",
+                        nal2name(ge->kpge_nalid), ge->kpge_nid,
+                        re->kpre_lo_nid, re->kpre_hi_nid,
+                        ge->kpge_alive ? "up" : "down");
+                chunk_len += line_len;
+                user_len += line_len;
 
-        if (entry == NULL) 
-       {
+                /* The route table will exceed one page */
+                if ((chunk_len > (PAGE_SIZE - 80)) || (user_len > count)) {
+                        prd->curr = prd->curr->next;
+                        break;
+                }
+        }
+
+        *eof = 0;
+
+        /* Caller received only a portion of the last entry, the
+         * remaining will be delivered in the next page if asked for.
+         */
+        if (user_len > count) {
+                prd->curr = prd->curr->prev;
+                prd->skip = line_len - (user_len - count);
+                read_unlock(&kpr_rwlock);
+                return count;
+        }
+
+        /* Not enough data to entirely satify callers request */
+        prd->skip = 0;
+        read_unlock(&kpr_rwlock);
+        return user_len;
+}
+
+static int kpr_proc_routes_write(struct file *file, const char *ubuffer,
+                                 unsigned long count, void *data)
+{
+        /* no-op; lctl should be used to adjust the routes */
+        return (count);
+}
+
+void kpr_proc_init(void)
+{
+        struct proc_dir_entry *router_entry;
+        struct proc_dir_entry *routes_entry;
+
+        /* Initialize KPR_PROC_ROUTER */
+        router_entry = create_proc_entry (KPR_PROC_ROUTER,
+                S_IFREG | S_IRUGO | S_IWUSR, NULL);
+
+        if (router_entry == NULL) {
                 CERROR("couldn't create proc entry %s\n", KPR_PROC_ROUTER);
                 return;
         }
 
-        entry->data = NULL;
-        entry->read_proc = kpr_proc_read;
-       entry->write_proc = kpr_proc_write;
+        router_entry->data = NULL;
+        router_entry->read_proc = kpr_proc_router_read;
+        router_entry->write_proc = kpr_proc_router_write;
+
+        /* Initialize KPR_PROC_ROUTES */
+        routes_entry = create_proc_entry (KPR_PROC_ROUTES,
+                S_IFREG | S_IRUGO | S_IWUSR, NULL);
+
+        if (routes_entry == NULL) {
+                CERROR("couldn't create proc entry %s\n", KPR_PROC_ROUTES);
+                return;
+        }
+
+        kpr_read_routes_data.curr = NULL;
+        kpr_read_routes_data.generation = 0;
+        kpr_read_routes_data.skip = 0;
+
+        routes_entry->data = &kpr_read_routes_data;
+        routes_entry->read_proc = kpr_proc_routes_read;
+        routes_entry->write_proc = kpr_proc_routes_write;
 }
 
-void 
-kpr_proc_fini(void)
+void kpr_proc_fini(void)
 {
         remove_proc_entry(KPR_PROC_ROUTER, 0);
+        remove_proc_entry(KPR_PROC_ROUTES, 0);
 }