]>
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 | ||
73ce9669 DW |
26 | /* |
27 | * Iterate all the extent block mappings between the key and fork end. | |
28 | * Returns 0 or a positive error number. | |
29 | */ | |
30 | int | |
31 | scrub_iterate_filemaps( | |
c6eb0ff2 | 32 | struct scrub_ctx *ctx, |
c6eb0ff2 DW |
33 | int fd, |
34 | int whichfork, | |
73ce9669 DW |
35 | struct file_bmap *key, |
36 | scrub_bmap_iter_fn fn, | |
c6eb0ff2 DW |
37 | void *arg) |
38 | { | |
39 | struct fsxattr fsx; | |
40 | struct getbmapx *map; | |
41 | struct getbmapx *p; | |
73ce9669 | 42 | struct file_bmap bmap; |
c6eb0ff2 DW |
43 | xfs_off_t new_off; |
44 | int getxattr_type; | |
45 | int i; | |
73ce9669 | 46 | int ret; |
c6eb0ff2 DW |
47 | |
48 | map = calloc(BMAP_NR, sizeof(struct getbmapx)); | |
73ce9669 DW |
49 | if (!map) |
50 | return errno; | |
c6eb0ff2 DW |
51 | |
52 | map->bmv_offset = BTOBB(key->bm_offset); | |
53 | map->bmv_block = BTOBB(key->bm_physical); | |
54 | if (key->bm_length == 0) | |
55 | map->bmv_length = ULLONG_MAX; | |
56 | else | |
57 | map->bmv_length = BTOBB(key->bm_length); | |
c6eb0ff2 DW |
58 | map->bmv_iflags = BMV_IF_NO_DMAPI_READ | BMV_IF_PREALLOC | |
59 | BMV_IF_NO_HOLES; | |
60 | switch (whichfork) { | |
61 | case XFS_ATTR_FORK: | |
62 | getxattr_type = XFS_IOC_FSGETXATTRA; | |
63 | map->bmv_iflags |= BMV_IF_ATTRFORK; | |
64 | break; | |
65 | case XFS_COW_FORK: | |
66 | map->bmv_iflags |= BMV_IF_COWFORK; | |
67 | getxattr_type = FS_IOC_FSGETXATTR; | |
68 | break; | |
69 | case XFS_DATA_FORK: | |
70 | getxattr_type = FS_IOC_FSGETXATTR; | |
71 | break; | |
72 | default: | |
73 | abort(); | |
74 | } | |
75 | ||
73ce9669 DW |
76 | ret = ioctl(fd, getxattr_type, &fsx); |
77 | if (ret < 0) { | |
78 | ret = errno; | |
c6eb0ff2 DW |
79 | goto out; |
80 | } | |
81 | ||
73ce9669 | 82 | if (fsx.fsx_nextents == 0) |
0f402dd8 | 83 | goto out; |
0f402dd8 DW |
84 | |
85 | map->bmv_count = min(fsx.fsx_nextents + 1, BMAP_NR); | |
86 | ||
73ce9669 | 87 | while ((ret = ioctl(fd, XFS_IOC_GETBMAPX, map)) == 0) { |
c6eb0ff2 DW |
88 | for (i = 0, p = &map[i + 1]; i < map->bmv_entries; i++, p++) { |
89 | bmap.bm_offset = BBTOB(p->bmv_offset); | |
90 | bmap.bm_physical = BBTOB(p->bmv_block); | |
91 | bmap.bm_length = BBTOB(p->bmv_length); | |
92 | bmap.bm_flags = p->bmv_oflags; | |
73ce9669 DW |
93 | ret = fn(ctx, fd, whichfork, &fsx, &bmap, arg); |
94 | if (ret) | |
c6eb0ff2 | 95 | goto out; |
73ce9669 | 96 | if (xfs_scrub_excessive_errors(ctx)) |
c6eb0ff2 | 97 | goto out; |
c6eb0ff2 DW |
98 | } |
99 | ||
100 | if (map->bmv_entries == 0) | |
101 | break; | |
102 | p = map + map->bmv_entries; | |
103 | if (p->bmv_oflags & BMV_OF_LAST) | |
104 | break; | |
105 | ||
106 | new_off = p->bmv_offset + p->bmv_length; | |
107 | map->bmv_length -= new_off - map->bmv_offset; | |
108 | map->bmv_offset = new_off; | |
109 | } | |
73ce9669 DW |
110 | if (ret < 0) |
111 | ret = errno; | |
c6eb0ff2 DW |
112 | |
113 | /* | |
114 | * Pre-reflink filesystems don't know about CoW forks, so don't | |
115 | * be too surprised if it fails. | |
116 | */ | |
73ce9669 DW |
117 | if (whichfork == XFS_COW_FORK && ret == EINVAL) |
118 | ret = 0; | |
c6eb0ff2 DW |
119 | out: |
120 | free(map); | |
73ce9669 | 121 | return ret; |
c6eb0ff2 | 122 | } |