]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/fiemap.c
xfs_repair: fix thread creation failure recovery
[thirdparty/xfsprogs-dev.git] / io / fiemap.c
CommitLineData
8f0e0912
CH
1/*
2 * Copyright (c) 2010 Red Hat, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
dcabd4e7 19#include "platform_defs.h"
6b803e5a 20#include "command.h"
fb2bfcdf 21#include "input.h"
8f0e0912 22#include <linux/fiemap.h>
8f0e0912
CH
23#include "init.h"
24#include "io.h"
25
26static cmdinfo_t fiemap_cmd;
27
28static void
29fiemap_help(void)
30{
31 printf(_(
32"\n"
33" prints the block mapping for a file's data or attribute forks"
34"\n"
35" Example:\n"
36" 'fiemap -v' - tabular format verbose map\n"
37"\n"
38" fiemap prints the map of disk blocks used by the current file.\n"
39" The map lists each extent used by the file, as well as regions in the\n"
40" file that do not have any corresponding blocks (holes).\n"
41" By default, each line of the listing takes the following form:\n"
42" extent: [startoffset..endoffset]: startblock..endblock\n"
43" Holes are marked by replacing the startblock..endblock with 'hole'.\n"
44" All the file offsets and disk blocks are in units of 512-byte blocks.\n"
45" -a -- prints the attribute fork map instead of the data fork.\n"
46" -l -- also displays the length of each extent in 512-byte blocks.\n"
47" -n -- query n extents.\n"
48" -v -- Verbose information\n"
49"\n"));
50}
51
8f0e0912
CH
52static void
53print_verbose(
54 struct fiemap_extent *extent,
55 int blocksize,
56 int foff_w,
57 int boff_w,
58 int tot_w,
59 int flg_w,
60 int max_extents,
61 int *cur_extent,
62 __u64 *last_logical)
63{
64 __u64 lstart;
ef45fa5e 65 __u64 llast;
8f0e0912
CH
66 __u64 len;
67 __u64 block;
68 char lbuf[48];
69 char bbuf[48];
70 char flgbuf[16];
71
ef45fa5e 72 llast = *last_logical / blocksize;
8f0e0912
CH
73 lstart = extent->fe_logical / blocksize;
74 len = extent->fe_length / blocksize;
75 block = extent->fe_physical / blocksize;
76
77 memset(lbuf, 0, sizeof(lbuf));
78 memset(bbuf, 0, sizeof(bbuf));
79
b3a5164e
ES
80 if (*cur_extent == 0) {
81 printf("%4s: %-*s %-*s %*s %*s\n", _("EXT"),
82 foff_w, _("FILE-OFFSET"),
83 boff_w, _("BLOCK-RANGE"),
84 tot_w, _("TOTAL"),
85 flg_w, _("FLAGS"));
86 }
87
ef45fa5e
DC
88 if (lstart != llast) {
89 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", llast,
8f0e0912
CH
90 lstart - 1ULL);
91 printf("%4d: %-*s %-*s %*llu\n", *cur_extent, foff_w, lbuf,
ef45fa5e 92 boff_w, _("hole"), tot_w, lstart - llast);
8f0e0912
CH
93 (*cur_extent)++;
94 memset(lbuf, 0, sizeof(lbuf));
95 }
96
97 if ((*cur_extent + 1) == max_extents)
98 return;
99
100 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:", lstart,
101 lstart + len - 1ULL);
102 snprintf(bbuf, sizeof(bbuf), "%llu..%llu", block, block + len - 1ULL);
103 snprintf(flgbuf, sizeof(flgbuf), "0x%x", extent->fe_flags);
104 printf("%4d: %-*s %-*s %*llu %*s\n", *cur_extent, foff_w, lbuf,
105 boff_w, bbuf, tot_w, len, flg_w, flgbuf);
106
107 (*cur_extent)++;
1b7b28f7 108 *last_logical = extent->fe_logical + extent->fe_length;
8f0e0912
CH
109}
110
111static void
112print_plain(
113 struct fiemap_extent *extent,
114 int lflag,
115 int blocksize,
116 int max_extents,
117 int *cur_extent,
118 __u64 *last_logical)
119{
120 __u64 lstart;
ef45fa5e 121 __u64 llast;
8f0e0912
CH
122 __u64 block;
123 __u64 len;
124
ef45fa5e 125 llast = *last_logical / blocksize;
8f0e0912
CH
126 lstart = extent->fe_logical / blocksize;
127 len = extent->fe_length / blocksize;
128 block = extent->fe_physical / blocksize;
129
ef45fa5e 130 if (lstart != llast) {
8f0e0912 131 printf("\t%d: [%llu..%llu]: hole", *cur_extent,
ef45fa5e 132 llast, lstart - 1ULL);
8f0e0912 133 if (lflag)
ef45fa5e 134 printf(_(" %llu blocks\n"), lstart - llast);
8f0e0912
CH
135 else
136 printf("\n");
137 (*cur_extent)++;
138 }
139
140 if ((*cur_extent + 1) == max_extents)
141 return;
142
143 printf("\t%d: [%llu..%llu]: %llu..%llu", *cur_extent,
144 lstart, lstart + len - 1ULL, block,
145 block + len - 1ULL);
146
147 if (lflag)
148 printf(_(" %llu blocks\n"), len);
149 else
150 printf("\n");
151 (*cur_extent)++;
1b7b28f7 152 *last_logical = extent->fe_logical + extent->fe_length;
8f0e0912
CH
153}
154
b3a5164e
ES
155/*
156 * Calculate the proper extent table format based on first
157 * set of extents
158 */
159static void
160calc_print_format(
161 struct fiemap *fiemap,
162 __u64 blocksize,
163 int *foff_w,
164 int *boff_w,
165 int *tot_w,
166 int *flg_w)
167{
168 int i;
169 char lbuf[32];
170 char bbuf[32];
171 __u64 logical;
172 __u64 block;
173 __u64 len;
174 struct fiemap_extent *extent;
175
176 for (i = 0; i < fiemap->fm_mapped_extents; i++) {
177
178 extent = &fiemap->fm_extents[i];
179 logical = extent->fe_logical / blocksize;
180 len = extent->fe_length / blocksize;
181 block = extent->fe_physical / blocksize;
182
183 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]", logical,
184 logical + len - 1);
185 snprintf(bbuf, sizeof(bbuf), "%llu..%llu", block,
186 block + len - 1);
187 *foff_w = max(*foff_w, strlen(lbuf));
188 *boff_w = max(*boff_w, strlen(bbuf));
189 *tot_w = max(*tot_w, numlen(len, 10));
190 *flg_w = max(*flg_w, numlen(extent->fe_flags, 16));
191 if (extent->fe_flags & FIEMAP_EXTENT_LAST)
192 break;
193 }
194}
195
8f0e0912
CH
196int
197fiemap_f(
198 int argc,
199 char **argv)
200{
201 struct fiemap *fiemap;
202 int max_extents = 0;
203 int num_extents = 32;
204 int last = 0;
8f0e0912
CH
205 int lflag = 0;
206 int vflag = 0;
207 int fiemap_flags = FIEMAP_FLAG_SYNC;
208 int c;
209 int i;
210 int map_size;
211 int ret;
212 int cur_extent = 0;
213 int foff_w = 16; /* 16 just for a good minimum range */
214 int boff_w = 16;
215 int tot_w = 5; /* 5 since its just one number */
216 int flg_w = 5;
217 __u64 blocksize = 512;
218 __u64 last_logical = 0;
219 struct stat st;
220
221 while ((c = getopt(argc, argv, "aln:v")) != EOF) {
222 switch (c) {
223 case 'a':
224 fiemap_flags |= FIEMAP_FLAG_XATTR;
225 break;
226 case 'l':
227 lflag = 1;
228 break;
229 case 'n':
230 max_extents = atoi(optarg);
8f0e0912
CH
231 break;
232 case 'v':
233 vflag++;
234 break;
235 default:
236 return command_usage(&fiemap_cmd);
237 }
238 }
239
240 if (max_extents)
241 num_extents = min(num_extents, max_extents);
242 map_size = sizeof(struct fiemap) +
243 (num_extents * sizeof(struct fiemap_extent));
244 fiemap = malloc(map_size);
245 if (!fiemap) {
246 fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
247 progname, map_size);
248 exitcode = 1;
249 return 0;
250 }
251
252 printf("%s:\n", file->name);
253
8f0e0912
CH
254 while (!last && ((cur_extent + 1) != max_extents)) {
255 if (max_extents)
256 num_extents = min(num_extents,
257 max_extents - (cur_extent + 1));
258
259 memset(fiemap, 0, map_size);
260 fiemap->fm_flags = fiemap_flags;
261 fiemap->fm_start = last_logical;
1b7b28f7 262 fiemap->fm_length = -1LL;
8f0e0912
CH
263 fiemap->fm_extent_count = num_extents;
264
265 ret = ioctl(file->fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
266 if (ret < 0) {
267 fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: "
268 "%s\n", progname, file->name, strerror(errno));
269 free(fiemap);
270 exitcode = 1;
271 return 0;
272 }
273
274 /* No more extents to map, exit */
275 if (!fiemap->fm_mapped_extents)
276 break;
277
278 for (i = 0; i < fiemap->fm_mapped_extents; i++) {
279 struct fiemap_extent *extent;
280
281 extent = &fiemap->fm_extents[i];
b3a5164e
ES
282 if (vflag) {
283 if (cur_extent == 0) {
284 calc_print_format(fiemap, blocksize,
285 &foff_w, &boff_w,
286 &tot_w, &flg_w);
287 }
f8149110 288
8f0e0912
CH
289 print_verbose(extent, blocksize, foff_w,
290 boff_w, tot_w, flg_w,
291 max_extents, &cur_extent,
292 &last_logical);
b3a5164e 293 } else
8f0e0912
CH
294 print_plain(extent, lflag, blocksize,
295 max_extents, &cur_extent,
296 &last_logical);
ef45fa5e 297
8f0e0912
CH
298 if (extent->fe_flags & FIEMAP_EXTENT_LAST) {
299 last = 1;
300 break;
301 }
302
303 if ((cur_extent + 1) == max_extents)
304 break;
305 }
306 }
307
308 if ((cur_extent + 1) == max_extents)
309 goto out;
310
311 memset(&st, 0, sizeof(st));
312 if (fstat(file->fd, &st)) {
313 fprintf(stderr, "%s: fstat failed: %s\n", progname,
314 strerror(errno));
315 free(fiemap);
316 exitcode = 1;
317 return 0;
318 }
319
ef45fa5e 320 if (cur_extent && last_logical < st.st_size) {
8f0e0912
CH
321 char lbuf[32];
322
323 snprintf(lbuf, sizeof(lbuf), "[%llu..%llu]:",
ef45fa5e 324 last_logical / blocksize, (st.st_size / blocksize) - 1);
8f0e0912
CH
325 if (vflag) {
326 printf("%4d: %-*s %-*s %*llu\n", cur_extent,
327 foff_w, lbuf, boff_w, _("hole"), tot_w,
ef45fa5e 328 (st.st_size - last_logical) / blocksize);
8f0e0912
CH
329 } else {
330 printf("\t%d: %s %s", cur_extent, lbuf,
331 _("hole"));
332 if (lflag)
333 printf(_(" %llu blocks\n"),
ef45fa5e 334 (st.st_size - last_logical) / blocksize);
8f0e0912
CH
335 else
336 printf("\n");
337 }
338 }
339
340out:
341 free(fiemap);
342 return 0;
343}
344
345void
346fiemap_init(void)
347{
348 fiemap_cmd.name = "fiemap";
349 fiemap_cmd.cfunc = fiemap_f;
350 fiemap_cmd.argmin = 0;
351 fiemap_cmd.argmax = -1;
352 fiemap_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
353 fiemap_cmd.args = _("[-alv] [-n nx]");
354 fiemap_cmd.oneline = _("print block mapping for a file");
355 fiemap_cmd.help = fiemap_help;
356
357 add_command(&fiemap_cmd);
358}