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 Public
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
;
59 struct extent_path
*path
;
62 struct ext2_extent_path
{
69 * Useful Debugging stuff
73 static void dbg_show_header(struct ext3_extent_header
*eh
)
75 printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n",
76 ext2fs_le16_to_cpu(eh
->eh_magic
),
77 ext2fs_le16_to_cpu(eh
->eh_entries
),
78 ext2fs_le16_to_cpu(eh
->eh_max
),
79 ext2fs_le16_to_cpu(eh
->eh_depth
),
80 ext2fs_le32_to_cpu(eh
->eh_generation
));
83 static void dbg_show_index(struct ext3_extent_idx
*ix
)
85 printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n",
86 ext2fs_le32_to_cpu(ix
->ei_block
),
87 ext2fs_le32_to_cpu(ix
->ei_leaf
),
88 ext2fs_le16_to_cpu(ix
->ei_leaf_hi
),
89 ext2fs_le16_to_cpu(ix
->ei_unused
));
92 static void dbg_show_extent(struct ext3_extent
*ex
)
94 printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n",
95 ext2fs_le32_to_cpu(ex
->ee_block
),
96 ext2fs_le32_to_cpu(ex
->ee_block
) +
97 ext2fs_le16_to_cpu(ex
->ee_len
) - 1,
98 ext2fs_le16_to_cpu(ex
->ee_len
),
99 ext2fs_le32_to_cpu(ex
->ee_start
),
100 ext2fs_le16_to_cpu(ex
->ee_start_hi
));
103 static void dbg_print_extent(char *desc
, struct ext2fs_extent
*extent
)
106 printf("%s: ", desc
);
107 printf("extent: lblk %llu--%llu, len %lu, pblk %llu, flags: ",
108 extent
->e_lblk
, extent
->e_lblk
+ extent
->e_len
- 1,
109 extent
->e_len
, extent
->e_pblk
);
110 if (extent
->e_flags
& EXT2_EXTENT_FLAGS_LEAF
)
111 fputs("LEAF ", stdout
);
112 if (extent
->e_flags
& EXT2_EXTENT_FLAGS_UNINIT
)
113 fputs("UNINIT ", stdout
);
114 if (extent
->e_flags
& EXT2_EXTENT_FLAGS_SECOND_VISIT
)
115 fputs("2ND_VISIT ", stdout
);
116 if (!extent
->e_flags
)
117 fputs("(none)", stdout
);
123 #define dbg_show_header(eh) do { } while (0)
124 #define dbg_show_index(ix) do { } while (0)
125 #define dbg_show_extent(ex) do { } while (0)
126 #define dbg_print_extent(desc, ex) do { } while (0)
130 * Verify the extent header as being sane
132 errcode_t
ext2fs_extent_header_verify(void *ptr
, int size
)
134 int eh_max
, entry_size
;
135 struct ext3_extent_header
*eh
= ptr
;
138 if (ext2fs_le16_to_cpu(eh
->eh_magic
) != EXT3_EXT_MAGIC
)
139 return EXT2_ET_EXTENT_HEADER_BAD
;
140 if (ext2fs_le16_to_cpu(eh
->eh_entries
) > ext2fs_le16_to_cpu(eh
->eh_max
))
141 return EXT2_ET_EXTENT_HEADER_BAD
;
142 if (eh
->eh_depth
== 0)
143 entry_size
= sizeof(struct ext3_extent
);
145 entry_size
= sizeof(struct ext3_extent_idx
);
147 eh_max
= (size
- sizeof(*eh
)) / entry_size
;
148 /* Allow two extent-sized items at the end of the block, for
149 * ext4_extent_tail with checksum in the future. */
150 if ((ext2fs_le16_to_cpu(eh
->eh_max
) > eh_max
) ||
151 (ext2fs_le16_to_cpu(eh
->eh_max
) < (eh_max
- 2)))
152 return EXT2_ET_EXTENT_HEADER_BAD
;
159 * Begin functions to handle an inode's extent information
161 extern void ext2fs_extent_free(ext2_extent_handle_t handle
)
169 ext2fs_free_mem(&handle
->inode
);
171 for (i
=1; i
< handle
->max_depth
; i
++) {
172 if (handle
->path
[i
].buf
)
173 ext2fs_free_mem(&handle
->path
[i
].buf
);
175 ext2fs_free_mem(&handle
->path
);
177 ext2fs_free_mem(&handle
);
180 extern errcode_t
ext2fs_extent_open(ext2_filsys fs
, ext2_ino_t ino
,
181 ext2_extent_handle_t
*ret_handle
)
183 struct ext2_extent_handle
*handle
;
185 int isize
= EXT2_INODE_SIZE(fs
->super
);
187 struct ext3_extent_header
*eh
;
189 EXT2_CHECK_MAGIC(fs
, EXT2_ET_MAGIC_EXT2FS_FILSYS
);
191 if ((ino
== 0) || (ino
> fs
->super
->s_inodes_count
))
192 return EXT2_ET_BAD_INODE_NUM
;
194 retval
= ext2fs_get_mem(sizeof(struct ext2_extent_handle
), &handle
);
197 memset(handle
, 0, sizeof(struct ext2_extent_handle
));
199 retval
= ext2fs_get_mem(isize
, &handle
->inode
);
206 retval
= ext2fs_read_inode_full(fs
, ino
, handle
->inode
, isize
);
210 eh
= (struct ext3_extent_header
*) &handle
->inode
->i_block
[0];
212 for (i
=0; i
< EXT2_N_BLOCKS
; i
++)
213 if (handle
->inode
->i_block
[i
])
215 if (i
>= EXT2_N_BLOCKS
) {
216 eh
->eh_magic
= ext2fs_cpu_to_le16(EXT3_EXT_MAGIC
);
219 i
= (sizeof(handle
->inode
->i_block
) - sizeof(*eh
)) /
220 sizeof(struct ext3_extent
);
221 eh
->eh_max
= ext2fs_cpu_to_le16(i
);
222 handle
->inode
->i_flags
|= EXT4_EXTENTS_FL
;
225 if (!(handle
->inode
->i_flags
& EXT4_EXTENTS_FL
)) {
226 retval
= EXT2_ET_INODE_NOT_EXTENT
;
230 retval
= ext2fs_extent_header_verify(eh
, sizeof(handle
->inode
->i_block
));
234 handle
->max_depth
= ext2fs_le16_to_cpu(eh
->eh_depth
);
235 handle
->type
= ext2fs_le16_to_cpu(eh
->eh_magic
);
237 retval
= ext2fs_get_mem(((handle
->max_depth
+1) *
238 sizeof(struct extent_path
)),
240 memset(handle
->path
, 0,
241 (handle
->max_depth
+1) * sizeof(struct extent_path
));
242 handle
->path
[0].buf
= (char *) handle
->inode
->i_block
;
244 handle
->path
[0].left
= handle
->path
[0].entries
=
245 ext2fs_le16_to_cpu(eh
->eh_entries
);
246 handle
->path
[0].max_entries
= ext2fs_le16_to_cpu(eh
->eh_max
);
247 handle
->path
[0].curr
= 0;
248 handle
->path
[0].end_blk
=
249 ((((__u64
) handle
->inode
->i_size_high
<< 32) +
250 handle
->inode
->i_size
+ (fs
->blocksize
- 1))
251 >> EXT2_BLOCK_SIZE_BITS(fs
->super
));
252 handle
->path
[0].visit_num
= 1;
254 handle
->magic
= EXT2_ET_MAGIC_EXTENT_HANDLE
;
256 *ret_handle
= handle
;
260 ext2fs_extent_free(handle
);
265 * This function is responsible for (optionally) moving through the
266 * extent tree and then returning the current extent
268 errcode_t
ext2fs_extent_get(ext2_extent_handle_t handle
,
269 int flags
, struct ext2fs_extent
*extent
)
271 struct extent_path
*path
, *newpath
;
272 struct ext3_extent_header
*eh
;
273 struct ext3_extent_idx
*ix
= 0;
274 struct ext3_extent
*ex
;
280 EXT2_CHECK_MAGIC(handle
, EXT2_ET_MAGIC_EXTENT_HANDLE
);
283 return EXT2_ET_NO_CURRENT_NODE
;
285 orig_op
= op
= flags
& EXT2_EXTENT_MOVE_MASK
;
288 path
= handle
->path
+ handle
->level
;
289 if ((orig_op
== EXT2_EXTENT_NEXT
) ||
290 (orig_op
== EXT2_EXTENT_NEXT_LEAF
)) {
291 if (handle
->level
< handle
->max_depth
) {
293 if (path
->visit_num
== 0) {
295 op
= EXT2_EXTENT_DOWN
;
296 } else if (path
->left
> 0)
297 op
= EXT2_EXTENT_NEXT_SIB
;
298 else if (handle
->level
> 0)
301 return EXT2_ET_EXTENT_NO_NEXT
;
305 op
= EXT2_EXTENT_NEXT_SIB
;
306 else if (handle
->level
> 0)
309 return EXT2_ET_EXTENT_NO_NEXT
;
311 if (op
!= EXT2_EXTENT_NEXT_SIB
) {
313 printf("<<<< OP = %s\n",
314 (op
== EXT2_EXTENT_DOWN
) ? "down" :
315 ((op
== EXT2_EXTENT_UP
) ? "up" : "unknown"));
320 if ((orig_op
== EXT2_EXTENT_PREV
) ||
321 (orig_op
== EXT2_EXTENT_PREV_LEAF
)) {
322 if (handle
->level
< handle
->max_depth
) {
324 if (path
->visit_num
> 0 ) {
325 /* path->visit_num = 0; */
326 op
= EXT2_EXTENT_DOWN_AND_LAST
;
327 } else if (path
->left
< path
->entries
-1)
328 op
= EXT2_EXTENT_PREV_SIB
;
329 else if (handle
->level
> 0)
332 return EXT2_ET_EXTENT_NO_PREV
;
335 if (path
->left
< path
->entries
-1)
336 op
= EXT2_EXTENT_PREV_SIB
;
337 else if (handle
->level
> 0)
340 return EXT2_ET_EXTENT_NO_PREV
;
342 if (op
!= EXT2_EXTENT_PREV_SIB
) {
344 printf("<<<< OP = %s\n",
345 (op
== EXT2_EXTENT_DOWN_AND_LAST
) ? "down/last" :
346 ((op
== EXT2_EXTENT_UP
) ? "up" : "unknown"));
351 if (orig_op
== EXT2_EXTENT_LAST_LEAF
) {
352 if ((handle
->level
< handle
->max_depth
) &&
354 op
= EXT2_EXTENT_DOWN
;
356 op
= EXT2_EXTENT_LAST_SIB
;
358 printf("<<<< OP = %s\n",
359 (op
== EXT2_EXTENT_DOWN
) ? "down" : "last_sib");
364 case EXT2_EXTENT_CURRENT
:
367 case EXT2_EXTENT_ROOT
:
369 path
= handle
->path
+ handle
->level
;
370 case EXT2_EXTENT_FIRST_SIB
:
371 path
->left
= path
->entries
;
373 case EXT2_EXTENT_NEXT_SIB
:
375 return EXT2_ET_EXTENT_NO_NEXT
;
380 eh
= (struct ext3_extent_header
*) path
->buf
;
381 ix
= EXT_FIRST_INDEX(eh
);
387 case EXT2_EXTENT_PREV_SIB
:
389 path
->left
+1 >= path
->entries
)
390 return EXT2_ET_EXTENT_NO_PREV
;
395 if (handle
->level
< handle
->max_depth
)
398 case EXT2_EXTENT_LAST_SIB
:
399 eh
= (struct ext3_extent_header
*) path
->buf
;
400 path
->curr
= EXT_LAST_EXTENT(eh
);
406 if (handle
->level
<= 0)
407 return EXT2_ET_EXTENT_NO_UP
;
411 if ((orig_op
== EXT2_EXTENT_PREV
) ||
412 (orig_op
== EXT2_EXTENT_PREV_LEAF
))
415 case EXT2_EXTENT_DOWN
:
416 case EXT2_EXTENT_DOWN_AND_LAST
:
417 if (!path
->curr
||(handle
->level
>= handle
->max_depth
))
418 return EXT2_ET_EXTENT_NO_DOWN
;
423 retval
= ext2fs_get_mem(handle
->fs
->blocksize
,
428 blk
= ext2fs_le32_to_cpu(ix
->ei_leaf
) +
429 ((__u64
) ext2fs_le16_to_cpu(ix
->ei_leaf_hi
) << 32);
430 if ((handle
->fs
->flags
& EXT2_FLAG_IMAGE_FILE
) &&
431 (handle
->fs
->io
!= handle
->fs
->image_io
))
432 memset(newpath
->buf
, 0, handle
->fs
->blocksize
);
434 retval
= io_channel_read_blk(handle
->fs
->io
,
435 blk
, 1, newpath
->buf
);
441 eh
= (struct ext3_extent_header
*) newpath
->buf
;
443 retval
= ext2fs_extent_header_verify(eh
, handle
->fs
->blocksize
);
447 newpath
->left
= newpath
->entries
=
448 ext2fs_le16_to_cpu(eh
->eh_entries
);
449 newpath
->max_entries
= ext2fs_le16_to_cpu(eh
->eh_max
);
451 if (path
->left
> 0) {
453 newpath
->end_blk
= ext2fs_le32_to_cpu(ix
->ei_block
);
455 newpath
->end_blk
= path
->end_blk
;
458 if (op
== EXT2_EXTENT_DOWN
) {
459 ix
= EXT_FIRST_INDEX((struct ext3_extent_header
*) eh
);
461 path
->left
= path
->entries
- 1;
464 ix
= EXT_LAST_INDEX((struct ext3_extent_header
*) eh
);
467 if (handle
->level
< handle
->max_depth
)
471 printf("Down to level %d/%d, end_blk=%llu\n",
472 handle
->level
, handle
->max_depth
,
477 return EXT2_ET_OP_NOT_SUPPORTED
;
481 return EXT2_ET_NO_CURRENT_NODE
;
485 printf("(Left %d)\n", path
->left
);
488 if (handle
->level
== handle
->max_depth
) {
489 ex
= (struct ext3_extent
*) ix
;
491 extent
->e_pblk
= ext2fs_le32_to_cpu(ex
->ee_start
) +
492 ((__u64
) ext2fs_le16_to_cpu(ex
->ee_start_hi
) << 32);
493 extent
->e_lblk
= ext2fs_le32_to_cpu(ex
->ee_block
);
494 extent
->e_len
= ext2fs_le16_to_cpu(ex
->ee_len
);
495 extent
->e_flags
|= EXT2_EXTENT_FLAGS_LEAF
;
496 if (extent
->e_len
> EXT_INIT_MAX_LEN
) {
497 extent
->e_len
-= EXT_INIT_MAX_LEN
;
498 extent
->e_flags
|= EXT2_EXTENT_FLAGS_UNINIT
;
501 extent
->e_pblk
= ext2fs_le32_to_cpu(ix
->ei_leaf
) +
502 ((__u64
) ext2fs_le16_to_cpu(ix
->ei_leaf_hi
) << 32);
503 extent
->e_lblk
= ext2fs_le32_to_cpu(ix
->ei_block
);
504 if (path
->left
> 0) {
506 end_blk
= ext2fs_le32_to_cpu(ix
->ei_block
);
508 end_blk
= path
->end_blk
;
510 extent
->e_len
= end_blk
- extent
->e_lblk
;
513 extent
->e_flags
|= EXT2_EXTENT_FLAGS_SECOND_VISIT
;
515 if (((orig_op
== EXT2_EXTENT_NEXT_LEAF
) ||
516 (orig_op
== EXT2_EXTENT_PREV_LEAF
)) &&
517 (handle
->level
!= handle
->max_depth
))
520 if ((orig_op
== EXT2_EXTENT_LAST_LEAF
) &&
521 ((handle
->level
!= handle
->max_depth
) ||
528 static errcode_t
update_path(ext2_extent_handle_t handle
)
532 struct ext3_extent_idx
*ix
;
534 if (handle
->level
== 0) {
535 retval
= ext2fs_write_inode_full(handle
->fs
, handle
->ino
,
536 handle
->inode
, EXT2_INODE_SIZE(handle
->fs
->super
));
538 ix
= handle
->path
[handle
->level
- 1].curr
;
539 blk
= ext2fs_le32_to_cpu(ix
->ei_leaf
) +
540 ((__u64
) ext2fs_le16_to_cpu(ix
->ei_leaf_hi
) << 32);
542 retval
= io_channel_write_blk(handle
->fs
->io
,
543 blk
, 1, handle
->path
[handle
->level
].buf
);
549 errcode_t
ext2fs_extent_save_path(ext2_extent_handle_t handle
,
550 ext2_extent_path_t
*ret_path
)
552 ext2_extent_path_t save_path
;
553 struct ext2fs_extent extent
;
554 struct ext2_extent_info info
;
557 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_CURRENT
, &extent
);
561 retval
= ext2fs_extent_get_info(handle
, &info
);
565 retval
= ext2fs_get_mem(sizeof(struct ext2_extent_path
), &save_path
);
568 memset(save_path
, 0, sizeof(struct ext2_extent_path
));
570 save_path
->magic
= EXT2_ET_MAGIC_EXTENT_PATH
;
571 save_path
->leaf_height
= info
.max_depth
- info
.curr_level
- 1;
572 save_path
->lblk
= extent
.e_lblk
;
574 *ret_path
= save_path
;
578 errcode_t
ext2fs_extent_free_path(ext2_extent_path_t path
)
580 EXT2_CHECK_MAGIC(path
, EXT2_ET_MAGIC_EXTENT_PATH
);
582 ext2fs_free_mem(&path
);
588 * Go to the node at leaf_level which contains logical block blk.
590 * leaf_level is height from the leaf node level, i.e.
591 * leaf_level 0 is at leaf node, leaf_level 1 is 1 above etc.
593 * If "blk" has no mapping (hole) then handle is left at last
596 static errcode_t
extent_goto(ext2_extent_handle_t handle
,
597 int leaf_level
, blk64_t blk
)
599 struct ext2fs_extent extent
;
602 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_ROOT
, &extent
);
604 if (retval
== EXT2_ET_EXTENT_NO_NEXT
)
605 retval
= EXT2_ET_EXTENT_NOT_FOUND
;
609 if (leaf_level
> handle
->max_depth
) {
611 printf("leaf level %d greater than tree depth %d\n",
612 leaf_level
, handle
->max_depth
);
614 return EXT2_ET_OP_NOT_SUPPORTED
;
617 dbg_print_extent("root", &extent
);
619 if (handle
->max_depth
- handle
->level
== leaf_level
) {
620 /* block is in this &extent */
621 if ((blk
>= extent
.e_lblk
) &&
622 (blk
< extent
.e_lblk
+ extent
.e_len
))
624 if (blk
< extent
.e_lblk
) {
625 retval
= ext2fs_extent_get(handle
,
626 EXT2_EXTENT_PREV_SIB
,
628 return EXT2_ET_EXTENT_NOT_FOUND
;
630 retval
= ext2fs_extent_get(handle
,
631 EXT2_EXTENT_NEXT_SIB
,
633 if (retval
== EXT2_ET_EXTENT_NO_NEXT
)
634 return EXT2_ET_EXTENT_NOT_FOUND
;
640 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_NEXT_SIB
,
642 if (retval
== EXT2_ET_EXTENT_NO_NEXT
)
647 dbg_print_extent("next", &extent
);
648 if (blk
== extent
.e_lblk
)
650 if (blk
> extent
.e_lblk
)
653 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_PREV_SIB
,
658 dbg_print_extent("prev", &extent
);
661 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_DOWN
,
666 dbg_print_extent("down", &extent
);
670 errcode_t
ext2fs_extent_goto(ext2_extent_handle_t handle
,
673 return extent_goto(handle
, 0, blk
);
677 * Traverse back up to root fixing parents of current node as needed.
679 * If we changed start of first entry in a node, fix parent index start
682 * Safe to call for any position in node; if not at the first entry,
683 * will simply return.
685 static errcode_t
ext2fs_extent_fix_parents(ext2_extent_handle_t handle
)
689 struct extent_path
*path
;
690 struct ext2fs_extent extent
;
692 EXT2_CHECK_MAGIC(handle
, EXT2_ET_MAGIC_EXTENT_HANDLE
);
694 if (!(handle
->fs
->flags
& EXT2_FLAG_RW
))
695 return EXT2_ET_RO_FILSYS
;
698 return EXT2_ET_NO_CURRENT_NODE
;
700 path
= handle
->path
+ handle
->level
;
702 return EXT2_ET_NO_CURRENT_NODE
;
704 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_CURRENT
, &extent
);
708 /* modified node's start block */
709 start
= extent
.e_lblk
;
711 /* traverse up until index not first, or startblk matches, or top */
712 while (handle
->level
> 0 &&
713 (path
->left
== path
->entries
- 1)) {
714 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_UP
, &extent
);
717 if (extent
.e_lblk
== start
)
719 path
= handle
->path
+ handle
->level
;
720 extent
.e_len
+= (extent
.e_lblk
- start
);
721 extent
.e_lblk
= start
;
722 retval
= ext2fs_extent_replace(handle
, 0, &extent
);
728 /* put handle back to where we started */
729 retval
= ext2fs_extent_goto(handle
, start
);
734 errcode_t
ext2fs_extent_replace(ext2_extent_handle_t handle
,
735 int flags
EXT2FS_ATTR((unused
)),
736 struct ext2fs_extent
*extent
)
738 struct extent_path
*path
;
739 struct ext3_extent_idx
*ix
;
740 struct ext3_extent
*ex
;
742 EXT2_CHECK_MAGIC(handle
, EXT2_ET_MAGIC_EXTENT_HANDLE
);
744 if (!(handle
->fs
->flags
& EXT2_FLAG_RW
))
745 return EXT2_ET_RO_FILSYS
;
748 return EXT2_ET_NO_CURRENT_NODE
;
750 path
= handle
->path
+ handle
->level
;
752 return EXT2_ET_NO_CURRENT_NODE
;
754 if (handle
->level
== handle
->max_depth
) {
757 ex
->ee_block
= ext2fs_cpu_to_le32(extent
->e_lblk
);
758 ex
->ee_start
= ext2fs_cpu_to_le32(extent
->e_pblk
& 0xFFFFFFFF);
759 ex
->ee_start_hi
= ext2fs_cpu_to_le16(extent
->e_pblk
>> 32);
760 if (extent
->e_flags
& EXT2_EXTENT_FLAGS_UNINIT
) {
761 if (extent
->e_len
> EXT_UNINIT_MAX_LEN
)
762 return EXT2_ET_EXTENT_INVALID_LENGTH
;
763 ex
->ee_len
= ext2fs_cpu_to_le16(extent
->e_len
+
766 if (extent
->e_len
> EXT_INIT_MAX_LEN
)
767 return EXT2_ET_EXTENT_INVALID_LENGTH
;
768 ex
->ee_len
= ext2fs_cpu_to_le16(extent
->e_len
);
773 ix
->ei_leaf
= ext2fs_cpu_to_le32(extent
->e_pblk
& 0xFFFFFFFF);
774 ix
->ei_leaf_hi
= ext2fs_cpu_to_le16(extent
->e_pblk
>> 32);
775 ix
->ei_block
= ext2fs_cpu_to_le32(extent
->e_lblk
);
783 * allocate a new block, move half the current node to it, and update parent
785 * handle will be left pointing at original record.
787 static errcode_t
extent_node_split(ext2_extent_handle_t handle
)
789 errcode_t retval
= 0;
791 blk64_t new_node_start
;
793 blk64_t goal_blk
= 0;
795 char *block_buf
= NULL
;
796 struct ext2fs_extent extent
;
797 struct extent_path
*path
, *newpath
= 0;
798 struct ext3_extent_header
*eh
, *neweh
;
801 struct ext2_extent_info info
;
804 EXT2_CHECK_MAGIC(handle
, EXT2_ET_MAGIC_EXTENT_HANDLE
);
806 if (!(handle
->fs
->flags
& EXT2_FLAG_RW
))
807 return EXT2_ET_RO_FILSYS
;
810 return EXT2_ET_NO_CURRENT_NODE
;
813 printf("splitting node at level %d\n", handle
->level
);
815 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_CURRENT
, &extent
);
819 retval
= ext2fs_extent_get_info(handle
, &info
);
823 /* save the position we were originally splitting... */
824 orig_height
= info
.max_depth
- info
.curr_level
;
825 orig_lblk
= extent
.e_lblk
;
827 /* Is there room in the parent for a new entry? */
829 (handle
->path
[handle
->level
- 1].entries
>=
830 handle
->path
[handle
->level
- 1].max_entries
)) {
833 printf("parent level %d full; splitting it too\n",
836 /* split the parent */
837 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_UP
, &extent
);
840 goal_blk
= extent
.e_pblk
;
842 retval
= extent_node_split(handle
);
846 /* get handle back to our original split position */
847 retval
= extent_goto(handle
, orig_height
, orig_lblk
);
852 /* At this point, parent should have room for this split */
853 path
= handle
->path
+ handle
->level
;
855 return EXT2_ET_NO_CURRENT_NODE
;
857 /* extent header of the current node we'll split */
858 eh
= (struct ext3_extent_header
*)path
->buf
;
860 /* splitting root level means moving them all out */
861 if (handle
->level
== 0) {
863 tocopy
= ext2fs_le16_to_cpu(eh
->eh_entries
);
864 retval
= ext2fs_get_mem(((handle
->max_depth
+2) *
865 sizeof(struct extent_path
)),
870 ((handle
->max_depth
+2) * sizeof(struct extent_path
)));
872 tocopy
= ext2fs_le16_to_cpu(eh
->eh_entries
) / 2;
876 printf("will copy out %d of %d entries at level %d\n",
877 tocopy
, ext2fs_le16_to_cpu(eh
->eh_entries
),
883 printf("Nothing to copy to new block!\n");
885 retval
= EXT2_ET_CANT_SPLIT_EXTENT
;
889 /* first we need a new block, or can do nothing. */
890 block_buf
= malloc(handle
->fs
->blocksize
);
897 dgrp_t group
= ext2fs_group_of_ino(handle
->fs
, handle
->ino
);
898 __u8 log_flex
= handle
->fs
->super
->s_log_groups_per_flex
;
901 group
= group
& ~((1 << (log_flex
)) - 1);
902 goal_blk
= (group
* handle
->fs
->super
->s_blocks_per_group
) +
903 handle
->fs
->super
->s_first_data_block
;
905 retval
= ext2fs_alloc_block(handle
->fs
, (blk_t
) goal_blk
, block_buf
,
911 printf("will copy to new node at block %lu\n", new_node_pblk
);
914 /* Copy data into new block buffer */
915 /* First the header for the new block... */
916 neweh
= (struct ext3_extent_header
*) block_buf
;
917 memcpy(neweh
, eh
, sizeof(struct ext3_extent_header
));
918 neweh
->eh_entries
= ext2fs_cpu_to_le16(tocopy
);
919 neweh
->eh_max
= ext2fs_cpu_to_le16((handle
->fs
->blocksize
-
920 sizeof(struct ext3_extent_header
)) /
921 sizeof(struct ext3_extent
));
923 /* then the entries for the new block... */
924 memcpy(EXT_FIRST_INDEX(neweh
),
925 EXT_FIRST_INDEX(eh
) +
926 (ext2fs_le16_to_cpu(eh
->eh_entries
) - tocopy
),
927 sizeof(struct ext3_extent_idx
) * tocopy
);
929 new_node_start
= ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh
)->ei_block
);
931 /* ...and write the new node block out to disk. */
932 retval
= io_channel_write_blk(handle
->fs
->io
, new_node_pblk
, 1, block_buf
);
937 /* OK! we've created the new node; now adjust the tree */
939 /* current path now has fewer active entries, we copied some out */
940 if (handle
->level
== 0) {
941 memcpy(newpath
, path
,
942 sizeof(struct extent_path
) * (handle
->max_depth
+1));
943 handle
->path
= newpath
;
947 path
->left
= path
->max_entries
- 1;
949 eh
->eh_depth
= ext2fs_cpu_to_le16(handle
->max_depth
);
951 path
->entries
-= tocopy
;
952 path
->left
-= tocopy
;
955 eh
->eh_entries
= ext2fs_cpu_to_le16(path
->entries
);
956 /* this writes out the node, incl. the modified header */
957 retval
= update_path(handle
);
961 /* now go up and insert/replace index for new node we created */
963 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_FIRST_SIB
, &extent
);
967 extent
.e_lblk
= new_node_start
;
968 extent
.e_pblk
= new_node_pblk
;
969 extent
.e_len
= handle
->path
[0].end_blk
- extent
.e_lblk
;
970 retval
= ext2fs_extent_replace(handle
, 0, &extent
);
974 __u32 new_node_length
;
976 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_UP
, &extent
);
977 /* will insert after this one; it's length is shorter now */
978 new_node_length
= new_node_start
- extent
.e_lblk
;
979 extent
.e_len
-= new_node_length
;
980 retval
= ext2fs_extent_replace(handle
, 0, &extent
);
984 /* now set up the new extent and insert it */
985 extent
.e_lblk
= new_node_start
;
986 extent
.e_pblk
= new_node_pblk
;
987 extent
.e_len
= new_node_length
;
988 retval
= ext2fs_extent_insert(handle
, EXT2_EXTENT_INSERT_AFTER
, &extent
);
993 /* get handle back to our original position */
994 retval
= extent_goto(handle
, orig_height
, orig_lblk
);
998 /* new node hooked in, so update inode block count (do this here?) */
999 handle
->inode
->i_blocks
+= handle
->fs
->blocksize
/ 512;
1000 retval
= ext2fs_write_inode_full(handle
->fs
, handle
->ino
,
1001 handle
->inode
, EXT2_INODE_SIZE(handle
->fs
->super
));
1007 ext2fs_free_mem(&newpath
);
1014 errcode_t
ext2fs_extent_insert(ext2_extent_handle_t handle
, int flags
,
1015 struct ext2fs_extent
*extent
)
1017 struct extent_path
*path
;
1018 struct ext3_extent_idx
*ix
;
1019 struct ext3_extent_header
*eh
;
1022 EXT2_CHECK_MAGIC(handle
, EXT2_ET_MAGIC_EXTENT_HANDLE
);
1024 if (!(handle
->fs
->flags
& EXT2_FLAG_RW
))
1025 return EXT2_ET_RO_FILSYS
;
1028 return EXT2_ET_NO_CURRENT_NODE
;
1030 path
= handle
->path
+ handle
->level
;
1032 if (path
->entries
>= path
->max_entries
) {
1033 if (flags
& EXT2_EXTENT_INSERT_NOSPLIT
) {
1034 return EXT2_ET_CANT_INSERT_EXTENT
;
1037 printf("node full (level %d) - splitting\n",
1040 retval
= extent_node_split(handle
);
1043 path
= handle
->path
+ handle
->level
;
1047 eh
= (struct ext3_extent_header
*) path
->buf
;
1050 if (flags
& EXT2_EXTENT_INSERT_AFTER
) {
1055 ix
= EXT_FIRST_INDEX(eh
);
1059 if (path
->left
>= 0)
1061 (path
->left
+1) * sizeof(struct ext3_extent_idx
));
1065 eh
= (struct ext3_extent_header
*) path
->buf
;
1066 eh
->eh_entries
= ext2fs_cpu_to_le16(path
->entries
);
1068 retval
= ext2fs_extent_replace(handle
, 0, extent
);
1072 retval
= update_path(handle
);
1079 ext2fs_extent_delete(handle
, 0);
1084 * Sets the physical block for a logical file block in the extent tree.
1086 * May: map unmapped, unmap mapped, or remap mapped blocks.
1088 * Mapping an unmapped block adds a single-block extent.
1090 * Unmapping first or last block modifies extent in-place
1091 * - But may need to fix parent's starts too in first-block case
1093 * Mapping any unmapped block requires adding a (single-block) extent
1094 * and inserting into proper point in tree.
1096 * Modifying (unmapping or remapping) a block in the middle
1097 * of an extent requires splitting the extent.
1098 * - Remapping case requires new single-block extent.
1100 * Remapping first or last block adds an extent.
1102 * We really need extent adding to be smart about merging.
1105 errcode_t
ext2fs_extent_set_bmap(ext2_extent_handle_t handle
,
1106 blk64_t logical
, blk64_t physical
, int flags
)
1108 errcode_t ec
, retval
= 0;
1109 int mapped
= 1; /* logical is mapped? */
1111 int extent_uninit
= 0;
1113 int max_len
= EXT_INIT_MAX_LEN
;
1115 struct extent_path
*path
;
1116 struct ext2fs_extent extent
;
1117 struct ext2fs_extent newextent
;
1118 struct ext2_extent_info info
;
1120 EXT2_CHECK_MAGIC(handle
, EXT2_ET_MAGIC_EXTENT_HANDLE
);
1122 if (!(handle
->fs
->flags
& EXT2_FLAG_RW
))
1123 return EXT2_ET_RO_FILSYS
;
1126 return EXT2_ET_NO_CURRENT_NODE
;
1128 path
= handle
->path
+ handle
->level
;
1130 if (flags
& EXT2_EXTENT_SET_BMAP_UNINIT
) {
1132 max_len
= EXT_UNINIT_MAX_LEN
;
1135 /* if (re)mapping, set up new extent to insert */
1137 newextent
.e_len
= 1;
1138 newextent
.e_pblk
= physical
;
1139 newextent
.e_lblk
= logical
;
1140 newextent
.e_flags
= EXT2_EXTENT_FLAGS_LEAF
;
1142 newextent
.e_flags
|= EXT2_EXTENT_FLAGS_UNINIT
;
1145 /* special case if the extent tree is completely empty */
1146 if ((handle
->max_depth
== 0) && (path
->entries
== 0)) {
1147 retval
= ext2fs_extent_insert(handle
, 0, &newextent
);
1151 /* save our original location in the extent tree */
1152 if ((retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_CURRENT
,
1154 if (retval
!= EXT2_ET_NO_CURRENT_NODE
)
1156 memset(&extent
, 0, sizeof(extent
));
1158 if ((retval
= ext2fs_extent_get_info(handle
, &info
)))
1160 orig_height
= info
.max_depth
- info
.curr_level
;
1161 orig_lblk
= extent
.e_lblk
;
1164 /* go to the logical spot we want to (re/un)map */
1165 retval
= ext2fs_extent_goto(handle
, logical
);
1167 if (retval
== EXT2_ET_EXTENT_NOT_FOUND
) {
1172 printf("block %llu already unmapped\n",
1182 * This may be the extent *before* the requested logical,
1183 * if it's currently unmapped.
1185 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_CURRENT
, &extent
);
1188 if (extent
.e_flags
& EXT2_EXTENT_FLAGS_UNINIT
)
1191 /* check if already pointing to the requested physical */
1192 if (mapped
&& (new_uninit
== extent_uninit
) &&
1193 (extent
.e_pblk
+ (logical
- extent
.e_lblk
) == physical
)) {
1195 printf("physical block (at %llu) unchanged\n", logical
);
1202 printf("mapping unmapped logical block %llu\n", logical
);
1204 if ((logical
== extent
.e_lblk
+ extent
.e_len
) &&
1205 (physical
== extent
.e_pblk
+ extent
.e_len
) &&
1206 (new_uninit
== extent_uninit
) &&
1207 ((int) extent
.e_len
< max_len
-1)) {
1209 retval
= ext2fs_extent_replace(handle
, 0, &extent
);
1210 } else if (logical
< extent
.e_lblk
)
1211 retval
= ext2fs_extent_insert(handle
, 0, &newextent
);
1213 retval
= ext2fs_extent_insert(handle
,
1214 EXT2_EXTENT_INSERT_AFTER
, &newextent
);
1217 retval
= ext2fs_extent_fix_parents(handle
);
1220 } else if ((logical
== extent
.e_lblk
) && (extent
.e_len
== 1)) {
1222 printf("(re/un)mapping only block in extent\n");
1225 retval
= ext2fs_extent_replace(handle
, 0, &newextent
);
1227 retval
= ext2fs_extent_delete(handle
, 0);
1230 ec
= ext2fs_extent_fix_parents(handle
);
1231 if (ec
!= EXT2_ET_NO_CURRENT_NODE
)
1237 } else if (logical
== extent
.e_lblk
+ extent
.e_len
- 1) {
1239 printf("(re/un)mapping last block in extent\n");
1242 retval
= ext2fs_extent_replace(handle
, 0, &extent
);
1246 retval
= ext2fs_extent_insert(handle
,
1247 EXT2_EXTENT_INSERT_AFTER
, &newextent
);
1251 } else if (logical
== extent
.e_lblk
) {
1253 printf("(re/un)mapping first block in extent\n");
1258 retval
= ext2fs_extent_replace(handle
, 0, &extent
);
1263 * We've removed the old block, now rely on
1264 * the optimized hueristics for adding a new
1265 * mapping with appropriate merging if necessary.
1269 retval
= ext2fs_extent_fix_parents(handle
);
1277 printf("(re/un)mapping in middle of extent\n");
1279 /* need to split this extent; later */
1281 orig_length
= extent
.e_len
;
1283 /* shorten pre-split extent */
1284 extent
.e_len
= (logical
- extent
.e_lblk
);
1285 retval
= ext2fs_extent_replace(handle
, 0, &extent
);
1288 /* insert our new extent, if any */
1290 /* insert new extent after current */
1291 retval
= ext2fs_extent_insert(handle
,
1292 EXT2_EXTENT_INSERT_AFTER
, &newextent
);
1296 /* add post-split extent */
1297 extent
.e_pblk
+= extent
.e_len
+ 1;
1298 extent
.e_lblk
+= extent
.e_len
+ 1;
1299 extent
.e_len
= orig_length
- extent
.e_len
- 1;
1300 retval
= ext2fs_extent_insert(handle
,
1301 EXT2_EXTENT_INSERT_AFTER
, &extent
);
1307 /* get handle back to its position */
1308 if (orig_height
> handle
->max_depth
)
1309 orig_height
= handle
->max_depth
; /* In case we shortened the tree */
1310 extent_goto(handle
, orig_height
, orig_lblk
);
1314 errcode_t
ext2fs_extent_delete(ext2_extent_handle_t handle
, int flags
)
1316 struct extent_path
*path
;
1318 struct ext3_extent_header
*eh
;
1319 errcode_t retval
= 0;
1321 EXT2_CHECK_MAGIC(handle
, EXT2_ET_MAGIC_EXTENT_HANDLE
);
1323 if (!(handle
->fs
->flags
& EXT2_FLAG_RW
))
1324 return EXT2_ET_RO_FILSYS
;
1327 return EXT2_ET_NO_CURRENT_NODE
;
1329 path
= handle
->path
+ handle
->level
;
1331 return EXT2_ET_NO_CURRENT_NODE
;
1336 memmove(cp
, cp
+ sizeof(struct ext3_extent_idx
),
1337 path
->left
* sizeof(struct ext3_extent_idx
));
1340 struct ext3_extent_idx
*ix
= path
->curr
;
1344 if (--path
->entries
== 0)
1347 /* if non-root node has no entries left, remove it & parent ptr to it */
1348 if (path
->entries
== 0 && handle
->level
) {
1349 if (!(flags
& EXT2_EXTENT_DELETE_KEEP_EMPTY
)) {
1350 struct ext2fs_extent extent
;
1352 retval
= ext2fs_extent_get(handle
, EXT2_EXTENT_UP
,
1357 retval
= ext2fs_extent_delete(handle
, flags
);
1358 handle
->inode
->i_blocks
-= handle
->fs
->blocksize
/ 512;
1359 retval
= ext2fs_write_inode_full(handle
->fs
,
1360 handle
->ino
, handle
->inode
,
1361 EXT2_INODE_SIZE(handle
->fs
->super
));
1362 ext2fs_block_alloc_stats(handle
->fs
, extent
.e_pblk
, -1);
1365 eh
= (struct ext3_extent_header
*) path
->buf
;
1366 eh
->eh_entries
= ext2fs_cpu_to_le16(path
->entries
);
1367 if ((path
->entries
== 0) && (handle
->level
== 0))
1368 eh
->eh_depth
= handle
->max_depth
= 0;
1369 retval
= update_path(handle
);
1374 errcode_t
ext2fs_extent_get_info(ext2_extent_handle_t handle
,
1375 struct ext2_extent_info
*info
)
1377 struct extent_path
*path
;
1379 EXT2_CHECK_MAGIC(handle
, EXT2_ET_MAGIC_EXTENT_HANDLE
);
1381 memset(info
, 0, sizeof(struct ext2_extent_info
));
1383 path
= handle
->path
+ handle
->level
;
1386 info
->curr_entry
= ((char *) path
->curr
- path
->buf
) /
1387 sizeof(struct ext3_extent_idx
);
1389 info
->curr_entry
= 0;
1390 info
->num_entries
= path
->entries
;
1391 info
->max_entries
= path
->max_entries
;
1392 info
->bytes_avail
= (path
->max_entries
- path
->entries
) *
1393 sizeof(struct ext3_extent
);
1396 info
->curr_level
= handle
->level
;
1397 info
->max_depth
= handle
->max_depth
;
1398 info
->max_lblk
= ((__u64
) 1 << 32) - 1;
1399 info
->max_pblk
= ((__u64
) 1 << 48) - 1;
1400 info
->max_len
= (1UL << 15);
1401 info
->max_uninit_len
= (1UL << 15) - 1;
1410 #include "debugfs.h"
1413 * Hook in new commands into debugfs
1415 const char *debug_prog_name
= "tst_extents";
1416 extern ss_request_table extent_cmds
;
1417 ss_request_table
*extra_cmds
= &extent_cmds
;
1419 ext2_ino_t current_ino
= 0;
1420 ext2_extent_handle_t current_handle
;
1422 int common_extent_args_process(int argc
, char *argv
[], int min_argc
,
1423 int max_argc
, const char *cmd
,
1424 const char *usage
, int flags
)
1426 if (common_args_process(argc
, argv
, min_argc
, max_argc
, cmd
,
1430 if (!current_handle
) {
1431 com_err(cmd
, 0, "Extent handle not open");
1437 void do_inode(int argc
, char *argv
[])
1441 struct ext3_extent_header
*eh
;
1444 if (check_fs_open(argv
[0]))
1449 printf("Current inode is %d\n", current_ino
);
1451 printf("No current inode\n");
1455 if (common_inode_args_process(argc
, argv
, &inode
, 0)) {
1461 retval
= ext2fs_extent_open(current_fs
, inode
, ¤t_handle
);
1463 com_err(argv
[1], retval
, "while opening extent handle");
1467 current_ino
= inode
;
1469 printf("Loaded inode %d\n", current_ino
);
1474 void generic_goto_node(char *cmd_name
, int op
)
1476 struct ext2fs_extent extent
;
1479 if (check_fs_open(cmd_name
))
1482 if (!current_handle
) {
1483 com_err(cmd_name
, 0, "Extent handle not open");
1487 retval
= ext2fs_extent_get(current_handle
, op
, &extent
);
1489 com_err(cmd_name
, retval
, 0);
1492 dbg_print_extent(0, &extent
);
1495 void do_current_node(int argc
, char *argv
[])
1497 generic_goto_node(argv
[0], EXT2_EXTENT_CURRENT
);
1500 void do_root_node(int argc
, char *argv
[])
1502 generic_goto_node(argv
[0], EXT2_EXTENT_ROOT
);
1505 void do_last_leaf(int argc
, char *argv
[])
1507 generic_goto_node(argv
[0], EXT2_EXTENT_LAST_LEAF
);
1510 void do_first_sib(int argc
, char *argv
[])
1512 generic_goto_node(argv
[0], EXT2_EXTENT_FIRST_SIB
);
1515 void do_last_sib(int argc
, char *argv
[])
1517 generic_goto_node(argv
[0], EXT2_EXTENT_LAST_SIB
);
1520 void do_next_sib(int argc
, char *argv
[])
1522 generic_goto_node(argv
[0], EXT2_EXTENT_NEXT_SIB
);
1525 void do_prev_sib(int argc
, char *argv
[])
1527 generic_goto_node(argv
[0], EXT2_EXTENT_PREV_SIB
);
1530 void do_next_leaf(int argc
, char *argv
[])
1532 generic_goto_node(argv
[0], EXT2_EXTENT_NEXT_LEAF
);
1535 void do_prev_leaf(int argc
, char *argv
[])
1537 generic_goto_node(argv
[0], EXT2_EXTENT_PREV_LEAF
);
1540 void do_next(int argc
, char *argv
[])
1542 generic_goto_node(argv
[0], EXT2_EXTENT_NEXT
);
1545 void do_prev(int argc
, char *argv
[])
1547 generic_goto_node(argv
[0], EXT2_EXTENT_PREV
);
1550 void do_up(int argc
, char *argv
[])
1552 generic_goto_node(argv
[0], EXT2_EXTENT_UP
);
1555 void do_down(int argc
, char *argv
[])
1557 generic_goto_node(argv
[0], EXT2_EXTENT_DOWN
);
1560 void do_delete_node(int argc
, char *argv
[])
1565 if (common_extent_args_process(argc
, argv
, 1, 1, "delete_node",
1566 "", CHECK_FS_RW
| CHECK_FS_BITMAPS
))
1569 retval
= ext2fs_extent_delete(current_handle
, 0);
1571 com_err(argv
[0], retval
, 0);
1574 if (current_handle
->path
&& current_handle
->path
[0].curr
)
1575 do_current_node(argc
, argv
);
1578 void do_replace_node(int argc
, char *argv
[])
1580 const char *usage
= "[--uninit] <lblk> <len> <pblk>";
1582 struct ext2fs_extent extent
;
1585 if (common_extent_args_process(argc
, argv
, 3, 5, "replace_node",
1586 usage
, CHECK_FS_RW
| CHECK_FS_BITMAPS
))
1591 if (!strcmp(argv
[1], "--uninit")) {
1594 extent
.e_flags
|= EXT2_EXTENT_FLAGS_UNINIT
;
1598 fprintf(stderr
, "Usage: %s %s\n", argv
[0], usage
);
1602 extent
.e_lblk
= parse_ulong(argv
[1], argv
[0], "logical block", &err
);
1606 extent
.e_len
= parse_ulong(argv
[2], argv
[0], "logical block", &err
);
1610 extent
.e_pblk
= parse_ulong(argv
[3], argv
[0], "logical block", &err
);
1614 retval
= ext2fs_extent_replace(current_handle
, 0, &extent
);
1616 com_err(argv
[0], retval
, 0);
1619 do_current_node(argc
, argv
);
1622 void do_split_node(int argc
, char *argv
[])
1625 struct ext2fs_extent extent
;
1628 if (common_extent_args_process(argc
, argv
, 1, 1, "split_node",
1629 "", CHECK_FS_RW
| CHECK_FS_BITMAPS
))
1632 retval
= extent_node_split(current_handle
);
1634 com_err(argv
[0], retval
, 0);
1637 do_current_node(argc
, argv
);
1640 void do_insert_node(int argc
, char *argv
[])
1642 const char *usage
= "[--after] [--uninit] <lblk> <len> <pblk>";
1644 struct ext2fs_extent extent
;
1649 if (common_extent_args_process(argc
, argv
, 3, 6, "insert_node",
1650 usage
, CHECK_FS_RW
| CHECK_FS_BITMAPS
))
1658 if (!strcmp(argv
[1], "--after")) {
1661 flags
|= EXT2_EXTENT_INSERT_AFTER
;
1664 if (!strcmp(argv
[1], "--uninit")) {
1667 extent
.e_flags
|= EXT2_EXTENT_FLAGS_UNINIT
;
1674 fprintf(stderr
, "usage: %s %s\n", cmd
, usage
);
1678 extent
.e_lblk
= parse_ulong(argv
[1], cmd
,
1679 "logical block", &err
);
1683 extent
.e_len
= parse_ulong(argv
[2], cmd
,
1688 extent
.e_pblk
= parse_ulong(argv
[3], cmd
,
1689 "pysical block", &err
);
1693 retval
= ext2fs_extent_insert(current_handle
, flags
, &extent
);
1695 com_err(cmd
, retval
, 0);
1698 do_current_node(argc
, argv
);
1701 void do_set_bmap(int argc
, char **argv
)
1703 const char *usage
= "[--uninit] <lblk> <pblk>";
1707 char *cmd
= argv
[0];
1711 if (common_extent_args_process(argc
, argv
, 3, 5, "set_bmap",
1712 usage
, CHECK_FS_RW
| CHECK_FS_BITMAPS
))
1715 if (argc
> 2 && !strcmp(argv
[1], "--uninit")) {
1718 flags
|= EXT2_EXTENT_SET_BMAP_UNINIT
;
1722 fprintf(stderr
, "Usage: %s %s\n", cmd
, usage
);
1726 logical
= parse_ulong(argv
[1], cmd
,
1727 "logical block", &err
);
1731 physical
= parse_ulong(argv
[2], cmd
,
1732 "physical block", &err
);
1736 retval
= ext2fs_extent_set_bmap(current_handle
, logical
,
1737 (blk64_t
) physical
, flags
);
1739 com_err(cmd
, retval
, 0);
1742 if (current_handle
->path
&& current_handle
->path
[0].curr
)
1743 do_current_node(argc
, argv
);
1746 void do_print_all(int argc
, char **argv
)
1748 const char *usage
= "[--leaf-only|--reverse|--reverse-leaf]";
1749 struct ext2fs_extent extent
;
1751 errcode_t end_err
= EXT2_ET_EXTENT_NO_NEXT
;
1752 int op
= EXT2_EXTENT_NEXT
;
1753 int first_op
= EXT2_EXTENT_ROOT
;
1756 if (common_extent_args_process(argc
, argv
, 1, 2, "print_all",
1761 if (!strcmp(argv
[1], "--leaf-only"))
1762 op
= EXT2_EXTENT_NEXT_LEAF
;
1763 else if (!strcmp(argv
[1], "--reverse")) {
1764 op
= EXT2_EXTENT_PREV
;
1765 first_op
= EXT2_EXTENT_LAST_LEAF
;
1766 end_err
= EXT2_ET_EXTENT_NO_PREV
;
1767 } else if (!strcmp(argv
[1], "--reverse-leaf")) {
1768 op
= EXT2_EXTENT_PREV_LEAF
;
1769 first_op
= EXT2_EXTENT_LAST_LEAF
;
1770 end_err
= EXT2_ET_EXTENT_NO_PREV
;
1772 fprintf(stderr
, "Usage: %s %s\n", argv
[0], usage
);
1777 retval
= ext2fs_extent_get(current_handle
, first_op
, &extent
);
1779 com_err(argv
[0], retval
, 0);
1782 dbg_print_extent(0, &extent
);
1785 retval
= ext2fs_extent_get(current_handle
, op
, &extent
);
1786 if (retval
== end_err
)
1790 com_err(argv
[0], retval
, 0);
1793 dbg_print_extent(0, &extent
);
1797 void do_info(int argc
, char **argv
)
1799 struct ext2fs_extent extent
;
1800 struct ext2_extent_info info
;
1803 if (common_extent_args_process(argc
, argv
, 1, 1, "info", "", 0))
1806 retval
= ext2fs_extent_get_info(current_handle
, &info
);
1808 com_err(argv
[0], retval
, 0);
1812 retval
= ext2fs_extent_get(current_handle
,
1813 EXT2_EXTENT_CURRENT
, &extent
);
1815 com_err(argv
[0], retval
, 0);
1819 dbg_print_extent(0, &extent
);
1821 printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
1822 info
.curr_entry
, info
.num_entries
, info
.max_entries
,
1823 info
.bytes_avail
, info
.curr_level
, info
.max_depth
);
1824 printf("\tmax lblk: %llu, max pblk: %llu\n", info
.max_lblk
,
1826 printf("\tmax_len: %u, max_uninit_len: %u\n", info
.max_len
,
1827 info
.max_uninit_len
);
1830 void do_goto_block(int argc
, char **argv
)
1832 struct ext2fs_extent extent
;
1834 int op
= EXT2_EXTENT_NEXT_LEAF
;
1838 if (common_extent_args_process(argc
, argv
, 2, 3, "goto_block",
1839 "block [level]", 0))
1842 if (strtoblk(argv
[0], argv
[1], &blk
))
1846 if (strtoblk(argv
[0], argv
[2], &level
))
1849 retval
= extent_goto(current_handle
, level
, (blk64_t
) blk
);
1852 com_err(argv
[0], retval
, "while trying to go to block %lu, level %d",
1857 generic_goto_node(argv
[0], EXT2_EXTENT_CURRENT
);