Commit 5450a5f4 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'hyperv-fixes-signed' of...

Merge tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux into char-misc-linus

Sasha writes:

Three fixes:

 1. Fix for a race condition in the hyper-v ringbuffer code by Kimberly
Brown.
 2. Fix to show monitor data only when monitor pages are actually
allocated, also by Kimberly Brown.
 3. Fix cpu reference counting in the vmbus code by Dexuan Cui.

* tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  Drivers: hv: vmbus: Remove the undesired put_cpu_ptr() in hv_synic_cleanup()
  Drivers: hv: vmbus: Fix race condition with new ring_buffer_info mutex
  Drivers: hv: vmbus: Set ring_info field to 0 and remove memset
  Drivers: hv: vmbus: Refactor chan->state if statement
  Drivers: hv: vmbus: Expose monitor data only when monitor pages are used
parents 085b7755 a0033bd1
...@@ -81,7 +81,9 @@ What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/latency ...@@ -81,7 +81,9 @@ What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/latency
Date: September. 2017 Date: September. 2017
KernelVersion: 4.14 KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com> 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 Users: Debugging tools
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/out_mask What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/out_mask
...@@ -95,7 +97,9 @@ What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/pending ...@@ -95,7 +97,9 @@ What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/pending
Date: September. 2017 Date: September. 2017
KernelVersion: 4.14 KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com> 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 Users: Debugging tools
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/read_avail What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/read_avail
...@@ -137,7 +141,9 @@ What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/monitor_id ...@@ -137,7 +141,9 @@ What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/monitor_id
Date: January. 2018 Date: January. 2018
KernelVersion: 4.16 KernelVersion: 4.16
Contact: Stephen Hemminger <sthemmin@microsoft.com> 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 Users: Debugging tools and userspace drivers
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/ring What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/ring
......
...@@ -336,6 +336,8 @@ static struct vmbus_channel *alloc_channel(void) ...@@ -336,6 +336,8 @@ static struct vmbus_channel *alloc_channel(void)
tasklet_init(&channel->callback_event, tasklet_init(&channel->callback_event,
vmbus_on_event, (unsigned long)channel); vmbus_on_event, (unsigned long)channel);
hv_ringbuffer_pre_init(channel);
return channel; return channel;
} }
...@@ -345,6 +347,7 @@ static struct vmbus_channel *alloc_channel(void) ...@@ -345,6 +347,7 @@ static struct vmbus_channel *alloc_channel(void)
static void free_channel(struct vmbus_channel *channel) static void free_channel(struct vmbus_channel *channel)
{ {
tasklet_kill(&channel->callback_event); tasklet_kill(&channel->callback_event);
vmbus_remove_channel_attr_group(channel);
kobject_put(&channel->kobj); kobject_put(&channel->kobj);
} }
......
...@@ -408,7 +408,6 @@ int hv_synic_cleanup(unsigned int cpu) ...@@ -408,7 +408,6 @@ int hv_synic_cleanup(unsigned int cpu)
clockevents_unbind_device(hv_cpu->clk_evt, cpu); clockevents_unbind_device(hv_cpu->clk_evt, cpu);
hv_ce_shutdown(hv_cpu->clk_evt); hv_ce_shutdown(hv_cpu->clk_evt);
put_cpu_ptr(hv_cpu);
} }
hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64); hv_get_synint_state(VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
......
...@@ -193,6 +193,7 @@ extern void hv_synic_clockevents_cleanup(void); ...@@ -193,6 +193,7 @@ extern void hv_synic_clockevents_cleanup(void);
/* Interface */ /* Interface */
void hv_ringbuffer_pre_init(struct vmbus_channel *channel);
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
struct page *pages, u32 pagecnt); struct page *pages, u32 pagecnt);
...@@ -321,6 +322,8 @@ void vmbus_device_unregister(struct hv_device *device_obj); ...@@ -321,6 +322,8 @@ void vmbus_device_unregister(struct hv_device *device_obj);
int vmbus_add_channel_kobj(struct hv_device *device_obj, int vmbus_add_channel_kobj(struct hv_device *device_obj,
struct vmbus_channel *channel); struct vmbus_channel *channel);
void vmbus_remove_channel_attr_group(struct vmbus_channel *channel);
struct vmbus_channel *relid2channel(u32 relid); struct vmbus_channel *relid2channel(u32 relid);
void vmbus_free_channels(void); void vmbus_free_channels(void);
......
...@@ -166,14 +166,18 @@ hv_get_ringbuffer_availbytes(const struct hv_ring_buffer_info *rbi, ...@@ -166,14 +166,18 @@ hv_get_ringbuffer_availbytes(const struct hv_ring_buffer_info *rbi,
} }
/* Get various debug metrics for the specified ring buffer. */ /* Get various debug metrics for the specified ring buffer. */
int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, int hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info) struct hv_ring_buffer_debug_info *debug_info)
{ {
u32 bytes_avail_towrite; u32 bytes_avail_towrite;
u32 bytes_avail_toread; u32 bytes_avail_toread;
if (!ring_info->ring_buffer) mutex_lock(&ring_info->ring_buffer_mutex);
if (!ring_info->ring_buffer) {
mutex_unlock(&ring_info->ring_buffer_mutex);
return -EINVAL; return -EINVAL;
}
hv_get_ringbuffer_availbytes(ring_info, hv_get_ringbuffer_availbytes(ring_info,
&bytes_avail_toread, &bytes_avail_toread,
...@@ -184,10 +188,19 @@ int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, ...@@ -184,10 +188,19 @@ int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
debug_info->current_write_index = ring_info->ring_buffer->write_index; debug_info->current_write_index = ring_info->ring_buffer->write_index;
debug_info->current_interrupt_mask debug_info->current_interrupt_mask
= ring_info->ring_buffer->interrupt_mask; = ring_info->ring_buffer->interrupt_mask;
mutex_unlock(&ring_info->ring_buffer_mutex);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo); EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo);
/* Initialize a channel's ring buffer info mutex locks */
void hv_ringbuffer_pre_init(struct vmbus_channel *channel)
{
mutex_init(&channel->inbound.ring_buffer_mutex);
mutex_init(&channel->outbound.ring_buffer_mutex);
}
/* Initialize the ring buffer. */ /* Initialize the ring buffer. */
int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
struct page *pages, u32 page_cnt) struct page *pages, u32 page_cnt)
...@@ -197,8 +210,6 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ...@@ -197,8 +210,6 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE)); BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE));
memset(ring_info, 0, sizeof(struct hv_ring_buffer_info));
/* /*
* First page holds struct hv_ring_buffer, do wraparound mapping for * First page holds struct hv_ring_buffer, do wraparound mapping for
* the rest. * the rest.
...@@ -232,6 +243,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ...@@ -232,6 +243,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
reciprocal_value(ring_info->ring_size / 10); reciprocal_value(ring_info->ring_size / 10);
ring_info->ring_datasize = ring_info->ring_size - ring_info->ring_datasize = ring_info->ring_size -
sizeof(struct hv_ring_buffer); sizeof(struct hv_ring_buffer);
ring_info->priv_read_index = 0;
spin_lock_init(&ring_info->ring_lock); spin_lock_init(&ring_info->ring_lock);
...@@ -241,8 +253,10 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ...@@ -241,8 +253,10 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
/* Cleanup the ring buffer. */ /* Cleanup the ring buffer. */
void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
{ {
mutex_lock(&ring_info->ring_buffer_mutex);
vunmap(ring_info->ring_buffer); vunmap(ring_info->ring_buffer);
ring_info->ring_buffer = NULL; ring_info->ring_buffer = NULL;
mutex_unlock(&ring_info->ring_buffer_mutex);
} }
/* Write to the ring buffer. */ /* Write to the ring buffer. */
......
...@@ -630,7 +630,36 @@ static struct attribute *vmbus_dev_attrs[] = { ...@@ -630,7 +630,36 @@ static struct attribute *vmbus_dev_attrs[] = {
&dev_attr_driver_override.attr, &dev_attr_driver_override.attr,
NULL, 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 * vmbus_uevent - add uevent for our device
...@@ -1381,7 +1410,7 @@ static void vmbus_chan_release(struct kobject *kobj) ...@@ -1381,7 +1410,7 @@ static void vmbus_chan_release(struct kobject *kobj)
struct vmbus_chan_attribute { struct vmbus_chan_attribute {
struct attribute attr; struct attribute attr;
ssize_t (*show)(const struct vmbus_channel *chan, char *buf); ssize_t (*show)(struct vmbus_channel *chan, char *buf);
ssize_t (*store)(struct vmbus_channel *chan, ssize_t (*store)(struct vmbus_channel *chan,
const char *buf, size_t count); const char *buf, size_t count);
}; };
...@@ -1400,15 +1429,12 @@ static ssize_t vmbus_chan_attr_show(struct kobject *kobj, ...@@ -1400,15 +1429,12 @@ static ssize_t vmbus_chan_attr_show(struct kobject *kobj,
{ {
const struct vmbus_chan_attribute *attribute const struct vmbus_chan_attribute *attribute
= container_of(attr, struct vmbus_chan_attribute, attr); = container_of(attr, struct vmbus_chan_attribute, attr);
const struct vmbus_channel *chan struct vmbus_channel *chan
= container_of(kobj, struct vmbus_channel, kobj); = container_of(kobj, struct vmbus_channel, kobj);
if (!attribute->show) if (!attribute->show)
return -EIO; return -EIO;
if (chan->state != CHANNEL_OPENED_STATE)
return -EINVAL;
return attribute->show(chan, buf); return attribute->show(chan, buf);
} }
...@@ -1416,45 +1442,81 @@ static const struct sysfs_ops vmbus_chan_sysfs_ops = { ...@@ -1416,45 +1442,81 @@ static const struct sysfs_ops vmbus_chan_sysfs_ops = {
.show = vmbus_chan_attr_show, .show = vmbus_chan_attr_show,
}; };
static ssize_t out_mask_show(const struct vmbus_channel *channel, char *buf) static ssize_t out_mask_show(struct vmbus_channel *channel, char *buf)
{ {
const struct hv_ring_buffer_info *rbi = &channel->outbound; struct hv_ring_buffer_info *rbi = &channel->outbound;
ssize_t ret;
mutex_lock(&rbi->ring_buffer_mutex);
if (!rbi->ring_buffer) {
mutex_unlock(&rbi->ring_buffer_mutex);
return -EINVAL;
}
return sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask); ret = sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask);
mutex_unlock(&rbi->ring_buffer_mutex);
return ret;
} }
static VMBUS_CHAN_ATTR_RO(out_mask); static VMBUS_CHAN_ATTR_RO(out_mask);
static ssize_t in_mask_show(const struct vmbus_channel *channel, char *buf) static ssize_t in_mask_show(struct vmbus_channel *channel, char *buf)
{ {
const struct hv_ring_buffer_info *rbi = &channel->inbound; struct hv_ring_buffer_info *rbi = &channel->inbound;
ssize_t ret;
mutex_lock(&rbi->ring_buffer_mutex);
if (!rbi->ring_buffer) {
mutex_unlock(&rbi->ring_buffer_mutex);
return -EINVAL;
}
return sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask); ret = sprintf(buf, "%u\n", rbi->ring_buffer->interrupt_mask);
mutex_unlock(&rbi->ring_buffer_mutex);
return ret;
} }
static VMBUS_CHAN_ATTR_RO(in_mask); static VMBUS_CHAN_ATTR_RO(in_mask);
static ssize_t read_avail_show(const struct vmbus_channel *channel, char *buf) static ssize_t read_avail_show(struct vmbus_channel *channel, char *buf)
{ {
const struct hv_ring_buffer_info *rbi = &channel->inbound; struct hv_ring_buffer_info *rbi = &channel->inbound;
ssize_t ret;
return sprintf(buf, "%u\n", hv_get_bytes_to_read(rbi)); mutex_lock(&rbi->ring_buffer_mutex);
if (!rbi->ring_buffer) {
mutex_unlock(&rbi->ring_buffer_mutex);
return -EINVAL;
}
ret = sprintf(buf, "%u\n", hv_get_bytes_to_read(rbi));
mutex_unlock(&rbi->ring_buffer_mutex);
return ret;
} }
static VMBUS_CHAN_ATTR_RO(read_avail); static VMBUS_CHAN_ATTR_RO(read_avail);
static ssize_t write_avail_show(const struct vmbus_channel *channel, char *buf) static ssize_t write_avail_show(struct vmbus_channel *channel, char *buf)
{ {
const struct hv_ring_buffer_info *rbi = &channel->outbound; struct hv_ring_buffer_info *rbi = &channel->outbound;
ssize_t ret;
mutex_lock(&rbi->ring_buffer_mutex);
if (!rbi->ring_buffer) {
mutex_unlock(&rbi->ring_buffer_mutex);
return -EINVAL;
}
return sprintf(buf, "%u\n", hv_get_bytes_to_write(rbi)); ret = sprintf(buf, "%u\n", hv_get_bytes_to_write(rbi));
mutex_unlock(&rbi->ring_buffer_mutex);
return ret;
} }
static VMBUS_CHAN_ATTR_RO(write_avail); static VMBUS_CHAN_ATTR_RO(write_avail);
static ssize_t show_target_cpu(const struct vmbus_channel *channel, char *buf) static ssize_t show_target_cpu(struct vmbus_channel *channel, char *buf)
{ {
return sprintf(buf, "%u\n", channel->target_cpu); return sprintf(buf, "%u\n", channel->target_cpu);
} }
static VMBUS_CHAN_ATTR(cpu, S_IRUGO, show_target_cpu, NULL); static VMBUS_CHAN_ATTR(cpu, S_IRUGO, show_target_cpu, NULL);
static ssize_t channel_pending_show(const struct vmbus_channel *channel, static ssize_t channel_pending_show(struct vmbus_channel *channel,
char *buf) char *buf)
{ {
return sprintf(buf, "%d\n", return sprintf(buf, "%d\n",
...@@ -1463,7 +1525,7 @@ static ssize_t channel_pending_show(const struct vmbus_channel *channel, ...@@ -1463,7 +1525,7 @@ static ssize_t channel_pending_show(const struct vmbus_channel *channel,
} }
static VMBUS_CHAN_ATTR(pending, S_IRUGO, channel_pending_show, NULL); static VMBUS_CHAN_ATTR(pending, S_IRUGO, channel_pending_show, NULL);
static ssize_t channel_latency_show(const struct vmbus_channel *channel, static ssize_t channel_latency_show(struct vmbus_channel *channel,
char *buf) char *buf)
{ {
return sprintf(buf, "%d\n", return sprintf(buf, "%d\n",
...@@ -1472,19 +1534,19 @@ static ssize_t channel_latency_show(const struct vmbus_channel *channel, ...@@ -1472,19 +1534,19 @@ static ssize_t channel_latency_show(const struct vmbus_channel *channel,
} }
static VMBUS_CHAN_ATTR(latency, S_IRUGO, channel_latency_show, NULL); static VMBUS_CHAN_ATTR(latency, S_IRUGO, channel_latency_show, NULL);
static ssize_t channel_interrupts_show(const struct vmbus_channel *channel, char *buf) static ssize_t channel_interrupts_show(struct vmbus_channel *channel, char *buf)
{ {
return sprintf(buf, "%llu\n", channel->interrupts); return sprintf(buf, "%llu\n", channel->interrupts);
} }
static VMBUS_CHAN_ATTR(interrupts, S_IRUGO, channel_interrupts_show, NULL); static VMBUS_CHAN_ATTR(interrupts, S_IRUGO, channel_interrupts_show, NULL);
static ssize_t channel_events_show(const struct vmbus_channel *channel, char *buf) static ssize_t channel_events_show(struct vmbus_channel *channel, char *buf)
{ {
return sprintf(buf, "%llu\n", channel->sig_events); return sprintf(buf, "%llu\n", channel->sig_events);
} }
static VMBUS_CHAN_ATTR(events, S_IRUGO, channel_events_show, NULL); static VMBUS_CHAN_ATTR(events, S_IRUGO, channel_events_show, NULL);
static ssize_t channel_intr_in_full_show(const struct vmbus_channel *channel, static ssize_t channel_intr_in_full_show(struct vmbus_channel *channel,
char *buf) char *buf)
{ {
return sprintf(buf, "%llu\n", return sprintf(buf, "%llu\n",
...@@ -1492,7 +1554,7 @@ static ssize_t channel_intr_in_full_show(const struct vmbus_channel *channel, ...@@ -1492,7 +1554,7 @@ static ssize_t channel_intr_in_full_show(const struct vmbus_channel *channel,
} }
static VMBUS_CHAN_ATTR(intr_in_full, 0444, channel_intr_in_full_show, NULL); static VMBUS_CHAN_ATTR(intr_in_full, 0444, channel_intr_in_full_show, NULL);
static ssize_t channel_intr_out_empty_show(const struct vmbus_channel *channel, static ssize_t channel_intr_out_empty_show(struct vmbus_channel *channel,
char *buf) char *buf)
{ {
return sprintf(buf, "%llu\n", return sprintf(buf, "%llu\n",
...@@ -1500,7 +1562,7 @@ static ssize_t channel_intr_out_empty_show(const struct vmbus_channel *channel, ...@@ -1500,7 +1562,7 @@ static ssize_t channel_intr_out_empty_show(const struct vmbus_channel *channel,
} }
static VMBUS_CHAN_ATTR(intr_out_empty, 0444, channel_intr_out_empty_show, NULL); static VMBUS_CHAN_ATTR(intr_out_empty, 0444, channel_intr_out_empty_show, NULL);
static ssize_t channel_out_full_first_show(const struct vmbus_channel *channel, static ssize_t channel_out_full_first_show(struct vmbus_channel *channel,
char *buf) char *buf)
{ {
return sprintf(buf, "%llu\n", return sprintf(buf, "%llu\n",
...@@ -1508,7 +1570,7 @@ static ssize_t channel_out_full_first_show(const struct vmbus_channel *channel, ...@@ -1508,7 +1570,7 @@ static ssize_t channel_out_full_first_show(const struct vmbus_channel *channel,
} }
static VMBUS_CHAN_ATTR(out_full_first, 0444, channel_out_full_first_show, NULL); static VMBUS_CHAN_ATTR(out_full_first, 0444, channel_out_full_first_show, NULL);
static ssize_t channel_out_full_total_show(const struct vmbus_channel *channel, static ssize_t channel_out_full_total_show(struct vmbus_channel *channel,
char *buf) char *buf)
{ {
return sprintf(buf, "%llu\n", return sprintf(buf, "%llu\n",
...@@ -1516,14 +1578,14 @@ static ssize_t channel_out_full_total_show(const struct vmbus_channel *channel, ...@@ -1516,14 +1578,14 @@ static ssize_t channel_out_full_total_show(const struct vmbus_channel *channel,
} }
static VMBUS_CHAN_ATTR(out_full_total, 0444, channel_out_full_total_show, NULL); static VMBUS_CHAN_ATTR(out_full_total, 0444, channel_out_full_total_show, NULL);
static ssize_t subchannel_monitor_id_show(const struct vmbus_channel *channel, static ssize_t subchannel_monitor_id_show(struct vmbus_channel *channel,
char *buf) char *buf)
{ {
return sprintf(buf, "%u\n", channel->offermsg.monitorid); return sprintf(buf, "%u\n", channel->offermsg.monitorid);
} }
static VMBUS_CHAN_ATTR(monitor_id, S_IRUGO, subchannel_monitor_id_show, NULL); static VMBUS_CHAN_ATTR(monitor_id, S_IRUGO, subchannel_monitor_id_show, NULL);
static ssize_t subchannel_id_show(const struct vmbus_channel *channel, static ssize_t subchannel_id_show(struct vmbus_channel *channel,
char *buf) char *buf)
{ {
return sprintf(buf, "%u\n", return sprintf(buf, "%u\n",
...@@ -1550,10 +1612,34 @@ static struct attribute *vmbus_chan_attrs[] = { ...@@ -1550,10 +1612,34 @@ static struct attribute *vmbus_chan_attrs[] = {
NULL 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 = { static struct kobj_type vmbus_chan_ktype = {
.sysfs_ops = &vmbus_chan_sysfs_ops, .sysfs_ops = &vmbus_chan_sysfs_ops,
.release = vmbus_chan_release, .release = vmbus_chan_release,
.default_attrs = vmbus_chan_attrs,
}; };
/* /*
...@@ -1561,6 +1647,7 @@ static struct kobj_type vmbus_chan_ktype = { ...@@ -1561,6 +1647,7 @@ static struct kobj_type vmbus_chan_ktype = {
*/ */
int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel) int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
{ {
const struct device *device = &dev->device;
struct kobject *kobj = &channel->kobj; struct kobject *kobj = &channel->kobj;
u32 relid = channel->offermsg.child_relid; u32 relid = channel->offermsg.child_relid;
int ret; int ret;
...@@ -1571,11 +1658,30 @@ int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel) ...@@ -1571,11 +1658,30 @@ int vmbus_add_channel_kobj(struct hv_device *dev, struct vmbus_channel *channel)
if (ret) if (ret)
return 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); kobject_uevent(kobj, KOBJ_ADD);
return 0; 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 * vmbus_device_create - Creates and registers a new child device
* on the vmbus. * on the vmbus.
......
...@@ -141,6 +141,11 @@ struct hv_ring_buffer_info { ...@@ -141,6 +141,11 @@ struct hv_ring_buffer_info {
u32 ring_datasize; /* < ring_size */ u32 ring_datasize; /* < ring_size */
u32 priv_read_index; u32 priv_read_index;
/*
* The ring buffer mutex lock. This lock prevents the ring buffer from
* being freed while the ring buffer is being accessed.
*/
struct mutex ring_buffer_mutex;
}; };
...@@ -1206,7 +1211,7 @@ struct hv_ring_buffer_debug_info { ...@@ -1206,7 +1211,7 @@ struct hv_ring_buffer_debug_info {
}; };
int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, int hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
struct hv_ring_buffer_debug_info *debug_info); struct hv_ring_buffer_debug_info *debug_info);
/* Vmbus interface */ /* Vmbus interface */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment