Skip to content

Commit c2e5df6

Browse files
shemmingergregkh
authored andcommitted
vmbus: add per-channel sysfs info
This extends existing vmbus related sysfs structure to provide per-channel state information. This is useful when diagnosing issues with multiple queues in networking and storage. The existing sysfs only displayed information about the primary channel. The one place it reported multiple channels was the channel_vp_mapping file which violated the sysfs convention of one value per file. Signed-off-by: Stephen Hemminger <[email protected]> Signed-off-by: K. Y. Srinivasan <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 876a1b0 commit c2e5df6

File tree

5 files changed

+246
-13
lines changed

5 files changed

+246
-13
lines changed

Documentation/ABI/stable/sysfs-bus-vmbus

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,59 @@ KernelVersion: 4.5
4141
Contact: K. Y. Srinivasan <[email protected]>
4242
Description: The 16 bit vendor ID of the device
4343
Users: tools/hv/lsvmbus and user level RDMA libraries
44+
45+
What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/cpu
46+
Date: September. 2017
47+
KernelVersion: 4.14
48+
Contact: Stephen Hemminger <[email protected]>
49+
Description: VCPU (sub)channel is affinitized to
50+
Users: tools/hv/lsvmbus and other debuggig tools
51+
52+
What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/cpu
53+
Date: September. 2017
54+
KernelVersion: 4.14
55+
Contact: Stephen Hemminger <[email protected]>
56+
Description: VCPU (sub)channel is affinitized to
57+
Users: tools/hv/lsvmbus and other debuggig tools
58+
59+
What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/in_mask
60+
Date: September. 2017
61+
KernelVersion: 4.14
62+
Contact: Stephen Hemminger <[email protected]>
63+
Description: Inbound channel signaling state
64+
Users: Debuggig tools
65+
66+
What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/latency
67+
Date: September. 2017
68+
KernelVersion: 4.14
69+
Contact: Stephen Hemminger <[email protected]>
70+
Description: Channel signaling latency
71+
Users: Debuggig tools
72+
73+
What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/out_mask
74+
Date: September. 2017
75+
KernelVersion: 4.14
76+
Contact: Stephen Hemminger <[email protected]>
77+
Description: Outbound channel signaling state
78+
Users: Debuggig tools
79+
80+
What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/pending
81+
Date: September. 2017
82+
KernelVersion: 4.14
83+
Contact: Stephen Hemminger <[email protected]>
84+
Description: Channel interrupt pending state
85+
Users: Debuggig tools
86+
87+
What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/read_avail
88+
Date: September. 2017
89+
KernelVersion: 4.14
90+
Contact: Stephen Hemminger <[email protected]>
91+
Description: Bytes availabble to read
92+
Users: Debuggig tools
93+
94+
What: /sys/bus/vmbus/devices/vmbus_*/channels/relid/write_avail
95+
Date: September. 2017
96+
KernelVersion: 4.14
97+
Contact: Stephen Hemminger <[email protected]>
98+
Description: Bytes availabble to write
99+
Users: Debuggig tools

drivers/hv/channel_mgmt.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ static void free_channel(struct vmbus_channel *channel)
350350
{
351351
tasklet_kill(&channel->callback_event);
352352

353-
kfree_rcu(channel, rcu);
353+
kobject_put(&channel->kobj);
354354
}
355355

356356
static void percpu_channel_enq(void *arg)
@@ -513,6 +513,14 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
513513
newchannel->state = CHANNEL_OPEN_STATE;
514514

515515
if (!fnew) {
516+
struct hv_device *dev
517+
= newchannel->primary_channel->device_obj;
518+
519+
if (vmbus_add_channel_kobj(dev, newchannel)) {
520+
atomic_dec(&vmbus_connection.offer_in_progress);
521+
goto err_free_chan;
522+
}
523+
516524
if (channel->sc_creation_callback != NULL)
517525
channel->sc_creation_callback(newchannel);
518526
return;

drivers/hv/hyperv_vmbus.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@ struct hv_device *vmbus_device_create(const uuid_le *type,
373373

374374
int vmbus_device_register(struct hv_device *child_device_obj);
375375
void vmbus_device_unregister(struct hv_device *device_obj);
376+
int vmbus_add_channel_kobj(struct hv_device *device_obj,
377+
struct vmbus_channel *channel);
376378

377379
struct vmbus_channel *relid2channel(u32 relid);
378380

drivers/hv/vmbus_drv.c

Lines changed: 173 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,28 +107,30 @@ static void print_alias_name(struct hv_device *hv_dev, char *alias_name)
107107
sprintf(&alias_name[i], "%02x", hv_dev->dev_type.b[i/2]);
108108
}
109109

110-
static u8 channel_monitor_group(struct vmbus_channel *channel)
110+
static u8 channel_monitor_group(const struct vmbus_channel *channel)
111111
{
112112
return (u8)channel->offermsg.monitorid / 32;
113113
}
114114

115-
static u8 channel_monitor_offset(struct vmbus_channel *channel)
115+
static u8 channel_monitor_offset(const struct vmbus_channel *channel)
116116
{
117117
return (u8)channel->offermsg.monitorid % 32;
118118
}
119119

120-
static u32 channel_pending(struct vmbus_channel *channel,
121-
struct hv_monitor_page *monitor_page)
120+
static u32 channel_pending(const struct vmbus_channel *channel,
121+
const struct hv_monitor_page *monitor_page)
122122
{
123123
u8 monitor_group = channel_monitor_group(channel);
124+
124125
return monitor_page->trigger_group[monitor_group].pending;
125126
}
126127

127-
static u32 channel_latency(struct vmbus_channel *channel,
128-
struct hv_monitor_page *monitor_page)
128+
static u32 channel_latency(const struct vmbus_channel *channel,
129+
const struct hv_monitor_page *monitor_page)
129130
{
130131
u8 monitor_group = channel_monitor_group(channel);
131132
u8 monitor_offset = channel_monitor_offset(channel);
133+
132134
return monitor_page->latency[monitor_group][monitor_offset];
133135
}
134136

@@ -1134,6 +1136,145 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver)
11341136
}
11351137
EXPORT_SYMBOL_GPL(vmbus_driver_unregister);
11361138

1139+
1140+
/*
1141+
* Called when last reference to channel is gone.
1142+
*/
1143+
static void vmbus_chan_release(struct kobject *kobj)
1144+
{
1145+
struct vmbus_channel *channel
1146+
= container_of(kobj, struct vmbus_channel, kobj);
1147+
1148+
kfree_rcu(channel, rcu);
1149+
}
1150+
1151+
struct vmbus_chan_attribute {
1152+
struct attribute attr;
1153+
ssize_t (*show)(const struct vmbus_channel *chan, char *buf);
1154+
ssize_t (*store)(struct vmbus_channel *chan,
1155+
const char *buf, size_t count);
1156+
};
1157+
#define VMBUS_CHAN_ATTR(_name, _mode, _show, _store) \
1158+
struct vmbus_chan_attribute chan_attr_##_name \
1159+
= __ATTR(_name, _mode, _show, _store)
1160+
#define VMBUS_CHAN_ATTR_RW(_name) \
1161+
struct vmbus_chan_attribute chan_attr_##_name = __ATTR_RW(_name)
1162+
#define VMBUS_CHAN_ATTR_RO(_name) \
1163+
struct vmbus_chan_attribute chan_attr_##_name = __ATTR_RO(_name)
1164+
#define VMBUS_CHAN_ATTR_WO(_name) \
1165+
struct vmbus_chan_attribute chan_attr_##_name = __ATTR_WO(_name)
1166+
1167+
static ssize_t vmbus_chan_attr_show(struct kobject *kobj,
1168+
struct attribute *attr, char *buf)
1169+
{
1170+
const struct vmbus_chan_attribute *attribute
1171+
= container_of(attr, struct vmbus_chan_attribute, attr);
1172+
const struct vmbus_channel *chan
1173+
= container_of(kobj, struct vmbus_channel, kobj);
1174+
1175+
if (!attribute->show)
1176+
return -EIO;
1177+
1178+
return attribute->show(chan, buf);
1179+
}
1180+
1181+
static const struct sysfs_ops vmbus_chan_sysfs_ops = {
1182+
.show = vmbus_chan_attr_show,
1183+
};
1184+
1185+
static ssize_t out_mask_show(const struct vmbus_channel *channel, char *buf)
1186+
{
1187+
const struct hv_ring_buffer_info *rbi = &channel->outbound;
1188+
1189+
return sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask);
1190+
}
1191+
VMBUS_CHAN_ATTR_RO(out_mask);
1192+
1193+
static ssize_t in_mask_show(const struct vmbus_channel *channel, char *buf)
1194+
{
1195+
const struct hv_ring_buffer_info *rbi = &channel->inbound;
1196+
1197+
return sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask);
1198+
}
1199+
VMBUS_CHAN_ATTR_RO(in_mask);
1200+
1201+
static ssize_t read_avail_show(const struct vmbus_channel *channel, char *buf)
1202+
{
1203+
const struct hv_ring_buffer_info *rbi = &channel->inbound;
1204+
1205+
return sprintf(buf, "%u\n", hv_get_bytes_to_read(rbi));
1206+
}
1207+
VMBUS_CHAN_ATTR_RO(read_avail);
1208+
1209+
static ssize_t write_avail_show(const struct vmbus_channel *channel, char *buf)
1210+
{
1211+
const struct hv_ring_buffer_info *rbi = &channel->outbound;
1212+
1213+
return sprintf(buf, "%u\n", hv_get_bytes_to_write(rbi));
1214+
}
1215+
VMBUS_CHAN_ATTR_RO(write_avail);
1216+
1217+
static ssize_t show_target_cpu(const struct vmbus_channel *channel, char *buf)
1218+
{
1219+
return sprintf(buf, "%u\n", channel->target_cpu);
1220+
}
1221+
VMBUS_CHAN_ATTR(cpu, S_IRUGO, show_target_cpu, NULL);
1222+
1223+
static ssize_t channel_pending_show(const struct vmbus_channel *channel,
1224+
char *buf)
1225+
{
1226+
return sprintf(buf, "%d\n",
1227+
channel_pending(channel,
1228+
vmbus_connection.monitor_pages[1]));
1229+
}
1230+
VMBUS_CHAN_ATTR(pending, S_IRUGO, channel_pending_show, NULL);
1231+
1232+
static ssize_t channel_latency_show(const struct vmbus_channel *channel,
1233+
char *buf)
1234+
{
1235+
return sprintf(buf, "%d\n",
1236+
channel_latency(channel,
1237+
vmbus_connection.monitor_pages[1]));
1238+
}
1239+
VMBUS_CHAN_ATTR(latency, S_IRUGO, channel_latency_show, NULL);
1240+
1241+
static struct attribute *vmbus_chan_attrs[] = {
1242+
&chan_attr_out_mask.attr,
1243+
&chan_attr_in_mask.attr,
1244+
&chan_attr_read_avail.attr,
1245+
&chan_attr_write_avail.attr,
1246+
&chan_attr_cpu.attr,
1247+
&chan_attr_pending.attr,
1248+
&chan_attr_latency.attr,
1249+
NULL
1250+
};
1251+
1252+
static struct kobj_type vmbus_chan_ktype = {
1253+
.sysfs_ops = &vmbus_chan_sysfs_ops,
1254+
.release = vmbus_chan_release,
1255+
.default_attrs = vmbus_chan_attrs,
1256+
};
1257+
1258+
/*
1259+
* vmbus_add_channel_kobj - setup a sub-directory under device/channels
1260+
*/
1261+
int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
1262+
{
1263+
struct kobject *kobj = &channel->kobj;
1264+
u32 relid = channel->offermsg.child_relid;
1265+
int ret;
1266+
1267+
kobj->kset = dev->channels_kset;
1268+
ret = kobject_init_and_add(kobj, &vmbus_chan_ktype, NULL,
1269+
"%u", relid);
1270+
if (ret)
1271+
return ret;
1272+
1273+
kobject_uevent(kobj, KOBJ_ADD);
1274+
1275+
return 0;
1276+
}
1277+
11371278
/*
11381279
* vmbus_device_create - Creates and registers a new child device
11391280
* on the vmbus.
@@ -1165,7 +1306,8 @@ struct hv_device *vmbus_device_create(const uuid_le *type,
11651306
*/
11661307
int vmbus_device_register(struct hv_device *child_device_obj)
11671308
{
1168-
int ret = 0;
1309+
struct kobject *kobj = &child_device_obj->device.kobj;
1310+
int ret;
11691311

11701312
dev_set_name(&child_device_obj->device, "%pUl",
11711313
child_device_obj->channel->offermsg.offer.if_instance.b);
@@ -1179,13 +1321,32 @@ int vmbus_device_register(struct hv_device *child_device_obj)
11791321
* binding...which will eventually call vmbus_match() and vmbus_probe()
11801322
*/
11811323
ret = device_register(&child_device_obj->device);
1182-
1183-
if (ret)
1324+
if (ret) {
11841325
pr_err("Unable to register child device\n");
1185-
else
1186-
pr_debug("child device %s registered\n",
1187-
dev_name(&child_device_obj->device));
1326+
return ret;
1327+
}
1328+
1329+
child_device_obj->channels_kset = kset_create_and_add("channels",
1330+
NULL, kobj);
1331+
if (!child_device_obj->channels_kset) {
1332+
ret = -ENOMEM;
1333+
goto err_dev_unregister;
1334+
}
1335+
1336+
ret = vmbus_add_channel_kobj(child_device_obj,
1337+
child_device_obj->channel);
1338+
if (ret) {
1339+
pr_err("Unable to register primary channeln");
1340+
goto err_kset_unregister;
1341+
}
1342+
1343+
return 0;
1344+
1345+
err_kset_unregister:
1346+
kset_unregister(child_device_obj->channels_kset);
11881347

1348+
err_dev_unregister:
1349+
device_unregister(&child_device_obj->device);
11891350
return ret;
11901351
}
11911352

include/linux/hyperv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,11 @@ struct vmbus_channel {
828828
*/
829829
struct rcu_head rcu;
830830

831+
/*
832+
* For sysfs per-channel properties.
833+
*/
834+
struct kobject kobj;
835+
831836
/*
832837
* For performance critical channels (storage, networking
833838
* etc,), Hyper-V has a mechanism to enhance the throughput
@@ -1089,6 +1094,7 @@ struct hv_device {
10891094
struct device device;
10901095

10911096
struct vmbus_channel *channel;
1097+
struct kset *channels_kset;
10921098
};
10931099

10941100

0 commit comments

Comments
 (0)