]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/io.c
3841c0dcb86eada13e33c8f937784f045cacef69
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
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);
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
};
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;
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
);
76 static inline void set_cur_boff(int off
)
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
);
88 if (iocur_top
== NULL
|| off
+ len
> BBTOB(iocur_top
->blen
))
89 dbprintf(_("can't set block offset to %d\n"), off
);
100 dbprintf(_("can't pop anything from I/O stack\n"));
104 libxfs_buf_relse(iocur_top
->bp
);
105 iocur_top
->bp
= NULL
;
107 if (iocur_top
->bbmap
) {
108 free(iocur_top
->bbmap
);
109 iocur_top
->bbmap
= NULL
;
111 if (--iocur_sp
>= 0) {
112 iocur_top
= iocur_base
+ iocur_sp
;
113 cur_typ
= iocur_top
->typ
;
115 iocur_top
= iocur_base
;
135 " Changes the address and data type to the first entry on the stack.\n"
141 iocur_is_ddev(const struct iocur
*ioc
)
146 return ioc
->bp
->b_target
== ioc
->bp
->b_mount
->m_ddev_targp
;
150 iocur_is_extlogdev(const struct iocur
*ioc
)
152 struct xfs_buf
*bp
= ioc
->bp
;
156 if (bp
->b_mount
->m_logdev_targp
== bp
->b_mount
->m_ddev_targp
)
159 return bp
->b_target
== bp
->b_mount
->m_logdev_targp
;
163 iocur_is_rtdev(const struct iocur
*ioc
)
168 return ioc
->bp
->b_target
== ioc
->bp
->b_mount
->m_rtdev_targp
;
176 const char *block_unit
= "fsbno?";
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";
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
,
190 (xfs_fsblock_t
)XFS_DADDR_TO_FSB(mp
, ioc
->bb
),
191 ioc
->blen
, ioc
->blen
== 1 ? "" : "s");
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
);
199 dbprintf(_("\tinode %lld, dir inode %lld, type %s\n"), ioc
->ino
,
200 ioc
->dirino
, ioc
->typ
== NULL
? _("none") : ioc
->typ
->name
);
209 if (ring_current
== -1) {
210 dbprintf(_("no entries in location ring.\n"));
214 dbprintf(_(" type bblock bblen fsbno inode\n"));
218 ioc
= &iocur_ring
[i
];
219 if (i
== ring_current
)
224 dbprintf("%-7.7s %8lld %5d %8lld %9lld\n",
225 ioc
->typ
== NULL
? "none" : ioc
->typ
->name
,
228 (xfs_fsblock_t
)XFS_DADDR_TO_FSB(mp
, ioc
->bb
),
235 i
= (i
+(RING_ENTRIES
-1))%RING_ENTRIES
;
243 if (iocur_sp
+ 1 >= iocur_len
) {
244 iocur_base
= xrealloc(iocur_base
,
245 sizeof(*iocur_base
) * (iocur_len
+ 1));
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;
258 push_cur_and_set_type(void)
260 /* save current state */
262 if (iocur_top
[-1].typ
&& iocur_top
[-1].typ
->typnm
== TYP_INODE
)
263 set_cur_inode(iocur_top
[-1].ino
);
265 set_cur(iocur_top
[-1].typ
, iocur_top
[-1].bb
,
266 iocur_top
[-1].blen
, DB_RING_IGN
,
267 iocur_top
[-1].bbmap
);
278 /* check we can execute command */
279 ct
= find_command(argv
[1]);
281 dbprintf(_("no such command %s\n"), argv
[1]);
285 dbprintf(_("no push form allowed for %s\n"), argv
[1]);
290 push_cur_and_set_type();
292 /* run requested command */
294 (void)command(argc
-1, argv
+1);
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"
310 /* move forward through the ring */
317 if (ring_current
== -1) {
318 dbprintf(_("ring is empty\n"));
321 if (ring_current
== ring_head
) {
322 dbprintf(_("no further entries\n"));
326 ring_current
= (ring_current
+1)%RING_ENTRIES
;
328 set_cur(iocur_ring
[ring_current
].typ
,
329 iocur_ring
[ring_current
].bb
,
330 iocur_ring
[ring_current
].blen
,
332 iocur_ring
[ring_current
].bbmap
);
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"
350 /* move backwards through the ring */
357 if (ring_current
== -1) {
358 dbprintf(_("ring is empty\n"));
361 if (ring_current
== ring_tail
) {
362 dbprintf(_("no previous entries\n"));
366 ring_current
= (ring_current
+(RING_ENTRIES
-1))%RING_ENTRIES
;
368 set_cur(iocur_ring
[ring_current
].typ
,
369 iocur_ring
[ring_current
].bb
,
370 iocur_ring
[ring_current
].blen
,
372 iocur_ring
[ring_current
].bbmap
);
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"
389 /* show or go to specific point in ring */
402 index
= (int)strtoul(argv
[1], NULL
, 0);
403 if (index
< 0 || index
>= RING_ENTRIES
) {
404 dbprintf(_("invalid entry: %d\n"), index
);
408 ring_current
= index
;
410 set_cur(iocur_ring
[index
].typ
,
411 iocur_ring
[index
].bb
,
412 iocur_ring
[index
].blen
,
414 iocur_ring
[index
].bbmap
);
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"
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"
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"
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"
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"
449 if (ring_head
== -1) {
450 /* only get here right after startup */
454 iocur_ring
[0] = *iocur_top
;
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
;
463 ring_current
= (ring_current
+1)%RING_ENTRIES
;
464 iocur_ring
[ring_current
] = *iocur_top
;
472 struct xfs_buftarg
*btp
= iocur_top
->bp
->b_target
;
475 ret
= -libxfs_bwrite(iocur_top
->bp
);
477 dbprintf(_("write error: %s\n"), strerror(ret
));
479 /* re-read buffer from disk */
480 ret
= -libxfs_readbufr(btp
, iocur_top
->bb
, iocur_top
->bp
,
483 dbprintf(_("read error: %s\n"), strerror(ret
));
489 struct xfs_buftarg
*btp
= iocur_top
->bp
->b_target
;
492 ret
= -libxfs_bwrite(iocur_top
->bp
);
494 dbprintf(_("write error: %s\n"), strerror(ret
));
497 /* re-read buffer from disk */
498 ret
= -libxfs_readbufr_map(btp
, iocur_top
->bp
, 0);
500 dbprintf(_("read error: %s\n"), strerror(ret
));
511 xfs_verify_recalc_crc(
514 xfs_buf_update_cksum(bp
, iocur_top
->typ
->crc_off
);
520 bool skip_crc
= false;
523 dbprintf(_("nothing to write\n"));
527 if (!xfs_has_crc(mp
) ||
528 !iocur_top
->bp
->b_ops
||
529 iocur_top
->bp
->b_ops
->verify_write
== xfs_dummy_verify
)
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
);
538 if (iocur_top
->bbmap
)
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
,
555 struct xfs_buftarg
*btargp
,
566 const struct xfs_buf_ops
*ops
= type
? type
->bops
: NULL
;
570 dbprintf(_("set_cur no stack element to set\n"));
574 ino
= iocur_top
->ino
;
575 dirino
= iocur_top
->dirino
;
576 mode
= iocur_top
->mode
;
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
,
590 iocur_top
->bbmap
= malloc(sizeof(struct bbmap
));
591 if (!iocur_top
->bbmap
)
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
,
598 error
= -libxfs_buf_read(btargp
, blknum
, len
,
599 LIBXFS_READBUF_SALVAGE
, &bp
, ops
);
600 iocur_top
->bbmap
= NULL
;
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.
610 iocur_top
->buf
= bp
->b_addr
;
614 bp
->b_flags
|= LIBXFS_B_UNCHECKED
;
617 iocur_top
->bb
= blknum
;
618 iocur_top
->blen
= len
;
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;
630 /* store location in ring */
643 __set_cur(mp
->m_ddev_targp
, type
, blknum
, len
, ring_flag
, bbmap
);
654 if (mp
->m_logdev_targp
->bt_bdev
== mp
->m_ddev_targp
->bt_bdev
) {
655 fprintf(stderr
, "no external log specified\n");
660 __set_cur(mp
->m_logdev_targp
, type
, blknum
, len
, ring_flag
, bbmap
);
671 if (!mp
->m_rtdev_targp
->bt_bdev
) {
672 printf(_("realtime device not loaded, use -R.\n"));
676 __set_cur(mp
->m_rtdev_targp
, type
, blknum
, len
, ring_flag
, bbmap
);
684 /* type's size in basic blocks */
685 int bb_count
= BTOBB(mp
->m_sb
.sb_sectsize
);
686 int boff
= iocur_top
->boff
;
689 * Inodes are special; verifier checks all inodes in the chunk, the
690 * set_cur_inode() will help that
692 if (type
->typnm
== TYP_INODE
) {
693 xfs_daddr_t b
= iocur_top
->bb
;
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
);
706 /* adjust buffer size for types with fields & hence fsize() */
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
);
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"
724 " The 'stack' allows explicit location saves, see 'ring' for implicit\n"
725 " position tracking.\n"
739 for (i
= iocur_sp
; i
> 0; i
--) {
740 snprintf(tagbuf
, sizeof(tagbuf
), "%d: ", i
);
741 print_iocur(tagbuf
, &iocur_base
[i
]);