diff mbox

[v7,14/24] nbd: Switch from close to eject notifier

Message ID 1447108773-6836-15-git-send-email-mreitz@redhat.com
State New
Headers show

Commit Message

Max Reitz Nov. 9, 2015, 10:39 p.m. UTC
The NBD code uses the BDS close notifier to determine when a medium is
ejected. However, now it should use the BB's BDS removal notifier for
that instead of the BDS's close notifier.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev-nbd.c | 37 +------------------------------------
 nbd.c          | 13 +++++++++++++
 2 files changed, 14 insertions(+), 36 deletions(-)

Comments

Kevin Wolf Nov. 30, 2015, 3:36 p.m. UTC | #1
Am 09.11.2015 um 23:39 hat Max Reitz geschrieben:
> The NBD code uses the BDS close notifier to determine when a medium is
> ejected. However, now it should use the BB's BDS removal notifier for
> that instead of the BDS's close notifier.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev-nbd.c | 37 +------------------------------------
>  nbd.c          | 13 +++++++++++++
>  2 files changed, 14 insertions(+), 36 deletions(-)
> 
> diff --git a/blockdev-nbd.c b/blockdev-nbd.c
> index bcdd18b..b28a55b 100644
> --- a/blockdev-nbd.c
> +++ b/blockdev-nbd.c
> @@ -46,37 +46,11 @@ void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
>      }
>  }
>  
> -/*
> - * Hook into the BlockBackend notifiers to close the export when the
> - * backend is closed.
> - */
> -typedef struct NBDCloseNotifier {
> -    Notifier n;
> -    NBDExport *exp;
> -    QTAILQ_ENTRY(NBDCloseNotifier) next;
> -} NBDCloseNotifier;
> -
> -static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
> -    QTAILQ_HEAD_INITIALIZER(close_notifiers);
> -
> -static void nbd_close_notifier(Notifier *n, void *data)
> -{
> -    NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
> -
> -    notifier_remove(&cn->n);
> -    QTAILQ_REMOVE(&close_notifiers, cn, next);
> -
> -    nbd_export_close(cn->exp);
> -    nbd_export_put(cn->exp);

Here you remove a close/put pair, but in the new code you only add the
close call. Why is this correct?

Kevin
Max Reitz Nov. 30, 2015, 5:22 p.m. UTC | #2
On 30.11.2015 16:36, Kevin Wolf wrote:
> Am 09.11.2015 um 23:39 hat Max Reitz geschrieben:
>> The NBD code uses the BDS close notifier to determine when a medium is
>> ejected. However, now it should use the BB's BDS removal notifier for
>> that instead of the BDS's close notifier.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>>  blockdev-nbd.c | 37 +------------------------------------
>>  nbd.c          | 13 +++++++++++++
>>  2 files changed, 14 insertions(+), 36 deletions(-)
>>
>> diff --git a/blockdev-nbd.c b/blockdev-nbd.c
>> index bcdd18b..b28a55b 100644
>> --- a/blockdev-nbd.c
>> +++ b/blockdev-nbd.c
>> @@ -46,37 +46,11 @@ void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
>>      }
>>  }
>>  
>> -/*
>> - * Hook into the BlockBackend notifiers to close the export when the
>> - * backend is closed.
>> - */
>> -typedef struct NBDCloseNotifier {
>> -    Notifier n;
>> -    NBDExport *exp;
>> -    QTAILQ_ENTRY(NBDCloseNotifier) next;
>> -} NBDCloseNotifier;
>> -
>> -static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
>> -    QTAILQ_HEAD_INITIALIZER(close_notifiers);
>> -
>> -static void nbd_close_notifier(Notifier *n, void *data)
>> -{
>> -    NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
>> -
>> -    notifier_remove(&cn->n);
>> -    QTAILQ_REMOVE(&close_notifiers, cn, next);
>> -
>> -    nbd_export_close(cn->exp);
>> -    nbd_export_put(cn->exp);
> 
> Here you remove a close/put pair, but in the new code you only add the
> close call. Why is this correct?

Thanks for putting so much unfounded faith in me. :-)

