2 * The logical block -> physical block routine.
4 * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file
5 * may be redistributed under the terms of the GNU Public License.
15 static const struct ext4_extent_header
*
16 ext4_find_leaf(struct fs_info
*fs
, const struct ext4_extent_header
*eh
,
19 struct ext4_extent_idx
*index
;
24 if (eh
->eh_magic
!= EXT4_EXT_MAGIC
)
26 if (eh
->eh_depth
== 0)
29 index
= EXT4_FIRST_INDEX(eh
);
30 for (i
= 0; i
< (int)eh
->eh_entries
; i
++) {
31 if (block
< index
[i
].ei_block
)
37 blk
= index
[i
].ei_leaf_hi
;
38 blk
= (blk
<< 32) + index
[i
].ei_leaf_lo
;
39 eh
= get_cache(fs
->fs_dev
, blk
);
43 /* handle the ext4 extents to get the phsical block number */
44 /* XXX: still need to handle sparse files with extents */
46 bmap_extent(struct inode
*inode
, uint32_t block
, size_t *nblocks
)
48 struct fs_info
*fs
= inode
->fs
;
49 const struct ext4_extent_header
*leaf
;
50 const struct ext4_extent
*ext
;
54 leaf
= ext4_find_leaf(fs
, &PVT(inode
)->i_extent_hdr
, block
);
56 printf("ERROR, extent leaf not found\n");
60 ext
= EXT4_FIRST_EXTENT(leaf
);
61 for (i
= 0; i
< leaf
->eh_entries
; i
++) {
62 if (block
< ext
[i
].ee_block
)
66 printf("ERROR, not find the right block\n");
71 block
-= ext
[i
].ee_block
;
72 if (block
>= ext
[i
].ee_len
)
74 start
= ((block_t
)ext
[i
].ee_start_hi
<< 32) + ext
[i
].ee_start_lo
;
77 *nblocks
= ext
[i
].ee_len
- block
;
83 * Scan forward in a range of blocks to see if they are contiguous,
84 * then return the initial value.
87 scan_set_nblocks(const uint32_t *map
, unsigned int count
, size_t *nblocks
)
92 uint32_t skip
= blk
? 1 : 0;
93 uint32_t next
= blk
+ skip
;
113 * The actual indirect block map handling - the block passed in should
114 * be relative to the beginning of the particular block hierarchy.
117 bmap_indirect(struct fs_info
*fs
, uint32_t start
, uint32_t block
,
118 int levels
, size_t *nblocks
)
120 int addr_shift
= BLOCK_SHIFT(fs
) - 2;
121 uint32_t addr_count
= 1 << addr_shift
;
122 const uint32_t *blk
= NULL
;
128 *nblocks
= addr_count
<< (levels
* addr_shift
);
131 blk
= get_cache(fs
->fs_dev
, start
);
132 index
= (block
>> (levels
* addr_shift
)) & (addr_count
- 1);
136 return scan_set_nblocks(blk
+ index
, addr_count
- index
, nblocks
);
140 * Handle the traditional block map, like indirect, double indirect
141 * and triple indirect
144 bmap_traditional(struct inode
*inode
, block_t block
, size_t *nblocks
)
146 struct fs_info
*fs
= inode
->fs
;
147 const uint32_t addr_per_block
= BLOCK_SIZE(fs
) >> 2;
148 const int shft_per_block
= BLOCK_SHIFT(fs
) - 2;
149 const uint32_t direct_blocks
= EXT2_NDIR_BLOCKS
;
150 const uint32_t indirect_blocks
= addr_per_block
;
151 const uint32_t double_blocks
= addr_per_block
<< shft_per_block
;
152 const uint32_t triple_blocks
= double_blocks
<< shft_per_block
;
155 if (block
< direct_blocks
)
156 return scan_set_nblocks(&PVT(inode
)->i_block
[block
],
157 direct_blocks
- block
, nblocks
);
159 /* indirect blocks */
160 block
-= direct_blocks
;
161 if (block
< indirect_blocks
)
162 return bmap_indirect(fs
, PVT(inode
)->i_block
[EXT2_IND_BLOCK
],
165 /* double indirect blocks */
166 block
-= indirect_blocks
;
167 if (block
< double_blocks
)
168 return bmap_indirect(fs
, PVT(inode
)->i_block
[EXT2_DIND_BLOCK
],
171 /* triple indirect block */
172 block
-= double_blocks
;
173 if (block
< triple_blocks
)
174 return bmap_indirect(fs
, PVT(inode
)->i_block
[EXT2_TIND_BLOCK
],
177 /* This can't happen... */
183 * Map the logical block to physic block where the file data stores.
184 * In EXT4, there are two ways to handle the map process, extents and indirect.
185 * EXT4 uses a inode flag to mark extent file and indirect block file.
187 * @fs: the fs_info structure.
188 * @inode: the inode structure.
189 * @block: the logical block to be mapped.
190 * @nblocks: optional pointer to number of contiguous blocks (low estimate)
191 * @retrun: the physical block number.
194 block_t
ext2_bmap(struct inode
*inode
, block_t block
, size_t *nblocks
)
198 if (inode
->flags
& EXT4_EXTENTS_FLAG
)
199 ret
= bmap_extent(inode
, block
, nblocks
);
201 ret
= bmap_traditional(inode
, block
, nblocks
);
208 * Next extent for getfssec
210 int ext2_next_extent(struct inode
*inode
, uint32_t lstart
)
212 struct fs_info
*fs
= inode
->fs
;
213 int blktosec
= BLOCK_SHIFT(fs
) - SECTOR_SHIFT(fs
);
214 int blkmask
= (1 << blktosec
) - 1;
218 block
= ext2_bmap(inode
, lstart
>> blktosec
, &nblocks
);
221 inode
->next_extent
.pstart
= EXTENT_ZERO
;
223 inode
->next_extent
.pstart
=
224 ((sector_t
)block
<< blktosec
) | (lstart
& blkmask
);
226 inode
->next_extent
.len
= (nblocks
<< blktosec
) - (lstart
& blkmask
);