From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (unknown [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id B54D9802A5 for ; Wed, 30 Sep 2026 05:46:37 +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 68U5jMn3011529; Wed, 30 Sep 2026 08:45:23 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 68U5jMn3011529 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="aGBg0JP4" Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 68U5jGxN011516 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Wed, 30 Sep 2026 08:45:16 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 68U5jGxN011516 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-48589603501so3369018f8f.3 for ; Tue, 29 Sep 2026 22:45:16 -0700 (PDT) X-Gm-Message-State: AFq9FYKKYDegXlr30G/ppUT4/TB8bE5lbfiKbOP1VgB0zHesXNVdOd4D OrBb2QD3SP+c6TuiDCZrO3Itg0uezSV2HYn5AsmQdNWciTJL9bchBoPK+5okhopNo+bnCxuB+vS F8sLROmyUR55ypN8VZ4+fmkTNpFcHwC4mc2ZoyNLcAiTOKmrLrppWtw== X-Gm-Gg: AYBFou0yYgy0Fntejrwrko8dA3Cb/XJ2AVSrJChRefAN8Fr+xNjMBEg2tQvZlA4uchx OgoSOO68ex6VLvlAp01qEs8HGqGqBKQ3fZRKy/mvnq3Til6/1NV6ugkIRbFhBnsPUFq+KeJ+joh +0RO95NDrn5ra/D3avMz4Zr3v2QGn5TZnqfkw1wxMSjtnM1b9PicGc65+gmG6Mak3hPxmAmMSMM z/g3wEqoKV50ytMadcr8CHUp32TWQkIdzaUrT5A+k9bfTHWHv14hT1H7Fs4FoGCyjyM0sePcHPd r2OsvgxtjGyet6+yNcnHxCKo7OCuqjwEeJESZa/nk3O6wRuJtUK9S0lKAQaJXyDttn1YP42Lzi0 XMHlAMU3DkEO85fM= X-Received: by 2002:a5d:6f1c:0:b0:484:3326:983b with SMTP id ffacd0b85a97d-48b025251f1mr587664f8f.26.1790747116294; Tue, 29 Sep 2026 22:45:16 -0700 (PDT) X-Received: by 2002:a5d:6f1c:0:b0:484:3326:983b with SMTP id ffacd0b85a97d-48b025251f1mr587631f8f.26.1790747115753; Tue, 29 Sep 2026 22:45:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1790747115; cv=none; d=google.com; s=arc-20260327; b=IyJrd1iu4AohXG0oMDJO8JCXLuHeSERUsLqlRrgD00JUDhLRJjPuxwJUxmjTkynRLw XSlrYXqulziNz59rRsU4RzhGrAtgZQxVdJgwVmwCdTb3md4jXzNeBe6Dpifb9UXQTstl FI2p1egou49r253+mKNekC4Cl0pK6p6s2BKZU4W6hZENQIQRRP+jrBWQzSwz/4rCQlCs IXhrAMl4LR39KHyVEtMVifNpWrs3Pzb3ShJJPjr02aFi783Tq1XUVKk2wbfcfbpwEv24 pFpXkgXeutZ/HDI/+meNi69VWKnbTEz6czuU0TWem9AW7jhO0VynHGNcUIfuxbGMyeBU EE7w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:dkim-signature; bh=hUy9jBItlhHu831lnxV61mP1qqqtmMx1D4QZ9BbDf0k=; fh=6JpqpGxFeFNaDh+k4t2UfZyo3rKe/54dyQ52T8vVmSc=; b=p/ElM6kWYMre+dsJ3RQDeJzNt/FS6ooEVmn4g0yhkgA4GkHbxBAJlSaeCgna+j8NH2 A3p5pFjrVdgn2LJk7UU9cY/fwKU4Kq0ZMKkPgZsYEvPSVjJWlaj3T/gsVqWNnnkruqad b0FqyjmKoN8Pup8yz79xqcdbIqb8iAfFCbF30m+ol6d5ZQaIlSeBS9pTp6UpL5e+4rLf rmNbvtxDKzYcgAMKh5RN0lGEhgDMZvXg+UT8amSZ8NG7ncTv9azmFBORUY1OtVTwAVX9 Op8oeymMql2Sfk8VEj2+3bpbgZSvREoy75hBzT7hyiadacjdPcnOvDci+Tf0NqwVXPDF 3K4w==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=aGBg0JP4; spf=pass (google.com: domain of kui.liu@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=kui.liu@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 ffacd0b85a97d-48b029dd3aesi448172f8f.228.2026.09.29.22.45.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 22:45:15 -0700 (PDT) Received-SPF: pass (google.com: domain of kui.liu@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=aGBg0JP4; spf=pass (google.com: domain of kui.liu@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=kui.liu@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=Message-Id:Content-Type:MIME-Version:Subject:Date :From; bh=hUy9jBItlhHu831lnxV61mP1qqqtmMx1D4QZ9BbDf0k=; b=aGBg0JP4qZ4r9A/mKxH gNUuQOZYyWHGT8nl9JZdRk0cP/YrKuOjpdzLbftV0EFvwAS0YvUFUa7I6IdvPXp1B94YH7bH74Nbp 8cGq1zfUmYOrkj4mekAxpYdfQDn8rLvCxwhCP92JXZmQ/CHL+PDX7j0Mf0Re/MV92CRQzE87fK6JM vSSmgGIn8qPiqIxvZJXJUWTRBxrLqRXpr5uRRPMg8/NBB//Q37U9VVEs7VrHgxGN7NcEObpVk+pi6 MIDsG27WNXFi6qxjmMioSz2fZgfQ6loGRzZlGNIAjXxXptPMc8YGI7WvKYEa/yAjK2yUa3h8tD/Fm Q7gSUtILa4RLxcA==; Received: from ch-vpn.virtuozzo.com ([130.117.225.6] helo=LK-MBP.local) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1xBn4t-00DrnK-2n; Wed, 30 Sep 2026 07:45:15 +0200 From: Liu Kui Date: Wed, 30 Sep 2026 13:44:50 +0800 MIME-Version: 1.0 Message-Id: <20260930-close-wait-rework-v2-v1-3-f8062178544a@virtuozzo.com> References: <20260930-close-wait-rework-v2-v1-0-f8062178544a@virtuozzo.com> In-Reply-To: <20260930-close-wait-rework-v2-v1-0-f8062178544a@virtuozzo.com> To: Konstantin Khorenko X-Mailer: b4 0.16.0 X-OZ-Fwd: true Cc: azaitsev@virtuozzo.com, devel@openvz.org, Liu Kui Subject: [Devel] [PATCH hci-8.1 3/3] fs/fuse: use wait_var_event to wait for fuse file references 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 On close_wait mounts, fuse_release_close_wait() needs to wait for all asynchronous references to the fuse file to be dropped before sending FUSE_RELEASE. This wait on fi->page_waitq was inherited from the past implementation and is no longer appropriate as the wait condition evolved: - fi->page_waitq is meant to serve page-under-writeback waiters and fuse_set_nowrite()'s writectr waiters; now it also has to serve the ff reference waiter, so every wakeup can wake unrelated waiters. - the wake is decoupled from the decrement, so every path dropping an ff reference must remember to wake fi->page_waitq, and because of this we grew two variants of the stock fuse_file_put(): __fuse_file_put() and fuse_release_ff(). This is bug prone, and a misuse can leave the releaser blocked forever. Instead of waiting on fi->page_waitq, a simple wait_var_event() on &ff->count serves the purpose best: the matching wake_up_var() uses the address purely as a hash key and never dereferences it, so the wakeup can be folded into fuse_file_put() itself. With that, both __fuse_file_put() and fuse_release_ff() become redundant and are removed. This cleanup also makes the code less divergent from mainline. https://virtuozzo.atlassian.net/browse/VSTOR-147878 Signed-off-by: Liu Kui --- fs/fuse/file.c | 69 +++++++++++++++++++++----------------- fs/fuse/fuse_i.h | 2 +- fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 3 +- 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index d7c9ea8a7c45..74c8d925e2fd 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -24,6 +24,7 @@ #include #include #include +#include unsigned int hash_seed_r; module_param(hash_seed_r, uint, 0644); @@ -140,12 +141,23 @@ static void fuse_release_end(struct fuse_mount *fm, struct fuse_args *args, kfree(ra); } -static void fuse_file_put(struct fuse_file *ff, bool sync) +void fuse_file_put(struct fuse_file *ff, bool sync) { + /* read before the drop: ff may not be touched after a non-final one */ + bool close_wait = ff->fm->fc->close_wait; + if (refcount_dec_and_test(&ff->count)) { struct fuse_release_args *ra = &ff->args->release_args; struct fuse_args *args = (ra ? &ra->args : NULL); + /* + * On close_wait the final put must come from a synchronous + * caller: fuse_release() waits for ff->count == 1 while + * holding its own reference, so an asynchronous completion + * can never drop the last one. + */ + WARN_ON(!sync && close_wait); + if (ra && ra->inode) fuse_file_io_release(ff, ra->inode); @@ -165,14 +177,25 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) fuse_release_end(ff->fm, args, -ENOTCONN); } kfree(ff); + return; } -} -static void __fuse_file_put(struct fuse_file *ff) -{ - if (refcount_dec_and_test(&ff->count)) - BUG(); + /* + * ff may already be freed by a racing final put -- don't touch it + * past this point. + */ + if (close_wait) { + /* + * Pairs with wait_var_event() in fuse_release_close_wait(): + * the wake_up_var() contract requires a full barrier between + * the counter update and the wakeup, and refcount_dec() + * alone is only release-ordered. + */ + smp_mb__after_atomic(); + wake_up_var(&ff->count); + } } +EXPORT_SYMBOL_GPL(fuse_file_put); struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, unsigned int open_flags, bool isdir) @@ -557,9 +580,10 @@ static void fuse_release_close_wait(struct inode *inode, struct file *file) /* * Wait until we are the last one holding a reference, so that all * in-flight requests on this file have finished and FUSE_RELEASE - * is sent by the releaser itself. + * is sent by the releaser itself. Woken by the wake_up_var() in + * fuse_file_put(). */ - wait_event(fi->page_waitq, refcount_read(&ff->count) == 1); + wait_var_event(&ff->count, refcount_read(&ff->count) == 1); inode_lock(inode); fuse_sync_writes(inode); @@ -1252,22 +1276,6 @@ static int fuse_read_folio(struct file *file, struct folio *folio) return err; } -void fuse_release_ff(struct inode *inode, struct fuse_file *ff) -{ - if (ff) { - if (ff->fm->fc->close_wait) { - struct fuse_inode *fi = get_fuse_inode(inode); - spin_lock(&fi->lock); - __fuse_file_put(ff); - wake_up(&fi->page_waitq); - spin_unlock(&fi->lock); - } else { - fuse_file_put(ff, false); - } - } -} -EXPORT_SYMBOL_GPL(fuse_release_ff); - void fuse_revoke_readpages(struct fuse_file *ff) { struct fuse_io_args *ia; @@ -1330,7 +1338,7 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args, fuse_invalidate_atime(inode); if (ff) - fuse_release_ff(inode, ff); + fuse_file_put(ff, false); fuse_io_free(ia); } @@ -2189,7 +2197,7 @@ static void fuse_writepage_free(struct fuse_writepage_args *wpa) for (i = 0; i < ap->num_pages; i++) __free_page(ap->pages[i]); - fuse_release_ff(wpa->inode, wpa->ia.ff); + fuse_file_put(wpa->ia.ff, false); kfree(ap->pages); kfree(wpa); @@ -2572,7 +2580,7 @@ static int fuse_writepage_locked(struct folio *folio) return 0; err_writepage_args: - fuse_release_ff(inode, ff); + fuse_file_put(ff, false); err_nofile: folio_put(tmp_folio); err: @@ -2859,7 +2867,8 @@ static int fuse_writepages(struct address_space *mapping, WARN_ON(!data.wpa->ia.ap.num_pages); fuse_writepages_send(&data); } - fuse_release_ff(inode, data.ff); + if (data.ff) + fuse_file_put(data.ff, false); kfree(data.orig_pages); out: @@ -3929,7 +3938,7 @@ static int fuse_request_fiemap(struct inode *inode, u32 cur_max, ap.pages = fuse_pages_alloc(fc->max_pages, GFP_KERNEL, &ap.descs); if (!ap.pages) { - fuse_release_ff(inode, ff); + fuse_file_put(ff, false); return -ENOMEM; } @@ -4021,7 +4030,7 @@ static int fuse_request_fiemap(struct inode *inode, u32 cur_max, ap.pages[allocated] = NULL; } kfree(ap.pages); - fuse_release_ff(inode, ff); + fuse_file_put(ff, false); return err; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index f6da643b9c86..e94d40458af3 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1673,7 +1673,7 @@ int fuse_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, struct fuse_file *__fuse_write_file_get(struct fuse_inode *fi); struct fuse_file *fuse_file_get(struct fuse_file *ff); -void fuse_release_ff(struct inode *inode, struct fuse_file *ff); +void fuse_file_put(struct fuse_file *ff, bool sync); struct fuse_req *fuse_dev_find_request(unsigned int fd, u64 unique); void fuse_revoke_readpages(struct fuse_file *ff); diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c index efbab75654c8..5064198a7b4c 100644 --- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c +++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c @@ -728,7 +728,8 @@ static int submit_size_grow(struct inode *inode, unsigned long long size) args.out_args[0].value = &outarg; err = fuse_simple_request(fm, &args); - fuse_release_ff(inode, ff); + if (ff) + fuse_file_put(ff, false); return err; -- Git-155) _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel