1 /*
2 * Check decoding of FS_IOC_FIEMAP ioctl command.
3 *
4 * Copyright (c) 2016-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <sys/ioctl.h>
15 #include <linux/types.h>
16 #include <linux/fiemap.h>
17 #include <linux/fs.h>
18
19 static const char *errstr;
20
21 static int
22 do_ioctl(kernel_ulong_t cmd, kernel_ulong_t arg)
23 {
24 int rc = ioctl(-1, cmd, arg);
25 errstr = sprintrc(rc);
26
27 #ifdef INJECT_RETVAL
28 if (rc != INJECT_RETVAL)
29 error_msg_and_fail("Return value [%d] does not match"
30 " expectations [%d]", rc, INJECT_RETVAL);
31
32 static char inj_errstr[4096];
33
34 snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
35 errstr = inj_errstr;
36 #endif
37
38 return rc;
39 }
40
41 static int
42 do_ioctl_ptr(kernel_ulong_t cmd, const void *arg)
43 {
44 return do_ioctl(cmd, (uintptr_t) arg);
45 }
46
47 #ifdef INJECT_RETVAL
48 static void
49 skip_ioctls(int argc, const char *argv[])
50 {
51 if (argc < 2)
52 error_msg_and_fail("Usage: %s NUM_SKIP", argv[0]);
53
54 unsigned long num_skip = strtoul(argv[1], NULL, 0);
55
56 for (size_t i = 0; i < num_skip; ++i) {
57 int rc = ioctl(-1, FS_IOC_FIEMAP, 0);
58
59 printf("ioctl(-1, %s, NULL) = %s%s\n",
60 XLAT_STR(FS_IOC_FIEMAP), sprintrc(rc),
61 rc == INJECT_RETVAL ? " (INJECTED)" : "");
62
63 if (rc == INJECT_RETVAL)
64 return;
65 }
66
67 error_msg_and_fail("Issued %lu ioctl syscalls but failed"
68 " to detect an injected return code %d",
69 num_skip, INJECT_RETVAL);
70 }
71 #endif /* INJECT_RETVAL */
72
73 int
74 main(int argc, const char *argv[])
75 {
76 #ifdef INJECT_RETVAL
77 skip_ioctls(argc, argv);
78 #endif
79
80 TAIL_ALLOC_OBJECT_VAR_PTR(struct fiemap, fiemap);
81
82 do_ioctl_ptr(FS_IOC_FIEMAP, (char *) fiemap + 1);
83 printf("ioctl(-1, %s, %p) = %s\n",
84 XLAT_STR(FS_IOC_FIEMAP), (char *) fiemap + 1, errstr);
85
86 #define VALID_FM_FLAGS 0x7
87 #define INVALID_FM_FLAGS 0xfffffff8
88
89 fiemap->fm_start = (typeof(fiemap->fm_start)) 0xdeadbeefcafef00dULL;
90 fiemap->fm_length = (typeof(fiemap->fm_length)) 0xfacefeedbabec0deULL;
91 fiemap->fm_flags = VALID_FM_FLAGS;
92 fiemap->fm_mapped_extents = 0xbadc0ded;
93 fiemap->fm_extent_count = 0xdeadc0de;
94
95 int rc = do_ioctl_ptr(FS_IOC_FIEMAP, fiemap);
96 printf("ioctl(-1, %s, {fm_start=%ju, fm_length=%ju"
97 ", fm_flags=%s, fm_extent_count=%u}",
98 XLAT_STR(FS_IOC_FIEMAP),
99 (uintmax_t) fiemap->fm_start, (uintmax_t) fiemap->fm_length,
100 XLAT_KNOWN(VALID_FM_FLAGS,
101 "FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR|"
102 "FIEMAP_FLAG_CACHE"),
103 fiemap->fm_extent_count);
104 if (rc < 0) {
105 printf(") = %s\n", errstr);
106 } else {
107 printf(" => {fm_flags=%s, fm_mapped_extents=%u, ",
108 XLAT_KNOWN(VALID_FM_FLAGS,
109 "FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR|"
110 "FIEMAP_FLAG_CACHE"),
111 fiemap->fm_mapped_extents);
112 #if VERBOSE
113 printf("fm_extents=%p", fiemap + 1);
114 #else
115 printf("...");
116 #endif
117 printf("}) = %s\n", errstr);
118 }
119
120 #define VALID_FE_FLAGS 0x3f8f
121 #define INVALID_FE_FLAGS 0xffffc070
122
123 fiemap = tail_alloc(sizeof(*fiemap) + 2 * sizeof(fiemap->fm_extents[0]));
124 fiemap->fm_start = (typeof(fiemap->fm_start)) 0xdeadbeefcafef00dULL;
125 fiemap->fm_length = (typeof(fiemap->fm_length)) 0xfacefeedbabec0deULL;
126 fiemap->fm_flags = ~VALID_FM_FLAGS;
127 fiemap->fm_mapped_extents = 2;
128 fiemap->fm_extent_count = 0xdeadc0de;
129
130 fiemap->fm_extents[0].fe_logical = 0xfacefed1deadbef1;
131 fiemap->fm_extents[0].fe_physical = 0xfacefed2deadbef2;
132 fiemap->fm_extents[0].fe_length = 0xfacefed3deadbef3;
133 fiemap->fm_extents[0].fe_flags = VALID_FE_FLAGS;
134
135 fiemap->fm_extents[1].fe_logical = 0xfacefed1deadbef4;
136 fiemap->fm_extents[1].fe_physical = 0xfacefed2deadbef5;
137 fiemap->fm_extents[1].fe_length = 0xfacefed3deadbef6;
138 fiemap->fm_extents[1].fe_flags = ~VALID_FE_FLAGS;
139
140 rc = do_ioctl_ptr(FS_IOC_FIEMAP, fiemap);
141 printf("ioctl(-1, %s, {fm_start=%ju, fm_length=%ju"
142 ", fm_flags=%s, fm_extent_count=%u}",
143 XLAT_STR(FS_IOC_FIEMAP),
144 (uintmax_t) fiemap->fm_start, (uintmax_t) fiemap->fm_length,
145 XLAT_UNKNOWN(INVALID_FM_FLAGS, "FIEMAP_FLAG_???"),
146 fiemap->fm_extent_count);
147 if (rc < 0) {
148 printf(") = %s\n", errstr);
149 } else {
150 printf(" => {fm_flags=%s, fm_mapped_extents=%u, ",
151 XLAT_UNKNOWN(INVALID_FM_FLAGS, "FIEMAP_FLAG_???"),
152 fiemap->fm_mapped_extents);
153 #if VERBOSE
154 printf("fm_extents=[{fe_logical=%ju, fe_physical=%ju"
155 ", fe_length=%ju, fe_flags=%s}"
156 ", {fe_logical=%ju, fe_physical=%ju"
157 ", fe_length=%ju, fe_flags=%s}]",
158 (uintmax_t) fiemap->fm_extents[0].fe_logical,
159 (uintmax_t) fiemap->fm_extents[0].fe_physical,
160 (uintmax_t) fiemap->fm_extents[0].fe_length,
161 XLAT_KNOWN(VALID_FE_FLAGS,
162 "FIEMAP_EXTENT_LAST|"
163 "FIEMAP_EXTENT_UNKNOWN|"
164 "FIEMAP_EXTENT_DELALLOC|"
165 "FIEMAP_EXTENT_ENCODED|"
166 "FIEMAP_EXTENT_DATA_ENCRYPTED|"
167 "FIEMAP_EXTENT_NOT_ALIGNED|"
168 "FIEMAP_EXTENT_DATA_INLINE|"
169 "FIEMAP_EXTENT_DATA_TAIL|"
170 "FIEMAP_EXTENT_UNWRITTEN|"
171 "FIEMAP_EXTENT_MERGED|"
172 "FIEMAP_EXTENT_SHARED"),
173 (uintmax_t) fiemap->fm_extents[1].fe_logical,
174 (uintmax_t) fiemap->fm_extents[1].fe_physical,
175 (uintmax_t) fiemap->fm_extents[1].fe_length,
176 XLAT_UNKNOWN(INVALID_FE_FLAGS, "FIEMAP_EXTENT_???"));
177 #else
178 printf("...");
179 #endif
180 printf("}) = %s\n", errstr);
181 }
182
183 /* The live version of this test is in btrfs.c */
184
185 puts("+++ exited with 0 +++");
186 return 0;
187 }