]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/io.c
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
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
7 * published by the Free Software Foundation.
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.
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
33 static int pop_f(int argc
, char **argv
);
34 static void pop_help(void);
35 static int push_f(int argc
, char **argv
);
36 static void push_help(void);
37 static int stack_f(int argc
, char **argv
);
38 static void stack_help(void);
39 static int forward_f(int argc
, char **argv
);
40 static void forward_help(void);
41 static int back_f(int argc
, char **argv
);
42 static void back_help(void);
43 static int ring_f(int argc
, char **argv
);
44 static void ring_help(void);
46 static const cmdinfo_t pop_cmd
=
47 { "pop", NULL
, pop_f
, 0, 0, 0, NULL
,
48 N_("pop location from the stack"), pop_help
};
49 static const cmdinfo_t push_cmd
=
50 { "push", NULL
, push_f
, 0, 2, 0, N_("[command]"),
51 N_("push location to the stack"), push_help
};
52 static const cmdinfo_t stack_cmd
=
53 { "stack", NULL
, stack_f
, 0, 0, 0, NULL
,
54 N_("view the location stack"), stack_help
};
55 static const cmdinfo_t forward_cmd
=
56 { "forward", "f", forward_f
, 0, 0, 0, NULL
,
57 N_("move forward to next entry in the position ring"), forward_help
};
58 static const cmdinfo_t back_cmd
=
59 { "back", "b", back_f
, 0, 0, 0, NULL
,
60 N_("move to the previous location in the position ring"), back_help
};
61 static const cmdinfo_t ring_cmd
=
62 { "ring", NULL
, ring_f
, 0, 1, 0, NULL
,
63 N_("show position ring or move to a specific entry"), ring_help
};
70 #define RING_ENTRIES 20
71 static iocur_t iocur_ring
[RING_ENTRIES
];
72 static int ring_head
= -1;
73 static int ring_tail
= -1;
74 static int ring_current
= -1;
79 add_command(&pop_cmd
);
80 add_command(&push_cmd
);
81 add_command(&stack_cmd
);
82 add_command(&forward_cmd
);
83 add_command(&back_cmd
);
84 add_command(&ring_cmd
);
92 if (iocur_top
== NULL
|| off
+ len
> BBTOB(iocur_top
->blen
))
93 dbprintf(_("can't set block offset to %d\n"), off
);
95 iocur_top
->boff
= off
;
96 iocur_top
->off
= ((xfs_off_t
)iocur_top
->bb
<< BBSHIFT
) + off
;
98 iocur_top
->data
= (void *)((char *)iocur_top
->buf
+ off
);
106 dbprintf(_("can't pop anything from I/O stack\n"));
110 libxfs_putbuf(iocur_top
->bp
);
111 iocur_top
->bp
= NULL
;
113 if (iocur_top
->bbmap
) {
114 free(iocur_top
->bbmap
);
115 iocur_top
->bbmap
= NULL
;
117 if (--iocur_sp
>= 0) {
118 iocur_top
= iocur_base
+ iocur_sp
;
119 cur_typ
= iocur_top
->typ
;
121 iocur_top
= iocur_base
;
141 " Changes the address and data type to the first entry on the stack.\n"
153 dbprintf("%s\n", tag
);
154 dbprintf(_("\tbyte offset %lld, length %d\n"), ioc
->off
, ioc
->len
);
155 dbprintf(_("\tbuffer block %lld (fsbno %lld), %d bb%s\n"), ioc
->bb
,
156 (xfs_fsblock_t
)XFS_DADDR_TO_FSB(mp
, ioc
->bb
), ioc
->blen
,
157 ioc
->blen
== 1 ? "" : "s");
159 dbprintf(_("\tblock map"));
160 for (i
= 0; i
< ioc
->bbmap
->nmaps
; i
++)
161 dbprintf(" %lld:%d", ioc
->bbmap
->b
[i
].bm_bn
,
162 ioc
->bbmap
->b
[i
].bm_len
);
165 dbprintf(_("\tinode %lld, dir inode %lld, type %s\n"), ioc
->ino
,
166 ioc
->dirino
, ioc
->typ
== NULL
? _("none") : ioc
->typ
->name
);
175 if (ring_current
== -1) {
176 dbprintf(_("no entries in location ring.\n"));
180 dbprintf(_(" type bblock bblen fsbno inode\n"));
184 ioc
= &iocur_ring
[i
];
185 if (i
== ring_current
)
190 dbprintf("%-7.7s %8lld %5d %8lld %9lld\n",
191 ioc
->typ
== NULL
? "none" : ioc
->typ
->name
,
194 (xfs_fsblock_t
)XFS_DADDR_TO_FSB(mp
, ioc
->bb
),
201 i
= (i
+(RING_ENTRIES
-1))%RING_ENTRIES
;
209 if (iocur_sp
+ 1 >= iocur_len
) {
210 iocur_base
= xrealloc(iocur_base
,
211 sizeof(*iocur_base
) * (iocur_len
+ 1));
215 iocur_top
= iocur_base
+ iocur_sp
;
216 memset(iocur_top
, 0, sizeof(*iocur_base
));
217 iocur_top
->ino
= iocur_sp
> 0 ? iocur_top
[-1].ino
: NULLFSINO
;
218 iocur_top
->dirino
= iocur_sp
> 0 ? iocur_top
[-1].dirino
: NULLFSINO
;
219 iocur_top
->mode
= iocur_sp
> 0 ? iocur_top
[-1].mode
: 0;
231 /* check we can execute command */
232 ct
= find_command(argv
[1]);
234 dbprintf(_("no such command %s\n"), argv
[1]);
238 dbprintf(_("no push form allowed for %s\n"), argv
[1]);
243 /* save current state */
245 if (iocur_top
[-1].typ
&& iocur_top
[-1].typ
->typnm
== TYP_INODE
)
246 set_cur_inode(iocur_top
[-1].ino
);
248 set_cur(iocur_top
[-1].typ
, iocur_top
[-1].bb
,
249 iocur_top
[-1].blen
, DB_RING_IGN
,
250 iocur_top
[-1].bbmap
);
252 /* run requested command */
254 (void)command(argc
-1, argv
+1);
263 " Allows you to push the current address and data type on the stack for\n"
264 " later return. 'push' also accepts an additional command to execute after\n"
265 " storing the current address (ex: 'push a rootino' from the superblock).\n"
270 /* move forward through the ring */
277 if (ring_current
== -1) {
278 dbprintf(_("ring is empty\n"));
281 if (ring_current
== ring_head
) {
282 dbprintf(_("no further entries\n"));
286 ring_current
= (ring_current
+1)%RING_ENTRIES
;
288 set_cur(iocur_ring
[ring_current
].typ
,
289 iocur_ring
[ring_current
].bb
,
290 iocur_ring
[ring_current
].blen
,
292 iocur_ring
[ring_current
].bbmap
);
302 " The 'forward' ('f') command moves to the next location in the position\n"
303 " ring, updating the current position and data type. If the current location\n"
304 " is the top entry in the ring, then the 'forward' command will have\n"
310 /* move backwards through the ring */
317 if (ring_current
== -1) {
318 dbprintf(_("ring is empty\n"));
321 if (ring_current
== ring_tail
) {
322 dbprintf(_("no previous entries\n"));
326 ring_current
= (ring_current
+(RING_ENTRIES
-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 'back' ('b') command moves to the previous location in the position\n"
343 " ring, updating the current position and data type. If the current location\n"
344 " is the last entry in the ring, then the 'back' command will have no effect.\n"
349 /* show or go to specific point in ring */
362 index
= (int)strtoul(argv
[1], NULL
, 0);
363 if (index
< 0 || index
>= RING_ENTRIES
) {
364 dbprintf(_("invalid entry: %d\n"), index
);
368 ring_current
= index
;
370 set_cur(iocur_ring
[index
].typ
,
371 iocur_ring
[index
].bb
,
372 iocur_ring
[index
].blen
,
374 iocur_ring
[index
].bbmap
);
384 " The position ring automatically keeps track of each disk location and\n"
385 " structure type for each change of position you make during your xfs_db\n"
386 " session. The last %d most recent entries are kept in the ring.\n"
388 " To display the current list of ring entries type 'ring' by itself on\n"
389 " the command line. The entry highlighted by an asterisk ('*') is the\n"
392 " To move to another entry in the ring type 'ring <num>' where <num> is\n"
393 " your desired entry from the ring position list.\n"
395 " You may also use the 'forward' ('f') or 'back' ('b') commands to move\n"
396 " to the previous or next entry in the ring, respectively.\n"
398 " Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n"
399 " location implicitly. Use the 'push' and 'pop' commands if you wish to\n"
400 " store a specific location explicitly for later return.\n"
409 if (ring_head
== -1) {
410 /* only get here right after startup */
414 iocur_ring
[0] = *iocur_top
;
416 if (ring_current
== ring_head
) {
417 ring_head
= (ring_head
+1)%RING_ENTRIES
;
418 iocur_ring
[ring_head
] = *iocur_top
;
419 if (ring_head
== ring_tail
)
420 ring_tail
= (ring_tail
+1)%RING_ENTRIES
;
421 ring_current
= ring_head
;
423 ring_current
= (ring_current
+1)%RING_ENTRIES
;
424 iocur_ring
[ring_current
] = *iocur_top
;
434 ret
= -libxfs_writebufr(iocur_top
->bp
);
436 dbprintf(_("write error: %s\n"), strerror(ret
));
438 /* re-read buffer from disk */
439 ret
= -libxfs_readbufr(mp
->m_ddev_targp
, iocur_top
->bb
, iocur_top
->bp
,
442 dbprintf(_("read error: %s\n"), strerror(ret
));
450 ret
= -libxfs_writebufr(iocur_top
->bp
);
452 dbprintf(_("write error: %s\n"), strerror(ret
));
455 /* re-read buffer from disk */
456 ret
= -libxfs_readbufr_map(mp
->m_ddev_targp
, iocur_top
->bp
, 0);
458 dbprintf(_("read error: %s\n"), strerror(ret
));
469 xfs_verify_recalc_inode_crc(
472 ASSERT(iocur_top
->ino_buf
);
473 ASSERT(iocur_top
->bp
== bp
);
475 libxfs_dinode_calc_crc(mp
, iocur_top
->data
);
476 iocur_top
->ino_crc_ok
= 1;
480 xfs_verify_recalc_dquot_crc(
483 ASSERT((iocur_top
->dquot_buf
));
484 ASSERT(iocur_top
->bp
== bp
);
486 xfs_update_cksum(iocur_top
->data
, sizeof(struct xfs_dqblk
),
491 xfs_verify_recalc_crc(
494 xfs_buf_update_cksum(bp
, iocur_top
->typ
->crc_off
);
500 bool skip_crc
= false;
503 dbprintf(_("nothing to write\n"));
507 if (!xfs_sb_version_hascrc(&mp
->m_sb
) ||
508 !iocur_top
->bp
->b_ops
||
509 iocur_top
->bp
->b_ops
->verify_write
== xfs_dummy_verify
)
513 if (iocur_top
->ino_buf
) {
514 libxfs_dinode_calc_crc(mp
, iocur_top
->data
);
515 iocur_top
->ino_crc_ok
= 1;
516 } else if (iocur_top
->dquot_buf
) {
517 xfs_update_cksum(iocur_top
->data
,
518 sizeof(struct xfs_dqblk
),
522 if (iocur_top
->bbmap
)
527 /* If we didn't write the crc automatically, re-check inode validity */
528 if (xfs_sb_version_hascrc(&mp
->m_sb
) &&
529 skip_crc
&& iocur_top
->ino_buf
) {
530 iocur_top
->ino_crc_ok
= libxfs_verify_cksum(iocur_top
->data
,
531 mp
->m_sb
.sb_inodesize
,
549 const struct xfs_buf_ops
*ops
= type
? type
->bops
: NULL
;
552 dbprintf(_("set_cur no stack element to set\n"));
556 ino
= iocur_top
->ino
;
557 dirino
= iocur_top
->dirino
;
558 mode
= iocur_top
->mode
;
565 printf(_("xfs_db got a bbmap for %lld\n"), (long long)blknum
);
566 printf(_("\tblock map"));
567 for (i
= 0; i
< bbmap
->nmaps
; i
++)
568 printf(" %lld:%d", (long long)bbmap
->b
[i
].bm_bn
,
572 iocur_top
->bbmap
= malloc(sizeof(struct bbmap
));
573 if (!iocur_top
->bbmap
)
575 memcpy(iocur_top
->bbmap
, bbmap
, sizeof(struct bbmap
));
576 bp
= libxfs_readbuf_map(mp
->m_ddev_targp
, bbmap
->b
,
577 bbmap
->nmaps
, 0, ops
);
579 bp
= libxfs_readbuf(mp
->m_ddev_targp
, blknum
, len
, 0, ops
);
580 iocur_top
->bbmap
= NULL
;
584 * Keep the buffer even if the verifier says it is corrupted.
585 * We're a diagnostic tool, after all.
587 if (!bp
|| (bp
->b_error
&& bp
->b_error
!= -EFSCORRUPTED
&&
588 bp
->b_error
!= -EFSBADCRC
))
590 iocur_top
->buf
= bp
->b_addr
;
593 bp
->b_flags
|= LIBXFS_B_UNCHECKED
;
595 iocur_top
->bb
= blknum
;
596 iocur_top
->blen
= len
;
598 iocur_top
->data
= iocur_top
->buf
;
599 iocur_top
->len
= BBTOB(len
);
600 iocur_top
->off
= blknum
<< BBSHIFT
;
601 iocur_top
->typ
= cur_typ
= type
;
602 iocur_top
->ino
= ino
;
603 iocur_top
->dirino
= dirino
;
604 iocur_top
->mode
= mode
;
605 iocur_top
->ino_buf
= 0;
606 iocur_top
->dquot_buf
= 0;
608 /* store location in ring */
617 struct xfs_buf
*bp
= iocur_top
->bp
;
619 /* Inodes are special; verifier checks all inodes in the chunk */
620 if (type
->typnm
== TYP_INODE
) {
621 xfs_daddr_t b
= iocur_top
->bb
;
625 * Note that this will back up to the beginning of the inode
626 * which contains the current disk location; daddr may change.
628 ino
= XFS_AGINO_TO_INO(mp
, xfs_daddr_to_agno(mp
, b
),
629 ((b
<< BBSHIFT
) >> mp
->m_sb
.sb_inodelog
) %
630 (mp
->m_sb
.sb_agblocks
<< mp
->m_sb
.sb_inopblog
));
635 /* adjust buffer size for types with fields & hence fsize() */
637 int bb_count
; /* type's size in basic blocks */
639 bb_count
= BTOBB(byteize(fsize(type
->fields
,
640 iocur_top
->data
, 0, 0)));
641 set_cur(type
, iocur_top
->bb
, bb_count
, DB_RING_IGN
, NULL
);
643 iocur_top
->typ
= type
;
645 /* verify the buffer if the type has one. */
650 bp
->b_flags
|= LIBXFS_B_UNCHECKED
;
653 if (!(bp
->b_flags
& LIBXFS_B_UPTODATE
))
656 bp
->b_ops
= type
->bops
;
657 bp
->b_ops
->verify_read(bp
);
658 bp
->b_flags
&= ~LIBXFS_B_UNCHECKED
;
666 " The stack is used to explicitly store your location and data type\n"
667 " for later return. The 'push' operation stores the current address\n"
668 " and type on the stack, the 'pop' operation returns you to the\n"
669 " position and datatype of the top entry on the stack.\n"
671 " The 'stack' allows explicit location saves, see 'ring' for implicit\n"
672 " position tracking.\n"
686 for (i
= iocur_sp
; i
> 0; i
--) {
687 snprintf(tagbuf
, sizeof(tagbuf
), "%d: ", i
);
688 print_iocur(tagbuf
, &iocur_base
[i
]);