diff mbox series

[v4] generic: test small swapfile without page-aligned contiguous blocks

Message ID 20210624042759.3304586-1-zlang@redhat.com (mailing list archive)
State New, archived
Headers show
Series [v4] generic: test small swapfile without page-aligned contiguous blocks | expand

Commit Message

Zorro Lang June 24, 2021, 4:27 a.m. UTC
If a swapfile doesn't contain even a single page-aligned contiguous
range of blocks, it's an invalid swapfile, and might cause kernel
issue. This case covered commit 5808fecc5723 ("iomap: Fix negative
assignment to unsigned sis->pages in iomap_swapfile_activate").

Signed-off-by: Zorro Lang <zlang@redhat.com>
---

Hi,

V4 did below changes:
1) Expect swapon return EINVAL
2) Compare swap size and swapfile size if swapon passed

It's passed on fixed kernel, panic on old kernel, failed on upstream unfixed
kernel. Thanks review points from djwong and riteshh!

PS: This case might trigger another KASAN bug[1], I hit it several times.
But looks like it's getting fixed:
  https://lore.kernel.org/linux-block/fb0804e5-bfae-62ac-c3e6-d46a9a33ca53@huawei.com/

Thanks,
Zorro

[  328.725559] BUG: KASAN: use-after-free in bt_iter+0x2a2/0x320
[  328.731994] Read of size 8 at addr ffff88828fea1200 by task kworker/23:1H/575

[  328.741634] CPU: 23 PID: 575 Comm: kworker/23:1H Tainted: G S                5.13.0-rc4-xfs #8
[  328.751255] Hardware name: IBM System x3650 M4 -[7915ON3]-/00J6520, BIOS -[VVE124AUS-1.30]- 11/21/2012
[  328.761651] Workqueue: kblockd blk_mq_timeout_work
[  328.767017] Call Trace:
[  328.769752]  dump_stack+0x9c/0xcf
[  328.773465]  print_address_description.constprop.0+0x18/0x130
[  328.779891]  ? bt_iter+0x2a2/0x320
[  328.783694]  ? bt_iter+0x2a2/0x320
[  328.787495]  kasan_report.cold+0x7f/0x111
[  328.791978]  ? bt_iter+0x2a2/0x320
[  328.795780]  bt_iter+0x2a2/0x320
[  328.799387]  blk_mq_queue_tag_busy_iter+0x42e/0x7e0
[  328.804839]  ? blk_mq_tag_to_rq+0xb0/0xb0
[  328.809321]  ? psi_group_change+0x842/0xd10
[  328.813998]  ? blk_mq_all_tag_iter+0x710/0x710
[  328.818964]  ? load_balance+0x22f0/0x22f0
[  328.823445]  ? blk_mq_tag_to_rq+0xb0/0xb0
[  328.827928]  ? psi_task_switch+0x1b5/0x630
[  328.832507]  blk_mq_timeout_work+0xa9/0x3a0
[  328.837185]  ? __blk_mq_end_request+0x440/0x440
[  328.842243]  process_one_work+0x671/0xfd0
[  328.846729]  ? _raw_write_lock_irq+0xb0/0xb0
[  328.851504]  worker_thread+0x562/0xf50
[  328.855698]  ? process_one_work+0xfd0/0xfd0
[  328.860365]  kthread+0x31c/0x3e0
[  328.863974]  ? __kthread_bind_mask+0x90/0x90
[  328.868747]  ret_from_fork+0x22/0x30

[  328.874415] Allocated by task 3056:
[  328.878311]  kasan_save_stack+0x1b/0x40
[  328.882604]  __kasan_slab_alloc+0x61/0x80
[  328.887084]  kmem_cache_alloc+0xec/0x250
[  328.891468]  xfs_buf_item_init+0x137/0x800 [xfs]
[  328.896997]  _xfs_trans_bjoin+0x75/0x2b0 [xfs]
[  328.902278]  xfs_trans_read_buf_map+0x4fa/0xb20 [xfs]
[  328.908246]  xfs_read_agf+0x173/0x3a0 [xfs]
[  328.913196]  xfs_alloc_read_agf+0x5a/0xcf0 [xfs]
[  328.918626]  xchk_ag_read_headers+0x119/0x2c0 [xfs]
[  328.924408]  xchk_ag_init+0x15/0x30 [xfs]
[  328.929217]  xchk_inode_xref+0x1ca/0x5a0 [xfs]
[  328.934515]  xchk_inode+0x1eb/0x680 [xfs]
[  328.939328]  xfs_scrub_metadata+0x59c/0xc00 [xfs]
[  328.944917]  xfs_ioc_scrub_metadata+0x80/0xe0 [xfs]
[  328.950675]  xfs_file_ioctl+0xe91/0x1380 [xfs]
[  328.955945]  __x64_sys_ioctl+0x127/0x190
[  328.960331]  do_syscall_64+0x40/0x80
[  328.964331]  entry_SYSCALL_64_after_hwframe+0x44/0xae

[  328.971639] Freed by task 3056:
[  328.975147]  kasan_save_stack+0x1b/0x40
[  328.979436]  kasan_set_track+0x1c/0x30
[  328.983624]  kasan_set_free_info+0x20/0x30
[  328.988200]  __kasan_slab_free+0xeb/0x120
[  328.992680]  slab_free_freelist_hook+0x61/0x120
[  328.997743]  kmem_cache_free+0xf3/0x440
[  329.002032]  xfs_buf_item_put+0xeb/0x160 [xfs]
[  329.007316]  xfs_trans_brelse+0x284/0x3d0 [xfs]
[  329.012702]  xchk_ag_free+0xde/0x2a0 [xfs]
[  329.017611]  xchk_inode_xref+0x394/0x5a0 [xfs]
[  329.022908]  xchk_inode+0x1eb/0x680 [xfs]
[  329.027720]  xfs_scrub_metadata+0x59c/0xc00 [xfs]
[  329.033307]  xfs_ioc_scrub_metadata+0x80/0xe0 [xfs]
[  329.039063]  xfs_file_ioctl+0xe91/0x1380 [xfs]
[  329.044333]  __x64_sys_ioctl+0x127/0x190
[  329.048717]  do_syscall_64+0x40/0x80
[  329.052715]  entry_SYSCALL_64_after_hwframe+0x44/0xae

[  329.060015] The buggy address belongs to the object at ffff88828fea1110
                which belongs to the cache xfs_buf_item of size 272
[  329.074095] The buggy address is located 240 bytes inside of
                272-byte region [ffff88828fea1110, ffff88828fea1220)
[  329.087206] The buggy address belongs to the page:
[  329.092550] page:00000000bdd5714b refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x28fea0
[  329.103049] head:00000000bdd5714b order:1 compound_mapcount:0
[  329.109469] flags: 0x57ffffc0010200(slab|head|node=1|zone=2|lastcpupid=0x1fffff)
[  329.117743] raw: 0057ffffc0010200 dead000000000100 dead000000000122 ffff88810b407540
[  329.126392] raw: 0000000000000000 0000000000180018 00000001ffffffff 0000000000000000
[  329.135038] page dumped because: kasan: bad access detected

[  329.142924] Memory state around the buggy address:
[  329.148266]  ffff88828fea1100: fc fc fa fb fb fb fb fb fb fb fb fb fb fb fb fb
[  329.156333]  ffff88828fea1180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[  329.164397] >ffff88828fea1200: fb fb fb fb fc fc fc fc fc fc fc fc fa fb fb fb
[  329.172462]                    ^
[  329.176068]  ffff88828fea1280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[  329.184134]  ffff88828fea1300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fc fc
[  329.192197] ==================================================================

Thanks,
Zorro

 tests/generic/639     | 94 +++++++++++++++++++++++++++++++++++++++++++
 tests/generic/639.out |  3 ++
 tests/generic/group   |  1 +
 3 files changed, 98 insertions(+)
 create mode 100755 tests/generic/639
 create mode 100644 tests/generic/639.out

Comments

Ritesh Harjani June 24, 2021, 8:46 a.m. UTC | #1
On 21/06/24 12:27PM, Zorro Lang wrote:
> If a swapfile doesn't contain even a single page-aligned contiguous
> range of blocks, it's an invalid swapfile, and might cause kernel
> issue. This case covered commit 5808fecc5723 ("iomap: Fix negative
> assignment to unsigned sis->pages in iomap_swapfile_activate").
>
> Signed-off-by: Zorro Lang <zlang@redhat.com>
> ---
>
> Hi,
>
> V4 did below changes:
> 1) Expect swapon return EINVAL
> 2) Compare swap size and swapfile size if swapon passed

Thanks for the changes. Looks good to me.

Reviewed-by: Ritesh Harjani <riteshh@linux.ibm.com>


>
> It's passed on fixed kernel, panic on old kernel, failed on upstream unfixed
> kernel. Thanks review points from djwong and riteshh!
>
> PS: This case might trigger another KASAN bug[1], I hit it several times.
> But looks like it's getting fixed:
>   https://lore.kernel.org/linux-block/fb0804e5-bfae-62ac-c3e6-d46a9a33ca53@huawei.com/
>
> Thanks,
> Zorro
>
> [  328.725559] BUG: KASAN: use-after-free in bt_iter+0x2a2/0x320
> [  328.731994] Read of size 8 at addr ffff88828fea1200 by task kworker/23:1H/575
>
> [  328.741634] CPU: 23 PID: 575 Comm: kworker/23:1H Tainted: G S                5.13.0-rc4-xfs #8
> [  328.751255] Hardware name: IBM System x3650 M4 -[7915ON3]-/00J6520, BIOS -[VVE124AUS-1.30]- 11/21/2012
> [  328.761651] Workqueue: kblockd blk_mq_timeout_work
> [  328.767017] Call Trace:
> [  328.769752]  dump_stack+0x9c/0xcf
> [  328.773465]  print_address_description.constprop.0+0x18/0x130
> [  328.779891]  ? bt_iter+0x2a2/0x320
> [  328.783694]  ? bt_iter+0x2a2/0x320
> [  328.787495]  kasan_report.cold+0x7f/0x111
> [  328.791978]  ? bt_iter+0x2a2/0x320
> [  328.795780]  bt_iter+0x2a2/0x320
> [  328.799387]  blk_mq_queue_tag_busy_iter+0x42e/0x7e0
> [  328.804839]  ? blk_mq_tag_to_rq+0xb0/0xb0
> [  328.809321]  ? psi_group_change+0x842/0xd10
> [  328.813998]  ? blk_mq_all_tag_iter+0x710/0x710
> [  328.818964]  ? load_balance+0x22f0/0x22f0
> [  328.823445]  ? blk_mq_tag_to_rq+0xb0/0xb0
> [  328.827928]  ? psi_task_switch+0x1b5/0x630
> [  328.832507]  blk_mq_timeout_work+0xa9/0x3a0
> [  328.837185]  ? __blk_mq_end_request+0x440/0x440
> [  328.842243]  process_one_work+0x671/0xfd0
> [  328.846729]  ? _raw_write_lock_irq+0xb0/0xb0
> [  328.851504]  worker_thread+0x562/0xf50
> [  328.855698]  ? process_one_work+0xfd0/0xfd0
> [  328.860365]  kthread+0x31c/0x3e0
> [  328.863974]  ? __kthread_bind_mask+0x90/0x90
> [  328.868747]  ret_from_fork+0x22/0x30
>
> [  328.874415] Allocated by task 3056:
> [  328.878311]  kasan_save_stack+0x1b/0x40
> [  328.882604]  __kasan_slab_alloc+0x61/0x80
> [  328.887084]  kmem_cache_alloc+0xec/0x250
> [  328.891468]  xfs_buf_item_init+0x137/0x800 [xfs]
> [  328.896997]  _xfs_trans_bjoin+0x75/0x2b0 [xfs]
> [  328.902278]  xfs_trans_read_buf_map+0x4fa/0xb20 [xfs]
> [  328.908246]  xfs_read_agf+0x173/0x3a0 [xfs]
> [  328.913196]  xfs_alloc_read_agf+0x5a/0xcf0 [xfs]
> [  328.918626]  xchk_ag_read_headers+0x119/0x2c0 [xfs]
> [  328.924408]  xchk_ag_init+0x15/0x30 [xfs]
> [  328.929217]  xchk_inode_xref+0x1ca/0x5a0 [xfs]
> [  328.934515]  xchk_inode+0x1eb/0x680 [xfs]
> [  328.939328]  xfs_scrub_metadata+0x59c/0xc00 [xfs]
> [  328.944917]  xfs_ioc_scrub_metadata+0x80/0xe0 [xfs]
> [  328.950675]  xfs_file_ioctl+0xe91/0x1380 [xfs]
> [  328.955945]  __x64_sys_ioctl+0x127/0x190
> [  328.960331]  do_syscall_64+0x40/0x80
> [  328.964331]  entry_SYSCALL_64_after_hwframe+0x44/0xae
>
> [  328.971639] Freed by task 3056:
> [  328.975147]  kasan_save_stack+0x1b/0x40
> [  328.979436]  kasan_set_track+0x1c/0x30
> [  328.983624]  kasan_set_free_info+0x20/0x30
> [  328.988200]  __kasan_slab_free+0xeb/0x120
> [  328.992680]  slab_free_freelist_hook+0x61/0x120
> [  328.997743]  kmem_cache_free+0xf3/0x440
> [  329.002032]  xfs_buf_item_put+0xeb/0x160 [xfs]
> [  329.007316]  xfs_trans_brelse+0x284/0x3d0 [xfs]
> [  329.012702]  xchk_ag_free+0xde/0x2a0 [xfs]
> [  329.017611]  xchk_inode_xref+0x394/0x5a0 [xfs]
> [  329.022908]  xchk_inode+0x1eb/0x680 [xfs]
> [  329.027720]  xfs_scrub_metadata+0x59c/0xc00 [xfs]
> [  329.033307]  xfs_ioc_scrub_metadata+0x80/0xe0 [xfs]
> [  329.039063]  xfs_file_ioctl+0xe91/0x1380 [xfs]
> [  329.044333]  __x64_sys_ioctl+0x127/0x190
> [  329.048717]  do_syscall_64+0x40/0x80
> [  329.052715]  entry_SYSCALL_64_after_hwframe+0x44/0xae
>
> [  329.060015] The buggy address belongs to the object at ffff88828fea1110
>                 which belongs to the cache xfs_buf_item of size 272
> [  329.074095] The buggy address is located 240 bytes inside of
>                 272-byte region [ffff88828fea1110, ffff88828fea1220)
> [  329.087206] The buggy address belongs to the page:
> [  329.092550] page:00000000bdd5714b refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x28fea0
> [  329.103049] head:00000000bdd5714b order:1 compound_mapcount:0
> [  329.109469] flags: 0x57ffffc0010200(slab|head|node=1|zone=2|lastcpupid=0x1fffff)
> [  329.117743] raw: 0057ffffc0010200 dead000000000100 dead000000000122 ffff88810b407540
> [  329.126392] raw: 0000000000000000 0000000000180018 00000001ffffffff 0000000000000000
> [  329.135038] page dumped because: kasan: bad access detected
>
> [  329.142924] Memory state around the buggy address:
> [  329.148266]  ffff88828fea1100: fc fc fa fb fb fb fb fb fb fb fb fb fb fb fb fb
> [  329.156333]  ffff88828fea1180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> [  329.164397] >ffff88828fea1200: fb fb fb fb fc fc fc fc fc fc fc fc fa fb fb fb
> [  329.172462]                    ^
> [  329.176068]  ffff88828fea1280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
> [  329.184134]  ffff88828fea1300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fc fc
> [  329.192197] ==================================================================
>
> Thanks,
> Zorro
>
>  tests/generic/639     | 94 +++++++++++++++++++++++++++++++++++++++++++
>  tests/generic/639.out |  3 ++
>  tests/generic/group   |  1 +
>  3 files changed, 98 insertions(+)
>  create mode 100755 tests/generic/639
>  create mode 100644 tests/generic/639.out
>
> diff --git a/tests/generic/639 b/tests/generic/639
> new file mode 100755
> index 00000000..b280ba62
> --- /dev/null
> +++ b/tests/generic/639
> @@ -0,0 +1,94 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2021 Red Hat Inc.  All Rights Reserved.
> +#
> +# FS QA Test No. 639
> +#
> +# Test small swapfile which doesn't contain even a single page-aligned contiguous
> +# range of blocks. This case covered commit 5808fecc5723 ("iomap: Fix negative
> +# assignment to unsigned sis->pages in iomap_swapfile_activate").
> +#
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +_supported_fs generic
> +_require_scratch
> +_require_scratch_swapfile
> +_require_test_program mkswap
> +_require_test_program swapon
> +_require_xfs_io_command fcollapse
> +
> +make_unaligned_swapfile()
> +{
> +	local fname=$1
> +	local n=$((psize / bsize - 1))
> +
> +	# Make sure the swapfile doesn't contain even a single page-aligned
> +	# contiguous range of blocks. This's necessary to cover the bug
> +	$XFS_IO_PROG -f -t -c "pwrite 0 $(((psize + bsize) * n))" $fname >> $seqres.full 2>&1
> +	for((i=1; i<=n; i++));do
> +		$XFS_IO_PROG -c "fcollapse $(((psize - bsize) * i)) $bsize" $fname
> +	done
> +	chmod 0600 $fname
> +	$CHATTR_PROG +C $fname > /dev/null 2>&1
> +	$here/src/mkswap $fname
> +}
> +
> +_scratch_mkfs >> $seqres.full 2>&1
> +_scratch_mount
> +psize=`get_page_size`
> +bsize=`_get_file_block_size $SCRATCH_MNT`
> +# Due to we need page-unaligned blocks, so blocksize < pagesize is necessary.
> +# If not, try to make a smaller enough block size
> +if [ $bsize -ge $psize ];then
> +	_scratch_unmount
> +	_scratch_mkfs_blocksized 1024 >> $seqres.full 2>&1
> +	if [ $? -ne 0 ];then
> +		_notrun "Can't make filesystem block size < page size."
> +	fi
> +	_scratch_mount
> +	bsize=`_get_file_block_size $SCRATCH_MNT`
> +	if [ $bsize -ne 1024 ];then
> +		_notrun "Can't force 1024-byte file block size."
> +	fi
> +fi
> +swapfile=$SCRATCH_MNT/$seq.swapfile
> +make_unaligned_swapfile $swapfile
> +# Expect EINVAL from swapon. If not, might miss 5808fecc5723 ("iomap: Fix
> +# negative assignment to unsigned sis->pages in iomap_swapfile_activate")
> +$here/src/swapon $swapfile
> +# Further testing, check if swap size <= swapfile size, if swapon passed
> +if [ $? -eq 0 ];then
> +	swapsize=$(awk -v fname="$swapfile" '{if ($1~fname) print $3}' /proc/swaps)
> +	swapsize=$((swapsize * 1024))
> +	filesize=$(_get_filesize $swapfile)
> +	if [ $swapsize -gt $filesize ]; then
> +		echo "Allocated swap size($swapsize) shouldn't be greater than swapfile size($filesize)"
> +	fi
> +fi
> +swapoff $swapfile 2>/dev/null
> +
> +echo "Silence is golden"
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/639.out b/tests/generic/639.out
> new file mode 100644
> index 00000000..181822e5
> --- /dev/null
> +++ b/tests/generic/639.out
> @@ -0,0 +1,3 @@
> +QA output created by 639
> +swapon: Invalid argument
> +Silence is golden
> diff --git a/tests/generic/group b/tests/generic/group
> index 9a636b23..48ffa3c7 100644
> --- a/tests/generic/group
> +++ b/tests/generic/group
> @@ -641,3 +641,4 @@
>  636 auto quick swap
>  637 auto quick dir
>  638 auto quick rw
> +639 auto quick swap
> --
> 2.31.1
>
diff mbox series

