]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/io.c
3841c0dcb86eada13e33c8f937784f045cacef69
[thirdparty/xfsprogs-dev.git] / db / io.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "libxfs.h"
8 #include "command.h"
9 #include "type.h"
10 #include "faddr.h"
11 #include "fprint.h"
12 #include "field.h"
13 #include "dquot.h"
14 #include "inode.h"
15 #include "io.h"
16 #include "output.h"
17 #include "init.h"
18 #include "malloc.h"
19 #include "crc.h"
20 #include "bit.h"
21
22 static int pop_f(int argc, char **argv);
23 static void pop_help(void);
24 static int push_f(int argc, char **argv);
25 static void push_help(void);
26 static int stack_f(int argc, char **argv);
27 static void stack_help(void);
28 static int forward_f(int argc, char **argv);
29 static void forward_help(void);
30 static int back_f(int argc, char **argv);
31 static void back_help(void);
32 static int ring_f(int argc, char **argv);
33 static void ring_help(void);
34
35 static const cmdinfo_t pop_cmd =
36 { "pop", NULL, pop_f, 0, 0, 0, NULL,
37 N_("pop location from the stack"), pop_help };
38 static const cmdinfo_t push_cmd =
39 { "push", NULL, push_f, 0, 2, 0, N_("[command]"),
40 N_("push location to the stack"), push_help };
41 static const cmdinfo_t stack_cmd =
42 { "stack", NULL, stack_f, 0, 0, 0, NULL,
43 N_("view the location stack"), stack_help };
44 static const cmdinfo_t forward_cmd =
45 { "forward", "f", forward_f, 0, 0, 0, NULL,
46 N_("move forward to next entry in the position ring"), forward_help };
47 static const cmdinfo_t back_cmd =
48 { "back", "b", back_f, 0, 0, 0, NULL,
49 N_("move to the previous location in the position ring"), back_help };
50 static const cmdinfo_t ring_cmd =
51 { "ring", NULL, ring_f, 0, 1, 0, NULL,
52 N_("show position ring or move to a specific entry"), ring_help };
53
54 iocur_t *iocur_base;
55 iocur_t *iocur_top;
56 int iocur_sp = -1;
57 int iocur_len;
58
59 #define RING_ENTRIES 20
60 static iocur_t iocur_ring[RING_ENTRIES];
61 static int ring_head = -1;
62 static int ring_tail = -1;
63 static int ring_current = -1;
64
65 void
66 io_init(void)
67 {
68 add_command(&pop_cmd);
69 add_command(&push_cmd);
70 add_command(&stack_cmd);
71 add_command(&forward_cmd);
72 add_command(&back_cmd);
73 add_command(&ring_cmd);
74 }
75
76 static inline void set_cur_boff(int off)
77 {
78 iocur_top->boff = off;
79 iocur_top->off = ((xfs_off_t)iocur_top->bb << BBSHIFT) + off;
80 iocur_top->data = (void *)((char *)iocur_top->buf + off);
81 }
82
83 void
84 off_cur(
85 int off,
86 int len)
87 {
88 if (iocur_top == NULL || off + len > BBTOB(iocur_top->blen))
89 dbprintf(_("can't set block offset to %d\n"), off);
90 else {
91 set_cur_boff(off);
92 iocur_top->len = len;
93 }
94 }
95
96 void
97 pop_cur(void)
98 {
99 if (iocur_sp < 0) {
100 dbprintf(_("can't pop anything from I/O stack\n"));
101 return;
102 }
103 if (iocur_top->bp) {
104 libxfs_buf_relse(iocur_top->bp);
105 iocur_top->bp = NULL;
106 }
107 if (iocur_top->bbmap) {
108 free(iocur_top->bbmap);
109 iocur_top->bbmap = NULL;
110 }
111 if (--iocur_sp >= 0) {
112 iocur_top = iocur_base + iocur_sp;
113 cur_typ = iocur_top->typ;
114 } else {
115 iocur_top = iocur_base;
116 iocur_sp = 0;
117 }
118 }
119
120 /*ARGSUSED*/
121 static int
122 pop_f(
123 int argc,
124 char **argv)
125 {
126 pop_cur();
127 return 0;
128 }
129
130 static void
131 pop_help(void)
132 {
133 dbprintf(_(
134 "\n"
135 " Changes the address and data type to the first entry on the stack.\n"
136 "\n"
137 ));
138 }
139
140 bool
141 iocur_is_ddev(const struct iocur *ioc)
142 {
143 if (!ioc->bp)
144 return false;
145
146 return ioc->bp->b_target == ioc->bp->b_mount->m_ddev_targp;
147 }
148
149 bool
150 iocur_is_extlogdev(const struct iocur *ioc)
151 {
152 struct xfs_buf *bp = ioc->bp;
153
154 if (!bp)
155 return false;
156 if (bp->b_mount->m_logdev_targp == bp->b_mount->m_ddev_targp)
157 return false;
158
159 return bp->b_target == bp->b_mount->m_logdev_targp;
160 }
161
162 bool
163 iocur_is_rtdev(const struct iocur *ioc)
164 {
165 if (!ioc->bp)
166 return false;
167
168 return ioc->bp->b_target == ioc->bp->b_mount->m_rtdev_targp;
169 }
170
171 void
172 print_iocur(
173 char *tag,
174 iocur_t *ioc)
175 {
176 const char *block_unit = "fsbno?";
177 int i;
178
179 if (iocur_is_ddev(ioc))
180 block_unit = "fsbno";
181 else if (iocur_is_extlogdev(ioc))
182 block_unit = "logbno";
183 else if (iocur_is_rtdev(ioc))
184 block_unit = "rtbno";
185
186 dbprintf("%s\n", tag);
187 dbprintf(_("\tbyte offset %lld, length %d\n"), ioc->off, ioc->len);
188 dbprintf(_("\tbuffer block %lld (%s %lld), %d bb%s\n"), ioc->bb,
189 block_unit,
190 (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb),
191 ioc->blen, ioc->blen == 1 ? "" : "s");
192 if (ioc->bbmap) {
193 dbprintf(_("\tblock map"));
194 for (i = 0; i < ioc->bbmap->nmaps; i++)
195 dbprintf(" %lld:%d", ioc->bbmap->b[i].bm_bn,
196 ioc->bbmap->b[i].bm_len);
197 dbprintf("\n");
198 }
199 dbprintf(_("\tinode %lld, dir inode %lld, type %s\n"), ioc->ino,
200 ioc->dirino, ioc->typ == NULL ? _("none") : ioc->typ->name);
201 }
202
203 static void
204 print_ring(void)
205 {
206 int i;
207 iocur_t *ioc;
208
209 if (ring_current == -1) {
210 dbprintf(_("no entries in location ring.\n"));
211 return;
212 }
213
214 dbprintf(_(" type bblock bblen fsbno inode\n"));
215
216 i = ring_head;
217 for (;;) {
218 ioc = &iocur_ring[i];
219 if (i == ring_current)
220 printf("*%2d: ", i);
221 else
222 printf(" %2d: ", i);
223
224 dbprintf("%-7.7s %8lld %5d %8lld %9lld\n",
225 ioc->typ == NULL ? "none" : ioc->typ->name,
226 ioc->bb,
227 ioc->blen,
228 (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb),
229 ioc->ino
230 );
231
232 if (i == ring_tail)
233 break;
234
235 i = (i+(RING_ENTRIES-1))%RING_ENTRIES;
236 }
237 }
238
239
240 void
241 push_cur(void)
242 {
243 if (iocur_sp + 1 >= iocur_len) {
244 iocur_base = xrealloc(iocur_base,
245 sizeof(*iocur_base) * (iocur_len + 1));
246 iocur_len++;
247 }
248 iocur_sp++;
249 iocur_top = iocur_base + iocur_sp;
250 memset(iocur_top, 0, sizeof(*iocur_base));
251 iocur_top->ino = iocur_sp > 0 ? iocur_top[-1].ino : NULLFSINO;
252 iocur_top->dirino = iocur_sp > 0 ? iocur_top[-1].dirino : NULLFSINO;
253 iocur_top->mode = iocur_sp > 0 ? iocur_top[-1].mode : 0;
254 cur_typ = NULL;
255 }
256
257 void
258 push_cur_and_set_type(void)
259 {
260 /* save current state */
261 push_cur();
262 if (iocur_top[-1].typ && iocur_top[-1].typ->typnm == TYP_INODE)
263 set_cur_inode(iocur_top[-1].ino);
264 else
265 set_cur(iocur_top[-1].typ, iocur_top[-1].bb,
266 iocur_top[-1].blen, DB_RING_IGN,
267 iocur_top[-1].bbmap);
268 }
269
270 static int
271 push_f(
272 int argc,
273 char **argv)
274 {
275 const cmdinfo_t *ct;
276
277 if (argc > 1) {
278 /* check we can execute command */
279 ct = find_command(argv[1]);
280 if (ct == NULL) {
281 dbprintf(_("no such command %s\n"), argv[1]);
282 return 0;
283 }
284 if (!ct->canpush) {
285 dbprintf(_("no push form allowed for %s\n"), argv[1]);
286 return 0;
287 }
288 }
289
290 push_cur_and_set_type();
291
292 /* run requested command */
293 if (argc>1)
294 (void)command(argc-1, argv+1);
295 return 0;
296 }
297
298 static void
299 push_help(void)
300 {
301 dbprintf(_(
302 "\n"
303 " Allows you to push the current address and data type on the stack for\n"
304 " later return. 'push' also accepts an additional command to execute after\n"
305 " storing the current address (ex: 'push a rootino' from the superblock).\n"
306 "\n"
307 ));
308 }
309
310 /* move forward through the ring */
311 /* ARGSUSED */
312 static int
313 forward_f(
314 int argc,
315 char **argv)
316 {
317 if (ring_current == -1) {
318 dbprintf(_("ring is empty\n"));
319 return 0;
320 }
321 if (ring_current == ring_head) {
322 dbprintf(_("no further entries\n"));
323 return 0;
324 }
325
326 ring_current = (ring_current+1)%RING_ENTRIES;
327
328 set_cur(iocur_ring[ring_current].typ,
329 iocur_ring[ring_current].bb,
330 iocur_ring[ring_current].blen,
331 DB_RING_IGN,
332 iocur_ring[ring_current].bbmap);
333
334 return 0;
335 }
336
337 static void
338 forward_help(void)
339 {
340 dbprintf(_(
341 "\n"
342 " The 'forward' ('f') command moves to the next location in the position\n"
343 " ring, updating the current position and data type. If the current location\n"
344 " is the top entry in the ring, then the 'forward' command will have\n"
345 " no effect.\n"
346 "\n"
347 ));
348 }
349
350 /* move backwards through the ring */
351 /* ARGSUSED */
352 static int
353 back_f(
354 int argc,
355 char **argv)
356 {
357 if (ring_current == -1) {
358 dbprintf(_("ring is empty\n"));
359 return 0;
360 }
361 if (ring_current == ring_tail) {
362 dbprintf(_("no previous entries\n"));
363 return 0;
364 }
365
366 ring_current = (ring_current+(RING_ENTRIES-1))%RING_ENTRIES;
367
368 set_cur(iocur_ring[ring_current].typ,
369 iocur_ring[ring_current].bb,
370 iocur_ring[ring_current].blen,
371 DB_RING_IGN,
372 iocur_ring[ring_current].bbmap);
373
374 return 0;
375 }
376
377 static void
378 back_help(void)
379 {
380 dbprintf(_(
381 "\n"
382 " The 'back' ('b') command moves to the previous location in the position\n"
383 " ring, updating the current position and data type. If the current location\n"
384 " is the last entry in the ring, then the 'back' command will have no effect.\n"
385 "\n"
386 ));
387 }
388
389 /* show or go to specific point in ring */
390 static int
391 ring_f(
392 int argc,
393 char **argv)
394 {
395 int index;
396
397 if (argc == 1) {
398 print_ring();
399 return 0;
400 }
401
402 index = (int)strtoul(argv[1], NULL, 0);
403 if (index < 0 || index >= RING_ENTRIES) {
404 dbprintf(_("invalid entry: %d\n"), index);
405 return 0;
406 }
407
408 ring_current = index;
409
410 set_cur(iocur_ring[index].typ,
411 iocur_ring[index].bb,
412 iocur_ring[index].blen,
413 DB_RING_IGN,
414 iocur_ring[index].bbmap);
415
416 return 0;
417 }
418
419 static void
420 ring_help(void)
421 {
422 dbprintf(_(
423 "\n"
424 " The position ring automatically keeps track of each disk location and\n"
425 " structure type for each change of position you make during your xfs_db\n"
426 " session. The last %d most recent entries are kept in the ring.\n"
427 "\n"
428 " To display the current list of ring entries type 'ring' by itself on\n"
429 " the command line. The entry highlighted by an asterisk ('*') is the\n"
430 " current entry.\n"
431 "\n"
432 " To move to another entry in the ring type 'ring <num>' where <num> is\n"
433 " your desired entry from the ring position list.\n"
434 "\n"
435 " You may also use the 'forward' ('f') or 'back' ('b') commands to move\n"
436 " to the previous or next entry in the ring, respectively.\n"
437 "\n"
438 " Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n"
439 " location implicitly. Use the 'push' and 'pop' commands if you wish to\n"
440 " store a specific location explicitly for later return.\n"
441 "\n"),
442 RING_ENTRIES);
443 }
444
445
446 void
447 ring_add(void)
448 {
449 if (ring_head == -1) {
450 /* only get here right after startup */
451 ring_head = 0;
452 ring_tail = 0;
453 ring_current = 0;
454 iocur_ring[0] = *iocur_top;
455 } else {
456 if (ring_current == ring_head) {
457 ring_head = (ring_head+1)%RING_ENTRIES;
458 iocur_ring[ring_head] = *iocur_top;
459 if (ring_head == ring_tail)
460 ring_tail = (ring_tail+1)%RING_ENTRIES;
461 ring_current = ring_head;
462 } else {
463 ring_current = (ring_current+1)%RING_ENTRIES;
464 iocur_ring[ring_current] = *iocur_top;
465 }
466 }
467 }
468
469 static void
470 write_cur_buf(void)
471 {
472 struct xfs_buftarg *btp = iocur_top->bp->b_target;
473 int ret;
474
475 ret = -libxfs_bwrite(iocur_top->bp);
476 if (ret != 0)
477 dbprintf(_("write error: %s\n"), strerror(ret));
478
479 /* re-read buffer from disk */
480 ret = -libxfs_readbufr(btp, iocur_top->bb, iocur_top->bp,
481 iocur_top->blen, 0);
482 if (ret != 0)
483 dbprintf(_("read error: %s\n"), strerror(ret));
484 }
485
486 static void
487 write_cur_bbs(void)
488 {
489 struct xfs_buftarg *btp = iocur_top->bp->b_target;
490 int ret;
491
492 ret = -libxfs_bwrite(iocur_top->bp);
493 if (ret != 0)
494 dbprintf(_("write error: %s\n"), strerror(ret));
495
496
497 /* re-read buffer from disk */
498 ret = -libxfs_readbufr_map(btp, iocur_top->bp, 0);
499 if (ret != 0)
500 dbprintf(_("read error: %s\n"), strerror(ret));
501 }
502
503 void
504 xfs_dummy_verify(
505 struct xfs_buf *bp)
506 {
507 return;
508 }
509
510 void
511 xfs_verify_recalc_crc(
512 struct xfs_buf *bp)
513 {
514 xfs_buf_update_cksum(bp, iocur_top->typ->crc_off);
515 }
516
517 void
518 write_cur(void)
519 {
520 bool skip_crc = false;
521
522 if (iocur_sp < 0) {
523 dbprintf(_("nothing to write\n"));
524 return;
525 }
526
527 if (!xfs_has_crc(mp) ||
528 !iocur_top->bp->b_ops ||
529 iocur_top->bp->b_ops->verify_write == xfs_dummy_verify)
530 skip_crc = true;
531
532 if (!skip_crc) {
533 if (iocur_top->ino_buf)
534 xfs_inode_set_crc(iocur_top->bp);
535 else if (iocur_top->dquot_buf)
536 xfs_dquot_set_crc(iocur_top->bp);
537 }
538 if (iocur_top->bbmap)
539 write_cur_bbs();
540 else
541 write_cur_buf();
542
543 /* If we didn't write the crc automatically, re-check inode validity */
544 if (xfs_has_crc(mp) &&
545 skip_crc && iocur_top->ino_buf) {
546 iocur_top->ino_crc_ok = libxfs_verify_cksum(iocur_top->data,
547 mp->m_sb.sb_inodesize,
548 XFS_DINODE_CRC_OFF);
549 }
550
551 }
552
553 static void
554 __set_cur(
555 struct xfs_buftarg *btargp,
556 const typ_t *type,
557 xfs_daddr_t blknum,
558 int len,
559 int ring_flag,
560 bbmap_t *bbmap)
561 {
562 struct xfs_buf *bp;
563 xfs_ino_t dirino;
564 xfs_ino_t ino;
565 uint16_t mode;
566 const struct xfs_buf_ops *ops = type ? type->bops : NULL;
567 int error;
568
569 if (iocur_sp < 0) {
570 dbprintf(_("set_cur no stack element to set\n"));
571 return;
572 }
573
574 ino = iocur_top->ino;
575 dirino = iocur_top->dirino;
576 mode = iocur_top->mode;
577 pop_cur();
578 push_cur();
579
580 if (bbmap) {
581 #ifdef DEBUG_BBMAP
582 int i;
583 printf(_("xfs_db got a bbmap for %lld\n"), (long long)blknum);
584 printf(_("\tblock map"));
585 for (i = 0; i < bbmap->nmaps; i++)
586 printf(" %lld:%d", (long long)bbmap->b[i].bm_bn,
587 bbmap->b[i].bm_len);
588 printf("\n");
589 #endif
590 iocur_top->bbmap = malloc(sizeof(struct bbmap));
591 if (!iocur_top->bbmap)
592 return;
593 memcpy(iocur_top->bbmap, bbmap, sizeof(struct bbmap));
594 error = -libxfs_buf_read_map(btargp, bbmap->b,
595 bbmap->nmaps, LIBXFS_READBUF_SALVAGE, &bp,
596 ops);
597 } else {
598 error = -libxfs_buf_read(btargp, blknum, len,
599 LIBXFS_READBUF_SALVAGE, &bp, ops);
600 iocur_top->bbmap = NULL;
601 }
602
603 /*
604 * Salvage mode means that we still get a buffer even if the verifier
605 * says the metadata is corrupt. Therefore, the only errors we should
606 * get are for IO errors or runtime errors.
607 */
608 if (error)
609 return;
610 iocur_top->buf = bp->b_addr;
611 iocur_top->bp = bp;
612 if (!ops) {
613 bp->b_ops = NULL;
614 bp->b_flags |= LIBXFS_B_UNCHECKED;
615 }
616
617 iocur_top->bb = blknum;
618 iocur_top->blen = len;
619 iocur_top->boff = 0;
620 iocur_top->data = iocur_top->buf;
621 iocur_top->len = BBTOB(len);
622 iocur_top->off = blknum << BBSHIFT;
623 iocur_top->typ = cur_typ = type;
624 iocur_top->ino = ino;
625 iocur_top->dirino = dirino;
626 iocur_top->mode = mode;
627 iocur_top->ino_buf = 0;
628 iocur_top->dquot_buf = 0;
629
630 /* store location in ring */
631 if (ring_flag)
632 ring_add();
633 }
634
635 void
636 set_cur(
637 const typ_t *type,
638 xfs_daddr_t blknum,
639 int len,
640 int ring_flag,
641 bbmap_t *bbmap)
642 {
643 __set_cur(mp->m_ddev_targp, type, blknum, len, ring_flag, bbmap);
644 }
645
646 void
647 set_log_cur(
648 const typ_t *type,
649 xfs_daddr_t blknum,
650 int len,
651 int ring_flag,
652 bbmap_t *bbmap)
653 {
654 if (mp->m_logdev_targp->bt_bdev == mp->m_ddev_targp->bt_bdev) {
655 fprintf(stderr, "no external log specified\n");
656 exitcode = 1;
657 return;
658 }
659
660 __set_cur(mp->m_logdev_targp, type, blknum, len, ring_flag, bbmap);
661 }
662
663 int
664 set_rt_cur(
665 const typ_t *type,
666 xfs_daddr_t blknum,
667 int len,
668 int ring_flag,
669 bbmap_t *bbmap)
670 {
671 if (!mp->m_rtdev_targp->bt_bdev) {
672 printf(_("realtime device not loaded, use -R.\n"));
673 return ENODEV;
674 }
675
676 __set_cur(mp->m_rtdev_targp, type, blknum, len, ring_flag, bbmap);
677 return 0;
678 }
679
680 void
681 set_iocur_type(
682 const typ_t *type)
683 {
684 /* type's size in basic blocks */
685 int bb_count = BTOBB(mp->m_sb.sb_sectsize);
686 int boff = iocur_top->boff;
687
688 /*
689 * Inodes are special; verifier checks all inodes in the chunk, the
690 * set_cur_inode() will help that
691 */
692 if (type->typnm == TYP_INODE) {
693 xfs_daddr_t b = iocur_top->bb;
694 xfs_agblock_t agbno;
695 xfs_agino_t agino;
696 xfs_ino_t ino;
697
698 agbno = xfs_daddr_to_agbno(mp, b);
699 agino = XFS_OFFBNO_TO_AGINO(mp, agbno,
700 iocur_top->boff / mp->m_sb.sb_inodesize);
701 ino = XFS_AGINO_TO_INO(mp, xfs_daddr_to_agno(mp, b), agino);
702 set_cur_inode(ino);
703 return;
704 }
705
706 /* adjust buffer size for types with fields & hence fsize() */
707 if (type->fields)
708 bb_count = BTOBB(byteize(fsize(type->fields,
709 iocur_top->data, 0, 0)));
710 set_cur(type, iocur_top->bb, bb_count, DB_RING_IGN, NULL);
711 set_cur_boff(boff);
712 }
713
714 static void
715 stack_help(void)
716 {
717 dbprintf(_(
718 "\n"
719 " The stack is used to explicitly store your location and data type\n"
720 " for later return. The 'push' operation stores the current address\n"
721 " and type on the stack, the 'pop' operation returns you to the\n"
722 " position and datatype of the top entry on the stack.\n"
723 "\n"
724 " The 'stack' allows explicit location saves, see 'ring' for implicit\n"
725 " position tracking.\n"
726 "\n"
727 ));
728 }
729
730 /*ARGSUSED*/
731 static int
732 stack_f(
733 int argc,
734 char **argv)
735 {
736 int i;
737 char tagbuf[14];
738
739 for (i = iocur_sp; i > 0; i--) {
740 snprintf(tagbuf, sizeof(tagbuf), "%d: ", i);
741 print_iocur(tagbuf, &iocur_base[i]);
742 }
743 return 0;
744 }