iscsi: fix deadlock during login
PATCH 1/1 iscsi: fix deadlock during login
If the connection is interrupted before the first login is successfully completed qemu-kvm is waiting forever in qemu_aio_wait().
This is fixed by performing an sync login to the target. If the connection breaks after the first successful login errors are handled internally by libiscsi.
--- block/iscsi.c | 56 +++++++++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 35 deletions(-)
block/iscsi.c +21 -35
@@ -798,30 +798,6 @@ iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data, } } -static void -iscsi_connect_cb (struct iscsi_context *iscsi,int status,void *command_data, -void *opaque) -{ -struct IscsiTask *itask = opaque; -struct scsi_task *task; - -if (status !=0 ) { - itask->status =1 ; - itask->complete =1 ; -return ; - } - - task =iscsi_inquiry_task (iscsi, itask->iscsilun->lun, -0 ,0 ,36 , - iscsi_inquiry_cb, opaque); -if (task ==NULL ) { -error_report ("iSCSI: failed to send inquiry command." ); - itask->status =1 ; - itask->complete =1 ; -return ; - } -} -static int parse_chap (struct iscsi_context *iscsi,const char *target) {QemuOptsList *list;
@@ -934,7 +910,8 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)IscsiLun *iscsilun = bs->opaque;struct iscsi_context *iscsi =NULL ;struct iscsi_url *iscsi_url =NULL ; -struct IscsiTask task; +struct IscsiTask itask; +struct scsi_task *task;char *initiator_name =NULL ;int ret;
@@ -997,27 +974,36 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)/* check if we got HEADER_DIGEST via the options */ parse_header_digest (iscsi, iscsi_url->target); - task.iscsilun = iscsilun; - task.status =0 ; - task.complete =0 ; - task.bs = bs; +if (iscsi_full_connect_sync (iscsi, iscsi_url->portal, iscsi_url->lun) !=0 ) { +error_report ("iSCSI: Failed to connect to LUN : %s" , +iscsi_get_error (iscsi)); + ret = -EINVAL ; + goto out; + } + + itask.iscsilun = iscsilun; + itask.status =0 ; + itask.complete =0 ; + itask.bs = bs; iscsilun->iscsi = iscsi; iscsilun->lun = iscsi_url->lun; -if (iscsi_full_connect_async (iscsi, iscsi_url->portal, iscsi_url->lun, - iscsi_connect_cb, &task) - !=0 ) { -error_report ("iSCSI: Failed to start async connect." ); + task =iscsi_inquiry_task (iscsi, iscsilun->lun, +0 ,0 ,36 , + iscsi_inquiry_cb, &itask); +if (task ==NULL ) { +error_report ("iSCSI: failed to send inquiry command." ); ret = -EINVAL ; goto out; } -while (!task.complete) { +while (!itask.complete) {iscsi_set_events (iscsilun);qemu_aio_wait (); } -if (task.status !=0 ) { + +if (itask.status !=0 ) {error_report ("iSCSI: Failed to connect to LUN : %s" ,iscsi_get_error (iscsi)); ret = -EINVAL ;
Signature · 1 line
1.7.9.5
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
Is it possible to add a timeout instead that would break out if the connect/login has not completed within a certain amount of time?
regards
ronnie sahlberg
Quoted 112 lines · Peter Lieven
If the connection is interrupted before the first login is successfully completed qemu-kvm is waiting forever in
qemu_aio_wait().This is fixed by performing an sync login to the target. If the connection breaks after the first successful login errors are handled internally by libiscsi.
Signed-off-by Peter Lieven <[email protected]>--- block/iscsi.c | 56 +++++++++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 35 deletions(-)block/iscsi.c +0
-24@@ -798,30 +798,6 @@ iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data, } } -static void -iscsi_connect_cb (struct iscsi_context *iscsi,int status,void *command_data, -void *opaque) -{ -struct IscsiTask *itask = opaque; -struct scsi_task *task; - -if (status !=0 ) { - itask->status =1 ; - itask->complete =1 ; -return ; - } - - task =iscsi_inquiry_task (iscsi, itask->iscsilun->lun, -0 ,0 ,36 , - iscsi_inquiry_cb, opaque); -if (task ==NULL ) { -error_report ("iSCSI: failed to send inquiry command." ); - itask->status =1 ; - itask->complete =1 ; -return ; - } -} - static int parse_chap(struct iscsi_context *iscsi, const char *target){ QemuOptsList *list;block/iscsi.c +21
-11@@ -934,7 +910,8 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) IscsiLun *iscsilun = bs->opaque;struct iscsi_context *iscsi =NULL ;struct iscsi_url *iscsi_url =NULL ; -struct IscsiTask task; +struct IscsiTask itask; +struct scsi_task *task;char *initiator_name =NULL ;int ret;@@ -997,27 +974,36 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)/* check if we got HEADER_DIGEST via the options */ parse_header_digest (iscsi, iscsi_url->target); - task.iscsilun = iscsilun; - task.status =0 ; - task.complete =0 ; - task.bs = bs; +if (iscsi_full_connect_sync (iscsi, iscsi_url->portal, iscsi_url->lun) !=0 ) { +error_report ("iSCSI: Failed to connect to LUN : %s" , +iscsi_get_error (iscsi)); + ret = -EINVAL ; + goto out; + } + + itask.iscsilun = iscsilun; + itask.status =0 ; + itask.complete =0 ; + itask.bs = bs; iscsilun->iscsi = iscsi; iscsilun->lun = iscsi_url->lun; -if (iscsi_full_connect_async (iscsi, iscsi_url->portal, iscsi_url->lun, - iscsi_connect_cb, &task) - !=0 ) { -error_report ("iSCSI: Failed to start async connect." ); + task =iscsi_inquiry_task (iscsi, iscsilun->lun, +0 ,0 ,36 , + iscsi_inquiry_cb, &itask); +if (task ==NULL ) { +error_report ("iSCSI: failed to send inquiry command." ); ret = -EINVAL ; goto out; } -while (!task.complete) { +while (!itask.complete) {iscsi_set_events (iscsilun);qemu_aio_wait (); } -if (task.status !=0 ) { + +if (itask.status !=0 ) { error_report("iSCSI: Failed to connect to LUN : %s",iscsi_get_error(iscsi)); ret = -EINVAL;--
1.7.9.5
Am 15.11.2012 um 15:57 schrieb ronnie sahlberg <[email protected]>:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
Of course, but its just the initial login after which qemu should exit if it fails.
Quoted 3 lines
Is it possible to add a timeout instead that would break out if the connect/login has not completed within a certain amount of time?
I think it is, but this has to be done by qemu or not?
I found switching to synchronous code fixed 2 issues at once, the issue that it hangs if the connection is interrupted during login and another issue that i submitted a patch for earlier:
https://github.com/sahlberg/libiscsi/commit/a9257d52a7577b607e237e209b9868c5ce78a927
it might be that this fix introduced the new issue.
Peter
Quoted 118 lines
regards
ronnie sahlbergQuoted 112 lines · Peter Lieven
If the connection is interrupted before the first login is successfully completed qemu-kvm is waiting forever in
qemu_aio_wait().This is fixed by performing an sync login to the target. If the connection breaks after the first successful login errors are handled internally by libiscsi.
Signed-off-by Peter Lieven <[email protected]>---
block/iscsi.c| 56
+++++++++++++++++++++-----------------------------------1 file changed, 21 insertions(+), 35 deletions(-)block/iscsi.c +0
-24@@ -798,30 +798,6 @@ iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data, } } -static void -iscsi_connect_cb (struct iscsi_context *iscsi,int status,void *command_data, -void *opaque) -{ -struct IscsiTask *itask = opaque; -struct scsi_task *task; - -if (status !=0 ) { - itask->status =1 ; - itask->complete =1 ; -return ; - } - - task =iscsi_inquiry_task (iscsi, itask->iscsilun->lun, -0 ,0 ,36 , - iscsi_inquiry_cb, opaque); -if (task ==NULL ) { -error_report ("iSCSI: failed to send inquiry command." ); - itask->status =1 ; - itask->complete =1 ; -return ; - } -} - static int parse_chap(struct iscsi_context *iscsi, const char *target){ QemuOptsList *list;block/iscsi.c +21
-11@@ -934,7 +910,8 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) IscsiLun *iscsilun = bs->opaque;struct iscsi_context *iscsi =NULL ;struct iscsi_url *iscsi_url =NULL ; -struct IscsiTask task; +struct IscsiTask itask; +struct scsi_task *task;char *initiator_name =NULL ;int ret;@@ -997,27 +974,36 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)/* check if we got HEADER_DIGEST via the options */ parse_header_digest (iscsi, iscsi_url->target); - task.iscsilun = iscsilun; - task.status =0 ; - task.complete =0 ; - task.bs = bs; +if (iscsi_full_connect_sync (iscsi, iscsi_url->portal, iscsi_url->lun) !=0 ) { +error_report ("iSCSI: Failed to connect to LUN : %s" , +iscsi_get_error (iscsi)); + ret = -EINVAL ; + goto out; + } + + itask.iscsilun = iscsilun; + itask.status =0 ; + itask.complete =0 ; + itask.bs = bs; iscsilun->iscsi = iscsi; iscsilun->lun = iscsi_url->lun; -if (iscsi_full_connect_async (iscsi, iscsi_url->portal, iscsi_url->lun, - iscsi_connect_cb, &task) - !=0 ) { -error_report ("iSCSI: Failed to start async connect." ); + task =iscsi_inquiry_task (iscsi, iscsilun->lun, +0 ,0 ,36 , + iscsi_inquiry_cb, &itask); +if (task ==NULL ) { +error_report ("iSCSI: failed to send inquiry command." ); ret = -EINVAL ; goto out; } -while (!task.complete) { +while (!itask.complete) {iscsi_set_events (iscsilun);qemu_aio_wait (); } -if (task.status !=0 ) { + +if (itask.status !=0 ) { error_report("iSCSI: Failed to connect to LUN : %s",iscsi_get_error(iscsi)); ret = -EINVAL;--
1.7.9.5
Il 15/11/2012 15:57, ronnie sahlberg ha scritto:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_open is generally synchronous, so I think Peter's patch is ok.
Paolo
Quoted 2 lines
Is it possible to add a timeout instead that would break out if the connect/login has not completed within a certain amount of time?
ronnie sahlberg
Acked-byQuoted 5 lines · Paolo Bonzini
Il 15/11/2012 15:57, ronnie sahlberg ha scritto:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.
I was thinking about the case where you disconnect/reconnect a device at runtime. Like swapping the medium in a CDROM.
If bdrv_open() is synchronous and blocks for a long time, would that not impact the rest of QEMU?
Otherwise:
Quoted 6 lines
Paolo
Quoted 2 lines
Is it possible to add a timeout instead that would break out if the connect/login has not completed within a certain amount of time?
Il 15/11/2012 17:13, ronnie sahlberg ha scritto:
Quoted 11 lines · Paolo Bonzini
Quoted 5 lines
Il 15/11/2012 15:57, ronnie sahlberg ha scritto:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.I was thinking about the case where you disconnect/reconnect a device at runtime. Like swapping the medium in a CDROM.
Ifbdrv_open()is synchronous and blocks for a long time, would that not impact the rest of QEMU?
Yes, it's not optimal, but VCPUs would still run until they request I/O.
But usually iscsi devices should be non-removable, no? That leaves
hotplug as the only problematic case.
Paolo
Quoted 10 lines
Otherwise:
Acked-by [email protected]Quoted 6 lines
Paolo
Quoted 2 lines
Is it possible to add a timeout instead that would break out if the connect/login has not completed within a certain amount of time?
Am 15.11.2012 17:37, schrieb Paolo Bonzini:
Quoted 8 lines
Il 15/11/2012 17:13, ronnie sahlberg ha scritto:
Quoted 7 lines · Paolo Bonzini
Quoted 5 lines
Il 15/11/2012 15:57, ronnie sahlberg ha scritto:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.
Quoted 8 lines
Quoted 4 lines
I was thinking about the case where you disconnect/reconnect a device at runtime. Like swapping the medium in a CDROM.
Ifbdrv_open()is synchronous and blocks for a long time, would that not impact the rest of QEMU?Yes, it's not optimal, but VCPUs would still run until they request I/O.
But usually iscsi devices should be non-removable, no? That leaves
hotplug as the only problematic case.
I guess we need a bdrv_co_open() for the long term.
Kevin
Am 16.11.2012 11:38, schrieb Kevin Wolf:
Quoted 7 lines
Am 15.11.2012 17:37, schrieb Paolo Bonzini:
Quoted 6 lines
Il 15/11/2012 17:13, ronnie sahlberg ha scritto:
Quoted 5 lines · Paolo Bonzini
Quoted 4 lines
Il 15/11/2012 15:57, ronnie sahlberg ha scritto:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.
Quoted 8 lines
Quoted 7 lines
Quoted 4 lines
I was thinking about the case where you disconnect/reconnect a device at runtime. Like swapping the medium in a CDROM.
Ifbdrv_open()is synchronous and blocks for a long time, would that not impact the rest of QEMU?Yes, it's not optimal, but VCPUs would still run until they request I/O.
But usually iscsi devices should be non-removable, no? That leaves
hotplug as the only problematic case.I guess we need a
bdrv_co_open()for the long term.
but for now its save to implement iscsi_open (and iscsi_create) completely sync?
Peter
Quoted 2 lines
Kevin
Il 16/11/2012 18:38, Peter Lieven ha scritto:
Quoted 13 lines
Am 16.11.2012 11:38, schrieb Kevin Wolf:
Quoted 12 lines
Am 15.11.2012 17:37, schrieb Paolo Bonzini:
Quoted 11 lines
Il 15/11/2012 17:13, ronnie sahlberg ha scritto:
Quoted 10 lines
Quoted 4 lines · Paolo Bonzini
Il 15/11/2012 15:57, ronnie sahlberg ha scritto:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.I was thinking about the case where you disconnect/reconnect a device at runtime. Like swapping the medium in a CDROM.
Ifbdrv_open()is synchronous and blocks for a long time, would that not impact the rest of QEMU?
Quoted 6 lines
Quoted 4 lines
Quoted 3 lines
Yes, it's not optimal, but VCPUs would still run until they request I/O.
But usually iscsi devices should be non-removable, no? That leaves
hotplug as the only problematic case.I guess we need a
bdrv_co_open()for the long term.but for now its save to implement
iscsi_open(andiscsi_create) completely sync?
Yes.
Paolo
Quoted 5 lines · Paolo Bonzini
Il 15/11/2012 15:57, ronnie sahlberg ha scritto:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.
if all is sync wouldn't it be best to have all code in iscsi_open sync then and convert the iscsi_inquiry and iscsi_readcapacity commands also to sync?
Peter
Quoted 8 lines
Paolo
Quoted 2 lines
Is it possible to add a timeout instead that would break out if the connect/login has not completed within a certain amount of time?
Il 15/11/2012 19:28, Peter Lieven ha scritto:
Quoted 7 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.if all is sync wouldn't it be best to have all code in
iscsi_opensync then and convert theiscsi_inquiryandiscsi_readcapacitycommands also to sync?
Indeed, there is no real advantage in using qemu_aio_wait(). I didn't know libiscsi also had sync APIs. :)
Paolo
Am 16.11.2012 08:44, schrieb Paolo Bonzini:
Quoted 9 lines
Il 15/11/2012 19:28, Peter Lieven ha scritto:
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 2 lines
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.if all is sync wouldn't it be best to have all code in
iscsi_opensync then and convert theiscsi_inquiryandiscsi_readcapacitycommands also to sync?Indeed, there is no real advantage in using
qemu_aio_wait(). I didn't know libiscsi also had sync APIs. :)
ok, give me some days to rewrite this patch. i think it should be ready by monday. i will also add the missing iscsi_create which is a few lines only then.
peter
Quoted 2 lines
Paolo
Am 15.11.2012 um 16:54 schrieb Paolo Bonzini <[email protected]>:
Quoted 5 lines
Il 15/11/2012 15:57, ronnie sahlberg ha scritto:
Quoted 2 lines
I dont know if we should switch to use synchronous code here. It is much nicer if all code is async.
bdrv_openis generally synchronous, so I think Peter's patch is ok.
would`t it be better to do the iscsi_inquiry commands and iscsi_readcapacity also sync?
peter
Quoted 6 lines
Paolo
Quoted 2 lines
Is it possible to add a timeout instead that would break out if the connect/login has not completed within a certain amount of time?