Patch

diff --git a/tests/generic/639 b/tests/generic/639
new file mode 100755
index 00000000..b280ba62
--- /dev/null
+++ b/tests/generic/639
@@ -0,0 +1,94 @@ 
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2021 Red Hat Inc.  All Rights Reserved.
+#
+# FS QA Test No. 639
+#
+# Test small swapfile which doesn't contain even a single page-aligned contiguous
+# range of blocks. This case covered commit 5808fecc5723 ("iomap: Fix negative
+# assignment to unsigned sis->pages in iomap_swapfile_activate").
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs generic
+_require_scratch
+_require_scratch_swapfile
+_require_test_program mkswap
+_require_test_program swapon
+_require_xfs_io_command fcollapse
+
+make_unaligned_swapfile()
+{
+	local fname=$1
+	local n=$((psize / bsize - 1))
+
+	# Make sure the swapfile doesn't contain even a single page-aligned
+	# contiguous range of blocks. This's necessary to cover the bug
+	$XFS_IO_PROG -f -t -c "pwrite 0 $(((psize + bsize) * n))" $fname >> $seqres.full 2>&1
+	for((i=1; i<=n; i++));do
+		$XFS_IO_PROG -c "fcollapse $(((psize - bsize) * i)) $bsize" $fname
+	done
+	chmod 0600 $fname
+	$CHATTR_PROG +C $fname > /dev/null 2>&1
+	$here/src/mkswap $fname
+}
+
+_scratch_mkfs >> $seqres.full 2>&1
+_scratch_mount
+psize=`get_page_size`
+bsize=`_get_file_block_size $SCRATCH_MNT`
+# Due to we need page-unaligned blocks, so blocksize < pagesize is necessary.
+# If not, try to make a smaller enough block size
+if [ $bsize -ge $psize ];then
+	_scratch_unmount
+	_scratch_mkfs_blocksized 1024 >> $seqres.full 2>&1
+	if [ $? -ne 0 ];then
+		_notrun "Can't make filesystem block size < page size."
+	fi
+	_scratch_mount
+	bsize=`_get_file_block_size $SCRATCH_MNT`
+	if [ $bsize -ne 1024 ];then
+		_notrun "Can't force 1024-byte file block size."
+	fi
+fi
+swapfile=$SCRATCH_MNT/$seq.swapfile
+make_unaligned_swapfile $swapfile
+# Expect EINVAL from swapon. If not, might miss 5808fecc5723 ("iomap: Fix
+# negative assignment to unsigned sis->pages in iomap_swapfile_activate")
+$here/src/swapon $swapfile
+# Further testing, check if swap size <= swapfile size, if swapon passed
+if [ $? -eq 0 ];then
+	swapsize=$(awk -v fname="$swapfile" '{if ($1~fname) print $3}' /proc/swaps)
+	swapsize=$((swapsize * 1024))
+	filesize=$(_get_filesize $swapfile)
+	if [ $swapsize -gt $filesize ]; then
+		echo "Allocated swap size($swapsize) shouldn't be greater than swapfile size($filesize)"
+	fi
+fi
+swapoff $swapfile 2>/dev/null
+
+echo "Silence is golden"
+# success, all done
+status=0
+exit
diff --git a/tests/generic/639.out b/tests/generic/639.out
new file mode 100644
index 00000000..181822e5
--- /dev/null
+++ b/tests/generic/639.out
@@ -0,0 +1,3 @@ 
+QA output created by 639
+swapon: Invalid argument
+Silence is golden
diff --git a/tests/generic/group b/tests/generic/group
index 9a636b23..48ffa3c7 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -641,3 +641,4 @@ 
 636 auto quick swap
 637 auto quick dir
 638 auto quick rw
+639 auto quick swap