Linux XFS filesystem development
 help / color / mirror / Atom feed
From: Aditya Srivastava <aditya.ansh182@gmail.com>
To: Zorro Lang <zlang@kernel.org>
Cc: Christoph Hellwig <hch@infradead.org>,
	"Darrick J . Wong" <djwong@kernel.org>,
	fstests@vger.kernel.org, linux-xfs@vger.kernel.org,
	Aditya Prakash Srivastava <aditya.ansh182@gmail.com>
Subject: [PATCH] xfs/842: test close() deadlocks on frozen filesystems
Date: Fri, 12 Jun 2026 12:37:42 +0000	[thread overview]
Message-ID: <20260612123742.2389-1-aditya.ansh182@gmail.com> (raw)

From: Aditya Prakash Srivastava <aditya.ansh182@gmail.com>

When a file with active speculative post-EOF preallocations is closed,
XFS synchronously attempts to free them via xfs_free_eofblocks().
This requires allocating a write transaction, which blocks indefinitely
if the filesystem is frozen, causing close() to hang.

Add a regression test using a helper C program to verify that close()
returns cleanly (with -EAGAIN if using XFS_TRANS_WRITECOUNT_TRYLOCK)
without blocking the close system call.

This is a regression test for the corresponding kernel patch:
"xfs: prevent close() from hanging on frozen filesystems"

On a successfully patched kernel, the close system call returns cleanly
and the test helper outputs 'close() completed immediately!', matching
the golden output. On an unpatched kernel, the close system call blocks,
the helper times out and outputs 'close() hung under freeze!', cleanly
flagging the deadlock to fstests.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=205833
Link: https://bugzilla.redhat.com/show_bug.cgi?id=1474726
Signed-off-by: Aditya Prakash Srivastava <aditya.ansh182@gmail.com>
---
 src/Makefile                 |   1 +
 src/xfs_freeze_close_repro.c | 127 +++++++++++++++++++++++++++++++++++
 tests/xfs/842                |  32 +++++++++
 tests/xfs/842.out            |   2 +
 4 files changed, 162 insertions(+)
 create mode 100644 src/xfs_freeze_close_repro.c
 create mode 100755 tests/xfs/842
 create mode 100644 tests/xfs/842.out

diff --git a/src/Makefile b/src/Makefile
index 31ac43b2..9553e7c9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -68,6 +68,7 @@ LCFLAGS += -DHAVE_FILE_GETATTR
 endif
 
 ifeq ($(PKG_PLATFORM),linux)
+LINUX_TARGETS += xfs_freeze_close_repro
 TARGETS += $(LINUX_TARGETS)
 endif
 
