]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame_incremental - db/io.c
xfsprogs: Release v6.15.0
[thirdparty/xfsprogs-dev.git] / db / io.c
... / ...
CommitLineData
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
22static int pop_f(int argc, char **argv);
23static void pop_help(void);
24static int push_f(int argc, char **argv);
25static void push_help(void);
26static int stack_f(int argc, char **argv);
27static void stack_help(void);
28static int forward_f(int argc, char **argv);
29static void forward_help(void);
30static int back_f(int argc, char **argv);
31static void back_help(void);
32static int ring_f(int argc, char **argv);
33static void ring_help(void);
34
35static const cmdinfo_t pop_cmd =
36 { "pop", NULL, pop_f, 0, 0, 0, NULL,
37 N_("pop location from the stack"), pop_help };
38static const cmdinfo_t push_cmd =
39 { "push", NULL, push_f, 0, 2, 0, N_("[command]"),
40 N_("push location to the stack"), push_help };
41static const cmdinfo_t stack_cmd =
42 { "stack", NULL, stack_f, 0, 0, 0, NULL,
43 N_("view the location stack"), stack_help };
44static 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 };
47static 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 };
50static 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
54iocur_t *iocur_base;
55iocur_t *iocur_top;
56int iocur_sp = -1;
57int iocur_len;
58
59#define RING_ENTRIES 20
60static iocur_t iocur_ring[RING_ENTRIES];
61static int ring_head = -1;
62static int ring_tail = -1;
63static int ring_current = -1;
64
65void
66io_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
76static 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
83void
84off_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
96void
97pop_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*/
121static int
122pop_f(
123 int argc,
124 char **argv)
125{
126 pop_cur();
127 return 0;
128}
129
130static void
131pop_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
140bool
141iocur_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
149bool
150iocur_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
162bool
163iocur_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
171void
172print_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
203static void
204print_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
240void
241push_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
257void
258push_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
270static int
271push_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
298static void
299push_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 */
312static int
313forward_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
337static void
338forward_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 */
352static int
353back_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
377static void
378back_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 */
390static int
391ring_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
419static void
420ring_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
446void
447ring_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
469static void
470write_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
486static void
487write_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
503void
504xfs_dummy_verify(
505 struct xfs_buf *bp)
506{
507 return;
508}
509
510void
511xfs_verify_recalc_crc(
512 struct xfs_buf *bp)
513{
514 xfs_buf_update_cksum(bp, iocur_top->typ->crc_off);
515}
516
517void
518write_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
553static 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
635void
636set_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
646void
647set_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
663int
664set_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
680void
681set_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
714static void
715stack_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*/
731static int
732stack_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}