This eventfd can be used to get an event when merge_backward start work have finished and is waiting for completion.
Note: The eventfd can be changed even while work is running. Locking: The backward_merge.eventfd_ctx is protected from being released by tgt->ctl_mutex. https://virtuozzo.atlassian.net/browse/VSTOR-100466 Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com> -- v2: Always report that work finished, e.g. also on error or then it was canceled, this should be more consistent from the userspace perspective. v4: Address Andrey's reveiw: signal that we are at completion waiting on change of eventfd. --- drivers/md/dm-qcow2-cmd.c | 42 ++++++++++++++++++++++++++++++++++++++- drivers/md/dm-qcow2.h | 2 ++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-qcow2-cmd.c b/drivers/md/dm-qcow2-cmd.c index 04a992f3ebba6..f16b4f731ca5a 100644 --- a/drivers/md/dm-qcow2-cmd.c +++ b/drivers/md/dm-qcow2-cmd.c @@ -5,6 +5,8 @@ #include <linux/device-mapper.h> #include <linux/sched/signal.h> #include <linux/file.h> +#include <linux/eventfd.h> +#include <linux/minmax.h> #include <linux/error-injection.h> #include "dm-qcow2.h" @@ -197,6 +199,8 @@ void qcow2_merge_backward_work(struct work_struct *work) mutex_lock(&tgt->ctl_mutex); if (tgt->backward_merge.state != BACKWARD_MERGE_START) { + if (tgt->backward_merge.eventfd_ctx) + eventfd_signal(tgt->backward_merge.eventfd_ctx, 1); mutex_unlock(&tgt->ctl_mutex); return; } @@ -249,6 +253,8 @@ void qcow2_merge_backward_work(struct work_struct *work) /* Finish merge */ tgt->backward_merge.state = BACKWARD_MERGE_WAIT_COMPLETION; } + if (tgt->backward_merge.eventfd_ctx) + eventfd_signal(tgt->backward_merge.eventfd_ctx, 1); mutex_unlock(&tgt->ctl_mutex); } @@ -312,6 +318,27 @@ static bool qcow2_backward_merge_should_stop(struct qcow2_target *tgt) return READ_ONCE(tgt->backward_merge.state) == BACKWARD_MERGE_STOP; } +#define QCOW2_FILE_UNBIND -1 + +static int qcow2_merge_backward_set_eventfd(struct qcow2_target *tgt, int efd) +{ + struct eventfd_ctx *ctx = NULL; + + ctx = efd == QCOW2_FILE_UNBIND ? NULL : eventfd_ctx_fdget(efd); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + mutex_lock(&tgt->ctl_mutex); + swap(ctx, tgt->backward_merge.eventfd_ctx); + if (ctx) + eventfd_ctx_put(ctx); + if (tgt->backward_merge.eventfd_ctx && + tgt->backward_merge.state == BACKWARD_MERGE_WAIT_COMPLETION) + eventfd_signal(tgt->backward_merge.eventfd_ctx, 1); + mutex_unlock(&tgt->ctl_mutex); + return 0; +} + static struct qcow2 *qcow2_get_img(struct qcow2_target *tgt, u32 img_id, u8 *ref_index) { struct qcow2 *qcow2; @@ -470,14 +497,27 @@ int qcow2_message(struct dm_target *ti, unsigned int argc, char **argv, ret = qcow2_get_event(tgt, result, maxlen); goto out; } else if (!strcmp(argv[0], "merge_backward")) { - if (argc != 2) { + if (argc < 2) { ret = -EINVAL; goto out; } if (!strcmp(argv[1], "cancel")) { + if (argc != 2) { + ret = -EINVAL; + goto out; + } qcow2_merge_backward_cancel(tgt); ret = 0; goto out; + } else if (!strcmp(argv[1], "set_eventfd")) { + int efd; + + if (argc != 3 || kstrtoint(argv[2], 10, &efd)) { + ret = -EINVAL; + goto out; + } + ret = qcow2_merge_backward_set_eventfd(tgt, efd); + goto out; } } diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h index bebfdc50ed6d4..c4956e3fd0eb7 100644 --- a/drivers/md/dm-qcow2.h +++ b/drivers/md/dm-qcow2.h @@ -5,6 +5,7 @@ #include <linux/percpu-refcount.h> #include <linux/device-mapper.h> #include <linux/fs.h> +#include <linux/eventfd.h> #include "dm-core.h" #define DM_MSG_PREFIX "qcow2" @@ -161,6 +162,7 @@ struct qcow2_backward_merge { struct work_struct work; enum qcow2_backward_merge_state state; int error; + struct eventfd_ctx *eventfd_ctx; }; struct qcow2_target { -- 2.48.1 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel