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 0DAD68017D for ; Wed, 30 Sep 2026 05:46:32 +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 68U5jGAD011520; Wed, 30 Sep 2026 08:45:17 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 68U5jGAD011520 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="Ly88D5cb" 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 68U5jC0n011504 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Wed, 30 Sep 2026 08:45:13 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 68U5jC0n011504 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-48aef5cfe43so1207508f8f.1 for ; Tue, 29 Sep 2026 22:45:13 -0700 (PDT) X-Gm-Message-State: AFq9FYJyx0U0tICZKYswOwPea7aN0fWC84cm/i4o2CoArrFkL5NYL/8o 3MKfWbQCamH0XbNFHGKbFPYlsUd5G25zEIYGPNEcpCsbC2qEmkm3ESwEdWbhSiQiS2MKgPK/tYq txawfFk362Nqck9HV1p4hhP6oSZfEmnVDAgEiD+LMRgmM0dQ8c7Ahew== X-Gm-Gg: AYBFou2gSbAxtLQAzEw+j14UNn5MZ6/Icn6S+K70vfK0cqoDvcalMZ/td3gyh3HGq/u wctdLRNqo/6+WXMw/3N1DS5YwR9uCBHJYpcaO9T5OB50E4QJfowlcSZLhTbp49WfhCXkvBqN+gT eQuE9vDfCP8lCq5SLM0wH09jb3TxxGytekGyD06xbqrUI3HtkdOgHbyJP47t5AujGpP4Vlmqhmg DWSSkNgPDqakge0v9oMwTO3P6AaUWVSHJDWcDzYWhxPt+eDQS5YfUNXHh8UGqFujRhaJRtyWUrM XFwpyfrN2GbwbBQEzg68wmVW8dLkkX1xQzP+3L7Wm3raLym6qQYKsSAnK+1dnQVuZHa3V3+63/s ot2UXiez2nqtVC6o= X-Received: by 2002:a05:6000:1847:b0:487:91e:d8ed with SMTP id ffacd0b85a97d-48b0244e1camr668923f8f.2.1790747112434; Tue, 29 Sep 2026 22:45:12 -0700 (PDT) X-Received: by 2002:a05:6000:1847:b0:487:91e:d8ed with SMTP id ffacd0b85a97d-48b0244e1camr668886f8f.2.1790747111873; Tue, 29 Sep 2026 22:45:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1790747111; cv=none; d=google.com; s=arc-20260327; b=E8Lx624lMqm02jAl69wePOUuf/Hw0pIMcN2xVbY7TBd2hZlAg6ps4EEPYDLgOcfixs OyWkUjDK25YmQF0Ph3iw/3UF/dN91DG8TJv9NCR07saMJ7JFePOgifhO9/YMR7w4cFZg fs5w6gos+LkLXi1RKG9mb8ySrLMCJaw0TXQFIpIGg8kUp4IaO5WuPQn+w0J8eP7Jx0Mt RYd7xpcQAw/aD0jq76KewYuLrnTT/Ip2aq+Y0Vq8Dw62wrTsoIFVZvjJDDjPeuGznBQo /KbkT7FOGnUENnXzLsfxpgRYCYr72h4yYAkCp8q4t9semKkCzpwKQ5vbAUMJLZWyjzR6 uc8A== 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=zs6WG/GIuQi2LYpSEau0jU65DLeKTg7pHkeQdiDtVmk=; fh=6JpqpGxFeFNaDh+k4t2UfZyo3rKe/54dyQ52T8vVmSc=; b=WW14DvDUqVbkRKZ41BgoI7jx3mNg7NdRecxe6lvBaA+4ghhcb+fqgCy7/lenqfY4/e nfFiz8UwnsGOrg9iJjuHRThx3SMmyt+srSw7hguruA3pkO6DkBeGgRKcuOgOcXs8MpEQ 6UkQ2T9QVsp7J0sQTgKdaczkYl6qg+UpXAIjAeTqvYOmY7NsArsO9ABaJRUnutQkhNep J7frOikjkR+jPOq0K6eN2FEhxKAru7JnOOp1HmF8+J4dRXFa5J9Xynya9bT94U/gDdIa 8G4fwlcgBuyLTl08FhAIGndNJFMMTovRFDUUGih0FrSfyLgQUKzKMEW6+d7ASox03CyZ 42+w==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=Ly88D5cb; 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-48b029c35bbsi475921f8f.135.2026.09.29.22.45.11 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Sep 2026 22:45:11 -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=Ly88D5cb; 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=zs6WG/GIuQi2LYpSEau0jU65DLeKTg7pHkeQdiDtVmk=; b=Ly88D5cbmSNEvTHdXid Ho5gSF+OJn20/oshabxbNxt8AN3PmjEL1Rsxc4j9r+alxJKc4jFJyTcrgYNhOArGP/6tH4Qm03N9d QzFeJcKeDa+/0rjF8MaBWbwlR+E49q91RAyB/0sGOa6D+Og45HsAMwo0ZHEAwzzVhHuirT6+c00oZ fgPxnSC+dRvIfmtX0KQ00rvgmn0we/k68HAx9zQzbw1C2K4JRDLiWXs+KuIXdvj6f0iAOVuC7e+O9 6bdeqcTaivJBBVKzN6nlfP73dmBHeLh1YKY9aBagi3LstcAS/euAXs7wP4lwMtFwwYCn2o3zK6yQe KpMDDTag8RD18uw==; 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 1xBn4p-00DrnK-3D; Wed, 30 Sep 2026 07:45:11 +0200 From: Liu Kui Date: Wed, 30 Sep 2026 13:44:49 +0800 MIME-Version: 1.0 Message-Id: <20260930-close-wait-rework-v2-v1-2-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 2/3] fs/fuse: move the close_wait handling of fuse_release() into a helper 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 Move all the close_wait handling of fuse_release() into a new helper fuse_release_close_wait(), and restore the !close_wait case to the mainline behavior except the FMODE_WRITE check. Unify the code paths: unconditionally remove the file from fi->write_files and wait until we hold the last reference. Decrement fi->num_openers under the inode lock, which detects the last open. This fixes two racing releasers both reading num_openers == 0 and calling kio's file_close twice, possible because the decrement was done early under fi->lock while the check ran later under the inode lock: releaser A releaser B ---------- ---------- --fi->num_openers (2 -> 1) --fi->num_openers (1 -> 0) inode_lock() num_openers == 0 -> file_close() inode_unlock() inode_lock() num_openers == 0 -> file_close() The atomic decrement under the inode lock also matches the increment in fuse_open_close_wait() for !writeback_cache files. https://virtuozzo.atlassian.net/browse/VSTOR-147878 Signed-off-by: Liu Kui --- fs/fuse/file.c | 103 ++++++++++++++++++++++++++------------------------------- 1 file changed, 46 insertions(+), 57 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c41d6445c7e5..d7c9ea8a7c45 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -537,82 +537,71 @@ void fuse_file_release(struct inode *inode, struct fuse_file *ff, fuse_file_put(ff, ff->fm->fc->destroy || ff->fm->fc->close_wait); } -void fuse_release_common(struct file *file, bool isdir) -{ - fuse_file_release(file_inode(file), file->private_data, file->f_flags, - (fl_owner_t) file, isdir); -} - static void fuse_sync_writes(struct inode *inode); -static int fuse_release(struct inode *inode, struct file *file) +static void fuse_release_close_wait(struct inode *inode, struct file *file) { struct fuse_file *ff = file->private_data; struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_conn *fc = ff->fm->fc; - set_bit(FUSE_S_CLOSING, &ff->ff_state); + /* + * Stop the write rerouting from picking this file, otherwise + * continuous writeback on the inode can keep the reference count + * elevated and the wait below may never finish. + */ spin_lock(&fi->lock); + list_del_init(&ff->write_entry); spin_unlock(&fi->lock); /* - * Dirty pages might remain despite write_inode_now() call from - * fuse_flush() due to writes racing with the close. + * 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. */ - if (fc->writeback_cache) { - if (file->f_mode & FMODE_WRITE) { - write_inode_now(inode, 1); + wait_event(fi->page_waitq, refcount_read(&ff->count) == 1); - /* Must remove file from write list. Otherwise it is possible this - * file will get more writeback from another files rerouted via write_files - */ - spin_lock(&fi->lock); - list_del_init(&ff->write_entry); - spin_unlock(&fi->lock); - - /* A writeback from another fuse file might come after - * filemap_write_and_wait() above - */ - if (!fc->close_wait) - filemap_write_and_wait(file->f_mapping); - } else - BUG_ON(!list_empty(&ff->write_entry)); - - /* This can livelock. Inode can be open via another file - * and that file can generate continuous writeback. - * I think i_mutex could be taken around this. - * - * For now we replace this with waiting on ff->count, - * it is safe, because we essentially wait only for writeback (and readahead) - * enqueued on this file and it is not going to get new one: it is closing. - */ - if (fc->close_wait) - wait_event(fi->page_waitq, refcount_read(&ff->count) == 1); + inode_lock(inode); + fuse_sync_writes(inode); + fuse_read_dio_wait(fi); + /* num_openers is serialized by the inode lock, no fi->lock needed */ + if (--fi->num_openers == 0) { + /* take the attributes from the server again */ spin_lock(&fi->lock); - /* - * Last opener is gone and its writeback has drained: from - * now on take the attributes from the server again. - */ - if (--fi->num_openers == 0) - fi->i_size_unstable = 1; + fi->i_size_unstable = 1; spin_unlock(&fi->lock); - } else if (fc->close_wait) - wait_event(fi->page_waitq, refcount_read(&ff->count) == 1); - - if (fc->kio.op) { - /* - * Flush pending requests before FUSE_RELEASE makes userspace - * to drop the lease of the file. Otherwise, they never finish. - */ - inode_lock(inode); - fuse_sync_writes(inode); - fuse_read_dio_wait(fi); - if (fi->num_openers == 0 && fc->kio.op->file_close) + if (fc->kio.op && fc->kio.op->file_close) fc->kio.op->file_close(file, inode); - inode_unlock(inode); } + inode_unlock(inode); +} + +void fuse_release_common(struct file *file, bool isdir) +{ + fuse_file_release(file_inode(file), file->private_data, file->f_flags, + (fl_owner_t) file, isdir); +} + +static int fuse_release(struct inode *inode, struct file *file) +{ + struct fuse_file *ff = file->private_data; + struct fuse_conn *fc = get_fuse_conn(inode); + + /* stop fiemap from picking this file before flushing starts */ + if (fc->close_wait) + set_bit(FUSE_S_CLOSING, &ff->ff_state); + + /* + * Dirty pages might remain despite write_inode_now() call from + * fuse_flush() due to writes racing with the close. + */ + if (fc->writeback_cache && (file->f_mode & FMODE_WRITE)) + write_inode_now(inode, 1); + + if (fc->close_wait) + fuse_release_close_wait(inode, file); fuse_release_common(file, false); -- Git-155) _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel