The crash is observed when a service is being disabled host side while userspace daemon is connected to the device: [ 90.244859] general protection fault: 0000 [#1] SMP ... [ 90.800082] Call Trace: [ 90.800082] [<ffffffff81187008>] __fput+0xc8/0x1f0 [ 90.800082] [<ffffffff8118716e>] ____fput+0xe/0x10 ... [ 90.800082] [<ffffffff81015278>] do_signal+0x28/0x580 [ 90.800082] [<ffffffff81086656>] ? finish_task_switch+0xa6/0x180 [ 90.800082] [<ffffffff81443ebf>] ? __schedule+0x28f/0x870 [ 90.800082] [<ffffffffa01ebbaa>] ? hvt_op_read+0x12a/0x140 [hv_utils] ... The problem is that hvutil_transport_destroy() which does misc_deregister() freeing the appropriate device is reachable by two paths: module unload and from util_remove(). While module unload path is protected by .owner in struct file_operations util_remove() path is not. Freeing the device while someone holds an open fd for it is a show stopper. In general, it is not possible to revoke an fd from all users so the only way to solve the issue is to defer freeing the hvutil_transport structure. Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> --- drivers/hv/hv_utils_transport.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 984cba5..174c72a 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -155,13 +155,22 @@ static int hvt_op_open(struct inode *inode, struct file *file) return ret; } +static void hvt_transport_free(struct hvutil_transport *hvt) +{ + misc_deregister(&hvt->mdev); + kfree(hvt->outmsg); + kfree(hvt); +} + static int hvt_op_release(struct inode *inode, struct file *file) { struct hvutil_transport *hvt; + int mode_old; hvt = container_of(file->f_op, struct hvutil_transport, fops); mutex_lock(&hvt->lock); + mode_old = hvt->mode; if (hvt->mode != HVUTIL_TRANSPORT_DESTROY) hvt->mode = HVUTIL_TRANSPORT_INIT; /* @@ -171,6 +180,9 @@ static int hvt_op_release(struct inode *inode, struct file *file) hvt_reset(hvt); mutex_unlock(&hvt->lock); + if (mode_old == HVUTIL_TRANSPORT_DESTROY) + hvt_transport_free(hvt); + return 0; } @@ -304,17 +316,25 @@ err_free_hvt: void hvutil_transport_destroy(struct hvutil_transport *hvt) { + int mode_old; + mutex_lock(&hvt->lock); + mode_old = hvt->mode; hvt->mode = HVUTIL_TRANSPORT_DESTROY; wake_up_interruptible(&hvt->outmsg_q); mutex_unlock(&hvt->lock); + /* + * In case we were in 'chardev' mode we still have an open fd so we + * have to defer freeing the device. Netlink interface can be freed + * now. + */ spin_lock(&hvt_list_lock); list_del(&hvt->list); spin_unlock(&hvt_list_lock); if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0) cn_del_callback(&hvt->cn_id); - misc_deregister(&hvt->mdev); - kfree(hvt->outmsg); - kfree(hvt); + + if (mode_old != HVUTIL_TRANSPORT_CHARDEV) + hvt_transport_free(hvt); } -- 2.4.3 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel