qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

block: let blk_add/remove_aio_context_notifier() tolerate BDS changes

Commit 2019ba0a0197 ("block: Add AioContextNotifier functions to BB")
added blk_add/remove_aio_context_notifier() and implemented them by
passing through the bdrv_*() equivalent.

This doesn't work across bdrv_append(), which detaches child->bs and
re-attaches it to a new BlockDriverState. When
blk_remove_aio_context_notifier() is called we will access the new BDS
instead of the one where the notifier was added!

>From the point of view of the blk_*() API user, changes to the root BDS
should be transparent.

This patch maintains a list of AioContext notifiers in BlockBackend and
adds/removes them from the BlockDriverState as needed.

Reported-by: Stefano Panella <spanella@gmail.com>
Cc: Max Reitz <mreitz@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20180306204819.11266-2-stefanha@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>

authored by

Stefan Hajnoczi and committed by
Eric Blake
d03654ea 65529782

+65
+63
block/block-backend.c
··· 31 31 32 32 static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb); 33 33 34 + typedef struct BlockBackendAioNotifier { 35 + void (*attached_aio_context)(AioContext *new_context, void *opaque); 36 + void (*detach_aio_context)(void *opaque); 37 + void *opaque; 38 + QLIST_ENTRY(BlockBackendAioNotifier) list; 39 + } BlockBackendAioNotifier; 40 + 34 41 struct BlockBackend { 35 42 char *name; 36 43 int refcnt; ··· 69 76 bool allow_write_beyond_eof; 70 77 71 78 NotifierList remove_bs_notifiers, insert_bs_notifiers; 79 + QLIST_HEAD(, BlockBackendAioNotifier) aio_notifiers; 72 80 73 81 int quiesce_counter; 74 82 VMChangeStateEntry *vmsh; ··· 247 255 return 0; 248 256 } 249 257 258 + static void blk_root_attach(BdrvChild *child) 259 + { 260 + BlockBackend *blk = child->opaque; 261 + BlockBackendAioNotifier *notifier; 262 + 263 + trace_blk_root_attach(child, blk, child->bs); 264 + 265 + QLIST_FOREACH(notifier, &blk->aio_notifiers, list) { 266 + bdrv_add_aio_context_notifier(child->bs, 267 + notifier->attached_aio_context, 268 + notifier->detach_aio_context, 269 + notifier->opaque); 270 + } 271 + } 272 + 273 + static void blk_root_detach(BdrvChild *child) 274 + { 275 + BlockBackend *blk = child->opaque; 276 + BlockBackendAioNotifier *notifier; 277 + 278 + trace_blk_root_detach(child, blk, child->bs); 279 + 280 + QLIST_FOREACH(notifier, &blk->aio_notifiers, list) { 281 + bdrv_remove_aio_context_notifier(child->bs, 282 + notifier->attached_aio_context, 283 + notifier->detach_aio_context, 284 + notifier->opaque); 285 + } 286 + } 287 + 250 288 static const BdrvChildRole child_root = { 251 289 .inherit_options = blk_root_inherit_options, 252 290 ··· 260 298 261 299 .activate = blk_root_activate, 262 300 .inactivate = blk_root_inactivate, 301 + 302 + .attach = blk_root_attach, 303 + .detach = blk_root_detach, 263 304 }; 264 305 265 306 /* ··· 287 328 288 329 notifier_list_init(&blk->remove_bs_notifiers); 289 330 notifier_list_init(&blk->insert_bs_notifiers); 331 + QLIST_INIT(&blk->aio_notifiers); 290 332 291 333 QTAILQ_INSERT_TAIL(&block_backends, blk, link); 292 334 return blk; ··· 364 406 } 365 407 assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers)); 366 408 assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers)); 409 + assert(QLIST_EMPTY(&blk->aio_notifiers)); 367 410 QTAILQ_REMOVE(&block_backends, blk, link); 368 411 drive_info_del(blk->legacy_dinfo); 369 412 block_acct_cleanup(&blk->stats); ··· 1857 1900 void (*attached_aio_context)(AioContext *new_context, void *opaque), 1858 1901 void (*detach_aio_context)(void *opaque), void *opaque) 1859 1902 { 1903 + BlockBackendAioNotifier *notifier; 1860 1904 BlockDriverState *bs = blk_bs(blk); 1861 1905 1906 + notifier = g_new(BlockBackendAioNotifier, 1); 1907 + notifier->attached_aio_context = attached_aio_context; 1908 + notifier->detach_aio_context = detach_aio_context; 1909 + notifier->opaque = opaque; 1910 + QLIST_INSERT_HEAD(&blk->aio_notifiers, notifier, list); 1911 + 1862 1912 if (bs) { 1863 1913 bdrv_add_aio_context_notifier(bs, attached_aio_context, 1864 1914 detach_aio_context, opaque); ··· 1871 1921 void (*detach_aio_context)(void *), 1872 1922 void *opaque) 1873 1923 { 1924 + BlockBackendAioNotifier *notifier; 1874 1925 BlockDriverState *bs = blk_bs(blk); 1875 1926 1876 1927 if (bs) { 1877 1928 bdrv_remove_aio_context_notifier(bs, attached_aio_context, 1878 1929 detach_aio_context, opaque); 1879 1930 } 1931 + 1932 + QLIST_FOREACH(notifier, &blk->aio_notifiers, list) { 1933 + if (notifier->attached_aio_context == attached_aio_context && 1934 + notifier->detach_aio_context == detach_aio_context && 1935 + notifier->opaque == opaque) { 1936 + QLIST_REMOVE(notifier, list); 1937 + g_free(notifier); 1938 + return; 1939 + } 1940 + } 1941 + 1942 + abort(); 1880 1943 } 1881 1944 1882 1945 void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify)
+2
block/trace-events
··· 7 7 # block/block-backend.c 8 8 blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x" 9 9 blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x" 10 + blk_root_attach(void *child, void *blk, void *bs) "child %p blk %p bs %p" 11 + blk_root_detach(void *child, void *blk, void *bs) "child %p blk %p bs %p" 10 12 11 13 # block/io.c 12 14 bdrv_co_preadv(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x"