Commit cbee7c8b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-5.6b-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen fixes from Juergen Gross:
 "Four fixes and a small cleanup patch:

   - two fixes by Dongli Zhang fixing races in the xenbus driver

   - two fixes by me fixing issues introduced in 5.6

   - a small cleanup by Gustavo Silva replacing a zero-length array with
     a flexible-array"

* tag 'for-linus-5.6b-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen/blkfront: fix ring info addressing
  xen/xenbus: fix locking
  xenbus: req->err should be updated before req->state
  xenbus: req->body should be updated before req->state
  xen: Replace zero-length array with flexible-array member
parents fa883d6a 4ab50af6
...@@ -213,6 +213,7 @@ struct blkfront_info ...@@ -213,6 +213,7 @@ struct blkfront_info
struct blk_mq_tag_set tag_set; struct blk_mq_tag_set tag_set;
struct blkfront_ring_info *rinfo; struct blkfront_ring_info *rinfo;
unsigned int nr_rings; unsigned int nr_rings;
unsigned int rinfo_size;
/* Save uncomplete reqs and bios for migration. */ /* Save uncomplete reqs and bios for migration. */
struct list_head requests; struct list_head requests;
struct bio_list bio_list; struct bio_list bio_list;
...@@ -259,6 +260,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo); ...@@ -259,6 +260,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo);
static void blkfront_gather_backend_features(struct blkfront_info *info); static void blkfront_gather_backend_features(struct blkfront_info *info);
static int negotiate_mq(struct blkfront_info *info); static int negotiate_mq(struct blkfront_info *info);
#define for_each_rinfo(info, ptr, idx) \
for ((ptr) = (info)->rinfo, (idx) = 0; \
(idx) < (info)->nr_rings; \
(idx)++, (ptr) = (void *)(ptr) + (info)->rinfo_size)
static inline struct blkfront_ring_info *
get_rinfo(const struct blkfront_info *info, unsigned int i)
{
BUG_ON(i >= info->nr_rings);
return (void *)info->rinfo + i * info->rinfo_size;
}
static int get_id_from_freelist(struct blkfront_ring_info *rinfo) static int get_id_from_freelist(struct blkfront_ring_info *rinfo)
{ {
unsigned long free = rinfo->shadow_free; unsigned long free = rinfo->shadow_free;
...@@ -883,8 +896,7 @@ static blk_status_t blkif_queue_rq(struct blk_mq_hw_ctx *hctx, ...@@ -883,8 +896,7 @@ static blk_status_t blkif_queue_rq(struct blk_mq_hw_ctx *hctx,
struct blkfront_info *info = hctx->queue->queuedata; struct blkfront_info *info = hctx->queue->queuedata;
struct blkfront_ring_info *rinfo = NULL; struct blkfront_ring_info *rinfo = NULL;
BUG_ON(info->nr_rings <= qid); rinfo = get_rinfo(info, qid);
rinfo = &info->rinfo[qid];
blk_mq_start_request(qd->rq); blk_mq_start_request(qd->rq);
spin_lock_irqsave(&rinfo->ring_lock, flags); spin_lock_irqsave(&rinfo->ring_lock, flags);
if (RING_FULL(&rinfo->ring)) if (RING_FULL(&rinfo->ring))
...@@ -1181,6 +1193,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, ...@@ -1181,6 +1193,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
static void xlvbd_release_gendisk(struct blkfront_info *info) static void xlvbd_release_gendisk(struct blkfront_info *info)
{ {
unsigned int minor, nr_minors, i; unsigned int minor, nr_minors, i;
struct blkfront_ring_info *rinfo;
if (info->rq == NULL) if (info->rq == NULL)
return; return;
...@@ -1188,9 +1201,7 @@ static void xlvbd_release_gendisk(struct blkfront_info *info) ...@@ -1188,9 +1201,7 @@ static void xlvbd_release_gendisk(struct blkfront_info *info)
/* No more blkif_request(). */ /* No more blkif_request(). */
blk_mq_stop_hw_queues(info->rq); blk_mq_stop_hw_queues(info->rq);
for (i = 0; i < info->nr_rings; i++) { for_each_rinfo(info, rinfo, i) {
struct blkfront_ring_info *rinfo = &info->rinfo[i];
/* No more gnttab callback work. */ /* No more gnttab callback work. */
gnttab_cancel_free_callback(&rinfo->callback); gnttab_cancel_free_callback(&rinfo->callback);
...@@ -1339,6 +1350,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo) ...@@ -1339,6 +1350,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
static void blkif_free(struct blkfront_info *info, int suspend) static void blkif_free(struct blkfront_info *info, int suspend)
{ {
unsigned int i; unsigned int i;
struct blkfront_ring_info *rinfo;
/* Prevent new requests being issued until we fix things up. */ /* Prevent new requests being issued until we fix things up. */
info->connected = suspend ? info->connected = suspend ?
...@@ -1347,8 +1359,8 @@ static void blkif_free(struct blkfront_info *info, int suspend) ...@@ -1347,8 +1359,8 @@ static void blkif_free(struct blkfront_info *info, int suspend)
if (info->rq) if (info->rq)
blk_mq_stop_hw_queues(info->rq); blk_mq_stop_hw_queues(info->rq);
for (i = 0; i < info->nr_rings; i++) for_each_rinfo(info, rinfo, i)
blkif_free_ring(&info->rinfo[i]); blkif_free_ring(rinfo);
kvfree(info->rinfo); kvfree(info->rinfo);
info->rinfo = NULL; info->rinfo = NULL;
...@@ -1775,6 +1787,7 @@ static int talk_to_blkback(struct xenbus_device *dev, ...@@ -1775,6 +1787,7 @@ static int talk_to_blkback(struct xenbus_device *dev,
int err; int err;
unsigned int i, max_page_order; unsigned int i, max_page_order;
unsigned int ring_page_order; unsigned int ring_page_order;
struct blkfront_ring_info *rinfo;
if (!info) if (!info)
return -ENODEV; return -ENODEV;
...@@ -1788,9 +1801,7 @@ static int talk_to_blkback(struct xenbus_device *dev, ...@@ -1788,9 +1801,7 @@ static int talk_to_blkback(struct xenbus_device *dev,
if (err) if (err)
goto destroy_blkring; goto destroy_blkring;
for (i = 0; i < info->nr_rings; i++) { for_each_rinfo(info, rinfo, i) {
struct blkfront_ring_info *rinfo = &info->rinfo[i];
/* Create shared ring, alloc event channel. */ /* Create shared ring, alloc event channel. */
err = setup_blkring(dev, rinfo); err = setup_blkring(dev, rinfo);
if (err) if (err)
...@@ -1815,7 +1826,7 @@ static int talk_to_blkback(struct xenbus_device *dev, ...@@ -1815,7 +1826,7 @@ static int talk_to_blkback(struct xenbus_device *dev,
/* We already got the number of queues/rings in _probe */ /* We already got the number of queues/rings in _probe */
if (info->nr_rings == 1) { if (info->nr_rings == 1) {
err = write_per_ring_nodes(xbt, &info->rinfo[0], dev->nodename); err = write_per_ring_nodes(xbt, info->rinfo, dev->nodename);
if (err) if (err)
goto destroy_blkring; goto destroy_blkring;
} else { } else {
...@@ -1837,10 +1848,10 @@ static int talk_to_blkback(struct xenbus_device *dev, ...@@ -1837,10 +1848,10 @@ static int talk_to_blkback(struct xenbus_device *dev,
goto abort_transaction; goto abort_transaction;
} }
for (i = 0; i < info->nr_rings; i++) { for_each_rinfo(info, rinfo, i) {
memset(path, 0, pathsize); memset(path, 0, pathsize);
snprintf(path, pathsize, "%s/queue-%u", dev->nodename, i); snprintf(path, pathsize, "%s/queue-%u", dev->nodename, i);
err = write_per_ring_nodes(xbt, &info->rinfo[i], path); err = write_per_ring_nodes(xbt, rinfo, path);
if (err) { if (err) {
kfree(path); kfree(path);
goto destroy_blkring; goto destroy_blkring;
...@@ -1868,9 +1879,8 @@ static int talk_to_blkback(struct xenbus_device *dev, ...@@ -1868,9 +1879,8 @@ static int talk_to_blkback(struct xenbus_device *dev,
goto destroy_blkring; goto destroy_blkring;
} }
for (i = 0; i < info->nr_rings; i++) { for_each_rinfo(info, rinfo, i) {
unsigned int j; unsigned int j;
struct blkfront_ring_info *rinfo = &info->rinfo[i];
for (j = 0; j < BLK_RING_SIZE(info); j++) for (j = 0; j < BLK_RING_SIZE(info); j++)
rinfo->shadow[j].req.u.rw.id = j + 1; rinfo->shadow[j].req.u.rw.id = j + 1;
...@@ -1900,6 +1910,7 @@ static int negotiate_mq(struct blkfront_info *info) ...@@ -1900,6 +1910,7 @@ static int negotiate_mq(struct blkfront_info *info)
{ {
unsigned int backend_max_queues; unsigned int backend_max_queues;
unsigned int i; unsigned int i;
struct blkfront_ring_info *rinfo;
BUG_ON(info->nr_rings); BUG_ON(info->nr_rings);
...@@ -1911,20 +1922,16 @@ static int negotiate_mq(struct blkfront_info *info) ...@@ -1911,20 +1922,16 @@ static int negotiate_mq(struct blkfront_info *info)
if (!info->nr_rings) if (!info->nr_rings)
info->nr_rings = 1; info->nr_rings = 1;
info->rinfo = kvcalloc(info->nr_rings, info->rinfo_size = struct_size(info->rinfo, shadow,
struct_size(info->rinfo, shadow, BLK_RING_SIZE(info));
BLK_RING_SIZE(info)), info->rinfo = kvcalloc(info->nr_rings, info->rinfo_size, GFP_KERNEL);
GFP_KERNEL);
if (!info->rinfo) { if (!info->rinfo) {
xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure"); xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure");
info->nr_rings = 0; info->nr_rings = 0;
return -ENOMEM; return -ENOMEM;
} }
for (i = 0; i < info->nr_rings; i++) { for_each_rinfo(info, rinfo, i) {
struct blkfront_ring_info *rinfo;
rinfo = &info->rinfo[i];
INIT_LIST_HEAD(&rinfo->indirect_pages); INIT_LIST_HEAD(&rinfo->indirect_pages);
INIT_LIST_HEAD(&rinfo->grants); INIT_LIST_HEAD(&rinfo->grants);
rinfo->dev_info = info; rinfo->dev_info = info;
...@@ -2017,6 +2024,7 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -2017,6 +2024,7 @@ static int blkif_recover(struct blkfront_info *info)
int rc; int rc;
struct bio *bio; struct bio *bio;
unsigned int segs; unsigned int segs;
struct blkfront_ring_info *rinfo;
blkfront_gather_backend_features(info); blkfront_gather_backend_features(info);
/* Reset limits changed by blk_mq_update_nr_hw_queues(). */ /* Reset limits changed by blk_mq_update_nr_hw_queues(). */
...@@ -2024,9 +2032,7 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -2024,9 +2032,7 @@ static int blkif_recover(struct blkfront_info *info)
segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST; segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST;
blk_queue_max_segments(info->rq, segs / GRANTS_PER_PSEG); blk_queue_max_segments(info->rq, segs / GRANTS_PER_PSEG);
for (r_index = 0; r_index < info->nr_rings; r_index++) { for_each_rinfo(info, rinfo, r_index) {
struct blkfront_ring_info *rinfo = &info->rinfo[r_index];
rc = blkfront_setup_indirect(rinfo); rc = blkfront_setup_indirect(rinfo);
if (rc) if (rc)
return rc; return rc;
...@@ -2036,10 +2042,7 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -2036,10 +2042,7 @@ static int blkif_recover(struct blkfront_info *info)
/* Now safe for us to use the shared ring */ /* Now safe for us to use the shared ring */
info->connected = BLKIF_STATE_CONNECTED; info->connected = BLKIF_STATE_CONNECTED;
for (r_index = 0; r_index < info->nr_rings; r_index++) { for_each_rinfo(info, rinfo, r_index) {
struct blkfront_ring_info *rinfo;
rinfo = &info->rinfo[r_index];
/* Kick any other new requests queued since we resumed */ /* Kick any other new requests queued since we resumed */
kick_pending_request_queues(rinfo); kick_pending_request_queues(rinfo);
} }
...@@ -2072,13 +2075,13 @@ static int blkfront_resume(struct xenbus_device *dev) ...@@ -2072,13 +2075,13 @@ static int blkfront_resume(struct xenbus_device *dev)
struct blkfront_info *info = dev_get_drvdata(&dev->dev); struct blkfront_info *info = dev_get_drvdata(&dev->dev);
int err = 0; int err = 0;
unsigned int i, j; unsigned int i, j;
struct blkfront_ring_info *rinfo;
dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename); dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
bio_list_init(&info->bio_list); bio_list_init(&info->bio_list);
INIT_LIST_HEAD(&info->requests); INIT_LIST_HEAD(&info->requests);
for (i = 0; i < info->nr_rings; i++) { for_each_rinfo(info, rinfo, i) {
struct blkfront_ring_info *rinfo = &info->rinfo[i];
struct bio_list merge_bio; struct bio_list merge_bio;
struct blk_shadow *shadow = rinfo->shadow; struct blk_shadow *shadow = rinfo->shadow;
...@@ -2337,6 +2340,7 @@ static void blkfront_connect(struct blkfront_info *info) ...@@ -2337,6 +2340,7 @@ static void blkfront_connect(struct blkfront_info *info)
unsigned int binfo; unsigned int binfo;
char *envp[] = { "RESIZE=1", NULL }; char *envp[] = { "RESIZE=1", NULL };
int err, i; int err, i;
struct blkfront_ring_info *rinfo;
switch (info->connected) { switch (info->connected) {
case BLKIF_STATE_CONNECTED: case BLKIF_STATE_CONNECTED:
...@@ -2394,8 +2398,8 @@ static void blkfront_connect(struct blkfront_info *info) ...@@ -2394,8 +2398,8 @@ static void blkfront_connect(struct blkfront_info *info)
"physical-sector-size", "physical-sector-size",
sector_size); sector_size);
blkfront_gather_backend_features(info); blkfront_gather_backend_features(info);
for (i = 0; i < info->nr_rings; i++) { for_each_rinfo(info, rinfo, i) {
err = blkfront_setup_indirect(&info->rinfo[i]); err = blkfront_setup_indirect(rinfo);
if (err) { if (err) {
xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s", xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
info->xbdev->otherend); info->xbdev->otherend);
...@@ -2416,8 +2420,8 @@ static void blkfront_connect(struct blkfront_info *info) ...@@ -2416,8 +2420,8 @@ static void blkfront_connect(struct blkfront_info *info)
/* Kick pending requests. */ /* Kick pending requests. */
info->connected = BLKIF_STATE_CONNECTED; info->connected = BLKIF_STATE_CONNECTED;
for (i = 0; i < info->nr_rings; i++) for_each_rinfo(info, rinfo, i)
kick_pending_request_queues(&info->rinfo[i]); kick_pending_request_queues(rinfo);
device_add_disk(&info->xbdev->dev, info->gd, NULL); device_add_disk(&info->xbdev->dev, info->gd, NULL);
...@@ -2652,9 +2656,9 @@ static void purge_persistent_grants(struct blkfront_info *info) ...@@ -2652,9 +2656,9 @@ static void purge_persistent_grants(struct blkfront_info *info)
{ {
unsigned int i; unsigned int i;
unsigned long flags; unsigned long flags;
struct blkfront_ring_info *rinfo;
for (i = 0; i < info->nr_rings; i++) { for_each_rinfo(info, rinfo, i) {
struct blkfront_ring_info *rinfo = &info->rinfo[i];
struct grant *gnt_list_entry, *tmp; struct grant *gnt_list_entry, *tmp;
spin_lock_irqsave(&rinfo->ring_lock, flags); spin_lock_irqsave(&rinfo->ring_lock, flags);
......
...@@ -52,7 +52,7 @@ struct xen_pcibk_dev_data { ...@@ -52,7 +52,7 @@ struct xen_pcibk_dev_data {
unsigned int ack_intr:1; /* .. and ACK-ing */ unsigned int ack_intr:1; /* .. and ACK-ing */
unsigned long handled; unsigned long handled;
unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */ unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
char irq_name[0]; /* xen-pcibk[000:04:00.0] */ char irq_name[]; /* xen-pcibk[000:04:00.0] */
}; };
/* Used by XenBus and xen_pcibk_ops.c */ /* Used by XenBus and xen_pcibk_ops.c */
......
...@@ -313,6 +313,8 @@ static int process_msg(void) ...@@ -313,6 +313,8 @@ static int process_msg(void)
req->msg.type = state.msg.type; req->msg.type = state.msg.type;
req->msg.len = state.msg.len; req->msg.len = state.msg.len;
req->body = state.body; req->body = state.body;
/* write body, then update state */
virt_wmb();
req->state = xb_req_state_got_reply; req->state = xb_req_state_got_reply;
req->cb(req); req->cb(req);
} else } else
...@@ -395,6 +397,8 @@ static int process_writes(void) ...@@ -395,6 +397,8 @@ static int process_writes(void)
if (state.req->state == xb_req_state_aborted) if (state.req->state == xb_req_state_aborted)
kfree(state.req); kfree(state.req);
else { else {
/* write err, then update state */
virt_wmb();
state.req->state = xb_req_state_got_reply; state.req->state = xb_req_state_got_reply;
wake_up(&state.req->wq); wake_up(&state.req->wq);
} }
......
...@@ -239,9 +239,9 @@ int xenbus_dev_probe(struct device *_dev) ...@@ -239,9 +239,9 @@ int xenbus_dev_probe(struct device *_dev)
goto fail; goto fail;
} }
spin_lock(&dev->reclaim_lock); down(&dev->reclaim_sem);
err = drv->probe(dev, id); err = drv->probe(dev, id);
spin_unlock(&dev->reclaim_lock); up(&dev->reclaim_sem);
if (err) if (err)
goto fail_put; goto fail_put;
...@@ -271,9 +271,9 @@ int xenbus_dev_remove(struct device *_dev) ...@@ -271,9 +271,9 @@ int xenbus_dev_remove(struct device *_dev)
free_otherend_watch(dev); free_otherend_watch(dev);
if (drv->remove) { if (drv->remove) {
spin_lock(&dev->reclaim_lock); down(&dev->reclaim_sem);
drv->remove(dev); drv->remove(dev);
spin_unlock(&dev->reclaim_lock); up(&dev->reclaim_sem);
} }
module_put(drv->driver.owner); module_put(drv->driver.owner);
...@@ -473,7 +473,7 @@ int xenbus_probe_node(struct xen_bus_type *bus, ...@@ -473,7 +473,7 @@ int xenbus_probe_node(struct xen_bus_type *bus,
goto fail; goto fail;
dev_set_name(&xendev->dev, "%s", devname); dev_set_name(&xendev->dev, "%s", devname);
spin_lock_init(&xendev->reclaim_lock); sema_init(&xendev->reclaim_sem, 1);
/* Register with generic device framework. */ /* Register with generic device framework. */
err = device_register(&xendev->dev); err = device_register(&xendev->dev);
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/semaphore.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -257,10 +258,10 @@ static int backend_reclaim_memory(struct device *dev, void *data) ...@@ -257,10 +258,10 @@ static int backend_reclaim_memory(struct device *dev, void *data)
drv = to_xenbus_driver(dev->driver); drv = to_xenbus_driver(dev->driver);
if (drv && drv->reclaim_memory) { if (drv && drv->reclaim_memory) {
xdev = to_xenbus_device(dev); xdev = to_xenbus_device(dev);
if (!spin_trylock(&xdev->reclaim_lock)) if (down_trylock(&xdev->reclaim_sem))
return 0; return 0;
drv->reclaim_memory(xdev); drv->reclaim_memory(xdev);
spin_unlock(&xdev->reclaim_lock); up(&xdev->reclaim_sem);
} }
return 0; return 0;
} }
......
...@@ -191,8 +191,11 @@ static bool xenbus_ok(void) ...@@ -191,8 +191,11 @@ static bool xenbus_ok(void)
static bool test_reply(struct xb_req_data *req) static bool test_reply(struct xb_req_data *req)
{ {
if (req->state == xb_req_state_got_reply || !xenbus_ok()) if (req->state == xb_req_state_got_reply || !xenbus_ok()) {
/* read req->state before all other fields */
virt_rmb();
return true; return true;
}
/* Make sure to reread req->state each time. */ /* Make sure to reread req->state each time. */
barrier(); barrier();
...@@ -202,7 +205,7 @@ static bool test_reply(struct xb_req_data *req) ...@@ -202,7 +205,7 @@ static bool test_reply(struct xb_req_data *req)
static void *read_reply(struct xb_req_data *req) static void *read_reply(struct xb_req_data *req)
{ {
while (req->state != xb_req_state_got_reply) { do {
wait_event(req->wq, test_reply(req)); wait_event(req->wq, test_reply(req));
if (!xenbus_ok()) if (!xenbus_ok())
...@@ -216,7 +219,7 @@ static void *read_reply(struct xb_req_data *req) ...@@ -216,7 +219,7 @@ static void *read_reply(struct xb_req_data *req)
if (req->err) if (req->err)
return ERR_PTR(req->err); return ERR_PTR(req->err);
} } while (req->state != xb_req_state_got_reply);
return req->body; return req->body;
} }
......
...@@ -46,7 +46,7 @@ struct vtpm_shared_page { ...@@ -46,7 +46,7 @@ struct vtpm_shared_page {
uint8_t pad; uint8_t pad;
uint8_t nr_extra_pages; /* extra pages for long packets; may be zero */ uint8_t nr_extra_pages; /* extra pages for long packets; may be zero */
uint32_t extra_pages[0]; /* grant IDs; length in nr_extra_pages */ uint32_t extra_pages[]; /* grant IDs; length in nr_extra_pages */
}; };
#endif #endif
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/semaphore.h>
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/interface/grant_table.h> #include <xen/interface/grant_table.h>
#include <xen/interface/io/xenbus.h> #include <xen/interface/io/xenbus.h>
...@@ -76,7 +77,7 @@ struct xenbus_device { ...@@ -76,7 +77,7 @@ struct xenbus_device {
enum xenbus_state state; enum xenbus_state state;
struct completion down; struct completion down;
struct work_struct work; struct work_struct work;
spinlock_t reclaim_lock; struct semaphore reclaim_sem;
}; };
static inline struct xenbus_device *to_xenbus_device(struct device *dev) static inline struct xenbus_device *to_xenbus_device(struct device *dev)
......
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