From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (mail.openvz.org [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id A5E358045D for ; Wed, 4 Nov 2026 08:44:04 +0000 (UTC) Received: from mail.openvz.org (localhost [127.0.0.1]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 6A48gmqg022382; Wed, 4 Nov 2026 11:42:49 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 6A48gmqg022382 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="rh1/gYNo" Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 6A48gbH1022336 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Wed, 4 Nov 2026 11:42:37 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 6A48gbH1022336 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4a1e489f97fso6036845e9.0 for ; Wed, 04 Nov 2026 00:42:37 -0800 (PST) X-Gm-Message-State: APuU4Z+zJwBLgG7VLEALbKlp18erQk2l9xlVjANbPNWYdXZhFeyJ5oZQ Cr9kWQlUfJWo7keJql7ZluNu/KY6j7i+HDTzCoo67dFZJUeX/vbmXFO2OPyOxinvrer43EGZ9Vv FhBBIGXwm+q4ILsyhaYwBi2rVwUKnATLYl5igGl0FK3kv5zb37sgwKA== X-Gm-Gg: AYBFou0Ht4JgotCulZBsifJC+NEVbqNObGjTqiQIeQPiHc0Mumxa6AP72MeV8oBv5JT fa0+WELN1fMcjMRsrtuU32LPWzQsTo0Hwg5Er71A9PPEP9n3eRrM3JJqyN0sVfg81NbgNPPK2KN nm8X7R8dSRJnyB3I0eTVnxHlaLIQuypYIOL0sDCufiBSonTAqRh0ezn54rXrRSr8aQtWVYdbeMz LcWhx1SSDKq8mPGrTQgtz6NtVMP0y5pmjoC+NlE2yOrpDkcFU1xbK3ZQIqQ/fH7FB00tb2Mpbka 9ttJiXBh18Ud8gmBkOLP2Z4lVF+A1gZ1g/1KMz79/IcDdzTZtFB4+aNcBI78vvleWTwXnRifDsR BMZ98lnpI/fDuTdcei7lLzj1J4csExw== X-Received: by 2002:a05:600c:138c:b0:4a1:acaa:9d4c with SMTP id 5b1f17b1804b1-4ac18c740c5mr339791345e9.25.1793781757144; Wed, 04 Nov 2026 00:42:37 -0800 (PST) X-Received: by 2002:a05:600c:138c:b0:4a1:acaa:9d4c with SMTP id 5b1f17b1804b1-4ac18c740c5mr339791045e9.25.1793781756700; Wed, 04 Nov 2026 00:42:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1793781756; cv=none; d=google.com; s=arc-20260327; b=muii30MDl2yawbiZseEmFeq1imQ+8yzCKDOClBlAdH1KycjAO98QF5fi1r+9j6V/U5 9XNm1Ag5NOaHog8G9bbFuchGkuXr08JmsvOVVpOFgzmE3sJ2WX/xFstwj2+CzDQ9F3V9 izZSpt6F74itXX4ewruf2vehyCUdvRlc7zM781e7+fO+d45A1947GNBQrKNg/GLzX9Ci MTYO6UVAoQ/QgiVQz0exmyUaRQ+QNbW92kpeo54JFxUjpbjHejZhxXF+SacPrUHnON3S ISKC78mmffDKqe/xZ6vLp3zjZHNQhPOHce/zTOksTSwJPmWqFgvZBVaZepZmti1xI+s8 StIw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=hcOW8iUqQYHh7lltuYVaK8q+VhumFRElLMW7SWV/xDg=; fh=ElTTnnNtphHTCCOZ+58STyaWac7y7ytLDJZIF4HMMJ4=; b=DdeJ3ruX8y1YOTP/SnME+87YmigFgumMRbFmjF+L+lQO/5QEvHCgLyNF9ADOxKXGL9 M+YSjif3yvkcA8cw061YRbfbR79/soP0A1tRwiSEfn7ZXpkTh0NKMFDEdAAICbTSkA4B 5jlLBYz2SC02K4w7dp0MowonvrfHCbY/PvUD0SSKbs4cJSSmmJvtW4Usy/vZ9g0k9syw KNcUxnkxZCSIHiagALhh9rBpPdFBQXEFIXwZKHRbJdqXWWjLg3zvBr+lhPNzR9zGllmb QmRW/Ij9vldaUj2BlG+C4KoiBI+Jh5OsQBELrX1BjrLmzfT7jgadkwiIKYblfutuLrR8 LCDA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b="rh1/gYNo"; spf=pass (google.com: domain of andrey.zhadchenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=andrey.zhadchenko@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: from relay.virtuozzo.com (relay.virtuozzo.com. [130.117.225.111]) by mx.google.com with ESMTPS id 5b1f17b1804b1-4b43c36d512si27823075e9.5.2026.11.04.00.42.36 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2026 00:42:36 -0800 (PST) Received-SPF: pass (google.com: domain of andrey.zhadchenko@virtuozzo.com designates 130.117.225.111 as permitted sender) client-ip=130.117.225.111; Authentication-Results: mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b="rh1/gYNo"; spf=pass (google.com: domain of andrey.zhadchenko@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=andrey.zhadchenko@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=hcOW8iUqQYHh7lltuYVaK8q+VhumFRElLMW7SWV/xDg=; b=rh1/gYNok0/h M3ghTUhLmq857xpBpL73UsEGFERPq+l+nzX3BpmxpW5EmmfKMMEbYauCvQQ9ere+Khs/Bh8UCBQ2e 8FKyH1ZNyonvVtp2T2cQZ59J15nby6uFWHoygfhj4s8zi6zWc//42aJ2p4qNrhXgZQc78HyCj4Juf xyZkJ30V3Ocn8cKkas2+h5IQC+wISadW5u4U5RfcGfwgYn8JGtfhUBiRjK6ha9e3kq75TClYsbVJu m4sCYn549z1nNmxeYaHmBhR7Kvn2yRIAZ9vtNDFDfdZGQHlcVAQFA706bF153QoholUIiNpIUIB7O /FVp7JEpBLiCI53CFdOg2w==; Received: from [130.117.225.5] (helo=vz9-demens-1.aci.vzint.dev) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1xOWVr-005ttV-3B; Wed, 04 Nov 2026 09:42:36 +0100 From: Andrey Zhadchenko To: khorenko@virtuozzo.com, alexander.ivanov@virtuozzo.com Date: Wed, 4 Nov 2026 11:38:16 +0300 Message-ID: <20261104083818.856720-6-andrey.zhadchenko@virtuozzo.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20261104083818.856720-1-andrey.zhadchenko@virtuozzo.com> References: <20261104083818.856720-1-andrey.zhadchenko@virtuozzo.com> MIME-Version: 1.0 X-OZ-Fwd: true Cc: devel@openvz.org Subject: [Devel] [PATCH hci-8.1 v6 5/7] dm/push_backup: arm deadline timer under pb->lock X-BeenThere: devel@openvz.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: OpenVZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: devel-bounces@openvz.org Errors-To: devel-bounces@openvz.org Both pb_timer_func() and postpone_if_required_for_backup() decide whether to arm the timer under pb->lock but call mod_timer() after dropping it, so the decisions can be applied out of order: CPU1 pb_timer_func() CPU2 postpone_if_required_for_backup() lock; deadline = S64_MAX unlock lock; nr_delayed = 1 deadline_jiffies = now + timeout unlock mod_timer(timeout) mod_timer(from S64_MAX) The late mod_timer() of the callback overwrites the fresh deadline, and the write is delayed with the timer parked in a very distant future. Only a later push_backup_write() that leaves requests delayed re-arms it; if the backup tool stops acknowledging ranges, the backup never expires. Make the decision and the arming atomic: call mod_timer() under pb->lock at both sites, and do not re-arm when nothing is delayed. mod_timer() and queue_work() are fine under a spinlock, and the timer base lock is dropped while the callback runs, so there is no lock inversion. The callback checks pb->nr_delayed rather than pb->alive on purpose. pb_message() clears pb->alive for "push_backup_stop" before taking pb->ctl_rwsem, and if the tool gets a fatal signal while waiting for the rwsem, push_backup_stop() never runs. The deadline must still expire then, so that do_pb_work() releases the delayed writes. cleanup_backup() zeroes nr_delayed under the same lock hold that clears alive, and postpone only delays while alive, so after stop the callback neither re-arms nor queues work. While alive, nr_delayed == 0 is the same as deadline_jiffies == S64_MAX. The callback racing with push_backup_stop() was never handled either. synchronize_rcu() waits for a callback that is already running when it starts, since the timer softirq is an RCU reader, but not for a firing that starts after the grace period. timer_delete_sync_try() is try_to_del_timer_sync(), it returns -1 without waiting when the callback is running, and we only WARN on that. Such a callback could re-arm the timer or queue do_pb_work() after flush_workqueue(), expiring a later session. The same happens in pb_destroy(), which WARNs and goes on to destroy_workqueue() and kfree(pb) under the running callback: a use-after-free. Use timer_delete_sync() in push_backup_stop() and timer_shutdown_sync() in pb_destroy() to wait for it; the work it may have queued is flushed by flush_workqueue()/destroy_workqueue() which follow. As a bonus the rcu_read_lock()/synchronize_rcu() dance between postpone_if_required_for_backup() and push_backup_stop() is no longer needed: the timer is only armed under pb->lock, by postpone while pb->alive is set and by the callback while requests are delayed, both of which cleanup_backup() ends under pb->lock, and the callback itself is waited for. Drop it. push_backup_write() still re-arms the timer outside pb->lock, but it is serialized with push_backup_stop() by pb->ctl_rwsem; the next patch removes that call. Fixes: 62e07487348e ("dm: Add push backup driver") https://virtuozzo.atlassian.net/browse/VSTOR-152912 Feature: dm-backup: push backup target driver Signed-off-by: Andrey Zhadchenko Reviewed-by: Alexander Ivanov --- v2: new patch v3: bail out of pb_timer_func() when !pb->alive; wait for a running callback with timer_delete_sync() in push_backup_stop() and timer_shutdown_sync() in pb_destroy() instead of WARNing on timer_delete_sync_try() < 0; fixed the commit message claim about it v4: no changes v5: moved before "do not re-arm deadline timer"; pb_timer_func() checks pb->nr_delayed instead of pb->alive, so an interrupted "push_backup_stop" still expires the deadline; commit message describes the race instead of the harmless parked timer, the synchronize_rcu() window precisely and the pb_destroy() use-after-free; added Fixes: tag v6: subject prefix changed to dm/push_backup, added Feature: tag drivers/md/dm-push-backup.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/md/dm-push-backup.c b/drivers/md/dm-push-backup.c index b6d1629245235..f0de26add11c2 100644 --- a/drivers/md/dm-push-backup.c +++ b/drivers/md/dm-push-backup.c @@ -241,23 +241,24 @@ static void pb_timer_func(struct timer_list *timer) spin_lock_irqsave(&pb->lock, flags); deadline = pb->deadline_jiffies; - spin_unlock_irqrestore(&pb->lock, flags); - + if (!pb->nr_delayed) + goto unlock; if (unlikely(time_before64(now, deadline))) mod_timer(timer, jiffies + (deadline - now) + 1); else queue_work(pb->wq, &pb->worker); +unlock: + spin_unlock_irqrestore(&pb->lock, flags); } static int postpone_if_required_for_backup(struct push_backup *pb, struct request *rq) { - bool queue_timer = false; struct pb_bio *pbio; unsigned long flags; + bool wake = false; int ret = 0; - rcu_read_lock(); /* See push_backup_stop() */ spin_lock_irqsave(&pb->lock, flags); if (!pb->alive) goto unlock; @@ -272,16 +273,13 @@ static int postpone_if_required_for_backup(struct push_backup *pb, pb->nr_delayed += 1; if (pb->nr_delayed == 1) { pb->deadline_jiffies = get_jiffies_64() + pb->timeout_in_jiffies; - queue_timer = true; + mod_timer(&pb->deadline_timer, jiffies + pb->timeout_in_jiffies + 1); + wake = true; } unlock: spin_unlock_irqrestore(&pb->lock, flags); - if (queue_timer) - mod_timer(&pb->deadline_timer, jiffies + pb->timeout_in_jiffies + 1); - rcu_read_unlock(); - - if (queue_timer) + if (wake) wake_up_interruptible(&pb->waitq); return ret; @@ -400,9 +398,7 @@ static int push_backup_stop(struct push_backup *pb, return -EBADF; cleanup_backup(pb); - /* Wait postpone_if_required_for_backup() starts timer */ - synchronize_rcu(); - WARN_ON_ONCE(timer_delete_sync_try(&pb->deadline_timer) < 0); + timer_delete_sync(&pb->deadline_timer); flush_workqueue(pb->wq); spin_lock_irq(&pb->lock); @@ -632,7 +628,7 @@ static void pb_destroy(struct push_backup *pb) { WARN_ON_ONCE(pb->nr_delayed); - WARN_ON_ONCE(timer_delete_sync_try(&pb->deadline_timer) < 0); + timer_shutdown_sync(&pb->deadline_timer); if (pb->wq) destroy_workqueue(pb->wq); kvfree(pb->map); /* Is's not zero if stop was not called */ -- 2.43.5 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel