[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAHB1NahoCEsw-vtu=6AUgG8oL0tTVV3gbP121zTgvdBzrMUo8w@mail.gmail.com>
Date: Wed, 21 Feb 2024 23:29:39 +0800
From: JunChao Sun <sunjunchao2870@...il.com>
To: Ext4 Developers List <linux-ext4@...r.kernel.org>
Cc: Jan Kara <jack@...e.cz>, "Theodore Ts'o" <tytso@....edu>
Subject: A problem about BLK_OPEN_RESTRICT_WRITES
Hi
I saw that ext4 has supported BLK_OPEN_RESTRICT_WRITES in commits
aca740cecbe("fs: open block device after superblock creation") and
afde134b5bd0("ext4: Block writes to journal device"). I'm not certain
whether these commits caused the following issue.
Environment:
6.8.0-rc3-00279-g4a7bbe7519b6-dirty(commit 4a7bbe7519b6a5).
sjc@...-laptop:~/linux$ mkfs.ext4 -V
mke2fs 1.47.0 (5-Feb-2023)
Using EXT2FS Library version 1.47.0
sjc@...-laptop:~/linux$ mount -V
mount from util-linux 2.39.1 (libmount 2.39.1: selinux, smack, btrfs,
verity, namespaces, idmapping, assert, debug)
Problem:
When I mounted the ext4 file system in the qemu system, I encountered
the following error:
root@q:~/linux# mount -t ext4 ext4.img /mnt/ext4/
[ 848.897532] loop1: detected capacity change from 0 to 2097152
[ 848.905535] /dev/loop1: Can't open blockdev
mount: /mnt/ext4: /dev/loop1 already mounted or mount point busy.
dmesg(1) may have more information after failed mount system call.
I reviewed the relevant code and found that the mount program first
calls the openat system call to open the /dev/loop1 file, followed by
the mount system call (with /dev/loop1 as the first parameter).
As for the former openat system call, it eventually reaches the chain
of (vfs_open->do_dentry_open->blkdev_open->bdev_open_by_dev->bdev_claim_write_access).
In bdev_claim_write_access, the following logic applies:
/* Claim exclusive or shared write access. */
if (mode & BLK_OPEN_RESTRICT_WRITES)
bdev_block_writes(bdev);
else if (mode & BLK_OPEN_WRITE)
bdev->bd_writers++;
The argument mode here doesn't set BLK_OPEN_RESTRICT_WRITES flag, so
goes bdev->bd_writers++.
And in the latter mount system call, the following logic is followed:
(vfs_get_tree->get_tree_bdev->setup_bdev_super->bdev_open_by_dev->bdev_may_open).
In bdev_may_open, the following logic applies:
if (mode & BLK_OPEN_RESTRICT_WRITES && bdev->bd_writers > 0)
return false;
Due to the fact that the argument mode has already been set with the
BLK_OPEN_RESTRICT_WRITES flag in the setup_bdev_super function, and
since bdev->bd_writers is already 1 at this point, the function
returns false. This ultimately leads to the mount system call
returning the EBUSY error.
Is this indeed a problem, or is there a misunderstanding in my
comprehension? If it is indeed a problem, can we resolve it by
removing the BLK_OPEN_RESTRICT_WRITES from the sb_open_mode macro
definition?
At last, here is a partial output of the trace captured using the
strace command:
openat(AT_FDCWD, "/home/sjc/linux/ext4.img", O_RDWR|O_CLOEXEC) = 3
openat(AT_FDCWD, "/dev/loop1", O_RDWR|O_CLOEXEC) = 4
ioctl(4, LOOP_CONFIGURE, {fd=3, block_size=0, info={lo_offset=0, lo_[
891.723213] /dev/loop1: Can't open blockdev
number=0, lo_flags=LO_FLAGS_AUTOCLEAR,
lo_file_name="/home/sjc/linux/ext4.img", ...}}) = 0
close(3) = 0
newfstatat(AT_FDCWD, "/dev/loop1", {st_mode=S_IFBLK|0600,
st_rdev=makedev(0x7, 0x1), ...}, 0) = 0
openat(AT_FDCWD, "/sys/dev/block/7:1", O_RDONLY|O_CLOEXEC) = 3
openat(3, "loop/autoclear", O_RDONLY|O_CLOEXEC) = 5
fcntl(5, F_GETFL) = 0x8000 (flags O_RDONLY|O_LARGEFILE)
newfstatat(5, "", {st_mode=S_IFREG|0444, st_size=4096, ...}, AT_EMPTY_PATH) = 0
read(5, "1\n", 4096) = 2
close(5) = 0
openat(3, "ro", O_RDONLY|O_CLOEXEC) = 5
fcntl(5, F_GETFL) = 0x8000 (flags O_RDONLY|O_LARGEFILE)
newfstatat(5, "", {st_mode=S_IFREG|0444, st_size=4096, ...}, AT_EMPTY_PATH) = 0
read(5, "0\n", 4096) = 2
close(5) = 0
close(3) = 0
statx(AT_FDCWD, "/sbin/mount.ext4",
AT_STATX_DONT_SYNC|AT_NO_AUTOMOUNT, STATX_TYPE|STATX_MODE|STATX_INO,
0x7ffd6c0b8ce0) = -1 ENOENT (No such file or directory)
statx(AT_FDCWD, "/sbin/fs.d/mount.ext4",
AT_STATX_DONT_SYNC|AT_NO_AUTOMOUNT, STATX_TYPE|STATX_MODE|STATX_INO,
0x7ffd6c0b8ce0) = -1 ENOENT (No such file or directory)
statx(AT_FDCWD, "/sbin/fs/mount.ext4",
AT_STATX_DONT_SYNC|AT_NO_AUTOMOUNT, STATX_TYPE|STATX_MODE|STATX_INO,
0x7ffd6c0b8ce0) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/run/mount/utab", {st_mode=S_IFREG|0644,
st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
newfstatat(AT_FDCWD, "/run/mount/utab", {st_mode=S_IFREG|0644,
st_size=0, ...}, 0) = 0
geteuid() = 0
getegid() = 0
getuid() = 0
getgid() = 0
access("/run/mount/utab", R_OK|W_OK) = 0
mount("/dev/loop1", "/mnt/ext4", "ext4", 0, NULL) = -1 EBUSY (Device
or resource busy)
Best regards.
Powered by blists - more mailing lists