Skip to content

Commit e0ff0da

Browse files
coolgwmetan-ucw
authored andcommitted
ioctl_fiemap01: New test for fiemap ioctl()
Fixes: #535 Local test show EOPNOTSUPP on exfat/vfat/ntfs/tmpfs, so descope related file system currently. Signed-off-by: Wei Gao <wegao@suse.com> Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
1 parent 8de50fc commit e0ff0da

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

runtest/syscalls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ ioctl_ficlone02 ioctl_ficlone02
609609
ioctl_ficlone03 ioctl_ficlone03
610610
ioctl_ficlonerange01 ioctl_ficlonerange01
611611
ioctl_ficlonerange02 ioctl_ficlonerange02
612+
ioctl_fiemap01 ioctl_fiemap01
612613

613614
inotify_init1_01 inotify_init1_01
614615
inotify_init1_02 inotify_init1_02

testcases/kernel/syscalls/ioctl/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@
2828
/ioctl_ficlone04
2929
/ioctl_ficlonerange01
3030
/ioctl_ficlonerange02
31+
/ioctl_fiemap01
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2025 Wei Gao <wegao@suse.com>
4+
*/
5+
6+
/*\
7+
* Verify basic fiemap ioctl functionality, including:
8+
*
9+
* - The ioctl returns EBADR if it receives invalid fm_flags.
10+
* - 0 extents are reported for an empty file.
11+
* - The ioctl correctly retrieves single and multiple extent mappings after writing to the file.
12+
*/
13+
14+
#include <linux/fs.h>
15+
#include <linux/fiemap.h>
16+
#include <stdlib.h>
17+
#include <sys/statvfs.h>
18+
19+
#include "tst_test.h"
20+
21+
#define MNTPOINT "mntpoint"
22+
#define TESTFILE "testfile"
23+
#define NUM_EXTENT 3
24+
25+
static void print_extens(struct fiemap *fiemap)
26+
{
27+
tst_res(TDEBUG, "File extent count: %u", fiemap->fm_mapped_extents);
28+
29+
for (unsigned int i = 0; i < fiemap->fm_mapped_extents; ++i) {
30+
tst_res(TDEBUG, "Extent %u: Logical offset: %llu, Physical offset: %llu, flags: %u, Length: %llu",
31+
i + 1,
32+
fiemap->fm_extents[i].fe_logical,
33+
fiemap->fm_extents[i].fe_physical,
34+
fiemap->fm_extents[i].fe_flags,
35+
fiemap->fm_extents[i].fe_length);
36+
}
37+
}
38+
39+
static void check_extent_count(struct fiemap *fiemap, unsigned int fm_mapped_extents)
40+
{
41+
TST_EXP_EXPR(fiemap->fm_mapped_extents == fm_mapped_extents,
42+
"extent fm_mapped_extents is %d", fm_mapped_extents);
43+
}
44+
45+
static void check_extent(struct fiemap *fiemap, int index_extents, unsigned int fe_mask,
46+
unsigned int fe_flags, unsigned int fe_length)
47+
{
48+
struct fiemap_extent *extent = &fiemap->fm_extents[index_extents];
49+
50+
TST_EXP_EQ_LU((extent->fe_flags & fe_mask), fe_flags);
51+
TST_EXP_EXPR(extent->fe_physical >= 1, "fe_physical > %d", 1);
52+
TST_EXP_EQ_LU(extent->fe_length, fe_length);
53+
}
54+
55+
static void verify_ioctl(void)
56+
{
57+
int fd;
58+
struct fiemap *fiemap;
59+
struct statvfs fs_info;
60+
unsigned long blk_size;
61+
62+
fd = SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT, 0644);
63+
64+
SAFE_STATVFS(".", &fs_info);
65+
66+
blk_size = fs_info.f_bsize;
67+
68+
fiemap = SAFE_MALLOC(sizeof(struct fiemap) + sizeof(struct fiemap_extent) * NUM_EXTENT);
69+
fiemap->fm_start = 0;
70+
fiemap->fm_length = ~0ULL;
71+
fiemap->fm_extent_count = 1;
72+
73+
fiemap->fm_flags = -1;
74+
TST_EXP_FAIL(ioctl(fd, FS_IOC_FIEMAP, fiemap), EBADR);
75+
76+
fiemap->fm_flags = 0;
77+
TST_EXP_PASS(ioctl(fd, FS_IOC_FIEMAP, fiemap));
78+
print_extens(fiemap);
79+
TST_EXP_EXPR(fiemap->fm_mapped_extents == 0,
80+
"Empty file should have 0 extends mapped");
81+
82+
char *buf = SAFE_MALLOC(blk_size);
83+
84+
SAFE_WRITE(SAFE_WRITE_ANY, fd, buf, blk_size);
85+
fiemap->fm_flags = FIEMAP_FLAG_SYNC;
86+
TST_EXP_PASS(ioctl(fd, FS_IOC_FIEMAP, fiemap));
87+
print_extens(fiemap);
88+
check_extent_count(fiemap, 1);
89+
check_extent(fiemap, 0, FIEMAP_EXTENT_LAST, FIEMAP_EXTENT_LAST, blk_size);
90+
91+
fiemap->fm_extent_count = NUM_EXTENT;
92+
SAFE_LSEEK(fd, 2 * blk_size, SEEK_SET);
93+
SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, blk_size);
94+
SAFE_LSEEK(fd, 4 * blk_size, SEEK_SET);
95+
SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, blk_size);
96+
TST_EXP_PASS(ioctl(fd, FS_IOC_FIEMAP, fiemap));
97+
print_extens(fiemap);
98+
check_extent_count(fiemap, NUM_EXTENT);
99+
100+
for (int i = 0; i < NUM_EXTENT - 1; i++)
101+
check_extent(fiemap, i, FIEMAP_EXTENT_LAST, 0, blk_size);
102+
103+
check_extent(fiemap, NUM_EXTENT - 1, FIEMAP_EXTENT_LAST, FIEMAP_EXTENT_LAST, blk_size);
104+
105+
free(buf);
106+
free(fiemap);
107+
SAFE_CLOSE(fd);
108+
SAFE_UNLINK(TESTFILE);
109+
}
110+
111+
static void setup(void)
112+
{
113+
SAFE_CHDIR(MNTPOINT);
114+
}
115+
116+
static struct tst_test test = {
117+
.setup = setup,
118+
.mount_device = 1,
119+
.mntpoint = MNTPOINT,
120+
.all_filesystems = 1,
121+
.skip_filesystems = (const char *const[]) {
122+
"exfat", "vfat", "fuse", "ntfs", "tmpfs", NULL
123+
},
124+
.test_all = verify_ioctl,
125+
.needs_root = 1,
126+
};

0 commit comments

Comments
 (0)