]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
c6eb0ff2 DW |
2 | /* |
3 | * Copyright (C) 2018 Oracle. All Rights Reserved. | |
c6eb0ff2 | 4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> |
c6eb0ff2 | 5 | */ |
a440f877 | 6 | #include "xfs.h" |
c6eb0ff2 DW |
7 | #include <stdint.h> |
8 | #include <stdlib.h> | |
9 | #include <unistd.h> | |
10 | #include <string.h> | |
11 | #include <sys/types.h> | |
c6eb0ff2 | 12 | #include <sys/statvfs.h> |
42b4c8e8 | 13 | #include "libfrog/paths.h" |
c6eb0ff2 DW |
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); | |
c6eb0ff2 DW |
74 | map->bmv_iflags = BMV_IF_NO_DMAPI_READ | BMV_IF_PREALLOC | |
75 | BMV_IF_NO_HOLES; | |
76 | switch (whichfork) { | |
77 | case XFS_ATTR_FORK: | |
78 | getxattr_type = XFS_IOC_FSGETXATTRA; | |
79 | map->bmv_iflags |= BMV_IF_ATTRFORK; | |
80 | break; | |
81 | case XFS_COW_FORK: | |
82 | map->bmv_iflags |= BMV_IF_COWFORK; | |
83 | getxattr_type = FS_IOC_FSGETXATTR; | |
84 | break; | |
85 | case XFS_DATA_FORK: | |
86 | getxattr_type = FS_IOC_FSGETXATTR; | |
87 | break; | |
88 | default: | |
89 | abort(); | |
90 | } | |
91 | ||
92 | error = ioctl(fd, getxattr_type, &fsx); | |
93 | if (error < 0) { | |
94 | str_errno(ctx, bmap_descr); | |
95 | moveon = false; | |
96 | goto out; | |
97 | } | |
98 | ||
0f402dd8 DW |
99 | if (fsx.fsx_nextents == 0) { |
100 | moveon = true; | |
101 | goto out; | |
102 | } | |
103 | ||
104 | map->bmv_count = min(fsx.fsx_nextents + 1, BMAP_NR); | |
105 | ||
c6eb0ff2 DW |
106 | while ((error = ioctl(fd, XFS_IOC_GETBMAPX, map)) == 0) { |
107 | for (i = 0, p = &map[i + 1]; i < map->bmv_entries; i++, p++) { | |
108 | bmap.bm_offset = BBTOB(p->bmv_offset); | |
109 | bmap.bm_physical = BBTOB(p->bmv_block); | |
110 | bmap.bm_length = BBTOB(p->bmv_length); | |
111 | bmap.bm_flags = p->bmv_oflags; | |
112 | moveon = fn(ctx, bmap_descr, fd, whichfork, &fsx, | |
113 | &bmap, arg); | |
114 | if (!moveon) | |
115 | goto out; | |
116 | if (xfs_scrub_excessive_errors(ctx)) { | |
117 | moveon = false; | |
118 | goto out; | |
119 | } | |
120 | } | |
121 | ||
122 | if (map->bmv_entries == 0) | |
123 | break; | |
124 | p = map + map->bmv_entries; | |
125 | if (p->bmv_oflags & BMV_OF_LAST) | |
126 | break; | |
127 | ||
128 | new_off = p->bmv_offset + p->bmv_length; | |
129 | map->bmv_length -= new_off - map->bmv_offset; | |
130 | map->bmv_offset = new_off; | |
131 | } | |
132 | ||
133 | /* | |
134 | * Pre-reflink filesystems don't know about CoW forks, so don't | |
135 | * be too surprised if it fails. | |
136 | */ | |
137 | if (whichfork == XFS_COW_FORK && error && errno == EINVAL) | |
138 | error = 0; | |
139 | ||
140 | if (error) | |
141 | str_errno(ctx, bmap_descr); | |
142 | out: | |
143 | free(map); | |
144 | return moveon; | |
145 | } |