After having put quite some time into looking into it, first I have to
say that it's a very good question.

First off, it's wrong. This is because I thought every export would have
a refcount of one. Turns out this is wrong, they have a refcount of two:
It is created with a refcount of one, and then it gains another by
giving it a name and entering it into the export list.

I did know about the second but I completely forgot about the former.
And indeed I do think it is wrong. qmp_nbd_server_add() does not keep
the reference to the export, once the function returns, it is gone.
Therefore, it should call nbd_export_put() before returning.

So in my opinion the current code is wrong and I didn't fix it enough.
*cough*

So, with the nbd_export_put() added to qmp_nbd_server_add(), every
export will have a refcount of 1 + |clients|. The eject notifier will
call nbd_close_notifier(), which first disconnects the clients, thus
reducing the refcount by |clients|, and then sets the name to NULL, thus
dropping the final refcount and destroying the export.

In the old code, we needed another nbd_export_put() because of the
superfluous reference from nbd_export_new(), which doesn't actually
exist for blockdev-nbd (it does for qemu-nbd, though).

Max
Kevin Wolf Dec. 1, 2015, 1:16 p.m. UTC | #3
Am 30.11.2015 um 18:22 hat Max Reitz geschrieben:
> On 30.11.2015 16:36, Kevin Wolf wrote:
> > Am 09.11.2015 um 23:39 hat Max Reitz geschrieben:
> >> The NBD code uses the BDS close notifier to determine when a medium is
> >> ejected. However, now it should use the BB's BDS removal notifier for
> >> that instead of the BDS's close notifier.
> >>
> >> Signed-off-by: Max Reitz <mreitz@redhat.com>
> >> ---
> >>  blockdev-nbd.c | 37 +------------------------------------
> >>  nbd.c          | 13 +++++++++++++
> >>  2 files changed, 14 insertions(+), 36 deletions(-)
> >>
> >> diff --git a/blockdev-nbd.c b/blockdev-nbd.c
> >> index bcdd18b..b28a55b 100644
> >> --- a/blockdev-nbd.c
> >> +++ b/blockdev-nbd.c
> >> @@ -46,37 +46,11 @@ void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
> >>      }
> >>  }
> >>  
> >> -/*
> >> - * Hook into the BlockBackend notifiers to close the export when the
> >> - * backend is closed.
> >> - */
> >> -typedef struct NBDCloseNotifier {
> >> -    Notifier n;
> >> -    NBDExport *exp;
> >> -    QTAILQ_ENTRY(NBDCloseNotifier) next;
> >> -} NBDCloseNotifier;
> >> -
> >> -static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
> >> -    QTAILQ_HEAD_INITIALIZER(close_notifiers);
> >> -
> >> -static void nbd_close_notifier(Notifier *n, void *data)
> >> -{
> >> -    NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
> >> -
> >> -    notifier_remove(&cn->n);
> >> -    QTAILQ_REMOVE(&close_notifiers, cn, next);
> >> -
> >> -    nbd_export_close(cn->exp);
> >> -    nbd_export_put(cn->exp);
> > 
> > Here you remove a close/put pair, but in the new code you only add the
> > close call. Why is this correct?
> 
> Thanks for putting so much unfounded faith in me. :-)
> 
> After having put quite some time into looking into it, first I have to
> say that it's a very good question.
> 
> First off, it's wrong. This is because I thought every export would have
> a refcount of one. Turns out this is wrong, they have a refcount of two:
> It is created with a refcount of one, and then it gains another by
> giving it a name and entering it into the export list.
> 
> I did know about the second but I completely forgot about the former.
> And indeed I do think it is wrong. qmp_nbd_server_add() does not keep
> the reference to the export, once the function returns, it is gone.
> Therefore, it should call nbd_export_put() before returning.
> 
> So in my opinion the current code is wrong and I didn't fix it enough.
> *cough*
> 
> So, with the nbd_export_put() added to qmp_nbd_server_add(), every
> export will have a refcount of 1 + |clients|. The eject notifier will
> call nbd_close_notifier(), which first disconnects the clients, thus
> reducing the refcount by |clients|, and then sets the name to NULL, thus
> dropping the final refcount and destroying the export.
> 
> In the old code, we needed another nbd_export_put() because of the
> superfluous reference from nbd_export_new(), which doesn't actually
> exist for blockdev-nbd (it does for qemu-nbd, though).

