staging: unisys: Remove num_visornic_open array

As pointed out in a recent review, the num_visornic_open array didn't do
anything useful, and it exposed a potential race in the visornic code that
could arise while taking down a net interface while reading from the
debugfs files. Fix that by removing the array entirely, and just iterating
over all the registered netdevs in a given namespace, filtering on them
having visornic ops (to identify which are ours), and having their queues
not be stopped (identifying that they are up). This should prevent any oops
conditions happening due to changing state in that array, and save us a
bunch of code too.

Signed-off-by: Neil Horman <nhorman@redhat.com>
Signed-off-by: Benjamin Romer <benjamin.romer@unisys.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Neil Horman 2015-07-21 09:55:35 -04:00 коммит произвёл Greg Kroah-Hartman
Родитель 80a60777d7
Коммит 52b1660d3b
1 изменённых файлов: 154 добавлений и 187 удалений

Просмотреть файл

@ -196,8 +196,6 @@ struct visornic_devdata {
struct chanstat chstat; struct chanstat chstat;
}; };
/* array of open devices maintained by open() and close() */
static struct net_device *num_visornic_open[VISORNICSOPENMAX];
/* List of all visornic_devdata structs, /* List of all visornic_devdata structs,
* linked via the list_all member * linked via the list_all member
@ -325,178 +323,15 @@ static void visor_thread_stop(struct visor_thread_info *thrinfo)
thrinfo->id = 0; thrinfo->id = 0;
} }
/* DebugFS code */
static ssize_t info_debugfs_read(struct file *file, char __user *buf,
size_t len, loff_t *offset)
{
int i;
ssize_t bytes_read = 0;
int str_pos = 0;
struct visornic_devdata *devdata;
char *vbuf;
if (len > MAX_BUF)
len = MAX_BUF;
vbuf = kzalloc(len, GFP_KERNEL);
if (!vbuf)
return -ENOMEM;
/* for each vnic channel
* dump out channel specific data
*/
for (i = 0; i < VISORNICSOPENMAX; i++) {
if (!num_visornic_open[i])
continue;
devdata = netdev_priv(num_visornic_open[i]);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
"Vnic i = %d\n", i);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
"netdev = %s (0x%p), MAC Addr %pM\n",
num_visornic_open[i]->name,
num_visornic_open[i],
num_visornic_open[i]->dev_addr);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
"VisorNic Dev Info = 0x%p\n", devdata);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" num_rcv_bufs = %d\n",
devdata->num_rcv_bufs);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" max_oustanding_next_xmits = %d\n",
devdata->max_outstanding_net_xmits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" upper_threshold_net_xmits = %d\n",
devdata->upper_threshold_net_xmits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" lower_threshold_net_xmits = %d\n",
devdata->lower_threshold_net_xmits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" queuefullmsg_logged = %d\n",
devdata->queuefullmsg_logged);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.got_rcv = %lu\n",
devdata->chstat.got_rcv);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.got_enbdisack = %lu\n",
devdata->chstat.got_enbdisack);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.got_xmit_done = %lu\n",
devdata->chstat.got_xmit_done);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.xmit_fail = %lu\n",
devdata->chstat.xmit_fail);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.sent_enbdis = %lu\n",
devdata->chstat.sent_enbdis);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.sent_promisc = %lu\n",
devdata->chstat.sent_promisc);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.sent_post = %lu\n",
devdata->chstat.sent_post);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.sent_xmit = %lu\n",
devdata->chstat.sent_xmit);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.reject_count = %lu\n",
devdata->chstat.reject_count);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.extra_rcvbufs_sent = %lu\n",
devdata->chstat.extra_rcvbufs_sent);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcv0 = %lu\n", devdata->n_rcv0);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcv1 = %lu\n", devdata->n_rcv1);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcv2 = %lu\n", devdata->n_rcv2);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcvx = %lu\n", devdata->n_rcvx);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" num_rcvbuf_in_iovm = %d\n",
atomic_read(&devdata->num_rcvbuf_in_iovm));
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" alloc_failed_in_if_needed_cnt = %lu\n",
devdata->alloc_failed_in_if_needed_cnt);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" alloc_failed_in_repost_rtn_cnt = %lu\n",
devdata->alloc_failed_in_repost_rtn_cnt);
/* str_pos += scnprintf(vbuf + str_pos, len - str_pos,
* " inner_loop_limit_reached_cnt = %lu\n",
* devdata->inner_loop_limit_reached_cnt);
*/
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" found_repost_rcvbuf_cnt = %lu\n",
devdata->found_repost_rcvbuf_cnt);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" repost_found_skb_cnt = %lu\n",
devdata->repost_found_skb_cnt);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_repost_deficit = %lu\n",
devdata->n_repost_deficit);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" bad_rcv_buf = %lu\n",
devdata->bad_rcv_buf);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcv_packets_not_accepted = %lu\n",
devdata->n_rcv_packets_not_accepted);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" interrupts_rcvd = %llu\n",
devdata->interrupts_rcvd);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" interrupts_notme = %llu\n",
devdata->interrupts_notme);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" interrupts_disabled = %llu\n",
devdata->interrupts_disabled);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" busy_cnt = %llu\n",
devdata->busy_cnt);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" flow_control_upper_hits = %llu\n",
devdata->flow_control_upper_hits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" flow_control_lower_hits = %llu\n",
devdata->flow_control_lower_hits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" thread_wait_ms = %d\n",
devdata->thread_wait_ms);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" netif_queue = %s\n",
netif_queue_stopped(devdata->netdev) ?
"stopped" : "running");
}
bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos);
kfree(vbuf);
return bytes_read;
}
static ssize_t enable_ints_write(struct file *file, static ssize_t enable_ints_write(struct file *file,
const char __user *buffer, const char __user *buffer,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char buf[4]; /*
int i, new_value; * Don't want to break ABI here by having a debugfs
struct visornic_devdata *devdata; * file that no longer exists or is writable, so
* lets just make this a vestigual function
if (count >= ARRAY_SIZE(buf)) */
return -EINVAL;
buf[count] = '\0';
if (copy_from_user(buf, buffer, count))
return -EFAULT;
i = kstrtoint(buf, 10, &new_value);
if (i != 0)
return -EFAULT;
/* set all counts to new_value usually 0 */
for (i = 0; i < VISORNICSOPENMAX; i++) {
if (num_visornic_open[i]) {
devdata = netdev_priv(num_visornic_open[i]);
/* TODO update features bit in channel */
}
}
return count; return count;
} }
@ -760,13 +595,6 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout)
} }
} }
/* remove references from array */
for (i = 0; i < VISORNICSOPENMAX; i++)
if (num_visornic_open[i] == netdev) {
num_visornic_open[i] = NULL;
break;
}
return 0; return 0;
} }
@ -882,16 +710,6 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout)
return -EIO; return -EIO;
} }
/* find an open slot in the array to save off VisorNic references
* for debug
*/
for (i = 0; i < VISORNICSOPENMAX; i++) {
if (!num_visornic_open[i]) {
num_visornic_open[i] = netdev;
break;
}
}
return 0; return 0;
} }
@ -1642,6 +1460,155 @@ static const struct net_device_ops visornic_dev_ops = {
.ndo_set_rx_mode = visornic_set_multi, .ndo_set_rx_mode = visornic_set_multi,
}; };
/* DebugFS code */
static ssize_t info_debugfs_read(struct file *file, char __user *buf,
size_t len, loff_t *offset)
{
ssize_t bytes_read = 0;
int str_pos = 0;
struct visornic_devdata *devdata;
struct net_device *dev;
char *vbuf;
if (len > MAX_BUF)
len = MAX_BUF;
vbuf = kzalloc(len, GFP_KERNEL);
if (!vbuf)
return -ENOMEM;
/* for each vnic channel
* dump out channel specific data
*/
rcu_read_lock();
for_each_netdev_rcu(current->nsproxy->net_ns, dev) {
/*
* Only consider netdevs that are visornic, and are open
*/
if ((dev->netdev_ops != &visornic_dev_ops) ||
(!netif_queue_stopped(dev)))
continue;
devdata = netdev_priv(dev);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
"netdev = %s (0x%p), MAC Addr %pM\n",
dev->name,
dev,
dev->dev_addr);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
"VisorNic Dev Info = 0x%p\n", devdata);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" num_rcv_bufs = %d\n",
devdata->num_rcv_bufs);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" max_oustanding_next_xmits = %d\n",
devdata->max_outstanding_net_xmits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" upper_threshold_net_xmits = %d\n",
devdata->upper_threshold_net_xmits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" lower_threshold_net_xmits = %d\n",
devdata->lower_threshold_net_xmits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" queuefullmsg_logged = %d\n",
devdata->queuefullmsg_logged);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.got_rcv = %lu\n",
devdata->chstat.got_rcv);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.got_enbdisack = %lu\n",
devdata->chstat.got_enbdisack);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.got_xmit_done = %lu\n",
devdata->chstat.got_xmit_done);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.xmit_fail = %lu\n",
devdata->chstat.xmit_fail);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.sent_enbdis = %lu\n",
devdata->chstat.sent_enbdis);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.sent_promisc = %lu\n",
devdata->chstat.sent_promisc);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.sent_post = %lu\n",
devdata->chstat.sent_post);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.sent_xmit = %lu\n",
devdata->chstat.sent_xmit);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.reject_count = %lu\n",
devdata->chstat.reject_count);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" chstat.extra_rcvbufs_sent = %lu\n",
devdata->chstat.extra_rcvbufs_sent);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcv0 = %lu\n", devdata->n_rcv0);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcv1 = %lu\n", devdata->n_rcv1);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcv2 = %lu\n", devdata->n_rcv2);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcvx = %lu\n", devdata->n_rcvx);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" num_rcvbuf_in_iovm = %d\n",
atomic_read(&devdata->num_rcvbuf_in_iovm));
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" alloc_failed_in_if_needed_cnt = %lu\n",
devdata->alloc_failed_in_if_needed_cnt);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" alloc_failed_in_repost_rtn_cnt = %lu\n",
devdata->alloc_failed_in_repost_rtn_cnt);
/* str_pos += scnprintf(vbuf + str_pos, len - str_pos,
* " inner_loop_limit_reached_cnt = %lu\n",
* devdata->inner_loop_limit_reached_cnt);
*/
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" found_repost_rcvbuf_cnt = %lu\n",
devdata->found_repost_rcvbuf_cnt);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" repost_found_skb_cnt = %lu\n",
devdata->repost_found_skb_cnt);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_repost_deficit = %lu\n",
devdata->n_repost_deficit);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" bad_rcv_buf = %lu\n",
devdata->bad_rcv_buf);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" n_rcv_packets_not_accepted = %lu\n",
devdata->n_rcv_packets_not_accepted);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" interrupts_rcvd = %llu\n",
devdata->interrupts_rcvd);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" interrupts_notme = %llu\n",
devdata->interrupts_notme);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" interrupts_disabled = %llu\n",
devdata->interrupts_disabled);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" busy_cnt = %llu\n",
devdata->busy_cnt);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" flow_control_upper_hits = %llu\n",
devdata->flow_control_upper_hits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" flow_control_lower_hits = %llu\n",
devdata->flow_control_lower_hits);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" thread_wait_ms = %d\n",
devdata->thread_wait_ms);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
" netif_queue = %s\n",
netif_queue_stopped(devdata->netdev) ?
"stopped" : "running");
}
rcu_read_unlock();
bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos);
kfree(vbuf);
return bytes_read;
}
/** /**
* send_rcv_posts_if_needed * send_rcv_posts_if_needed
* @devdata: visornic device * @devdata: visornic device