[LTP] [PATCH] swapon: commit swapfile caches to disk
Li Wang
liwang@redhat.com
Thu Jun 14 08:37:02 CEST 2018
On Tue, Jun 12, 2018 at 9:12 PM, Li Wang <liwang@redhat.com> wrote:
>
>
>
> On Tue, Jun 12, 2018 at 8:56 PM, Jan Stancek <jstancek@redhat.com> wrote:
>>
>>
>> ----- Original Message -----
>> > Testcase include swapon(8) fails on mainline kernel-v4.17+ as:
>> > swapon01 1 TFAIL : swapon01.c:47: Failed to turn on swapfile:
>> > TEST_ERRNO=EINVAL(22): Invalid argument
>> > swapon02 4 TFAIL : swapon02.c:91: swapon(2) failed to produce
>> > expected error: 16, errno: EBUSY and got 22.
>> > swapon03 1 TFAIL : swapon03.c:243: Failed to setup swaps
>> > swapoff01 1 TBROK : swapoff01.c:64: Failed to turn on the swap file,
>> > skipping test iteration
>> >
>> > And dmesg shows that:
>> > [ 128.698981] swapon: file is not committed
>> >
>> > The error located in IOMAP_F_DIRTY(linux/fs/iomap.c) checking, which means
>> > this swapfile have uncommitted metadata in caches. After adding sync() to
>> > the end of all mkswap opertaion, these errors were gone.
>> >
>> > linux/fs/iomap.c:
>> > static loff_t iomap_swapfile_activate_actor(
>> > struct inode *inode,
>> > loff_t pos,
>> > loff_t count,
>> > void *data,
>> > struct iomap *iomap)
>> > {
>> > struct iomap_swapfile_info *isi = data;
>> > int error;
>> > ...
>> >
>> > /* No uncommitted metadata or shared blocks. */
>> > if (iomap->flags & IOMAP_F_DIRTY) {
>> > pr_err("swapon: file is not committed\n");
>> > return -EINVAL;
>> > }
>> > ...
>> > }
>> > }
>> > Signed-off-by: Li Wang <liwang@redhat.com>
>> > ---
>> >
>> > Notes:
>> > The new changes about swapfile activation function were merged in
>> > kernel-4.17
>> > recently, so we didn't hit this failures before.
>>
>> Comment/code in mkswap, that has been present for years:
>> /*
>> * A subsequent swapon() will fail if the signature
>> * is not actually on disk. (This is a kernel bug.)
>> * The fsync() in close_fd() will take care of writing.
>> */
>>
>> I'm assuming your mkswap is recent enough. Any idea why fsync()
>> in mkswap is no longer enough?
>
>
>
> Good catch, Jan. It sounds like a mkswap/fsync issue.
I looked into this issue today. It seems like a new kernel bug which
has been fixed by commit 117a148ffe0 (iomap: fsync swap files before
iterating mappings) in linus tree.
------------------
Simple steps to reproduce that:
# dd if=/dev/zero of=swapfile01 bs=2048 count=1024
1024+0 records in
1024+0 records out
2097152 bytes (2.1 MB) copied, 0.00408662 s, 513 MB/s
# mkswap swapfile01
Setting up swapspace version 1, size = 2044 KiB
no label, UUID=17830401-9cf2-4143-88a8-5a89c0b2d01d
# chmod 600 swapfile01
# swapon swapfile01
swapon: swapfile01: swapon failed: Invalid argument
Checking dmesg and get the root cause is swapfile01 have uncommitted
metadata in caches:
[ 128.698981] swapon: file is not committed
Then, I tracking the __x64_sys_swapon function calltrace on my bad kernel:
xfs_iomap_swapfile_activate [xfs]() {
iomap_swapfile_activate() {
filemap_write_and_wait() { <===== [1]
mapping_needs_writeback();
__filemap_fdatawrite_range() {
_raw_spin_lock();
wbc_attach_and_unlock_inode();
do_writepages() {
xfs_vm_writepages [xfs]() {
_raw_spin_lock();
write_cache_pages() {
tag_pages_for_writeback() {
_raw_spin_lock_irq();
}
pagevec_lookup_range_tag() {
find_get_pages_range_tag();
}
}
}
}
wbc_detach_inode();
}
Noticed [1] was being replaced by "ret = vfs_fsync(swap_file, 1);" in
the kernel commit 117a148ff. And this change works fine to me.
But I still have a query as Jan mentioned that, the command mkswap has
already done the write-back action via fsync() in close_fd(). Why we
have to do this fsync() again in kernel side and then have effect to
swapfile?
$ tail util-linux/disk-utils/mkswap.c
#endif
/*
* A subsequent swapon() will fail if the signature
* is not actually on disk. (This is a kernel bug.)
* The fsync() in close_fd() will take care of writing.
*/
if (close_fd(ctl.fd) != 0)
err(EXIT_FAILURE, _("write failed"));
return EXIT_SUCCESS;
}
$ tail -12 util-linux/disk-utils/include/closestream.h
static inline int
close_fd(int fd)
{
const int fsync_fail = (fsync(fd) != 0);
const int close_fail = (close(fd) != 0);
if (fsync_fail || close_fail)
return EOF;
return 0;
}
#endif /* UTIL_LINUX_CLOSESTREAM_H */
--------------
Anyway, this is not a LTP issue, so plz ignore my previous patch.
Thanks,
Li Wang
More information about the ltp
mailing list