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