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

filemon: ensure watch IDs are unique to QFileMonitor scope

The watch IDs are mistakenly only unique within the scope of the
directory being monitored. This is not useful for clients which are
monitoring multiple directories. They require watch IDs to be unique
globally within the QFileMonitor scope.

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Tested-by: Bandan Das <bsd@redhat.com>
Reviewed-by: Bandan Das <bsd@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>

+110 -11
+108 -8
tests/test-util-filemonitor.c
··· 35 35 QFILE_MONITOR_TEST_OP_RENAME, 36 36 QFILE_MONITOR_TEST_OP_TOUCH, 37 37 QFILE_MONITOR_TEST_OP_UNLINK, 38 + QFILE_MONITOR_TEST_OP_MKDIR, 39 + QFILE_MONITOR_TEST_OP_RMDIR, 38 40 }; 39 41 40 42 typedef struct { ··· 298 300 .eventid = QFILE_MONITOR_EVENT_DELETED }, 299 301 300 302 303 + { .type = QFILE_MONITOR_TEST_OP_MKDIR, 304 + .filesrc = "fish", }, 305 + { .type = QFILE_MONITOR_TEST_OP_EVENT, 306 + .filesrc = "fish", .watchid = 0, 307 + .eventid = QFILE_MONITOR_EVENT_CREATED }, 308 + 309 + 310 + { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH, 311 + .filesrc = "fish/", .watchid = 4 }, 312 + { .type = QFILE_MONITOR_TEST_OP_ADD_WATCH, 313 + .filesrc = "fish/one.txt", .watchid = 5 }, 314 + { .type = QFILE_MONITOR_TEST_OP_CREATE, 315 + .filesrc = "fish/one.txt", }, 316 + { .type = QFILE_MONITOR_TEST_OP_EVENT, 317 + .filesrc = "one.txt", .watchid = 4, 318 + .eventid = QFILE_MONITOR_EVENT_CREATED }, 319 + { .type = QFILE_MONITOR_TEST_OP_EVENT, 320 + .filesrc = "one.txt", .watchid = 5, 321 + .eventid = QFILE_MONITOR_EVENT_CREATED }, 322 + 323 + 324 + { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 325 + .filesrc = "fish/one.txt", .watchid = 5 }, 326 + { .type = QFILE_MONITOR_TEST_OP_RENAME, 327 + .filesrc = "fish/one.txt", .filedst = "two.txt", }, 328 + { .type = QFILE_MONITOR_TEST_OP_EVENT, 329 + .filesrc = "one.txt", .watchid = 4, 330 + .eventid = QFILE_MONITOR_EVENT_DELETED }, 331 + { .type = QFILE_MONITOR_TEST_OP_EVENT, 332 + .filesrc = "two.txt", .watchid = 0, 333 + .eventid = QFILE_MONITOR_EVENT_CREATED }, 334 + { .type = QFILE_MONITOR_TEST_OP_EVENT, 335 + .filesrc = "two.txt", .watchid = 2, 336 + .eventid = QFILE_MONITOR_EVENT_CREATED }, 337 + 338 + 339 + { .type = QFILE_MONITOR_TEST_OP_RMDIR, 340 + .filesrc = "fish", }, 341 + { .type = QFILE_MONITOR_TEST_OP_EVENT, 342 + .filesrc = "", .watchid = 4, 343 + .eventid = QFILE_MONITOR_EVENT_IGNORED }, 344 + { .type = QFILE_MONITOR_TEST_OP_EVENT, 345 + .filesrc = "fish", .watchid = 0, 346 + .eventid = QFILE_MONITOR_EVENT_DELETED }, 347 + { .type = QFILE_MONITOR_TEST_OP_DEL_WATCH, 348 + .filesrc = "fish", .watchid = 4 }, 349 + 350 + 301 351 { .type = QFILE_MONITOR_TEST_OP_UNLINK, 302 352 .filesrc = "two.txt", }, 303 353 { .type = QFILE_MONITOR_TEST_OP_EVENT, ··· 366 416 int fd; 367 417 int watchid; 368 418 struct utimbuf ubuf; 419 + char *watchdir; 420 + const char *watchfile; 369 421 370 422 pathsrc = g_strdup_printf("%s/%s", dir, op->filesrc); 371 423 if (op->filedst) { ··· 378 430 g_printerr("Add watch %s %s %d\n", 379 431 dir, op->filesrc, op->watchid); 380 432 } 433 + if (op->filesrc && strchr(op->filesrc, '/')) { 434 + watchdir = g_strdup_printf("%s/%s", dir, op->filesrc); 435 + watchfile = strrchr(watchdir, '/'); 436 + *(char *)watchfile = '\0'; 437 + watchfile++; 438 + if (*watchfile == '\0') { 439 + watchfile = NULL; 440 + } 441 + } else { 442 + watchdir = g_strdup(dir); 443 + watchfile = op->filesrc; 444 + } 381 445 watchid = 382 446 qemu_file_monitor_add_watch(mon, 383 - dir, 384 - op->filesrc, 447 + watchdir, 448 + watchfile, 385 449 qemu_file_monitor_test_handler, 386 450 &data, 387 451 &local_err); 452 + g_free(watchdir); 388 453 if (watchid < 0) { 389 454 g_printerr("Unable to add watch %s", 390 455 error_get_pretty(local_err)); ··· 400 465 if (debug) { 401 466 g_printerr("Del watch %s %d\n", dir, op->watchid); 402 467 } 468 + if (op->filesrc && strchr(op->filesrc, '/')) { 469 + watchdir = g_strdup_printf("%s/%s", dir, op->filesrc); 470 + watchfile = strrchr(watchdir, '/'); 471 + *(char *)watchfile = '\0'; 472 + } else { 473 + watchdir = g_strdup(dir); 474 + } 403 475 qemu_file_monitor_remove_watch(mon, 404 - dir, 476 + watchdir, 405 477 op->watchid); 478 + g_free(watchdir); 406 479 break; 407 480 case QFILE_MONITOR_TEST_OP_EVENT: 408 481 if (debug) { ··· 492 565 } 493 566 break; 494 567 568 + case QFILE_MONITOR_TEST_OP_MKDIR: 569 + if (debug) { 570 + g_printerr("Mkdir %s\n", pathsrc); 571 + } 572 + if (mkdir(pathsrc, 0700) < 0) { 573 + g_printerr("Unable to mkdir %s: %s", 574 + pathsrc, strerror(errno)); 575 + goto cleanup; 576 + } 577 + break; 578 + 579 + case QFILE_MONITOR_TEST_OP_RMDIR: 580 + if (debug) { 581 + g_printerr("Rmdir %s\n", pathsrc); 582 + } 583 + if (rmdir(pathsrc) < 0) { 584 + g_printerr("Unable to rmdir %s: %s", 585 + pathsrc, strerror(errno)); 586 + goto cleanup; 587 + } 588 + break; 589 + 495 590 default: 496 591 g_assert_not_reached(); 497 592 } ··· 532 627 const QFileMonitorTestOp *op = &(ops[i]); 533 628 char *path = g_strdup_printf("%s/%s", 534 629 dir, op->filesrc); 535 - unlink(path); 536 - g_free(path); 537 - if (op->filedst) { 538 - path = g_strdup_printf("%s/%s", 539 - dir, op->filedst); 630 + if (op->type == QFILE_MONITOR_TEST_OP_MKDIR) { 631 + rmdir(path); 632 + g_free(path); 633 + } else { 540 634 unlink(path); 541 635 g_free(path); 636 + if (op->filedst) { 637 + path = g_strdup_printf("%s/%s", 638 + dir, op->filedst); 639 + unlink(path); 640 + g_free(path); 641 + } 542 642 } 543 643 } 544 644 if (rmdir(dir) < 0) {
+2 -3
util/filemonitor-inotify.c
··· 29 29 30 30 struct QFileMonitor { 31 31 int fd; 32 - 32 + int nextid; /* watch ID counter */ 33 33 QemuMutex lock; /* protects dirs & idmap */ 34 34 GHashTable *dirs; /* dirname => QFileMonitorDir */ 35 35 GHashTable *idmap; /* inotify ID => dirname */ ··· 47 47 typedef struct { 48 48 char *path; 49 49 int id; /* inotify ID */ 50 - int nextid; /* watch ID counter */ 51 50 GArray *watches; /* QFileMonitorWatch elements */ 52 51 } QFileMonitorDir; 53 52 ··· 277 276 } 278 277 } 279 278 280 - watch.id = dir->nextid++; 279 + watch.id = mon->nextid++; 281 280 watch.filename = g_strdup(filename); 282 281 watch.cb = cb; 283 282 watch.opaque = opaque;