summaryrefslogtreecommitdiffstats
path: root/drivers/hv
diff options
context:
space:
mode:
authorKimberly Brown <kimbrownkd@gmail.com>2019-03-19 00:04:01 -0400
committerSasha Levin <sashal@kernel.org>2019-03-20 23:55:56 -0400
commit46fc15487d02451448c11b83c4d086d87a6ad588 (patch)
tree65420705efeb4871aaa3a936e228bd8f8d8d6253 /drivers/hv
parent9e98c678c2d6ae3a17cb2de55d17f69dddaa231b (diff)
Drivers: hv: vmbus: Expose monitor data only when monitor pages are used
There are two methods for signaling the host: the monitor page mechanism and hypercalls. The monitor page mechanism is used by performance critical channels (storage, networking, etc.) because it provides improved throughput. However, latency is increased. Monitor pages are allocated to these channels. Monitor pages are not allocated to channels that do not use the monitor page mechanism. Therefore, these channels do not have a valid monitor id or valid monitor page data. In these cases, some of the "_show" functions return incorrect data. They return an invalid monitor id and data that is beyond the bounds of the hv_monitor_page array fields. The "channel->offermsg.monitor_allocated" value can be used to determine whether monitor pages have been allocated to a channel. Add "is_visible()" callback functions for the device-level and channel-level attribute groups. These functions will hide the monitor sysfs files when the monitor mechanism is not used. Remove ".default_attributes" from "vmbus_chan_attrs" and create a channel-level attribute group. These changes allow the new "is_visible()" callback function to be applied to the channel-level attributes. Call "sysfs_create_group()" in "vmbus_add_channel_kobj()" to create the channel's sysfs files. Add a new function, “vmbus_remove_channel_attr_group()”, and call it in "free_channel()" to remove the channel's sysfs files when the channel is closed. Signed-off-by: Kimberly Brown <kimbrownkd@gmail.com> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Michael Kelley <mikelley@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/hv')
-rw-r--r--drivers/hv/channel_mgmt.c1
-rw-r--r--drivers/hv/hyperv_vmbus.h2
-rw-r--r--drivers/hv/vmbus_drv.c77
3 files changed, 78 insertions, 2 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 62703b354d6d..d32cac501fc7 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -345,6 +345,7 @@ static struct vmbus_channel *alloc_channel(void)
345static void free_channel(struct vmbus_channel *channel) 345static void free_channel(struct vmbus_channel *channel)
346{ 346{
347 tasklet_kill(&channel->callback_event); 347 tasklet_kill(&channel->callback_event);
348 vmbus_remove_channel_attr_group(channel);
348 349
349 kobject_put(&channel->kobj); 350 kobject_put(&channel->kobj);
350} 351}
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index cb86b133eb4d..a94aab94e0b5 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -321,6 +321,8 @@ void vmbus_device_unregister(struct hv_device *device_obj);
321int vmbus_add_channel_kobj(struct hv_device *device_obj, 321int vmbus_add_channel_kobj(struct hv_device *device_obj,
322 struct vmbus_channel *channel); 322 struct vmbus_channel *channel);
323 323
324void vmbus_remove_channel_attr_group(struct vmbus_channel *channel);
325
324struct vmbus_channel *relid2channel(u32 relid); 326struct vmbus_channel *relid2channel(u32 relid);
325 327
326void vmbus_free_channels(void); 328void vmbus_free_channels(void);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 000b53e5a17a..b23aea86d029 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -630,7 +630,36 @@ static struct attribute *vmbus_dev_attrs[] = {
630 &dev_attr_driver_override.attr, 630 &dev_attr_driver_override.attr,
631 NULL, 631 NULL,
632}; 632};
633ATTRIBUTE_GROUPS(vmbus_dev); 633
634/*
635 * Device-level attribute_group callback function. Returns the permission for
636 * each attribute, and returns 0 if an attribute is not visible.
637 */
638static umode_t vmbus_dev_attr_is_visible(struct kobject *kobj,
639 struct attribute *attr, int idx)
640{
641 struct device *dev = kobj_to_dev(kobj);
642 const struct hv_device *hv_dev = device_to_hv_device(dev);
643
644 /* Hide the monitor attributes if the monitor mechanism is not used. */
645 if (!hv_dev->channel->offermsg.monitor_allocated &&
646 (attr == &dev_attr_monitor_id.attr ||
647 attr == &dev_attr_server_monitor_pending.attr ||
648 attr == &dev_attr_client_monitor_pending.attr ||
649 attr == &dev_attr_server_monitor_latency.attr ||
650 attr == &dev_attr_client_monitor_latency.attr ||
651 attr == &dev_attr_server_monitor_conn_id.attr ||
652 attr == &dev_attr_client_monitor_conn_id.attr))
653 return 0;
654
655 return attr->mode;
656}
657
658static const struct attribute_group vmbus_dev_group = {
659 .attrs = vmbus_dev_attrs,
660 .is_visible = vmbus_dev_attr_is_visible
661};
662__ATTRIBUTE_GROUPS(vmbus_dev);
634 663
635/* 664/*
636 * vmbus_uevent - add uevent for our device 665 * vmbus_uevent - add uevent for our device
@@ -1550,10 +1579,34 @@ static struct attribute *vmbus_chan_attrs[] = {
1550 NULL 1579 NULL
1551}; 1580};
1552 1581
1582/*
1583 * Channel-level attribute_group callback function. Returns the permission for
1584 * each attribute, and returns 0 if an attribute is not visible.
1585 */
1586static umode_t vmbus_chan_attr_is_visible(struct kobject *kobj,
1587 struct attribute *attr, int idx)
1588{
1589 const struct vmbus_channel *channel =
1590 container_of(kobj, struct vmbus_channel, kobj);
1591
1592 /* Hide the monitor attributes if the monitor mechanism is not used. */
1593 if (!channel->offermsg.monitor_allocated &&
1594 (attr == &chan_attr_pending.attr ||
1595 attr == &chan_attr_latency.attr ||
1596 attr == &chan_attr_monitor_id.attr))
1597 return 0;
1598
1599 return attr->mode;
1600}
1601
1602static struct attribute_group vmbus_chan_group = {
1603 .attrs = vmbus_chan_attrs,
1604 .is_visible = vmbus_chan_attr_is_visible
1605};
1606
1553static struct kobj_type vmbus_chan_ktype = { 1607static struct kobj_type vmbus_chan_ktype = {
1554 .sysfs_ops = &vmbus_chan_sysfs_ops, 1608 .sysfs_ops = &vmbus_chan_sysfs_ops,
1555 .release = vmbus_chan_release, 1609 .release = vmbus_chan_release,
1556 .default_attrs = vmbus_chan_attrs,
1557}; 1610};
1558 1611
1559/* 1612/*
@@ -1561,6 +1614,7 @@ static struct kobj_type vmbus_chan_ktype = {
1561 */ 1614 */
1562int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel) 1615int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
1563{ 1616{
1617 const struct device *device = &dev->device;
1564 struct kobject *kobj = &channel->kobj; 1618 struct kobject *kobj = &channel->kobj;
1565 u32 relid = channel->offermsg.child_relid; 1619 u32 relid = channel->offermsg.child_relid;
1566 int ret; 1620 int ret;
@@ -1571,12 +1625,31 @@ int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
1571 if (ret) 1625 if (ret)
1572 return ret; 1626 return ret;
1573 1627
1628 ret = sysfs_create_group(kobj, &vmbus_chan_group);
1629
1630 if (ret) {
1631 /*
1632 * The calling functions' error handling paths will cleanup the
1633 * empty channel directory.
1634 */
1635 dev_err(device, "Unable to set up channel sysfs files\n");
1636 return ret;
1637 }
1638
1574 kobject_uevent(kobj, KOBJ_ADD); 1639 kobject_uevent(kobj, KOBJ_ADD);
1575 1640
1576 return 0; 1641 return 0;
1577} 1642}
1578 1643
1579/* 1644/*
1645 * vmbus_remove_channel_attr_group - remove the channel's attribute group
1646 */
1647void vmbus_remove_channel_attr_group(struct vmbus_channel *channel)
1648{
1649 sysfs_remove_group(&channel->kobj, &vmbus_chan_group);
1650}
1651
1652/*
1580 * vmbus_device_create - Creates and registers a new child device 1653 * vmbus_device_create - Creates and registers a new child device
1581 * on the vmbus. 1654 * on the vmbus.
1582 */ 1655 */