]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/io.c
xfs: define the on-disk refcount btree format
[thirdparty/xfsprogs-dev.git] / db / io.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2002,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
NS
21#include "type.h"
22#include "faddr.h"
23#include "fprint.h"
24#include "field.h"
25#include "inode.h"
26#include "io.h"
27#include "output.h"
4ca431fc 28#include "init.h"
2bd0ea18 29#include "malloc.h"
b64af2c4 30#include "crc.h"
2bd0ea18
NS
31
32static int pop_f(int argc, char **argv);
33static void pop_help(void);
34static int push_f(int argc, char **argv);
35static void push_help(void);
36static int stack_f(int argc, char **argv);
37static void stack_help(void);
38static int forward_f(int argc, char **argv);
39static void forward_help(void);
40static int back_f(int argc, char **argv);
41static void back_help(void);
42static int ring_f(int argc, char **argv);
43static void ring_help(void);
44
45static const cmdinfo_t pop_cmd =
46 { "pop", NULL, pop_f, 0, 0, 0, NULL,
9ee7055c 47 N_("pop location from the stack"), pop_help };
2bd0ea18 48static const cmdinfo_t push_cmd =
9ee7055c
AM
49 { "push", NULL, push_f, 0, 2, 0, N_("[command]"),
50 N_("push location to the stack"), push_help };
2bd0ea18
NS
51static const cmdinfo_t stack_cmd =
52 { "stack", NULL, stack_f, 0, 0, 0, NULL,
9ee7055c 53 N_("view the location stack"), stack_help };
dfc130f3 54static const cmdinfo_t forward_cmd =
2bd0ea18 55 { "forward", "f", forward_f, 0, 0, 0, NULL,
9ee7055c 56 N_("move forward to next entry in the position ring"), forward_help };
dfc130f3 57static const cmdinfo_t back_cmd =
2bd0ea18 58 { "back", "b", back_f, 0, 0, 0, NULL,
9ee7055c 59 N_("move to the previous location in the position ring"), back_help };
dfc130f3 60static const cmdinfo_t ring_cmd =
2bd0ea18 61 { "ring", NULL, ring_f, 0, 1, 0, NULL,
9ee7055c 62 N_("show position ring or move to a specific entry"), ring_help };
2bd0ea18
NS
63
64iocur_t *iocur_base;
65iocur_t *iocur_top;
66int iocur_sp = -1;
67int iocur_len;
68
69#define RING_ENTRIES 20
70static iocur_t iocur_ring[RING_ENTRIES];
71static int ring_head = -1;
72static int ring_tail = -1;
73static int ring_current = -1;
74
75void
76io_init(void)
77{
78 add_command(&pop_cmd);
79 add_command(&push_cmd);
80 add_command(&stack_cmd);
81 add_command(&forward_cmd);
82 add_command(&back_cmd);
83 add_command(&ring_cmd);
84}
85
86void
87off_cur(
88 int off,
89 int len)
90{
91 if (iocur_top == NULL || off + len > BBTOB(iocur_top->blen))
9ee7055c 92 dbprintf(_("can't set block offset to %d\n"), off);
2bd0ea18
NS
93 else {
94 iocur_top->boff = off;
95 iocur_top->off = ((xfs_off_t)iocur_top->bb << BBSHIFT) + off;
96 iocur_top->len = len;
97 iocur_top->data = (void *)((char *)iocur_top->buf + off);
98 }
99}
100
101void
102pop_cur(void)
103{
104 if (iocur_sp < 0) {
9ee7055c 105 dbprintf(_("can't pop anything from I/O stack\n"));
2bd0ea18
NS
106 return;
107 }
72298d16
DC
108 if (iocur_top->bp) {
109 libxfs_putbuf(iocur_top->bp);
110 iocur_top->bp = NULL;
111 }
112 if (iocur_top->bbmap) {
113 free(iocur_top->bbmap);
114 iocur_top->bbmap = NULL;
115 }
2bd0ea18
NS
116 if (--iocur_sp >= 0) {
117 iocur_top = iocur_base + iocur_sp;
118 cur_typ = iocur_top->typ;
119 } else {
120 iocur_top = iocur_base;
121 iocur_sp = 0;
122 }
123}
124
125/*ARGSUSED*/
126static int
127pop_f(
128 int argc,
129 char **argv)
130{
131 pop_cur();
132 return 0;
133}
134
135static void
136pop_help(void)
137{
9ee7055c 138 dbprintf(_(
2bd0ea18
NS
139"\n"
140" Changes the address and data type to the first entry on the stack.\n"
141"\n"
9ee7055c 142 ));
2bd0ea18
NS
143}
144
145void
146print_iocur(
147 char *tag,
148 iocur_t *ioc)
149{
150 int i;
151
152 dbprintf("%s\n", tag);
9ee7055c
AM
153 dbprintf(_("\tbyte offset %lld, length %d\n"), ioc->off, ioc->len);
154 dbprintf(_("\tbuffer block %lld (fsbno %lld), %d bb%s\n"), ioc->bb,
5a35bf2c 155 (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb), ioc->blen,
2bd0ea18 156 ioc->blen == 1 ? "" : "s");
72298d16 157 if (ioc->bbmap) {
9ee7055c 158 dbprintf(_("\tblock map"));
72298d16
DC
159 for (i = 0; i < ioc->bbmap->nmaps; i++)
160 dbprintf(" %lld:%d", ioc->bbmap->b[i].bm_bn,
161 ioc->bbmap->b[i].bm_len);
2bd0ea18
NS
162 dbprintf("\n");
163 }
9ee7055c
AM
164 dbprintf(_("\tinode %lld, dir inode %lld, type %s\n"), ioc->ino,
165 ioc->dirino, ioc->typ == NULL ? _("none") : ioc->typ->name);
2bd0ea18
NS
166}
167
168void
169print_ring(void)
170{
171 int i;
172 iocur_t *ioc;
173
174 if (ring_current == -1) {
9ee7055c 175 dbprintf(_("no entries in location ring.\n"));
2bd0ea18
NS
176 return;
177 }
178
9ee7055c 179 dbprintf(_(" type bblock bblen fsbno inode\n"));
2bd0ea18
NS
180
181 i = ring_head;
182 for (;;) {
183 ioc = &iocur_ring[i];
184 if (i == ring_current)
185 printf("*%2d: ", i);
186 else
187 printf(" %2d: ", i);
188
189 dbprintf("%-7.7s %8lld %5d %8lld %9lld\n",
190 ioc->typ == NULL ? "none" : ioc->typ->name,
191 ioc->bb,
192 ioc->blen,
5a35bf2c 193 (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb),
2bd0ea18
NS
194 ioc->ino
195 );
196
197 if (i == ring_tail)
198 break;
199
200 i = (i+(RING_ENTRIES-1))%RING_ENTRIES;
201 }
202}
203
204
205void
206push_cur(void)
207{
208 if (iocur_sp + 1 >= iocur_len) {
209 iocur_base = xrealloc(iocur_base,
210 sizeof(*iocur_base) * (iocur_len + 1));
211 iocur_len++;
212 }
213 iocur_sp++;
214 iocur_top = iocur_base + iocur_sp;
215 memset(iocur_top, 0, sizeof(*iocur_base));
216 iocur_top->ino = iocur_sp > 0 ? iocur_top[-1].ino : NULLFSINO;
217 iocur_top->dirino = iocur_sp > 0 ? iocur_top[-1].dirino : NULLFSINO;
218 iocur_top->mode = iocur_sp > 0 ? iocur_top[-1].mode : 0;
219 cur_typ = NULL;
220}
221
222static int
223push_f(
224 int argc,
225 char **argv)
226{
227 const cmdinfo_t *ct;
228
229 if (argc > 1) {
dfc130f3
RC
230 /* check we can execute command */
231 ct = find_command(argv[1]);
232 if (ct == NULL) {
9ee7055c 233 dbprintf(_("no such command %s\n"), argv[1]);
dfc130f3
RC
234 return 0;
235 }
236 if (!ct->canpush) {
9ee7055c 237 dbprintf(_("no push form allowed for %s\n"), argv[1]);
dfc130f3
RC
238 return 0;
239 }
240 }
241
242 /* save current state */
243 push_cur();
2bd0ea18
NS
244 if (iocur_top[-1].typ && iocur_top[-1].typ->typnm == TYP_INODE)
245 set_cur_inode(iocur_top[-1].ino);
246 else
247 set_cur(iocur_top[-1].typ, iocur_top[-1].bb,
dfc130f3 248 iocur_top[-1].blen, DB_RING_IGN,
72298d16 249 iocur_top[-1].bbmap);
2bd0ea18 250
dfc130f3
RC
251 /* run requested command */
252 if (argc>1)
253 (void)command(argc-1, argv+1);
2bd0ea18
NS
254 return 0;
255}
256
257static void
258push_help(void)
259{
9ee7055c 260 dbprintf(_(
2bd0ea18
NS
261"\n"
262" Allows you to push the current address and data type on the stack for\n"
263" later return. 'push' also accepts an additional command to execute after\n"
264" storing the current address (ex: 'push a rootino' from the superblock).\n"
265"\n"
9ee7055c 266 ));
2bd0ea18
NS
267}
268
269/* move forward through the ring */
270/* ARGSUSED */
271static int
272forward_f(
273 int argc,
274 char **argv)
275{
276 if (ring_current == -1) {
9ee7055c 277 dbprintf(_("ring is empty\n"));
2bd0ea18
NS
278 return 0;
279 }
280 if (ring_current == ring_head) {
9ee7055c 281 dbprintf(_("no further entries\n"));
2bd0ea18
NS
282 return 0;
283 }
284
285 ring_current = (ring_current+1)%RING_ENTRIES;
286
287 set_cur(iocur_ring[ring_current].typ,
288 iocur_ring[ring_current].bb,
289 iocur_ring[ring_current].blen,
290 DB_RING_IGN,
72298d16 291 iocur_ring[ring_current].bbmap);
2bd0ea18
NS
292
293 return 0;
294}
295
296static void
297forward_help(void)
298{
9ee7055c 299 dbprintf(_(
2bd0ea18
NS
300"\n"
301" The 'forward' ('f') command moves to the next location in the position\n"
302" ring, updating the current position and data type. If the current location\n"
303" is the top entry in the ring, then the 'forward' command will have\n"
304" no effect.\n"
305"\n"
9ee7055c 306 ));
2bd0ea18
NS
307}
308
309/* move backwards through the ring */
310/* ARGSUSED */
311static int
312back_f(
313 int argc,
314 char **argv)
315{
316 if (ring_current == -1) {
9ee7055c 317 dbprintf(_("ring is empty\n"));
2bd0ea18
NS
318 return 0;
319 }
320 if (ring_current == ring_tail) {
9ee7055c 321 dbprintf(_("no previous entries\n"));
2bd0ea18
NS
322 return 0;
323 }
324
325 ring_current = (ring_current+(RING_ENTRIES-1))%RING_ENTRIES;
326
327 set_cur(iocur_ring[ring_current].typ,
328 iocur_ring[ring_current].bb,
329 iocur_ring[ring_current].blen,
330 DB_RING_IGN,
72298d16 331 iocur_ring[ring_current].bbmap);
2bd0ea18
NS
332
333 return 0;
334}
335
336static void
337back_help(void)
338{
9ee7055c 339 dbprintf(_(
2bd0ea18
NS
340"\n"
341" The 'back' ('b') command moves to the previous location in the position\n"
342" ring, updating the current position and data type. If the current location\n"
343" is the last entry in the ring, then the 'back' command will have no effect.\n"
344"\n"
9ee7055c 345 ));
2bd0ea18
NS
346}
347
348/* show or go to specific point in ring */
349static int
350ring_f(
351 int argc,
352 char **argv)
353{
354 int index;
355
356 if (argc == 1) {
357 print_ring();
358 return 0;
359 }
360
b3d6b800 361 index = (int)strtoul(argv[1], NULL, 0);
d15f7cfb 362 if (index < 0 || index >= RING_ENTRIES) {
9ee7055c 363 dbprintf(_("invalid entry: %d\n"), index);
d15f7cfb
ES
364 return 0;
365 }
2bd0ea18
NS
366
367 ring_current = index;
368
369 set_cur(iocur_ring[index].typ,
370 iocur_ring[index].bb,
371 iocur_ring[index].blen,
372 DB_RING_IGN,
72298d16 373 iocur_ring[index].bbmap);
2bd0ea18
NS
374
375 return 0;
376}
377
378static void
379ring_help(void)
380{
9ee7055c 381 dbprintf(_(
2bd0ea18
NS
382"\n"
383" The position ring automatically keeps track of each disk location and\n"
384" structure type for each change of position you make during your xfs_db\n"
385" session. The last %d most recent entries are kept in the ring.\n"
386"\n"
387" To display the current list of ring entries type 'ring' by itself on\n"
388" the command line. The entry highlighted by an asterisk ('*') is the\n"
389" current entry.\n"
390"\n"
391" To move to another entry in the ring type 'ring <num>' where <num> is\n"
392" your desired entry from the ring position list.\n"
393"\n"
394" You may also use the 'forward' ('f') or 'back' ('b') commands to move\n"
395" to the previous or next entry in the ring, respectively.\n"
396"\n"
397" Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n"
398" location implicitly. Use the 'push' and 'pop' commands if you wish to\n"
399" store a specific location explicitly for later return.\n"
9ee7055c 400"\n"),
2bd0ea18
NS
401 RING_ENTRIES);
402}
403
404
405void
406ring_add(void)
407{
408 if (ring_head == -1) {
409 /* only get here right after startup */
410 ring_head = 0;
411 ring_tail = 0;
412 ring_current = 0;
413 iocur_ring[0] = *iocur_top;
414 } else {
415 if (ring_current == ring_head) {
416 ring_head = (ring_head+1)%RING_ENTRIES;
417 iocur_ring[ring_head] = *iocur_top;
418 if (ring_head == ring_tail)
419 ring_tail = (ring_tail+1)%RING_ENTRIES;
420 ring_current = ring_head;
421 } else {
422 ring_current = (ring_current+1)%RING_ENTRIES;
423 iocur_ring[ring_current] = *iocur_top;
424 }
425 }
426}
427
2a8b3fdf
DC
428static void
429write_cur_buf(void)
430{
431 int ret;
432
12b53197 433 ret = -libxfs_writebufr(iocur_top->bp);
72298d16 434 if (ret != 0)
2a8b3fdf
DC
435 dbprintf(_("write error: %s\n"), strerror(ret));
436
437 /* re-read buffer from disk */
12b53197 438 ret = -libxfs_readbufr(mp->m_ddev_targp, iocur_top->bb, iocur_top->bp,
72298d16
DC
439 iocur_top->blen, 0);
440 if (ret != 0)
2a8b3fdf
DC
441 dbprintf(_("read error: %s\n"), strerror(ret));
442}
443
2a8b3fdf
DC
444static void
445write_cur_bbs(void)
2bd0ea18
NS
446{
447 int ret;
448
12b53197 449 ret = -libxfs_writebufr(iocur_top->bp);
72298d16 450 if (ret != 0)
9ee7055c 451 dbprintf(_("write error: %s\n"), strerror(ret));
2a8b3fdf 452
72298d16 453
2bd0ea18 454 /* re-read buffer from disk */
12b53197 455 ret = -libxfs_readbufr_map(mp->m_ddev_targp, iocur_top->bp, 0);
72298d16 456 if (ret != 0)
9ee7055c 457 dbprintf(_("read error: %s\n"), strerror(ret));
2bd0ea18
NS
458}
459
c9f5e3db
ES
460void
461xfs_dummy_verify(
462 struct xfs_buf *bp)
463{
464 return;
465}
466
86769b32
DC
467void
468xfs_verify_recalc_crc(
469 struct xfs_buf *bp)
470{
471 xfs_buf_update_cksum(bp, iocur_top->typ->crc_off);
472}
473
2a8b3fdf
DC
474void
475write_cur(void)
476{
b64af2c4
ES
477 bool skip_crc = false;
478
2a8b3fdf
DC
479 if (iocur_sp < 0) {
480 dbprintf(_("nothing to write\n"));
481 return;
482 }
483
b64af2c4
ES
484 if (!xfs_sb_version_hascrc(&mp->m_sb) ||
485 !iocur_top->bp->b_ops ||
486 iocur_top->bp->b_ops->verify_write == xfs_dummy_verify)
487 skip_crc = true;
488
489 if (!skip_crc) {
490 if (iocur_top->ino_buf) {
491 libxfs_dinode_calc_crc(mp, iocur_top->data);
492 iocur_top->ino_crc_ok = 1;
493 } else if (iocur_top->dquot_buf) {
494 xfs_update_cksum(iocur_top->data,
495 sizeof(struct xfs_dqblk),
496 XFS_DQUOT_CRC_OFF);
497 }
b335ecb5 498 }
72298d16 499 if (iocur_top->bbmap)
2a8b3fdf
DC
500 write_cur_bbs();
501 else
502 write_cur_buf();
b64af2c4
ES
503
504 /* If we didn't write the crc automatically, re-check inode validity */
505 if (xfs_sb_version_hascrc(&mp->m_sb) &&
506 skip_crc && iocur_top->ino_buf) {
507 iocur_top->ino_crc_ok = xfs_verify_cksum(iocur_top->data,
508 mp->m_sb.sb_inodesize,
509 XFS_DINODE_CRC_OFF);
510 }
511
2a8b3fdf
DC
512}
513
2bd0ea18
NS
514void
515set_cur(
516 const typ_t *t,
dfc130f3 517 __int64_t d,
2bd0ea18 518 int c,
b64af2c4 519 int ring_flag,
2bd0ea18
NS
520 bbmap_t *bbmap)
521{
72298d16 522 struct xfs_buf *bp;
2bd0ea18
NS
523 xfs_ino_t dirino;
524 xfs_ino_t ino;
525 __uint16_t mode;
6fea8f83 526 const struct xfs_buf_ops *ops = t ? t->bops : NULL;
2bd0ea18
NS
527
528 if (iocur_sp < 0) {
9ee7055c 529 dbprintf(_("set_cur no stack element to set\n"));
2bd0ea18
NS
530 return;
531 }
532
6fea8f83 533
2bd0ea18
NS
534 ino = iocur_top->ino;
535 dirino = iocur_top->dirino;
536 mode = iocur_top->mode;
537 pop_cur();
538 push_cur();
2a8b3fdf
DC
539
540 if (bbmap) {
857592d2 541#ifdef DEBUG_BBMAP
72298d16 542 int i;
2a8b3fdf 543 printf(_("xfs_db got a bbmap for %lld\n"), (long long)d);
72298d16
DC
544 printf(_("\tblock map"));
545 for (i = 0; i < bbmap->nmaps; i++)
546 printf(" %lld:%d", (long long)bbmap->b[i].bm_bn,
547 bbmap->b[i].bm_len);
548 printf("\n");
2a8b3fdf 549#endif
72298d16
DC
550 iocur_top->bbmap = malloc(sizeof(struct bbmap));
551 if (!iocur_top->bbmap)
2a8b3fdf 552 return;
72298d16
DC
553 memcpy(iocur_top->bbmap, bbmap, sizeof(struct bbmap));
554 bp = libxfs_readbuf_map(mp->m_ddev_targp, bbmap->b,
6fea8f83 555 bbmap->nmaps, 0, ops);
2a8b3fdf 556 } else {
6fea8f83 557 bp = libxfs_readbuf(mp->m_ddev_targp, d, c, 0, ops);
72298d16 558 iocur_top->bbmap = NULL;
2a8b3fdf 559 }
6fea8f83
DC
560
561 /*
9c0a86ed 562 * Keep the buffer even if the verifier says it is corrupted.
6fea8f83
DC
563 * We're a diagnostic tool, after all.
564 */
66fc04e0
DW
565 if (!bp || (bp->b_error && bp->b_error != -EFSCORRUPTED &&
566 bp->b_error != -EFSBADCRC))
72298d16
DC
567 return;
568 iocur_top->buf = bp->b_addr;
569 iocur_top->bp = bp;
b511ff41
DC
570 if (!ops)
571 bp->b_flags |= LIBXFS_B_UNCHECKED;
2a8b3fdf 572
2bd0ea18
NS
573 iocur_top->bb = d;
574 iocur_top->blen = c;
575 iocur_top->boff = 0;
576 iocur_top->data = iocur_top->buf;
577 iocur_top->len = BBTOB(c);
578 iocur_top->off = d << BBSHIFT;
579 iocur_top->typ = cur_typ = t;
580 iocur_top->ino = ino;
581 iocur_top->dirino = dirino;
582 iocur_top->mode = mode;
a73b88f2 583 iocur_top->ino_buf = 0;
66a40d02 584 iocur_top->dquot_buf = 0;
2bd0ea18
NS
585
586 /* store location in ring */
587 if (ring_flag)
588 ring_add();
589}
590
9ba69ce2
DC
591void
592set_iocur_type(
593 const typ_t *t)
594{
595 struct xfs_buf *bp = iocur_top->bp;
596
597 iocur_top->typ = t;
598
599 /* verify the buffer if the type has one. */
600 if (!bp)
601 return;
602 if (!t->bops) {
603 bp->b_ops = NULL;
604 bp->b_flags |= LIBXFS_B_UNCHECKED;
605 return;
606 }
607 if (!(bp->b_flags & LIBXFS_B_UPTODATE))
608 return;
609 bp->b_error = 0;
610 bp->b_ops = t->bops;
611 bp->b_ops->verify_read(bp);
612 bp->b_flags &= ~LIBXFS_B_UNCHECKED;
613}
614
2bd0ea18
NS
615static void
616stack_help(void)
617{
9ee7055c 618 dbprintf(_(
2bd0ea18
NS
619"\n"
620" The stack is used to explicitly store your location and data type\n"
621" for later return. The 'push' operation stores the current address\n"
622" and type on the stack, the 'pop' operation returns you to the\n"
623" position and datatype of the top entry on the stack.\n"
624"\n"
625" The 'stack' allows explicit location saves, see 'ring' for implicit\n"
626" position tracking.\n"
627"\n"
9ee7055c 628 ));
2bd0ea18
NS
629}
630
631/*ARGSUSED*/
632static int
633stack_f(
634 int argc,
635 char **argv)
636{
637 int i;
638 char tagbuf[8];
639
2d9475a4
NS
640 for (i = iocur_sp; i > 0; i--) {
641 snprintf(tagbuf, sizeof(tagbuf), "%d: ", i);
2bd0ea18
NS
642 print_iocur(tagbuf, &iocur_base[i]);
643 }
644 return 0;
645}