]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/bmap.c
xfs_db: dump refcount btree data
[thirdparty/xfsprogs-dev.git] / db / bmap.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
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
2bd0ea18 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
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.
dfc130f3 13 *
da23017d
NS
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
2bd0ea18
NS
17 */
18
6b803e5a 19#include "libxfs.h"
2bd0ea18 20#include "command.h"
2bd0ea18 21#include "type.h"
128efca1
NS
22#include "fprint.h"
23#include "faddr.h"
24#include "field.h"
2bd0ea18
NS
25#include "bmap.h"
26#include "io.h"
27#include "inode.h"
28#include "output.h"
4ca431fc 29#include "init.h"
2bd0ea18
NS
30
31static int bmap_f(int argc, char **argv);
56b2de80 32static int bmap_one_extent(xfs_bmbt_rec_t *ep,
5a35bf2c 33 xfs_fileoff_t *offp, xfs_fileoff_t eoff,
2bd0ea18 34 int *idxp, bmap_ext_t *bep);
5a35bf2c 35static xfs_fsblock_t select_child(xfs_fileoff_t off, xfs_bmbt_key_t *kp,
2bd0ea18
NS
36 xfs_bmbt_ptr_t *pp, int nrecs);
37
38static const cmdinfo_t bmap_cmd =
9ee7055c
AM
39 { "bmap", NULL, bmap_f, 0, 3, 0, N_("[-ad] [block [len]]"),
40 N_("show block map for current file"), NULL };
2bd0ea18
NS
41
42void
43bmap(
5a35bf2c
DC
44 xfs_fileoff_t offset,
45 xfs_filblks_t len,
2bd0ea18
NS
46 int whichfork,
47 int *nexp,
48 bmap_ext_t *bep)
49{
b3563c19 50 struct xfs_btree_block *block;
2bd0ea18 51 xfs_fsblock_t bno;
5a35bf2c 52 xfs_fileoff_t curoffset;
2bd0ea18 53 xfs_dinode_t *dip;
5a35bf2c 54 xfs_fileoff_t eoffset;
56b2de80 55 xfs_bmbt_rec_t *ep;
2bd0ea18
NS
56 xfs_dinode_fmt_t fmt;
57 int fsize;
58 xfs_bmbt_key_t *kp;
59 int n;
60 int nex;
61 xfs_fsblock_t nextbno;
62 int nextents;
63 xfs_bmbt_ptr_t *pp;
64 xfs_bmdr_block_t *rblock;
65 typnm_t typ;
56b2de80 66 xfs_bmbt_rec_t *xp;
2bd0ea18
NS
67
68 push_cur();
69 set_cur_inode(iocur_top->ino);
70 nex = *nexp;
71 *nexp = 0;
72 ASSERT(nex > 0);
73 dip = iocur_top->data;
74 n = 0;
75 eoffset = offset + len - 1;
76 curoffset = offset;
46eca962 77 fmt = (xfs_dinode_fmt_t)XFS_DFORK_FORMAT(dip, whichfork);
2bd0ea18
NS
78 typ = whichfork == XFS_DATA_FORK ? TYP_BMAPBTD : TYP_BMAPBTA;
79 ASSERT(typtab[typ].typnm == typ);
c9ee470e
BN
80 ASSERT(fmt == XFS_DINODE_FMT_LOCAL || fmt == XFS_DINODE_FMT_EXTENTS ||
81 fmt == XFS_DINODE_FMT_BTREE);
2bd0ea18 82 if (fmt == XFS_DINODE_FMT_EXTENTS) {
46eca962 83 nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
56b2de80 84 xp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork);
2bd0ea18
NS
85 for (ep = xp; ep < &xp[nextents] && n < nex; ep++) {
86 if (!bmap_one_extent(ep, &curoffset, eoffset, &n, bep))
87 break;
88 }
c9ee470e 89 } else if (fmt == XFS_DINODE_FMT_BTREE) {
2bd0ea18 90 push_cur();
46eca962
NS
91 rblock = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
92 fsize = XFS_DFORK_SIZE(dip, mp, whichfork);
e2f60652 93 pp = XFS_BMDR_PTR_ADDR(rblock, 1, libxfs_bmdr_maxrecs(fsize, 0));
b3563c19 94 kp = XFS_BMDR_KEY_ADDR(rblock, 1);
f8149110 95 bno = select_child(curoffset, kp, pp,
5e656dbb 96 be16_to_cpu(rblock->bb_numrecs));
2bd0ea18
NS
97 for (;;) {
98 set_cur(&typtab[typ], XFS_FSB_TO_DADDR(mp, bno),
99 blkbb, DB_RING_IGN, NULL);
b3563c19 100 block = (struct xfs_btree_block *)iocur_top->data;
5e656dbb 101 if (be16_to_cpu(block->bb_level) == 0)
2bd0ea18 102 break;
7db1e7b9 103 pp = XFS_BMBT_PTR_ADDR(mp, block, 1,
e2f60652 104 libxfs_bmbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0));
7db1e7b9 105 kp = XFS_BMBT_KEY_ADDR(mp, block, 1);
2bd0ea18 106 bno = select_child(curoffset, kp, pp,
5e656dbb 107 be16_to_cpu(block->bb_numrecs));
2bd0ea18
NS
108 }
109 for (;;) {
b3563c19 110 nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
5e656dbb 111 nextents = be16_to_cpu(block->bb_numrecs);
56b2de80 112 xp = (xfs_bmbt_rec_t *)
b3563c19 113 XFS_BMBT_REC_ADDR(mp, block, 1);
2bd0ea18
NS
114 for (ep = xp; ep < &xp[nextents] && n < nex; ep++) {
115 if (!bmap_one_extent(ep, &curoffset, eoffset,
116 &n, bep)) {
117 nextbno = NULLFSBLOCK;
118 break;
119 }
120 }
121 bno = nextbno;
122 if (bno == NULLFSBLOCK)
123 break;
124 set_cur(&typtab[typ], XFS_FSB_TO_DADDR(mp, bno),
125 blkbb, DB_RING_IGN, NULL);
b3563c19 126 block = (struct xfs_btree_block *)iocur_top->data;
2bd0ea18
NS
127 }
128 pop_cur();
129 }
130 pop_cur();
131 *nexp = n;
132}
133
134static int
135bmap_f(
136 int argc,
137 char **argv)
138{
139 int afork = 0;
140 bmap_ext_t be;
141 int c;
5a35bf2c 142 xfs_fileoff_t co, cosave;
2bd0ea18
NS
143 int dfork = 0;
144 xfs_dinode_t *dip;
5a35bf2c
DC
145 xfs_fileoff_t eo;
146 xfs_filblks_t len;
2bd0ea18
NS
147 int nex;
148 char *p;
149 int whichfork;
150
151 if (iocur_top->ino == NULLFSINO) {
9ee7055c 152 dbprintf(_("no current inode\n"));
2bd0ea18
NS
153 return 0;
154 }
155 optind = 0;
156 if (argc) while ((c = getopt(argc, argv, "ad")) != EOF) {
157 switch (c) {
158 case 'a':
159 afork = 1;
160 break;
161 case 'd':
162 dfork = 1;
163 break;
164 default:
9ee7055c 165 dbprintf(_("bad option for bmap command\n"));
2bd0ea18
NS
166 return 0;
167 }
168 }
169 if (afork + dfork == 0) {
170 push_cur();
171 set_cur_inode(iocur_top->ino);
172 dip = iocur_top->data;
56b2de80 173 if (be32_to_cpu(dip->di_nextents))
2bd0ea18 174 dfork = 1;
56b2de80 175 if (be16_to_cpu(dip->di_anextents))
2bd0ea18
NS
176 afork = 1;
177 pop_cur();
178 }
179 if (optind < argc) {
5a35bf2c 180 co = (xfs_fileoff_t)strtoull(argv[optind], &p, 0);
2bd0ea18 181 if (*p != '\0') {
9ee7055c 182 dbprintf(_("bad block number for bmap %s\n"),
2bd0ea18
NS
183 argv[optind]);
184 return 0;
185 }
186 optind++;
187 if (optind < argc) {
5a35bf2c 188 len = (xfs_filblks_t)strtoull(argv[optind], &p, 0);
2bd0ea18 189 if (*p != '\0') {
9ee7055c 190 dbprintf(_("bad len for bmap %s\n"), argv[optind]);
2bd0ea18
NS
191 return 0;
192 }
193 eo = co + len - 1;
194 } else
195 eo = co;
196 } else {
197 co = 0;
198 eo = -1;
199 }
c9ee470e 200 cosave = co;
2bd0ea18
NS
201 for (whichfork = XFS_DATA_FORK;
202 whichfork <= XFS_ATTR_FORK;
203 whichfork++) {
204 if (whichfork == XFS_DATA_FORK && !dfork)
205 continue;
206 if (whichfork == XFS_ATTR_FORK && !afork)
207 continue;
208 for (;;) {
209 nex = 1;
210 bmap(co, eo - co + 1, whichfork, &nex, &be);
211 if (nex == 0)
212 break;
9ee7055c
AM
213 dbprintf(_("%s offset %lld startblock %llu (%u/%u) count "
214 "%llu flag %u\n"),
215 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2bd0ea18
NS
216 be.startoff, be.startblock,
217 XFS_FSB_TO_AGNO(mp, be.startblock),
218 XFS_FSB_TO_AGBNO(mp, be.startblock),
219 be.blockcount, be.flag);
220 co = be.startoff + be.blockcount;
221 }
c9ee470e 222 co = cosave;
2bd0ea18
NS
223 }
224 return 0;
225}
226
227void
228bmap_init(void)
229{
230 add_command(&bmap_cmd);
231}
232
233static int
234bmap_one_extent(
56b2de80 235 xfs_bmbt_rec_t *ep,
5a35bf2c
DC
236 xfs_fileoff_t *offp,
237 xfs_fileoff_t eoff,
2bd0ea18
NS
238 int *idxp,
239 bmap_ext_t *bep)
240{
5a35bf2c
DC
241 xfs_filblks_t c;
242 xfs_fileoff_t curoffset;
2bd0ea18
NS
243 int f;
244 int idx;
5a35bf2c
DC
245 xfs_fileoff_t o;
246 xfs_fsblock_t s;
2bd0ea18
NS
247
248 convert_extent(ep, &o, &s, &c, &f);
249 curoffset = *offp;
250 idx = *idxp;
251 if (o + c <= curoffset)
252 return 1;
253 if (o > eoff)
254 return 0;
255 if (o < curoffset) {
256 c -= curoffset - o;
257 s += curoffset - o;
258 o = curoffset;
259 }
260 if (o + c - 1 > eoff)
261 c -= (o + c - 1) - eoff;
262 bep[idx].startoff = o;
263 bep[idx].startblock = s;
264 bep[idx].blockcount = c;
265 bep[idx].flag = f;
266 *idxp = idx + 1;
267 *offp = o + c;
268 return 1;
269}
270
271void
272convert_extent(
56b2de80 273 xfs_bmbt_rec_t *rp,
5a35bf2c
DC
274 xfs_fileoff_t *op,
275 xfs_fsblock_t *sp,
276 xfs_filblks_t *cp,
2bd0ea18
NS
277 int *fp)
278{
ff105f75 279 struct xfs_bmbt_irec irec;
2bd0ea18 280
9c32ccfc 281 libxfs_bmbt_disk_get_all(rp, &irec);
9c32ccfc
BN
282 *fp = irec.br_state == XFS_EXT_UNWRITTEN;
283 *op = irec.br_startoff;
284 *sp = irec.br_startblock;
285 *cp = irec.br_blockcount;
2bd0ea18
NS
286}
287
288void
289make_bbmap(
290 bbmap_t *bbmap,
291 int nex,
292 bmap_ext_t *bmp)
293{
2bd0ea18 294 int i;
2bd0ea18 295
48e32b40
DC
296 for (i = 0; i < nex; i++) {
297 bbmap->b[i].bm_bn = XFS_FSB_TO_DADDR(mp, bmp[i].startblock);
298 bbmap->b[i].bm_len = XFS_FSB_TO_BB(mp, bmp[i].blockcount);
2bd0ea18 299 }
48e32b40 300 bbmap->nmaps = nex;
2bd0ea18
NS
301}
302
303static xfs_fsblock_t
304select_child(
5a35bf2c 305 xfs_fileoff_t off,
2bd0ea18
NS
306 xfs_bmbt_key_t *kp,
307 xfs_bmbt_ptr_t *pp,
308 int nrecs)
309{
310 int i;
311
312 for (i = 0; i < nrecs; i++) {
5e656dbb
BN
313 if (be64_to_cpu(kp[i].br_startoff) == off)
314 return be64_to_cpu(pp[i]);
315 if (be64_to_cpu(kp[i].br_startoff) > off) {
2bd0ea18 316 if (i == 0)
5e656dbb 317 return be64_to_cpu(pp[i]);
2bd0ea18 318 else
5e656dbb 319 return be64_to_cpu(pp[i - 1]);
2bd0ea18
NS
320 }
321 }
5e656dbb 322 return be64_to_cpu(pp[nrecs - 1]);
2bd0ea18 323}