diff --git a/changelogs/unreleased/gh-9995-vy-scheduler-crash-fix.md b/changelogs/unreleased/gh-9995-vy-scheduler-crash-fix.md new file mode 100644 index 0000000000000000000000000000000000000000..f8ffbff55667aed9a3309f780fd0235a9b838a26 --- /dev/null +++ b/changelogs/unreleased/gh-9995-vy-scheduler-crash-fix.md @@ -0,0 +1,4 @@ +## bugfix/vinyl + +* Fixed a use-after-free bug in the compaction scheduler triggered by a race + with a concurrent DDL operation (gh-9995). diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c index daddff071cef4b75664b69af8cb092159c7c6a6e..ea9b438bdb7a7c3f3ce4778898ba18cd3cba7380 100644 --- a/src/box/vy_scheduler.c +++ b/src/box/vy_scheduler.c @@ -1839,6 +1839,11 @@ vy_scheduler_peek_dump(struct vy_scheduler *scheduler, struct vy_task **ptask) } if (!lsm->is_dumping && lsm->pin_count == 0 && vy_lsm_generation(lsm) == scheduler->dump_generation) { + /* + * The code below may yield. Take a reference to the LSM tree + * to make sure it isn't deleted in the meantime. + */ + vy_lsm_ref(lsm); /* * Dump is in progress and there is an LSM tree that * contains data that must be dumped at the current @@ -1846,13 +1851,17 @@ vy_scheduler_peek_dump(struct vy_scheduler *scheduler, struct vy_task **ptask) */ if (worker == NULL) { worker = vy_worker_pool_get(&scheduler->dump_pool); - if (worker == NULL) + if (worker == NULL) { + vy_lsm_unref(lsm); return 0; /* all workers are busy */ + } } if (vy_task_dump_new(scheduler, worker, lsm, ptask) != 0) { vy_worker_pool_put(worker); + vy_lsm_unref(lsm); return -1; } + vy_lsm_unref(lsm); if (*ptask != NULL) return 0; /* new task */ /* @@ -1909,15 +1918,24 @@ vy_scheduler_peek_compaction(struct vy_scheduler *scheduler, goto no_task; /* nothing to do */ if (vy_lsm_compaction_priority(lsm) <= 1) goto no_task; /* nothing to do */ + /* + * The code below may yield. Take a reference to the LSM tree + * to make sure it isn't deleted in the meantime. + */ + vy_lsm_ref(lsm); if (worker == NULL) { worker = vy_worker_pool_get(&scheduler->compaction_pool); - if (worker == NULL) + if (worker == NULL) { + vy_lsm_unref(lsm); return 0; /* all workers are busy */ + } } if (vy_task_compaction_new(scheduler, worker, lsm, ptask) != 0) { vy_worker_pool_put(worker); + vy_lsm_unref(lsm); return -1; } + vy_lsm_unref(lsm); if (*ptask == NULL) goto retry; /* LSM tree dropped or range split/coalesced */ return 0; /* new task */