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