]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/filemap.c
xfs_scrub: check label for misleading characters
[thirdparty/xfsprogs-dev.git] / scrub / filemap.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 */
6 #include "xfs.h"
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/statvfs.h>
13 #include "path.h"
14 #include "xfs_scrub.h"
15 #include "common.h"
16 #include "filemap.h"
17
18 /*
19 * These routines provide a simple interface to query the block
20 * mappings of the fork of a given inode via GETBMAPX and call a
21 * function to iterate each mapping result.
22 */
23
24 #define BMAP_NR 2048
25
26 /* Iterate all the extent block mappings between the key and fork end. */
27 bool
28 xfs_iterate_filemaps(
29 struct scrub_ctx *ctx,
30 const char *descr,
31 int fd,
32 int whichfork,
33 struct xfs_bmap *key,
34 xfs_bmap_iter_fn fn,
35 void *arg)
36 {
37 struct fsxattr fsx;
38 struct getbmapx *map;
39 struct getbmapx *p;
40 struct xfs_bmap bmap;
41 char bmap_descr[DESCR_BUFSZ];
42 bool moveon = true;
43 xfs_off_t new_off;
44 int getxattr_type;
45 int i;
46 int error;
47
48 switch (whichfork) {
49 case XFS_ATTR_FORK:
50 snprintf(bmap_descr, DESCR_BUFSZ, _("%s attr"), descr);
51 break;
52 case XFS_COW_FORK:
53 snprintf(bmap_descr, DESCR_BUFSZ, _("%s CoW"), descr);
54 break;
55 case XFS_DATA_FORK:
56 snprintf(bmap_descr, DESCR_BUFSZ, _("%s data"), descr);
57 break;
58 default:
59 abort();
60 }
61
62 map = calloc(BMAP_NR, sizeof(struct getbmapx));
63 if (!map) {
64 str_errno(ctx, bmap_descr);
65 return false;
66 }
67
68 map->bmv_offset = BTOBB(key->bm_offset);
69 map->bmv_block = BTOBB(key->bm_physical);
70 if (key->bm_length == 0)
71 map->bmv_length = ULLONG_MAX;
72 else
73 map->bmv_length = BTOBB(key->bm_length);
74 map->bmv_count = BMAP_NR;
75 map->bmv_iflags = BMV_IF_NO_DMAPI_READ | BMV_IF_PREALLOC |
76 BMV_IF_NO_HOLES;
77 switch (whichfork) {
78 case XFS_ATTR_FORK:
79 getxattr_type = XFS_IOC_FSGETXATTRA;
80 map->bmv_iflags |= BMV_IF_ATTRFORK;
81 break;
82 case XFS_COW_FORK:
83 map->bmv_iflags |= BMV_IF_COWFORK;
84 getxattr_type = FS_IOC_FSGETXATTR;
85 break;
86 case XFS_DATA_FORK:
87 getxattr_type = FS_IOC_FSGETXATTR;
88 break;
89 default:
90 abort();
91 }
92
93 error = ioctl(fd, getxattr_type, &fsx);
94 if (error < 0) {
95 str_errno(ctx, bmap_descr);
96 moveon = false;
97 goto out;
98 }
99
100 while ((error = ioctl(fd, XFS_IOC_GETBMAPX, map)) == 0) {
101 for (i = 0, p = &map[i + 1]; i < map->bmv_entries; i++, p++) {
102 bmap.bm_offset = BBTOB(p->bmv_offset);
103 bmap.bm_physical = BBTOB(p->bmv_block);
104 bmap.bm_length = BBTOB(p->bmv_length);
105 bmap.bm_flags = p->bmv_oflags;
106 moveon = fn(ctx, bmap_descr, fd, whichfork, &fsx,
107 &bmap, arg);
108 if (!moveon)
109 goto out;
110 if (xfs_scrub_excessive_errors(ctx)) {
111 moveon = false;
112 goto out;
113 }
114 }
115
116 if (map->bmv_entries == 0)
117 break;
118 p = map + map->bmv_entries;
119 if (p->bmv_oflags & BMV_OF_LAST)
120 break;
121
122 new_off = p->bmv_offset + p->bmv_length;
123 map->bmv_length -= new_off - map->bmv_offset;
124 map->bmv_offset = new_off;
125 }
126
127 /*
128 * Pre-reflink filesystems don't know about CoW forks, so don't
129 * be too surprised if it fails.
130 */
131 if (whichfork == XFS_COW_FORK && error && errno == EINVAL)
132 error = 0;
133
134 if (error)
135 str_errno(ctx, bmap_descr);
136 out:
137 free(map);
138 return moveon;
139 }