Okay, that makes sense to me. So first a patch that moves the existing
nbd_export_put() call from nbd_close_notifier() to qmp_nbd_server_add()
and then this one on top?

Kevin
Max Reitz Dec. 2, 2015, 3:51 p.m. UTC | #4
On 01.12.2015 14:16, Kevin Wolf wrote:
> Am 30.11.2015 um 18:22 hat Max Reitz geschrieben:
>> On 30.11.2015 16:36, Kevin Wolf wrote:
>>> Am 09.11.2015 um 23:39 hat Max Reitz geschrieben:
>>>> The NBD code uses the BDS close notifier to determine when a medium is
>>>> ejected. However, now it should use the BB's BDS removal notifier for
>>>> that instead of the BDS's close notifier.
>>>>
>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>> ---
>>>>  blockdev-nbd.c | 37 +------------------------------------
>>>>  nbd.c          | 13 +++++++++++++
>>>>  2 files changed, 14 insertions(+), 36 deletions(-)
>>>>
>>>> diff --git a/blockdev-nbd.c b/blockdev-nbd.c
>>>> index bcdd18b..b28a55b 100644
>>>> --- a/blockdev-nbd.c
>>>> +++ b/blockdev-nbd.c
>>>> @@ -46,37 +46,11 @@ void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
>>>>      }
>>>>  }
>>>>  
>>>> -/*
>>>> - * Hook into the BlockBackend notifiers to close the export when the
>>>> - * backend is closed.
>>>> - */
>>>> -typedef struct NBDCloseNotifier {
>>>> -    Notifier n;
>>>> -    NBDExport *exp;
>>>> -    QTAILQ_ENTRY(NBDCloseNotifier) next;
>>>> -} NBDCloseNotifier;
>>>> -
>>>> -static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
>>>> -    QTAILQ_HEAD_INITIALIZER(close_notifiers);
>>>> -
>>>> -static void nbd_close_notifier(Notifier *n, void *data)
>>>> -{
>>>> -    NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
>>>> -
>>>> -    notifier_remove(&cn->n);
>>>> -    QTAILQ_REMOVE(&close_notifiers, cn, next);
>>>> -
>>>> -    nbd_export_close(cn->exp);
>>>> -    nbd_export_put(cn->exp);
>>>
>>> Here you remove a close/put pair, but in the new code you only add the
>>> close call. Why is this correct?
>>
>> Thanks for putting so much unfounded faith in me. :-)
>>
>> After having put quite some time into looking into it, first I have to
>> say that it's a very good question.
>>
>> First off, it's wrong. This is because I thought every export would have
>> a refcount of one. Turns out this is wrong, they have a refcount of two:
>> It is created with a refcount of one, and then it gains another by
>> giving it a name and entering it into the export list.
>>
>> I did know about the second but I completely forgot about the former.
>> And indeed I do think it is wrong. qmp_nbd_server_add() does not keep
>> the reference to the export, once the function returns, it is gone.
>> Therefore, it should call nbd_export_put() before returning.
>>
>> So in my opinion the current code is wrong and I didn't fix it enough.
>> *cough*
>>
>> So, with the nbd_export_put() added to qmp_nbd_server_add(), every
>> export will have a refcount of 1 + |clients|. The eject notifier will
>> call nbd_close_notifier(), which first disconnects the clients, thus
>> reducing the refcount by |clients|, and then sets the name to NULL, thus
>> dropping the final refcount and destroying the export.
>>
>> In the old code, we needed another nbd_export_put() because of the
>> superfluous reference from nbd_export_new(), which doesn't actually
>> exist for blockdev-nbd (it does for qemu-nbd, though).
> 
> Okay, that makes sense to me. So first a patch that moves the existing
> nbd_export_put() call from nbd_close_notifier() to qmp_nbd_server_add()
> and then this one on top?

