Error logs: [ 35.574120] ------------[ cut here ]------------ [ 35.574122] WARNING: CPU: 0 PID: 10 at fs/sysfs/file.c:591 sysfs_create_bin_file+0x81/0x90 [ 35.574168] Workqueue: hv_pri_chan vmbus_add_channel_work [ 35.574172] RIP: 0010:sysfs_create_bin_file+0x81/0x90 [ 35.574197] Call Trace: [ 35.574199] <TASK> [ 35.574200] ? show_regs+0x69/0x80 [ 35.574217] ? __warn+0x8d/0x130 [ 35.574220] ? sysfs_create_bin_file+0x81/0x90 [ 35.574222] ? report_bug+0x182/0x190 [ 35.574225] ? handle_bug+0x5b/0x90 [ 35.574244] ? exc_invalid_op+0x19/0x70 [ 35.574247] ? asm_exc_invalid_op+0x1b/0x20 [ 35.574252] ? sysfs_create_bin_file+0x81/0x90 [ 35.574255] hv_uio_probe+0x1e7/0x410 [uio_hv_generic] [ 35.574271] vmbus_probe+0x3b/0x90 [ 35.574275] really_probe+0xf4/0x3b0 [ 35.574279] __driver_probe_device+0x8a/0x170 [ 35.574282] driver_probe_device+0x23/0xc0 [ 35.574285] __device_attach_driver+0xb5/0x140 [ 35.574288] ? __pfx___device_attach_driver+0x10/0x10 [ 35.574291] bus_for_each_drv+0x86/0xe0 [ 35.574294] __device_attach+0xc1/0x200 [ 35.574297] device_initial_probe+0x13/0x20 [ 35.574315] bus_probe_device+0x99/0xa0 [ 35.574318] device_add+0x647/0x870 [ 35.574320] ? hrtimer_init+0x28/0x70 [ 35.574323] device_register+0x1b/0x30 [ 35.574326] vmbus_device_register+0x83/0x130 [ 35.574328] vmbus_add_channel_work+0x135/0x1a0 [ 35.574331] process_one_work+0x177/0x340 [ 35.574348] worker_thread+0x2b2/0x3c0 [ 35.574350] kthread+0xe3/0x1f0 [ 35.574353] ? __pfx_worker_thread+0x10/0x10 [ 35.574356] ? __pfx_kthread+0x10/0x10 [ 35.574358] ret_from_fork+0x39/0x60 [ 35.574362] ? __pfx_kthread+0x10/0x10 [ 35.574364] ret_from_fork_asm+0x1a/0x30 [ 35.574368] </TASK> [ 35.574385] ---[ end trace 0000000000000000 ]--- [ 35.574388] uio_hv_generic eb765408-105f-49b6-b4aa-c123b64d17d4: sysfs create ring bin file failed; -22 Thanks. --- drivers/hv/vmbus_drv.c | 7 +++++++ drivers/uio/uio_hv_generic.c | 33 ++++++++++++++++++++++++++++----- include/linux/hyperv.h | 4 ++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 0f6cd44fff29..16f7d7f2d7fd 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -835,6 +835,7 @@ static int vmbus_probe(struct device *child_device) struct hv_device *dev = device_to_hv_device(child_device); const struct hv_vmbus_device_id *dev_id; + dev->device_registered = false; dev_id = hv_vmbus_get_id(drv, dev); if (drv->probe) { ret = drv->probe(dev, dev_id); @@ -1927,6 +1928,7 @@ int vmbus_device_register(struct hv_device *child_device_obj) child_device_obj->device.dma_mask = &child_device_obj->dma_mask; dma_set_mask(&child_device_obj->device, DMA_BIT_MASK(64)); + init_waitqueue_head(&child_device_obj->wait_event); /* * Register with the LDM. This will kick off the driver/device * binding...which will eventually call vmbus_match() and vmbus_probe() @@ -1951,6 +1953,11 @@ int vmbus_device_register(struct hv_device *child_device_obj) pr_err("Unable to register primary channeln"); goto err_kset_unregister; } + + /* channel kobj allocated, now inform anyone waiting for it */ + child_device_obj->device_registered = true; + wake_up_interruptible(&child_device_obj->wait_event); + hv_debug_add_dev_dir(child_device_obj); return 0; diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 1b19b5647495..99d6ecaa8f86 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -63,6 +63,8 @@ struct hv_uio_private_data { void *send_buf; struct vmbus_gpadl send_gpadl; char send_name[32]; + + struct work_struct sysfs_work; }; /* @@ -243,6 +245,29 @@ hv_uio_release(struct uio_info *info, struct inode *inode) return ret; } +static void hv_uio_sysfs_work(struct work_struct *work) +{ + struct hv_uio_private_data *pdata = + container_of(work, struct hv_uio_private_data, sysfs_work); + struct vmbus_channel *channel = pdata->device->channel; + int ret; + + ret = pdata->device->channels_kset || + wait_event_interruptible_timeout(pdata->device->wait_event, + pdata->device->device_registered, + msecs_to_jiffies(5)); + if (!ret) { + dev_warn(&pdata->device->device, + "kset taking too long to initialize; %d\n", ret); + return; + } + + ret = sysfs_create_bin_file(&channel->kobj, &ring_buffer_bin_attr); + if (ret) + dev_notice(&pdata->device->device, + "sysfs create ring bin file failed; %d\n", ret); +} + static int hv_uio_probe(struct hv_device *dev, const struct hv_vmbus_device_id *dev_id) @@ -349,11 +374,8 @@ hv_uio_probe(struct hv_device *dev, dev_err(&dev->device, "hv_uio register failed\n"); goto fail_close; } - - ret = sysfs_create_bin_file(&channel->kobj, &ring_buffer_bin_attr); - if (ret) - dev_notice(&dev->device, - "sysfs create ring bin file failed; %d\n", ret); + INIT_WORK(&pdata->sysfs_work, hv_uio_sysfs_work); + schedule_work(&pdata->sysfs_work); hv_set_drvdata(dev, pdata); @@ -376,6 +398,7 @@ hv_uio_remove(struct hv_device *dev) return; sysfs_remove_bin_file(&dev->channel->kobj, &ring_buffer_bin_attr); + cancel_work_sync(&pdata->sysfs_work); uio_unregister_device(&pdata->info); hv_uio_cleanup(dev, pdata); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 4179add2864b..6180231aff8d 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1302,6 +1302,10 @@ struct hv_device { u16 vendor_id; u16 device_id; + /* check for device registration completion */ + bool device_registered; + wait_queue_head_t wait_event; + struct device device; /* * Driver name to force a match. Do not set directly, because core base-commit: 00f3246adeeacbda0bd0b303604e46eb59c32e6e -- 2.34.1