2 * extent.c --- routines to implement extents support
4 * Copyright (C) 2007 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
24 #include <sys/types.h>
32 * Definitions to be dropped in lib/ext2fs/ext2fs.h
51 struct ext2_extent_handle {
55 struct ext2_inode *inode;
56 struct ext2_inode inodebuf;
60 struct extent_path *path;
63 struct ext2_extent_path {
70 * Useful Debugging stuff
74 static void dbg_show_header(struct ext3_extent_header *eh)
76 printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n",
77 ext2fs_le16_to_cpu(eh->eh_magic),
78 ext2fs_le16_to_cpu(eh->eh_entries),
79 ext2fs_le16_to_cpu(eh->eh_max),
80 ext2fs_le16_to_cpu(eh->eh_depth),
81 ext2fs_le32_to_cpu(eh->eh_generation));
84 static void dbg_show_index(struct ext3_extent_idx *ix)
86 printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n",
87 ext2fs_le32_to_cpu(ix->ei_block),
88 ext2fs_le32_to_cpu(ix->ei_leaf),
89 ext2fs_le16_to_cpu(ix->ei_leaf_hi),
90 ext2fs_le16_to_cpu(ix->ei_unused));
93 static void dbg_show_extent(struct ext3_extent *ex)
95 printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n",
96 ext2fs_le32_to_cpu(ex->ee_block),
97 ext2fs_le32_to_cpu(ex->ee_block) +
98 ext2fs_le16_to_cpu(ex->ee_len) - 1,
99 ext2fs_le16_to_cpu(ex->ee_len),
100 ext2fs_le32_to_cpu(ex->ee_start),
101 ext2fs_le16_to_cpu(ex->ee_start_hi));
104 static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
107 printf("%s: ", desc);
108 printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
109 extent->e_lblk, extent->e_lblk + extent->e_len - 1,
110 extent->e_len, extent->e_pblk);
111 if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
112 fputs("LEAF ", stdout);
113 if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
114 fputs("UNINIT ", stdout);
115 if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
116 fputs("2ND_VISIT ", stdout);
117 if (!extent->e_flags)
118 fputs("(none)", stdout);
124 #define dbg_show_header(eh) do { } while (0)
125 #define dbg_show_index(ix) do { } while (0)
126 #define dbg_show_extent(ex) do { } while (0)
127 #define dbg_print_extent(desc, ex) do { } while (0)
131 * Verify the extent header as being sane
133 errcode_t ext2fs_extent_header_verify(void *ptr, int size)
135 int eh_max, entry_size;
136 struct ext3_extent_header *eh = ptr;
139 if (ext2fs_le16_to_cpu(eh->eh_magic) != EXT3_EXT_MAGIC)
140 return EXT2_ET_EXTENT_HEADER_BAD;
141 if (ext2fs_le16_to_cpu(eh->eh_entries) > ext2fs_le16_to_cpu(eh->eh_max))
142 return EXT2_ET_EXTENT_HEADER_BAD;
143 if (eh->eh_depth == 0)
144 entry_size = sizeof(struct ext3_extent);
146 entry_size = sizeof(struct ext3_extent_idx);
148 eh_max = (size - sizeof(*eh)) / entry_size;
149 /* Allow two extent-sized items at the end of the block, for
150 * ext4_extent_tail with checksum in the future. */
151 if ((ext2fs_le16_to_cpu(eh->eh_max) > eh_max) ||
152 (ext2fs_le16_to_cpu(eh->eh_max) < (eh_max - 2)))
153 return EXT2_ET_EXTENT_HEADER_BAD;
160 * Begin functions to handle an inode's extent information
162 extern void ext2fs_extent_free(ext2_extent_handle_t handle)
170 for (i=1; i <= handle->max_depth; i++) {
171 if (handle->path[i].buf)
172 ext2fs_free_mem(&handle->path[i].buf);
174 ext2fs_free_mem(&handle->path);
176 ext2fs_free_mem(&handle);
179 extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
180 ext2_extent_handle_t *ret_handle)
182 return ext2fs_extent_open2(fs, ino, NULL, ret_handle);
185 extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
186 struct ext2_inode *inode,
187 ext2_extent_handle_t *ret_handle)
189 struct ext2_extent_handle *handle;
192 struct ext3_extent_header *eh;
194 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
197 if ((ino == 0) || (ino > fs->super->s_inodes_count))
198 return EXT2_ET_BAD_INODE_NUM;
200 retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle);
203 memset(handle, 0, sizeof(struct ext2_extent_handle));
209 handle->inode = inode;
211 handle->inode = &handle->inodebuf;
212 retval = ext2fs_read_inode(fs, ino, handle->inode);
217 eh = (struct ext3_extent_header *) &handle->inode->i_block[0];
219 for (i=0; i < EXT2_N_BLOCKS; i++)
220 if (handle->inode->i_block[i])
222 if (i >= EXT2_N_BLOCKS) {
223 eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
226 i = (sizeof(handle->inode->i_block) - sizeof(*eh)) /
227 sizeof(struct ext3_extent);
228 eh->eh_max = ext2fs_cpu_to_le16(i);
229 handle->inode->i_flags |= EXT4_EXTENTS_FL;
232 if (!(handle->inode->i_flags & EXT4_EXTENTS_FL)) {
233 retval = EXT2_ET_INODE_NOT_EXTENT;
237 retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block));
241 handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth);
242 handle->type = ext2fs_le16_to_cpu(eh->eh_magic);
244 retval = ext2fs_get_mem(((handle->max_depth+1) *
245 sizeof(struct extent_path)),
247 memset(handle->path, 0,
248 (handle->max_depth+1) * sizeof(struct extent_path));
249 handle->path[0].buf = (char *) handle->inode->i_block;
251 handle->path[0].left = handle->path[0].entries =
252 ext2fs_le16_to_cpu(eh->eh_entries);
253 handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max);
254 handle->path[0].curr = 0;
255 handle->path[0].end_blk =
256 (EXT2_I_SIZE(handle->inode) + fs->blocksize - 1) >>
257 EXT2_BLOCK_SIZE_BITS(fs->super);
258 handle->path[0].visit_num = 1;
260 handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE;
262 *ret_handle = handle;
266 ext2fs_extent_free(handle);
271 * This function is responsible for (optionally) moving through the
272 * extent tree and then returning the current extent
274 errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
275 int flags, struct ext2fs_extent *extent)
277 struct extent_path *path, *newpath;
278 struct ext3_extent_header *eh;
279 struct ext3_extent_idx *ix = 0;
280 struct ext3_extent *ex;
286 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
289 return EXT2_ET_NO_CURRENT_NODE;
291 orig_op = op = flags & EXT2_EXTENT_MOVE_MASK;
294 path = handle->path + handle->level;
295 if ((orig_op == EXT2_EXTENT_NEXT) ||
296 (orig_op == EXT2_EXTENT_NEXT_LEAF)) {
297 if (handle->level < handle->max_depth) {
299 if (path->visit_num == 0) {
301 op = EXT2_EXTENT_DOWN;
302 } else if (path->left > 0)
303 op = EXT2_EXTENT_NEXT_SIB;
304 else if (handle->level > 0)
307 return EXT2_ET_EXTENT_NO_NEXT;
311 op = EXT2_EXTENT_NEXT_SIB;
312 else if (handle->level > 0)
315 return EXT2_ET_EXTENT_NO_NEXT;
317 if (op != EXT2_EXTENT_NEXT_SIB) {
318 #ifdef DEBUG_GET_EXTENT
319 printf("<<<< OP = %s\n",
320 (op == EXT2_EXTENT_DOWN) ? "down" :
321 ((op == EXT2_EXTENT_UP) ? "up" : "unknown"));
326 if ((orig_op == EXT2_EXTENT_PREV) ||
327 (orig_op == EXT2_EXTENT_PREV_LEAF)) {
328 if (handle->level < handle->max_depth) {
330 if (path->visit_num > 0 ) {
331 /* path->visit_num = 0; */
332 op = EXT2_EXTENT_DOWN_AND_LAST;
333 } else if (path->left < path->entries-1)
334 op = EXT2_EXTENT_PREV_SIB;
335 else if (handle->level > 0)
338 return EXT2_ET_EXTENT_NO_PREV;
341 if (path->left < path->entries-1)
342 op = EXT2_EXTENT_PREV_SIB;
343 else if (handle->level > 0)
346 return EXT2_ET_EXTENT_NO_PREV;
348 if (op != EXT2_EXTENT_PREV_SIB) {
349 #ifdef DEBUG_GET_EXTENT
350 printf("<<<< OP = %s\n",
351 (op == EXT2_EXTENT_DOWN_AND_LAST) ? "down/last" :
352 ((op == EXT2_EXTENT_UP) ? "up" : "unknown"));
357 if (orig_op == EXT2_EXTENT_LAST_LEAF) {
358 if ((handle->level < handle->max_depth) &&
360 op = EXT2_EXTENT_DOWN;
362 op = EXT2_EXTENT_LAST_SIB;
363 #ifdef DEBUG_GET_EXTENT
364 printf("<<<< OP = %s\n",
365 (op == EXT2_EXTENT_DOWN) ? "down" : "last_sib");
370 case EXT2_EXTENT_CURRENT:
373 case EXT2_EXTENT_ROOT:
375 path = handle->path + handle->level;
377 case EXT2_EXTENT_FIRST_SIB:
378 path->left = path->entries;
381 case EXT2_EXTENT_NEXT_SIB:
383 return EXT2_ET_EXTENT_NO_NEXT;
388 eh = (struct ext3_extent_header *) path->buf;
389 ix = EXT_FIRST_INDEX(eh);
395 case EXT2_EXTENT_PREV_SIB:
397 path->left+1 >= path->entries)
398 return EXT2_ET_EXTENT_NO_PREV;
403 if (handle->level < handle->max_depth)
406 case EXT2_EXTENT_LAST_SIB:
407 eh = (struct ext3_extent_header *) path->buf;
408 path->curr = EXT_LAST_EXTENT(eh);
414 if (handle->level <= 0)
415 return EXT2_ET_EXTENT_NO_UP;
419 if ((orig_op == EXT2_EXTENT_PREV) ||
420 (orig_op == EXT2_EXTENT_PREV_LEAF))
423 case EXT2_EXTENT_DOWN:
424 case EXT2_EXTENT_DOWN_AND_LAST:
425 if (!path->curr ||(handle->level >= handle->max_depth))
426 return EXT2_ET_EXTENT_NO_DOWN;
431 retval = ext2fs_get_mem(handle->fs->blocksize,
436 blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
437 ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
438 if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) &&
439 (handle->fs->io != handle->fs->image_io))
440 memset(newpath->buf, 0, handle->fs->blocksize);
442 retval = io_channel_read_blk64(handle->fs->io,
443 blk, 1, newpath->buf);
449 eh = (struct ext3_extent_header *) newpath->buf;
451 retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize);
457 newpath->left = newpath->entries =
458 ext2fs_le16_to_cpu(eh->eh_entries);
459 newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
461 if (path->left > 0) {
463 newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block);
465 newpath->end_blk = path->end_blk;
468 if (op == EXT2_EXTENT_DOWN) {
469 ix = EXT_FIRST_INDEX((struct ext3_extent_header *) eh);
471 path->left = path->entries - 1;
474 ix = EXT_LAST_INDEX((struct ext3_extent_header *) eh);
477 if (handle->level < handle->max_depth)
480 #ifdef DEBUG_GET_EXTENT
481 printf("Down to level %d/%d, end_blk=%llu\n",
482 handle->level, handle->max_depth,
487 return EXT2_ET_OP_NOT_SUPPORTED;
491 return EXT2_ET_NO_CURRENT_NODE;
494 #ifdef DEBUG_GET_EXTENT
495 printf("(Left %d)\n", path->left);
498 if (handle->level == handle->max_depth) {
499 ex = (struct ext3_extent *) ix;
501 extent->e_pblk = ext2fs_le32_to_cpu(ex->ee_start) +
502 ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32);
503 extent->e_lblk = ext2fs_le32_to_cpu(ex->ee_block);
504 extent->e_len = ext2fs_le16_to_cpu(ex->ee_len);
505 extent->e_flags |= EXT2_EXTENT_FLAGS_LEAF;
506 if (extent->e_len > EXT_INIT_MAX_LEN) {
507 extent->e_len -= EXT_INIT_MAX_LEN;
508 extent->e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
511 extent->e_pblk = ext2fs_le32_to_cpu(ix->ei_leaf) +
512 ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
513 extent->e_lblk = ext2fs_le32_to_cpu(ix->ei_block);
514 if (path->left > 0) {
516 end_blk = ext2fs_le32_to_cpu(ix->ei_block);
518 end_blk = path->end_blk;
520 extent->e_len = end_blk - extent->e_lblk;
523 extent->e_flags |= EXT2_EXTENT_FLAGS_SECOND_VISIT;
525 if (((orig_op == EXT2_EXTENT_NEXT_LEAF) ||
526 (orig_op == EXT2_EXTENT_PREV_LEAF)) &&
527 (handle->level != handle->max_depth))
530 if ((orig_op == EXT2_EXTENT_LAST_LEAF) &&
531 ((handle->level != handle->max_depth) ||
538 static errcode_t update_path(ext2_extent_handle_t handle)
542 struct ext3_extent_idx *ix;
544 if (handle->level == 0) {
545 retval = ext2fs_write_inode(handle->fs, handle->ino,
548 ix = handle->path[handle->level - 1].curr;
549 blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
550 ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
552 retval = io_channel_write_blk64(handle->fs->io,
553 blk, 1, handle->path[handle->level].buf);
559 errcode_t ext2fs_extent_save_path(ext2_extent_handle_t handle,
560 ext2_extent_path_t *ret_path)
562 ext2_extent_path_t save_path;
563 struct ext2fs_extent extent;
564 struct ext2_extent_info info;
567 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
571 retval = ext2fs_extent_get_info(handle, &info);
575 retval = ext2fs_get_mem(sizeof(struct ext2_extent_path), &save_path);
578 memset(save_path, 0, sizeof(struct ext2_extent_path));
580 save_path->magic = EXT2_ET_MAGIC_EXTENT_PATH;
581 save_path->leaf_height = info.max_depth - info.curr_level - 1;
582 save_path->lblk = extent.e_lblk;
584 *ret_path = save_path;
588 errcode_t ext2fs_extent_free_path(ext2_extent_path_t path)
590 EXT2_CHECK_MAGIC(path, EXT2_ET_MAGIC_EXTENT_PATH);
592 ext2fs_free_mem(&path);
598 * Go to the node at leaf_level which contains logical block blk.
600 * leaf_level is height from the leaf node level, i.e.
601 * leaf_level 0 is at leaf node, leaf_level 1 is 1 above etc.
603 * If "blk" has no mapping (hole) then handle is left at last
606 static errcode_t extent_goto(ext2_extent_handle_t handle,
607 int leaf_level, blk64_t blk)
609 struct ext2fs_extent extent;
612 retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent);
614 if (retval == EXT2_ET_EXTENT_NO_NEXT)
615 retval = EXT2_ET_EXTENT_NOT_FOUND;
619 if (leaf_level > handle->max_depth) {
621 printf("leaf level %d greater than tree depth %d\n",
622 leaf_level, handle->max_depth);
624 return EXT2_ET_OP_NOT_SUPPORTED;
628 printf("goto extent ino %u, level %d, %llu\n", handle->ino,
632 #ifdef DEBUG_GOTO_EXTENTS
633 dbg_print_extent("root", &extent);
636 if (handle->max_depth - handle->level == leaf_level) {
637 /* block is in this &extent */
638 if ((blk >= extent.e_lblk) &&
639 (blk < extent.e_lblk + extent.e_len))
641 if (blk < extent.e_lblk) {
642 retval = ext2fs_extent_get(handle,
643 EXT2_EXTENT_PREV_SIB,
645 return EXT2_ET_EXTENT_NOT_FOUND;
647 retval = ext2fs_extent_get(handle,
648 EXT2_EXTENT_NEXT_SIB,
650 if (retval == EXT2_ET_EXTENT_NO_NEXT)
651 return EXT2_ET_EXTENT_NOT_FOUND;
657 retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_SIB,
659 if (retval == EXT2_ET_EXTENT_NO_NEXT)
664 #ifdef DEBUG_GOTO_EXTENTS
665 dbg_print_extent("next", &extent);
667 if (blk == extent.e_lblk)
669 if (blk > extent.e_lblk)
672 retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_SIB,
677 #ifdef DEBUG_GOTO_EXTENTS
678 dbg_print_extent("prev", &extent);
682 retval = ext2fs_extent_get(handle, EXT2_EXTENT_DOWN,
687 #ifdef DEBUG_GOTO_EXTENTS
688 dbg_print_extent("down", &extent);
693 errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
696 return extent_goto(handle, 0, blk);
700 * Traverse back up to root fixing parents of current node as needed.
702 * If we changed start of first entry in a node, fix parent index start
705 * Safe to call for any position in node; if not at the first entry,
706 * will simply return.
708 static errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
712 struct extent_path *path;
713 struct ext2fs_extent extent;
715 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
717 if (!(handle->fs->flags & EXT2_FLAG_RW))
718 return EXT2_ET_RO_FILSYS;
721 return EXT2_ET_NO_CURRENT_NODE;
723 path = handle->path + handle->level;
725 return EXT2_ET_NO_CURRENT_NODE;
727 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
731 /* modified node's start block */
732 start = extent.e_lblk;
734 /* traverse up until index not first, or startblk matches, or top */
735 while (handle->level > 0 &&
736 (path->left == path->entries - 1)) {
737 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
740 if (extent.e_lblk == start)
742 path = handle->path + handle->level;
743 extent.e_len += (extent.e_lblk - start);
744 extent.e_lblk = start;
745 retval = ext2fs_extent_replace(handle, 0, &extent);
751 /* put handle back to where we started */
752 retval = ext2fs_extent_goto(handle, start);
757 errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle,
758 int flags EXT2FS_ATTR((unused)),
759 struct ext2fs_extent *extent)
761 struct extent_path *path;
762 struct ext3_extent_idx *ix;
763 struct ext3_extent *ex;
765 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
767 if (!(handle->fs->flags & EXT2_FLAG_RW))
768 return EXT2_ET_RO_FILSYS;
771 return EXT2_ET_NO_CURRENT_NODE;
773 path = handle->path + handle->level;
775 return EXT2_ET_NO_CURRENT_NODE;
778 printf("extent replace: %u ", handle->ino);
779 dbg_print_extent(0, extent);
782 if (handle->level == handle->max_depth) {
785 ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk);
786 ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
787 ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
788 if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
789 if (extent->e_len > EXT_UNINIT_MAX_LEN)
790 return EXT2_ET_EXTENT_INVALID_LENGTH;
791 ex->ee_len = ext2fs_cpu_to_le16(extent->e_len +
794 if (extent->e_len > EXT_INIT_MAX_LEN)
795 return EXT2_ET_EXTENT_INVALID_LENGTH;
796 ex->ee_len = ext2fs_cpu_to_le16(extent->e_len);
801 ix->ei_leaf = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
802 ix->ei_leaf_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
803 ix->ei_block = ext2fs_cpu_to_le32(extent->e_lblk);
811 * allocate a new block, move half the current node to it, and update parent
813 * handle will be left pointing at original record.
815 static errcode_t extent_node_split(ext2_extent_handle_t handle)
817 errcode_t retval = 0;
818 blk64_t new_node_pblk;
819 blk64_t new_node_start;
821 blk64_t goal_blk = 0;
823 char *block_buf = NULL;
824 struct ext2fs_extent extent;
825 struct extent_path *path, *newpath = 0;
826 struct ext3_extent_header *eh, *neweh;
829 struct ext2_extent_info info;
832 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
834 if (!(handle->fs->flags & EXT2_FLAG_RW))
835 return EXT2_ET_RO_FILSYS;
838 return EXT2_ET_NO_CURRENT_NODE;
841 printf("splitting node at level %d\n", handle->level);
843 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
847 retval = ext2fs_extent_get_info(handle, &info);
851 /* save the position we were originally splitting... */
852 orig_height = info.max_depth - info.curr_level;
853 orig_lblk = extent.e_lblk;
855 /* Is there room in the parent for a new entry? */
857 (handle->path[handle->level - 1].entries >=
858 handle->path[handle->level - 1].max_entries)) {
861 printf("parent level %d full; splitting it too\n",
864 /* split the parent */
865 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
868 goal_blk = extent.e_pblk;
870 retval = extent_node_split(handle);
874 /* get handle back to our original split position */
875 retval = extent_goto(handle, orig_height, orig_lblk);
880 /* At this point, parent should have room for this split */
881 path = handle->path + handle->level;
883 return EXT2_ET_NO_CURRENT_NODE;
885 /* extent header of the current node we'll split */
886 eh = (struct ext3_extent_header *)path->buf;
888 /* splitting root level means moving them all out */
889 if (handle->level == 0) {
891 tocopy = ext2fs_le16_to_cpu(eh->eh_entries);
892 retval = ext2fs_get_mem(((handle->max_depth+2) *
893 sizeof(struct extent_path)),
898 ((handle->max_depth+2) * sizeof(struct extent_path)));
900 tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2;
904 printf("will copy out %d of %d entries at level %d\n",
905 tocopy, ext2fs_le16_to_cpu(eh->eh_entries),
911 printf("Nothing to copy to new block!\n");
913 retval = EXT2_ET_CANT_SPLIT_EXTENT;
917 /* first we need a new block, or can do nothing. */
918 block_buf = malloc(handle->fs->blocksize);
925 dgrp_t group = ext2fs_group_of_ino(handle->fs, handle->ino);
926 __u8 log_flex = handle->fs->super->s_log_groups_per_flex;
929 group = group & ~((1 << (log_flex)) - 1);
930 goal_blk = (group * handle->fs->super->s_blocks_per_group) +
931 handle->fs->super->s_first_data_block;
933 retval = ext2fs_alloc_block2(handle->fs, goal_blk, block_buf,
939 printf("will copy to new node at block %lu\n",
940 (unsigned long) new_node_pblk);
943 /* Copy data into new block buffer */
944 /* First the header for the new block... */
945 neweh = (struct ext3_extent_header *) block_buf;
946 memcpy(neweh, eh, sizeof(struct ext3_extent_header));
947 neweh->eh_entries = ext2fs_cpu_to_le16(tocopy);
948 neweh->eh_max = ext2fs_cpu_to_le16((handle->fs->blocksize -
949 sizeof(struct ext3_extent_header)) /
950 sizeof(struct ext3_extent));
952 /* then the entries for the new block... */
953 memcpy(EXT_FIRST_INDEX(neweh),
954 EXT_FIRST_INDEX(eh) +
955 (ext2fs_le16_to_cpu(eh->eh_entries) - tocopy),
956 sizeof(struct ext3_extent_idx) * tocopy);
958 new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
960 /* ...and write the new node block out to disk. */
961 retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1,
967 /* OK! we've created the new node; now adjust the tree */
969 /* current path now has fewer active entries, we copied some out */
970 if (handle->level == 0) {
971 memcpy(newpath, path,
972 sizeof(struct extent_path) * (handle->max_depth+1));
973 handle->path = newpath;
977 path->left = path->max_entries - 1;
979 eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth);
981 path->entries -= tocopy;
982 path->left -= tocopy;
985 eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
986 /* this writes out the node, incl. the modified header */
987 retval = update_path(handle);
991 /* now go up and insert/replace index for new node we created */
993 retval = ext2fs_extent_get(handle, EXT2_EXTENT_FIRST_SIB, &extent);
997 extent.e_lblk = new_node_start;
998 extent.e_pblk = new_node_pblk;
999 extent.e_len = handle->path[0].end_blk - extent.e_lblk;
1000 retval = ext2fs_extent_replace(handle, 0, &extent);
1004 __u32 new_node_length;
1006 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
1007 /* will insert after this one; it's length is shorter now */
1008 new_node_length = new_node_start - extent.e_lblk;
1009 extent.e_len -= new_node_length;
1010 retval = ext2fs_extent_replace(handle, 0, &extent);
1014 /* now set up the new extent and insert it */
1015 extent.e_lblk = new_node_start;
1016 extent.e_pblk = new_node_pblk;
1017 extent.e_len = new_node_length;
1018 retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &extent);
1023 /* get handle back to our original position */
1024 retval = extent_goto(handle, orig_height, orig_lblk);
1028 /* new node hooked in, so update inode block count (do this here?) */
1029 handle->inode->i_blocks += handle->fs->blocksize / 512;
1030 retval = ext2fs_write_inode(handle->fs, handle->ino,
1037 ext2fs_free_mem(&newpath);
1043 errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
1044 struct ext2fs_extent *extent)
1046 struct extent_path *path;
1047 struct ext3_extent_idx *ix;
1048 struct ext3_extent_header *eh;
1051 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1053 if (!(handle->fs->flags & EXT2_FLAG_RW))
1054 return EXT2_ET_RO_FILSYS;
1057 return EXT2_ET_NO_CURRENT_NODE;
1060 printf("extent insert: %u ", handle->ino);
1061 dbg_print_extent(0, extent);
1064 path = handle->path + handle->level;
1066 if (path->entries >= path->max_entries) {
1067 if (flags & EXT2_EXTENT_INSERT_NOSPLIT) {
1068 return EXT2_ET_CANT_INSERT_EXTENT;
1071 printf("node full (level %d) - splitting\n",
1074 retval = extent_node_split(handle);
1077 path = handle->path + handle->level;
1081 eh = (struct ext3_extent_header *) path->buf;
1084 if (flags & EXT2_EXTENT_INSERT_AFTER) {
1089 ix = EXT_FIRST_INDEX(eh);
1093 if (path->left >= 0)
1095 (path->left+1) * sizeof(struct ext3_extent_idx));
1099 eh = (struct ext3_extent_header *) path->buf;
1100 eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
1102 retval = ext2fs_extent_replace(handle, 0, extent);
1106 retval = update_path(handle);
1113 ext2fs_extent_delete(handle, 0);
1118 * Sets the physical block for a logical file block in the extent tree.
1120 * May: map unmapped, unmap mapped, or remap mapped blocks.
1122 * Mapping an unmapped block adds a single-block extent.
1124 * Unmapping first or last block modifies extent in-place
1125 * - But may need to fix parent's starts too in first-block case
1127 * Mapping any unmapped block requires adding a (single-block) extent
1128 * and inserting into proper point in tree.
1130 * Modifying (unmapping or remapping) a block in the middle
1131 * of an extent requires splitting the extent.
1132 * - Remapping case requires new single-block extent.
1134 * Remapping first or last block adds an extent.
1136 * We really need extent adding to be smart about merging.
1139 errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
1140 blk64_t logical, blk64_t physical, int flags)
1142 errcode_t ec, retval = 0;
1143 int mapped = 1; /* logical is mapped? */
1145 int extent_uninit = 0;
1146 int prev_uninit = 0;
1147 int next_uninit = 0;
1149 int max_len = EXT_INIT_MAX_LEN;
1150 int has_prev, has_next;
1152 struct extent_path *path;
1153 struct ext2fs_extent extent, next_extent, prev_extent;
1154 struct ext2fs_extent newextent;
1155 struct ext2_extent_info info;
1157 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1160 printf("set_bmap ino %u log %lld phys %lld flags %d\n",
1161 handle->ino, logical, physical, flags);
1164 if (!(handle->fs->flags & EXT2_FLAG_RW))
1165 return EXT2_ET_RO_FILSYS;
1168 return EXT2_ET_NO_CURRENT_NODE;
1170 path = handle->path + handle->level;
1172 if (flags & EXT2_EXTENT_SET_BMAP_UNINIT) {
1174 max_len = EXT_UNINIT_MAX_LEN;
1177 /* if (re)mapping, set up new extent to insert */
1179 newextent.e_len = 1;
1180 newextent.e_pblk = physical;
1181 newextent.e_lblk = logical;
1182 newextent.e_flags = EXT2_EXTENT_FLAGS_LEAF;
1184 newextent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
1187 /* special case if the extent tree is completely empty */
1188 if ((handle->max_depth == 0) && (path->entries == 0)) {
1189 retval = ext2fs_extent_insert(handle, 0, &newextent);
1193 /* save our original location in the extent tree */
1194 if ((retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
1196 if (retval != EXT2_ET_NO_CURRENT_NODE)
1198 memset(&extent, 0, sizeof(extent));
1200 if ((retval = ext2fs_extent_get_info(handle, &info)))
1202 orig_height = info.max_depth - info.curr_level;
1203 orig_lblk = extent.e_lblk;
1205 /* go to the logical spot we want to (re/un)map */
1206 retval = ext2fs_extent_goto(handle, logical);
1208 if (retval == EXT2_ET_EXTENT_NOT_FOUND) {
1213 printf("block %llu already unmapped\n",
1223 * This may be the extent *before* the requested logical,
1224 * if it's currently unmapped.
1226 * Get the previous and next leaf extents, if they are present.
1228 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
1231 if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1233 retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &next_extent);
1236 if (retval != EXT2_ET_EXTENT_NO_NEXT)
1239 dbg_print_extent("set_bmap: next_extent",
1242 if (next_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1245 retval = ext2fs_extent_goto(handle, logical);
1246 if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND)
1248 retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_LEAF, &prev_extent);
1251 if (retval != EXT2_ET_EXTENT_NO_PREV)
1255 dbg_print_extent("set_bmap: prev_extent",
1257 if (prev_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1260 retval = ext2fs_extent_goto(handle, logical);
1261 if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND)
1264 /* check if already pointing to the requested physical */
1265 if (mapped && (new_uninit == extent_uninit) &&
1266 (extent.e_pblk + (logical - extent.e_lblk) == physical)) {
1268 printf("physical block (at %llu) unchanged\n", logical);
1275 printf("mapping unmapped logical block %llu\n", logical);
1277 if ((logical == extent.e_lblk + extent.e_len) &&
1278 (physical == extent.e_pblk + extent.e_len) &&
1279 (new_uninit == extent_uninit) &&
1280 ((int) extent.e_len < max_len-1)) {
1282 retval = ext2fs_extent_replace(handle, 0, &extent);
1283 } else if ((logical == extent.e_lblk - 1) &&
1284 (physical == extent.e_pblk - 1) &&
1285 (new_uninit == extent_uninit) &&
1286 ((int) extent.e_len < max_len - 1)) {
1290 retval = ext2fs_extent_replace(handle, 0, &extent);
1291 } else if (has_next &&
1292 (logical == next_extent.e_lblk - 1) &&
1293 (physical == next_extent.e_pblk - 1) &&
1294 (new_uninit == next_uninit) &&
1295 ((int) next_extent.e_len < max_len - 1)) {
1296 retval = ext2fs_extent_get(handle,
1297 EXT2_EXTENT_NEXT_LEAF,
1301 next_extent.e_len++;
1302 next_extent.e_lblk--;
1303 next_extent.e_pblk--;
1304 retval = ext2fs_extent_replace(handle, 0, &next_extent);
1305 } else if (logical < extent.e_lblk)
1306 retval = ext2fs_extent_insert(handle, 0, &newextent);
1308 retval = ext2fs_extent_insert(handle,
1309 EXT2_EXTENT_INSERT_AFTER, &newextent);
1312 retval = ext2fs_extent_fix_parents(handle);
1315 } else if ((logical == extent.e_lblk) && (extent.e_len == 1)) {
1317 printf("(re/un)mapping only block in extent\n");
1320 retval = ext2fs_extent_replace(handle, 0, &newextent);
1322 retval = ext2fs_extent_delete(handle, 0);
1325 ec = ext2fs_extent_fix_parents(handle);
1326 if (ec != EXT2_ET_NO_CURRENT_NODE)
1332 } else if (logical == extent.e_lblk + extent.e_len - 1) {
1334 printf("(re/un)mapping last block in extent\n");
1338 (logical == (next_extent.e_lblk - 1)) &&
1339 (physical == (next_extent.e_pblk - 1)) &&
1340 (new_uninit == next_uninit) &&
1341 ((int) next_extent.e_len < max_len - 1)) {
1342 retval = ext2fs_extent_get(handle,
1343 EXT2_EXTENT_NEXT_LEAF, &next_extent);
1346 next_extent.e_len++;
1347 next_extent.e_lblk--;
1348 next_extent.e_pblk--;
1349 retval = ext2fs_extent_replace(handle, 0,
1354 retval = ext2fs_extent_insert(handle,
1355 EXT2_EXTENT_INSERT_AFTER, &newextent);
1358 /* Now pointing at inserted extent; move back to prev */
1359 retval = ext2fs_extent_get(handle,
1360 EXT2_EXTENT_PREV_LEAF,
1366 retval = ext2fs_extent_replace(handle, 0, &extent);
1369 } else if (logical == extent.e_lblk) {
1371 printf("(re/un)mapping first block in extent\n");
1375 (logical == (prev_extent.e_lblk +
1376 prev_extent.e_len)) &&
1377 (physical == (prev_extent.e_pblk +
1378 prev_extent.e_len)) &&
1379 (new_uninit == prev_uninit) &&
1380 ((int) prev_extent.e_len < max_len-1)) {
1381 retval = ext2fs_extent_get(handle,
1382 EXT2_EXTENT_PREV_LEAF, &prev_extent);
1385 prev_extent.e_len++;
1386 retval = ext2fs_extent_replace(handle, 0,
1389 retval = ext2fs_extent_insert(handle,
1393 retval = ext2fs_extent_get(handle,
1394 EXT2_EXTENT_NEXT_LEAF,
1402 retval = ext2fs_extent_replace(handle, 0, &extent);
1409 printf("(re/un)mapping in middle of extent\n");
1411 /* need to split this extent; later */
1413 orig_length = extent.e_len;
1415 /* shorten pre-split extent */
1416 extent.e_len = (logical - extent.e_lblk);
1417 retval = ext2fs_extent_replace(handle, 0, &extent);
1420 /* insert our new extent, if any */
1422 /* insert new extent after current */
1423 retval = ext2fs_extent_insert(handle,
1424 EXT2_EXTENT_INSERT_AFTER, &newextent);
1428 /* add post-split extent */
1429 extent.e_pblk += extent.e_len + 1;
1430 extent.e_lblk += extent.e_len + 1;
1431 extent.e_len = orig_length - extent.e_len - 1;
1432 retval = ext2fs_extent_insert(handle,
1433 EXT2_EXTENT_INSERT_AFTER, &extent);
1439 /* get handle back to its position */
1440 if (orig_height > handle->max_depth)
1441 orig_height = handle->max_depth; /* In case we shortened the tree */
1442 extent_goto(handle, orig_height, orig_lblk);
1446 errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags)
1448 struct extent_path *path;
1450 struct ext3_extent_header *eh;
1451 errcode_t retval = 0;
1453 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1455 if (!(handle->fs->flags & EXT2_FLAG_RW))
1456 return EXT2_ET_RO_FILSYS;
1459 return EXT2_ET_NO_CURRENT_NODE;
1463 struct ext2fs_extent extent;
1465 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
1468 printf("extent delete %u ", handle->ino);
1469 dbg_print_extent(0, &extent);
1474 path = handle->path + handle->level;
1476 return EXT2_ET_NO_CURRENT_NODE;
1481 memmove(cp, cp + sizeof(struct ext3_extent_idx),
1482 path->left * sizeof(struct ext3_extent_idx));
1485 struct ext3_extent_idx *ix = path->curr;
1489 if (--path->entries == 0)
1492 /* if non-root node has no entries left, remove it & parent ptr to it */
1493 if (path->entries == 0 && handle->level) {
1494 if (!(flags & EXT2_EXTENT_DELETE_KEEP_EMPTY)) {
1495 struct ext2fs_extent extent;
1497 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP,
1502 retval = ext2fs_extent_delete(handle, flags);
1503 handle->inode->i_blocks -= handle->fs->blocksize / 512;
1504 retval = ext2fs_write_inode(handle->fs, handle->ino,
1506 ext2fs_block_alloc_stats2(handle->fs,
1510 eh = (struct ext3_extent_header *) path->buf;
1511 eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
1512 if ((path->entries == 0) && (handle->level == 0))
1513 eh->eh_depth = handle->max_depth = 0;
1514 retval = update_path(handle);
1519 errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
1520 struct ext2_extent_info *info)
1522 struct extent_path *path;
1524 EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1526 memset(info, 0, sizeof(struct ext2_extent_info));
1528 path = handle->path + handle->level;
1531 info->curr_entry = ((char *) path->curr - path->buf) /
1532 sizeof(struct ext3_extent_idx);
1534 info->curr_entry = 0;
1535 info->num_entries = path->entries;
1536 info->max_entries = path->max_entries;
1537 info->bytes_avail = (path->max_entries - path->entries) *
1538 sizeof(struct ext3_extent);
1541 info->curr_level = handle->level;
1542 info->max_depth = handle->max_depth;
1543 info->max_lblk = ((__u64) 1 << 32) - 1;
1544 info->max_pblk = ((__u64) 1 << 48) - 1;
1545 info->max_len = (1UL << 15);
1546 info->max_uninit_len = (1UL << 15) - 1;
1555 #include "debugfs.h"
1558 * Hook in new commands into debugfs
1560 const char *debug_prog_name = "tst_extents";
1561 extern ss_request_table extent_cmds;
1562 ss_request_table *extra_cmds = &extent_cmds;
1564 ext2_ino_t current_ino = 0;
1565 ext2_extent_handle_t current_handle;
1567 int common_extent_args_process(int argc, char *argv[], int min_argc,
1568 int max_argc, const char *cmd,
1569 const char *usage, int flags)
1571 if (common_args_process(argc, argv, min_argc, max_argc, cmd,
1575 if (!current_handle) {
1576 com_err(cmd, 0, "Extent handle not open");
1582 void do_inode(int argc, char *argv[])
1586 struct ext3_extent_header *eh;
1589 if (check_fs_open(argv[0]))
1594 printf("Current inode is %d\n", current_ino);
1596 printf("No current inode\n");
1600 if (common_inode_args_process(argc, argv, &inode, 0)) {
1606 retval = ext2fs_extent_open(current_fs, inode, ¤t_handle);
1608 com_err(argv[1], retval, "while opening extent handle");
1612 current_ino = inode;
1614 printf("Loaded inode %d\n", current_ino);
1619 void generic_goto_node(char *cmd_name, int op)
1621 struct ext2fs_extent extent;
1624 if (check_fs_open(cmd_name))
1627 if (!current_handle) {
1628 com_err(cmd_name, 0, "Extent handle not open");
1632 retval = ext2fs_extent_get(current_handle, op, &extent);
1634 com_err(cmd_name, retval, 0);
1637 dbg_print_extent(0, &extent);
1640 void do_current_node(int argc, char *argv[])
1642 generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);
1645 void do_root_node(int argc, char *argv[])
1647 generic_goto_node(argv[0], EXT2_EXTENT_ROOT);
1650 void do_last_leaf(int argc, char *argv[])
1652 generic_goto_node(argv[0], EXT2_EXTENT_LAST_LEAF);
1655 void do_first_sib(int argc, char *argv[])
1657 generic_goto_node(argv[0], EXT2_EXTENT_FIRST_SIB);
1660 void do_last_sib(int argc, char *argv[])
1662 generic_goto_node(argv[0], EXT2_EXTENT_LAST_SIB);
1665 void do_next_sib(int argc, char *argv[])
1667 generic_goto_node(argv[0], EXT2_EXTENT_NEXT_SIB);
1670 void do_prev_sib(int argc, char *argv[])
1672 generic_goto_node(argv[0], EXT2_EXTENT_PREV_SIB);
1675 void do_next_leaf(int argc, char *argv[])
1677 generic_goto_node(argv[0], EXT2_EXTENT_NEXT_LEAF);
1680 void do_prev_leaf(int argc, char *argv[])
1682 generic_goto_node(argv[0], EXT2_EXTENT_PREV_LEAF);
1685 void do_next(int argc, char *argv[])
1687 generic_goto_node(argv[0], EXT2_EXTENT_NEXT);
1690 void do_prev(int argc, char *argv[])
1692 generic_goto_node(argv[0], EXT2_EXTENT_PREV);
1695 void do_up(int argc, char *argv[])
1697 generic_goto_node(argv[0], EXT2_EXTENT_UP);
1700 void do_down(int argc, char *argv[])
1702 generic_goto_node(argv[0], EXT2_EXTENT_DOWN);
1705 void do_delete_node(int argc, char *argv[])
1710 if (common_extent_args_process(argc, argv, 1, 1, "delete_node",
1711 "", CHECK_FS_RW | CHECK_FS_BITMAPS))
1714 retval = ext2fs_extent_delete(current_handle, 0);
1716 com_err(argv[0], retval, 0);
1719 if (current_handle->path && current_handle->path[0].curr)
1720 do_current_node(argc, argv);
1723 void do_replace_node(int argc, char *argv[])
1725 const char *usage = "[--uninit] <lblk> <len> <pblk>";
1727 struct ext2fs_extent extent;
1730 if (common_extent_args_process(argc, argv, 3, 5, "replace_node",
1731 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
1736 if (!strcmp(argv[1], "--uninit")) {
1739 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
1743 fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
1747 extent.e_lblk = parse_ulong(argv[1], argv[0], "logical block", &err);
1751 extent.e_len = parse_ulong(argv[2], argv[0], "logical block", &err);
1755 extent.e_pblk = parse_ulong(argv[3], argv[0], "logical block", &err);
1759 retval = ext2fs_extent_replace(current_handle, 0, &extent);
1761 com_err(argv[0], retval, 0);
1764 do_current_node(argc, argv);
1767 void do_split_node(int argc, char *argv[])
1770 struct ext2fs_extent extent;
1773 if (common_extent_args_process(argc, argv, 1, 1, "split_node",
1774 "", CHECK_FS_RW | CHECK_FS_BITMAPS))
1777 retval = extent_node_split(current_handle);
1779 com_err(argv[0], retval, 0);
1782 do_current_node(argc, argv);
1785 void do_insert_node(int argc, char *argv[])
1787 const char *usage = "[--after] [--uninit] <lblk> <len> <pblk>";
1789 struct ext2fs_extent extent;
1794 if (common_extent_args_process(argc, argv, 3, 6, "insert_node",
1795 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
1803 if (!strcmp(argv[1], "--after")) {
1806 flags |= EXT2_EXTENT_INSERT_AFTER;
1809 if (!strcmp(argv[1], "--uninit")) {
1812 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
1819 fprintf(stderr, "usage: %s %s\n", cmd, usage);
1823 extent.e_lblk = parse_ulong(argv[1], cmd,
1824 "logical block", &err);
1828 extent.e_len = parse_ulong(argv[2], cmd,
1833 extent.e_pblk = parse_ulong(argv[3], cmd,
1834 "pysical block", &err);
1838 retval = ext2fs_extent_insert(current_handle, flags, &extent);
1840 com_err(cmd, retval, 0);
1843 do_current_node(argc, argv);
1846 void do_set_bmap(int argc, char **argv)
1848 const char *usage = "[--uninit] <lblk> <pblk>";
1852 char *cmd = argv[0];
1856 if (common_extent_args_process(argc, argv, 3, 5, "set_bmap",
1857 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
1860 if (argc > 2 && !strcmp(argv[1], "--uninit")) {
1863 flags |= EXT2_EXTENT_SET_BMAP_UNINIT;
1867 fprintf(stderr, "Usage: %s %s\n", cmd, usage);
1871 logical = parse_ulong(argv[1], cmd,
1872 "logical block", &err);
1876 physical = parse_ulong(argv[2], cmd,
1877 "physical block", &err);
1881 retval = ext2fs_extent_set_bmap(current_handle, logical,
1882 (blk64_t) physical, flags);
1884 com_err(cmd, retval, 0);
1887 if (current_handle->path && current_handle->path[0].curr)
1888 do_current_node(argc, argv);
1891 void do_print_all(int argc, char **argv)
1893 const char *usage = "[--leaf-only|--reverse|--reverse-leaf]";
1894 struct ext2fs_extent extent;
1896 errcode_t end_err = EXT2_ET_EXTENT_NO_NEXT;
1897 int op = EXT2_EXTENT_NEXT;
1898 int first_op = EXT2_EXTENT_ROOT;
1901 if (common_extent_args_process(argc, argv, 1, 2, "print_all",
1906 if (!strcmp(argv[1], "--leaf-only"))
1907 op = EXT2_EXTENT_NEXT_LEAF;
1908 else if (!strcmp(argv[1], "--reverse")) {
1909 op = EXT2_EXTENT_PREV;
1910 first_op = EXT2_EXTENT_LAST_LEAF;
1911 end_err = EXT2_ET_EXTENT_NO_PREV;
1912 } else if (!strcmp(argv[1], "--reverse-leaf")) {
1913 op = EXT2_EXTENT_PREV_LEAF;
1914 first_op = EXT2_EXTENT_LAST_LEAF;
1915 end_err = EXT2_ET_EXTENT_NO_PREV;
1917 fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
1922 retval = ext2fs_extent_get(current_handle, first_op, &extent);
1924 com_err(argv[0], retval, 0);
1927 dbg_print_extent(0, &extent);
1930 retval = ext2fs_extent_get(current_handle, op, &extent);
1931 if (retval == end_err)
1935 com_err(argv[0], retval, 0);
1938 dbg_print_extent(0, &extent);
1942 void do_info(int argc, char **argv)
1944 struct ext2fs_extent extent;
1945 struct ext2_extent_info info;
1948 if (common_extent_args_process(argc, argv, 1, 1, "info", "", 0))
1951 retval = ext2fs_extent_get_info(current_handle, &info);
1953 com_err(argv[0], retval, 0);
1957 retval = ext2fs_extent_get(current_handle,
1958 EXT2_EXTENT_CURRENT, &extent);
1960 com_err(argv[0], retval, 0);
1964 dbg_print_extent(0, &extent);
1966 printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
1967 info.curr_entry, info.num_entries, info.max_entries,
1968 info.bytes_avail, info.curr_level, info.max_depth);
1969 printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk,
1971 printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len,
1972 info.max_uninit_len);
1975 void do_goto_block(int argc, char **argv)
1977 struct ext2fs_extent extent;
1979 int op = EXT2_EXTENT_NEXT_LEAF;
1983 if (common_extent_args_process(argc, argv, 2, 3, "goto_block",
1984 "block [level]", 0))
1987 if (strtoblk(argv[0], argv[1], &blk))
1991 level = parse_ulong(argv[2], argv[0], "level", &err);
1996 retval = extent_goto(current_handle, level, (blk64_t) blk);
1999 com_err(argv[0], retval,
2000 "while trying to go to block %llu, level %d",
2001 (unsigned long long) blk, level);
2005 generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);