I would have put both in the same patch, but this does make more sense.
I'll do so.

Max
diff mbox

Patch

diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index bcdd18b..b28a55b 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -46,37 +46,11 @@  void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
     }
 }
 
-/*
- * Hook into the BlockBackend notifiers to close the export when the
- * backend is closed.
- */
-typedef struct NBDCloseNotifier {
-    Notifier n;
-    NBDExport *exp;
-    QTAILQ_ENTRY(NBDCloseNotifier) next;
-} NBDCloseNotifier;
-
-static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
-    QTAILQ_HEAD_INITIALIZER(close_notifiers);
-
-static void nbd_close_notifier(Notifier *n, void *data)
-{
-    NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
-
-    notifier_remove(&cn->n);
-    QTAILQ_REMOVE(&close_notifiers, cn, next);
-
-    nbd_export_close(cn->exp);
-    nbd_export_put(cn->exp);
-    g_free(cn);
-}
-
 void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
                         Error **errp)
 {
     BlockBackend *blk;
     NBDExport *exp;
-    NBDCloseNotifier *n;
 
     if (server_fd == -1) {
         error_setg(errp, "NBD server not running");
@@ -113,20 +87,11 @@  void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
     }
 
     nbd_export_set_name(exp, device);
-
-    n = g_new0(NBDCloseNotifier, 1);
-    n->n.notify = nbd_close_notifier;
-    n->exp = exp;
-    blk_add_close_notifier(blk, &n->n);
-    QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
 }
 
 void qmp_nbd_server_stop(Error **errp)
 {
-    while (!QTAILQ_EMPTY(&close_notifiers)) {
-        NBDCloseNotifier *cn = QTAILQ_FIRST(&close_notifiers);
-        nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp));
-    }
+    nbd_export_close_all();
 
     if (server_fd != -1) {
         qemu_set_fd_handler(server_fd, NULL, NULL, NULL);
diff --git a/nbd.c b/nbd.c
index b3d9654..ab2e725 100644
--- a/nbd.c
+++ b/nbd.c
@@ -162,6 +162,8 @@  struct NBDExport {
     QTAILQ_ENTRY(NBDExport) next;
 
     AioContext *ctx;
+
+    Notifier eject_notifier;
 };
 
 static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
@@ -1053,6 +1055,12 @@  static void blk_aio_detach(void *opaque)
     exp->ctx = NULL;
 }
 
+static void nbd_eject_notifier(Notifier *n, void *data)
+{
+    NBDExport *exp = container_of(n, NBDExport, eject_notifier);
+    nbd_export_close(exp);
+}
+
 NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
                           uint32_t nbdflags, void (*close)(NBDExport *),
                           Error **errp)
@@ -1075,6 +1083,10 @@  NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
     exp->ctx = blk_get_aio_context(blk);
     blk_ref(blk);
     blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp);
+
+    exp->eject_notifier.notify = nbd_eject_notifier;
+    blk_add_remove_bs_notifier(blk, &exp->eject_notifier);
+
     /*
      * NBD exports are used for non-shared storage migration.  Make sure
      * that BDRV_O_INCOMING is cleared and the image is ready for write
@@ -1154,6 +1166,7 @@  void nbd_export_put(NBDExport *exp)
         }
 
         if (exp->blk) {
+            notifier_remove(&exp->eject_notifier);
             blk_remove_aio_context_notifier(exp->blk, blk_aio_attached,
                                             blk_aio_detach, exp);
             blk_unref(exp->blk);