diff --git a/src/xfs_freeze_close_repro.c b/src/xfs_freeze_close_repro.c
new file mode 100644
index 00000000..075f2d18
--- /dev/null
+++ b/src/xfs_freeze_close_repro.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026 Aditya Prakash Srivastava. All Rights Reserved.
+ *
+ * xfstests helper to reproduce close() hang on frozen XFS filesystems.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+#include <sys/vfs.h>
+#include <linux/fs.h>
+#include <libgen.h>
+
+int close_started;
+int close_completed;
+
+void *
+close_thread(void *arg)
+{
+	int fd = *(int *)arg;
+
+	close_started = 1;
+	close(fd);
+	close_completed = 1;
+	return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct statfs sfs;
+	char *dir_buf;
+	char *parent_dir;
+	int freeze_fd;
+	int write_fd;
+	char buf[65536];
+	pthread_t thread;
+	int hung = 1;
+	int i;
+
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s <file_on_xfs>\n", argv[0]);
+		return 1;
+	}
+
+	if (statfs(argv[1], &sfs) < 0) {
+		dir_buf = strdup(argv[1]);
+		parent_dir = dirname(dir_buf);
+		if (statfs(parent_dir, &sfs) < 0) {
+			perror("statfs");
+			free(dir_buf);
+			return 1;
+		}
+		free(dir_buf);
+	}
+	if (sfs.f_type != 0x58465342) {
+		fprintf(stderr, "Not on XFS\n");
+		return 1;
+	}
+
+	dir_buf = strdup(argv[1]);
+	freeze_fd = open(dirname(dir_buf), O_RDONLY);
+	if (freeze_fd < 0) {
+		perror("open dir");
+		free(dir_buf);
+		return 1;
+	}
+	free(dir_buf);
+
+	write_fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	if (write_fd < 0) {
+		perror("open file");
+		close(freeze_fd);
+		return 1;
+	}
+
+	memset(buf, 'A', sizeof(buf));
+	for (i = 0; i < 320; i++) {
+		if (write(write_fd, buf, sizeof(buf)) < 0) {
+			perror("write");
+			close(write_fd);
+			close(freeze_fd);
+			return 1;
+		}
+	}
+
+	if (ioctl(freeze_fd, FIFREEZE, 0) < 0) {
+		perror("ioctl FIFREEZE");
+		close(write_fd);
+		close(freeze_fd);
+		return 1;
+	}
+
+	if (pthread_create(&thread, NULL, close_thread, &write_fd) != 0) {
+		perror("pthread_create");
+		ioctl(freeze_fd, FITHAW, 0);
+		close(write_fd);
+		close(freeze_fd);
+		return 1;
+	}
+
+	while (!close_started)
+		usleep(1000);
+
+	for (i = 0; i < 30; i++) {
+		usleep(100000);
+		if (close_completed) {
+			hung = 0;
+			break;
+		}
+	}
+
+	if (hung)
+		printf("close() hung under freeze!\n");
+	else
+		printf("close() completed immediately!\n");
+
+	ioctl(freeze_fd, FITHAW, 0);
+	pthread_join(thread, NULL);
+	close(freeze_fd);
+	return hung ? 0 : 1;
+}
diff --git a/tests/xfs/842 b/tests/xfs/842
new file mode 100755
index 00000000..8b225ea2
--- /dev/null
+++ b/tests/xfs/842
@@ -0,0 +1,32 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2026 Aditya Prakash Srivastava.  All Rights Reserved.
+#
+# FS QA Test No. 842
+#
+# Verify that closing a file with active speculative post-EOF preallocations
+# on a frozen XFS filesystem does not deadlock inside close().
+#
+. ./common/preamble
+_begin_fstest auto quick freeze
+
+# Import helper functions
+. ./common/rc
+. ./common/filter
+
+# Real-world configs
+_supported_fs xfs
+_require_scratch
+_require_test_program "xfs_freeze_close_repro"
+
+_scratch_mkfs >> $seqres.full 2>&1
+_scratch_mount
+
+TEST_FILE=$SCRATCH_MNT/test_eofblocks_freeze
+
+# Execute the reproducer helper on scratch mount
+$here/src/xfs_freeze_close_repro $TEST_FILE
+
+status=$?
+_scratch_unmount
+_exit
diff --git a/tests/xfs/842.out b/tests/xfs/842.out
new file mode 100644
index 00000000..386fb9cc
--- /dev/null
+++ b/tests/xfs/842.out
@@ -0,0 +1,2 @@
+QA output created by 842
+close() completed immediately!
-- 
2.47.3


             reply	other threads:[~2026-06-12 12:38 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-12 12:37 Aditya Srivastava [this message]
2026-06-14 18:52 ` [PATCH] xfs/842: test close() deadlocks on frozen filesystems Zorro Lang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260612123742.2389-1-aditya.ansh182@gmail.com \
    --to=aditya.ansh182@gmail.com \
    --cc=djwong@kernel.org \
    --cc=fstests@vger.kernel.org \
    --cc=hch@infradead.org \
    --cc=linux-xfs@vger.kernel.org \
    --cc=zlang@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox