-lnet_route_seq_open(struct inode *inode, struct file *file)
-{
- struct proc_dir_entry *dp = PDE(inode);
- struct seq_file *sf;
- int rc;
-
- rc = seq_open(file, &lnet_routes_sops);
- if (rc == 0) {
- sf = file->private_data;
- sf->private = dp->data;
- }
-
- return rc;
-}
-
-static struct file_operations lnet_routes_fops;
-
-static void
-lnet_init_routes_fops(void)
-{
- lnet_routes_fops.owner = THIS_MODULE;
- lnet_routes_fops.llseek = seq_lseek;
- lnet_routes_fops.read = seq_read;
- lnet_routes_fops.open = lnet_route_seq_open;
- lnet_routes_fops.release = seq_release;
-}
-
-typedef struct {
- __u64 lrtrsi_version;
- lnet_peer_t *lrtrsi_router;
- loff_t lrtrsi_off;
-} lnet_router_seq_iterator_t;
-
-int
-lnet_router_seq_seek (lnet_router_seq_iterator_t *lrtrsi, loff_t off)
-{
- struct list_head *r;
- lnet_peer_t *lp;
- int rc;
- loff_t here;
-
- if (off == 0) {
- lrtrsi->lrtrsi_router = NULL;
- lrtrsi->lrtrsi_off = 0;
- return 0;
- }
-
- LNET_LOCK();
-
- lp = lrtrsi->lrtrsi_router;
-
- if (lp != NULL &&
- lrtrsi->lrtrsi_version != the_lnet.ln_routers_version) {
- /* tables have changed */
- rc = -ESTALE;
- goto out;
- }
-
- if (lp == NULL || lrtrsi->lrtrsi_off > off) {
- /* search from start */
- r = the_lnet.ln_routers.next;
- here = 1;
- } else {
- /* continue search */
- r = &lp->lp_rtr_list;
- here = lrtrsi->lrtrsi_off;
- }
-
- lrtrsi->lrtrsi_version = the_lnet.ln_routers_version;
- lrtrsi->lrtrsi_off = off;
-
- while (r != &the_lnet.ln_routers) {
- lnet_peer_t *rtr = list_entry(r,
- lnet_peer_t,
- lp_rtr_list);
-
- if (here == off) {
- lrtrsi->lrtrsi_router = rtr;
- rc = 0;
- goto out;
- }
-
- r = r->next;
- here++;
- }
-
- lrtrsi->lrtrsi_router = NULL;
- rc = -ENOENT;
- out:
- LNET_UNLOCK();
- return rc;
-}
-
-static void *
-lnet_router_seq_start (struct seq_file *s, loff_t *pos)
-{
- lnet_router_seq_iterator_t *lrtrsi;
- int rc;
-
- LIBCFS_ALLOC(lrtrsi, sizeof(*lrtrsi));
- if (lrtrsi == NULL)
- return NULL;
-
- lrtrsi->lrtrsi_router = NULL;
- rc = lnet_router_seq_seek(lrtrsi, *pos);
- if (rc == 0)
- return lrtrsi;
-
- LIBCFS_FREE(lrtrsi, sizeof(*lrtrsi));
- return NULL;
-}
-
-static void
-lnet_router_seq_stop (struct seq_file *s, void *iter)
-{
- lnet_router_seq_iterator_t *lrtrsi = iter;
-
- if (lrtrsi != NULL)
- LIBCFS_FREE(lrtrsi, sizeof(*lrtrsi));
-}
-
-static void *
-lnet_router_seq_next (struct seq_file *s, void *iter, loff_t *pos)
-{
- lnet_router_seq_iterator_t *lrtrsi = iter;
- int rc;
- loff_t next = *pos + 1;
-
- rc = lnet_router_seq_seek(lrtrsi, next);
- if (rc != 0) {
- LIBCFS_FREE(lrtrsi, sizeof(*lrtrsi));
- return NULL;
- }
-
- *pos = next;
- return lrtrsi;
+proc_lnet_routers(struct ctl_table *table, int write, void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ int rc = 0;
+ char *tmpstr;
+ char *s;
+ const int tmpsiz = 256;
+ int len;
+ int ver;
+ int off;
+
+ off = LNET_PROC_HOFF_GET(*ppos);
+ ver = LNET_PROC_VER_GET(*ppos);
+
+ LASSERT(!write);
+
+ if (*lenp == 0)
+ return 0;
+
+ LIBCFS_ALLOC(tmpstr, tmpsiz);
+ if (tmpstr == NULL)
+ return -ENOMEM;
+
+ s = tmpstr; /* points to current position in tmpstr[] */
+
+ if (*ppos == 0) {
+ s += snprintf(s, tmpstr + tmpsiz - s,
+ "%-4s %7s %9s %6s %12s %9s %8s %7s %s\n",
+ "ref", "rtr_ref", "alive_cnt", "state",
+ "last_ping", "ping_sent", "deadline",
+ "down_ni", "router");
+ LASSERT(tmpstr + tmpsiz - s > 0);
+
+ lnet_net_lock(0);
+ ver = (unsigned int)the_lnet.ln_routers_version;
+ lnet_net_unlock(0);
+ *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
+ } else {
+ struct list_head *r;
+ struct lnet_peer *peer = NULL;
+ int skip = off - 1;
+
+ lnet_net_lock(0);
+
+ if (ver != LNET_PROC_VERSION(the_lnet.ln_routers_version)) {
+ lnet_net_unlock(0);
+
+ LIBCFS_FREE(tmpstr, tmpsiz);
+ return -ESTALE;
+ }
+
+ r = the_lnet.ln_routers.next;
+
+ while (r != &the_lnet.ln_routers) {
+ lnet_peer_t *lp = list_entry(r, lnet_peer_t,
+ lp_rtr_list);
+
+ if (skip == 0) {
+ peer = lp;
+ break;
+ }
+
+ skip--;
+ r = r->next;
+ }
+
+ if (peer != NULL) {
+ lnet_nid_t nid = peer->lp_nid;
+ cfs_time_t now = cfs_time_current();
+ cfs_time_t deadline = peer->lp_ping_deadline;
+ int nrefs = peer->lp_refcount;
+ int nrtrrefs = peer->lp_rtr_refcount;
+ int alive_cnt = peer->lp_alive_count;
+ int alive = peer->lp_alive;
+ int pingsent = !peer->lp_ping_notsent;
+ int last_ping = cfs_duration_sec(cfs_time_sub(now,
+ peer->lp_ping_timestamp));
+ int down_ni = 0;
+ lnet_route_t *rtr;
+
+ if ((peer->lp_ping_feats &
+ LNET_PING_FEAT_NI_STATUS) != 0) {
+ list_for_each_entry(rtr, &peer->lp_routes,
+ lr_gwlist) {
+ /* downis on any route should be the
+ * number of downis on the gateway */
+ if (rtr->lr_downis != 0) {
+ down_ni = rtr->lr_downis;
+ break;
+ }
+ }
+ }
+
+ if (deadline == 0)
+ s += snprintf(s, tmpstr + tmpsiz - s,
+ "%-4d %7d %9d %6s %12d %9d %8s %7d %s\n",
+ nrefs, nrtrrefs, alive_cnt,
+ alive ? "up" : "down", last_ping,
+ pingsent, "NA", down_ni,
+ libcfs_nid2str(nid));
+ else
+ s += snprintf(s, tmpstr + tmpsiz - s,
+ "%-4d %7d %9d %6s %12d %9d %8lu %7d %s\n",
+ nrefs, nrtrrefs, alive_cnt,
+ alive ? "up" : "down", last_ping,
+ pingsent,
+ cfs_duration_sec(cfs_time_sub(deadline, now)),
+ down_ni, libcfs_nid2str(nid));
+ LASSERT(tmpstr + tmpsiz - s > 0);
+ }
+
+ lnet_net_unlock(0);
+ }
+
+ len = s - tmpstr; /* how many bytes was written */
+
+ if (len > *lenp) { /* linux-supplied buffer is too small */
+ rc = -EINVAL;
+ } else if (len > 0) { /* wrote something */
+ if (copy_to_user(buffer, tmpstr, len))
+ rc = -EFAULT;
+ else {
+ off += 1;
+ *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
+ }
+ }
+
+ LIBCFS_FREE(tmpstr, tmpsiz);
+
+ if (rc == 0)
+ *lenp = len;
+
+ return rc;