]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Drivers: hv: vmbus: Expose monitor data only when monitor pages are used
authorKimberly Brown <kimbrownkd@gmail.com>
Tue, 19 Mar 2019 04:04:01 +0000 (00:04 -0400)
committerSasha Levin <sashal@kernel.org>
Thu, 21 Mar 2019 03:55:56 +0000 (23:55 -0400)
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>
Documentation/ABI/stable/sysfs-bus-vmbus
drivers/hv/channel_mgmt.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c

index 826689dcc2e67370102d73eae9c359e9547df710..8e8d167eca3145c049e44a9d9b8b0bdbe17c6838 100644 (file)
@@ -81,7 +81,9 @@ What:         /sys/bus/vmbus/devices/<UUID>/channels/<N>/latency
 Date:          September. 2017
 KernelVersion: 4.14
 Contact:       Stephen Hemminger <sthemmin@microsoft.com>
-Description:   Channel signaling latency
+Description:   Channel signaling latency. This file is available only for
+               performance critical channels (storage, network, etc.) that use
+               the monitor page mechanism.
 Users:         Debugging tools
 
 What:          /sys/bus/vmbus/devices/<UUID>/channels/<N>/out_mask
@@ -95,7 +97,9 @@ What:         /sys/bus/vmbus/devices/<UUID>/channels/<N>/pending
 Date:          September. 2017
 KernelVersion: 4.14
 Contact:       Stephen Hemminger <sthemmin@microsoft.com>
-Description:   Channel interrupt pending state
+Description:   Channel interrupt pending state. This file is available only for
+               performance critical channels (storage, network, etc.) that use
+               the monitor page mechanism.
 Users:         Debugging tools
 
 What:          /sys/bus/vmbus/devices/<UUID>/channels/<N>/read_avail
@@ -137,7 +141,9 @@ What:               /sys/bus/vmbus/devices/<UUID>/channels/<N>/monitor_id
 Date:          January. 2018
 KernelVersion: 4.16
 Contact:       Stephen Hemminger <sthemmin@microsoft.com>
-Description:   Monitor bit associated with channel
+Description:   Monitor bit associated with channel. This file is available only
+               for performance critical channels (storage, network, etc.) that
+               use the monitor page mechanism.
 Users:         Debugging tools and userspace drivers
 
 What:          /sys/bus/vmbus/devices/<UUID>/channels/<N>/ring
index 62703b354d6dfba9b63f0358c8972bd881397300..d32cac501fc72b17e7521e181485548fb04771bc 100644 (file)
@@ -345,6 +345,7 @@ static struct vmbus_channel *alloc_channel(void)
 static void free_channel(struct vmbus_channel *channel)
 {
        tasklet_kill(&channel->callback_event);
+       vmbus_remove_channel_attr_group(channel);
 
        kobject_put(&channel->kobj);
 }
index cb86b133eb4d945d6a1811362afc8923e666f6ef..a94aab94e0b54fa4a719a3351556e55603db9d22 100644 (file)
@@ -321,6 +321,8 @@ void vmbus_device_unregister(struct hv_device *device_obj);
 int vmbus_add_channel_kobj(struct hv_device *device_obj,
                           struct vmbus_channel *channel);
 
+void vmbus_remove_channel_attr_group(struct vmbus_channel *channel);
+
 struct vmbus_channel *relid2channel(u32 relid);
 
 void vmbus_free_channels(void);
index 000b53e5a17a55c8c20add4d1036cac250f40c80..b23aea86d029eb6791eadf860552abca1c274ae7 100644 (file)
@@ -630,7 +630,36 @@ static struct attribute *vmbus_dev_attrs[] = {
        &dev_attr_driver_override.attr,
        NULL,
 };
-ATTRIBUTE_GROUPS(vmbus_dev);
+
+/*
+ * Device-level attribute_group callback function. Returns the permission for
+ * each attribute, and returns 0 if an attribute is not visible.
+ */
+static umode_t vmbus_dev_attr_is_visible(struct kobject *kobj,
+                                        struct attribute *attr, int idx)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       const struct hv_device *hv_dev = device_to_hv_device(dev);
+
+       /* Hide the monitor attributes if the monitor mechanism is not used. */
+       if (!hv_dev->channel->offermsg.monitor_allocated &&
+           (attr == &dev_attr_monitor_id.attr ||
+            attr == &dev_attr_server_monitor_pending.attr ||
+            attr == &dev_attr_client_monitor_pending.attr ||
+            attr == &dev_attr_server_monitor_latency.attr ||
+            attr == &dev_attr_client_monitor_latency.attr ||
+            attr == &dev_attr_server_monitor_conn_id.attr ||
+            attr == &dev_attr_client_monitor_conn_id.attr))
+               return 0;
+
+       return attr->mode;
+}
+
+static const struct attribute_group vmbus_dev_group = {
+       .attrs = vmbus_dev_attrs,
+       .is_visible = vmbus_dev_attr_is_visible
+};
+__ATTRIBUTE_GROUPS(vmbus_dev);
 
 /*
  * vmbus_uevent - add uevent for our device
@@ -1550,10 +1579,34 @@ static struct attribute *vmbus_chan_attrs[] = {
        NULL
 };
 
+/*
+ * Channel-level attribute_group callback function. Returns the permission for
+ * each attribute, and returns 0 if an attribute is not visible.
+ */
+static umode_t vmbus_chan_attr_is_visible(struct kobject *kobj,
+                                         struct attribute *attr, int idx)
+{
+       const struct vmbus_channel *channel =
+               container_of(kobj, struct vmbus_channel, kobj);
+
+       /* Hide the monitor attributes if the monitor mechanism is not used. */
+       if (!channel->offermsg.monitor_allocated &&
+           (attr == &chan_attr_pending.attr ||
+            attr == &chan_attr_latency.attr ||
+            attr == &chan_attr_monitor_id.attr))
+               return 0;
+
+       return attr->mode;
+}
+
+static struct attribute_group vmbus_chan_group = {
+       .attrs = vmbus_chan_attrs,
+       .is_visible = vmbus_chan_attr_is_visible
+};
+
 static struct kobj_type vmbus_chan_ktype = {
        .sysfs_ops = &vmbus_chan_sysfs_ops,
        .release = vmbus_chan_release,
-       .default_attrs = vmbus_chan_attrs,
 };
 
 /*
@@ -1561,6 +1614,7 @@ static struct kobj_type vmbus_chan_ktype = {
  */
 int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
 {
+       const struct device *device = &dev->device;
        struct kobject *kobj = &channel->kobj;
        u32 relid = channel->offermsg.child_relid;
        int ret;
@@ -1571,11 +1625,30 @@ int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
        if (ret)
                return ret;
 
+       ret = sysfs_create_group(kobj, &vmbus_chan_group);
+
+       if (ret) {
+               /*
+                * The calling functions' error handling paths will cleanup the
+                * empty channel directory.
+                */
+               dev_err(device, "Unable to set up channel sysfs files\n");
+               return ret;
+       }
+
        kobject_uevent(kobj, KOBJ_ADD);
 
        return 0;
 }
 
+/*
+ * vmbus_remove_channel_attr_group - remove the channel's attribute group
+ */
+void vmbus_remove_channel_attr_group(struct vmbus_channel *channel)
+{
+       sysfs_remove_group(&channel->kobj, &vmbus_chan_group);
+}
+
 /*
  * vmbus_device_create - Creates and registers a new child device
  * on the vmbus.