]>
Commit | Line | Data |
---|---|---|
86bb49e4 DW |
1 | /* |
2 | * Copyright (C) 2016 Oracle. All Rights Reserved. | |
3 | * | |
4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it would be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write the Free Software Foundation, | |
18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | */ | |
20 | #include "libxfs.h" | |
21 | #include "command.h" | |
22 | #include "fsmap.h" | |
23 | #include "output.h" | |
24 | #include "init.h" | |
25 | ||
26 | struct fsmap_info { | |
27 | unsigned long long nr; | |
28 | xfs_agnumber_t agno; | |
29 | }; | |
30 | ||
31 | static int | |
32 | fsmap_fn( | |
33 | struct xfs_btree_cur *cur, | |
34 | struct xfs_rmap_irec *rec, | |
35 | void *priv) | |
36 | { | |
37 | struct fsmap_info *info = priv; | |
38 | ||
39 | dbprintf(_("%llu: %u/%u len %u owner %lld offset %llu bmbt %d attrfork %d extflag %d\n"), | |
40 | info->nr, info->agno, rec->rm_startblock, | |
41 | rec->rm_blockcount, rec->rm_owner, rec->rm_offset, | |
42 | !!(rec->rm_flags & XFS_RMAP_BMBT_BLOCK), | |
43 | !!(rec->rm_flags & XFS_RMAP_ATTR_FORK), | |
44 | !!(rec->rm_flags & XFS_RMAP_UNWRITTEN)); | |
45 | info->nr++; | |
46 | ||
47 | return 0; | |
48 | } | |
49 | ||
50 | static void | |
51 | fsmap( | |
52 | xfs_fsblock_t start_fsb, | |
53 | xfs_fsblock_t end_fsb) | |
54 | { | |
55 | struct fsmap_info info; | |
56 | xfs_agnumber_t start_ag; | |
57 | xfs_agnumber_t end_ag; | |
58 | xfs_agnumber_t agno; | |
59 | xfs_daddr_t eofs; | |
138ce9ff DW |
60 | struct xfs_rmap_irec low = {0}; |
61 | struct xfs_rmap_irec high = {0}; | |
86bb49e4 DW |
62 | struct xfs_btree_cur *bt_cur; |
63 | struct xfs_buf *agbp; | |
64 | int error; | |
65 | ||
66 | eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); | |
67 | if (XFS_FSB_TO_DADDR(mp, end_fsb) >= eofs) | |
68 | end_fsb = XFS_DADDR_TO_FSB(mp, eofs - 1); | |
69 | ||
70 | low.rm_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb); | |
86bb49e4 DW |
71 | high.rm_startblock = -1U; |
72 | high.rm_owner = ULLONG_MAX; | |
73 | high.rm_offset = ULLONG_MAX; | |
74 | high.rm_flags = XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK | XFS_RMAP_UNWRITTEN; | |
75 | ||
76 | start_ag = XFS_FSB_TO_AGNO(mp, start_fsb); | |
77 | end_ag = XFS_FSB_TO_AGNO(mp, end_fsb); | |
78 | ||
79 | info.nr = 0; | |
80 | for (agno = start_ag; agno <= end_ag; agno++) { | |
81 | if (agno == end_ag) | |
82 | high.rm_startblock = XFS_FSB_TO_AGBNO(mp, end_fsb); | |
83 | ||
e2f60652 | 84 | error = -libxfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); |
86bb49e4 DW |
85 | if (error) { |
86 | dbprintf(_("Error %d while reading AGF.\n"), error); | |
87 | return; | |
88 | } | |
89 | ||
e2f60652 | 90 | bt_cur = libxfs_rmapbt_init_cursor(mp, NULL, agbp, agno); |
86bb49e4 DW |
91 | if (!bt_cur) { |
92 | libxfs_putbuf(agbp); | |
93 | dbprintf(_("Not enough memory.\n")); | |
94 | return; | |
95 | } | |
96 | ||
97 | info.agno = agno; | |
98 | error = -libxfs_rmap_query_range(bt_cur, &low, &high, | |
99 | fsmap_fn, &info); | |
100 | if (error) { | |
e2f60652 | 101 | libxfs_btree_del_cursor(bt_cur, XFS_BTREE_ERROR); |
86bb49e4 DW |
102 | libxfs_putbuf(agbp); |
103 | dbprintf(_("Error %d while querying fsmap btree.\n"), | |
104 | error); | |
105 | return; | |
106 | } | |
107 | ||
e2f60652 | 108 | libxfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR); |
86bb49e4 DW |
109 | libxfs_putbuf(agbp); |
110 | ||
111 | if (agno == start_ag) | |
112 | low.rm_startblock = 0; | |
113 | } | |
114 | } | |
115 | ||
116 | int | |
117 | fsmap_f( | |
118 | int argc, | |
119 | char **argv) | |
120 | { | |
121 | char *p; | |
122 | int c; | |
123 | xfs_fsblock_t start_fsb = 0; | |
124 | xfs_fsblock_t end_fsb = NULLFSBLOCK; | |
125 | ||
126 | if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) { | |
127 | dbprintf(_("Filesystem does not support reverse mapping btree.\n")); | |
128 | return 0; | |
129 | } | |
130 | ||
131 | while ((c = getopt(argc, argv, "")) != EOF) { | |
132 | switch (c) { | |
133 | default: | |
134 | dbprintf(_("Bad option for fsmap command.\n")); | |
135 | return 0; | |
136 | } | |
137 | } | |
138 | ||
139 | if (argc > optind) { | |
140 | start_fsb = strtoull(argv[optind], &p, 0); | |
141 | if (*p != '\0' || start_fsb >= mp->m_sb.sb_dblocks) { | |
142 | dbprintf(_("Bad fsmap start_fsb %s.\n"), argv[optind]); | |
143 | return 0; | |
144 | } | |
145 | } | |
146 | ||
147 | if (argc > optind + 1) { | |
148 | end_fsb = strtoull(argv[optind + 1], &p, 0); | |
149 | if (*p != '\0') { | |
150 | dbprintf(_("Bad fsmap end_fsb %s.\n"), argv[optind + 1]); | |
151 | return 0; | |
152 | } | |
153 | } | |
154 | ||
155 | fsmap(start_fsb, end_fsb); | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
160 | static const cmdinfo_t fsmap_cmd = | |
161 | { "fsmap", NULL, fsmap_f, 0, 2, 0, | |
162 | N_("[start_fsb] [end_fsb]"), | |
163 | N_("display reverse mapping(s)"), NULL }; | |
164 | ||
165 | void | |
166 | fsmap_init(void) | |
167 | { | |
168 | add_command(&fsmap_cmd); | |
169 | } |