1 /* vi: set sw=4 ts=4: */
3 * bmap.c --- logical to physical block mapping
5 * Copyright (C) 1997 Theodore Ts'o.
8 * This file may be redistributed under the terms of the GNU Public
22 extern errcode_t
ext2fs_bmap(ext2_filsys fs
, ext2_ino_t ino
,
23 struct ext2_inode
*inode
,
24 char *block_buf
, int bmap_flags
,
25 blk_t block
, blk_t
*phys_blk
);
27 #define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
29 static errcode_t
block_ind_bmap(ext2_filsys fs
, int flags
,
30 blk_t ind
, char *block_buf
,
32 blk_t nr
, blk_t
*ret_blk
)
39 return EXT2_ET_SET_BMAP_NO_IND
;
43 retval
= io_channel_read_blk(fs
->io
, ind
, 1, block_buf
);
47 if (flags
& BMAP_SET
) {
50 if ((fs
->flags
& EXT2_FLAG_SWAP_BYTES
) ||
51 (fs
->flags
& EXT2_FLAG_SWAP_BYTES_WRITE
))
54 ((blk_t
*) block_buf
)[nr
] = b
;
55 return io_channel_write_blk(fs
->io
, ind
, 1, block_buf
);
58 b
= ((blk_t
*) block_buf
)[nr
];
61 if ((fs
->flags
& EXT2_FLAG_SWAP_BYTES
) ||
62 (fs
->flags
& EXT2_FLAG_SWAP_BYTES_READ
))
66 if (!b
&& (flags
& BMAP_ALLOC
)) {
67 b
= nr
? ((blk_t
*) block_buf
)[nr
-1] : 0;
68 retval
= ext2fs_alloc_block(fs
, b
,
69 block_buf
+ fs
->blocksize
, &b
);
74 if ((fs
->flags
& EXT2_FLAG_SWAP_BYTES
) ||
75 (fs
->flags
& EXT2_FLAG_SWAP_BYTES_WRITE
))
76 ((blk_t
*) block_buf
)[nr
] = ext2fs_swab32(b
);
79 ((blk_t
*) block_buf
)[nr
] = b
;
81 retval
= io_channel_write_blk(fs
->io
, ind
, 1, block_buf
);
92 static errcode_t
block_dind_bmap(ext2_filsys fs
, int flags
,
93 blk_t dind
, char *block_buf
,
95 blk_t nr
, blk_t
*ret_blk
)
101 addr_per_block
= (blk_t
) fs
->blocksize
>> 2;
103 retval
= block_ind_bmap(fs
, flags
& ~BMAP_SET
, dind
, block_buf
,
104 blocks_alloc
, nr
/ addr_per_block
, &b
);
107 retval
= block_ind_bmap(fs
, flags
, b
, block_buf
, blocks_alloc
,
108 nr
% addr_per_block
, ret_blk
);
112 static errcode_t
block_tind_bmap(ext2_filsys fs
, int flags
,
113 blk_t tind
, char *block_buf
,
115 blk_t nr
, blk_t
*ret_blk
)
119 blk_t addr_per_block
;
121 addr_per_block
= (blk_t
) fs
->blocksize
>> 2;
123 retval
= block_dind_bmap(fs
, flags
& ~BMAP_SET
, tind
, block_buf
,
124 blocks_alloc
, nr
/ addr_per_block
, &b
);
127 retval
= block_ind_bmap(fs
, flags
, b
, block_buf
, blocks_alloc
,
128 nr
% addr_per_block
, ret_blk
);
132 errcode_t
ext2fs_bmap(ext2_filsys fs
, ext2_ino_t ino
, struct ext2_inode
*inode
,
133 char *block_buf
, int bmap_flags
, blk_t block
,
136 struct ext2_inode inode_buf
;
137 blk_t addr_per_block
;
140 errcode_t retval
= 0;
141 int blocks_alloc
= 0, inode_dirty
= 0;
143 if (!(bmap_flags
& BMAP_SET
))
146 /* Read inode structure if necessary */
148 retval
= ext2fs_read_inode(fs
, ino
, &inode_buf
);
153 addr_per_block
= (blk_t
) fs
->blocksize
>> 2;
156 retval
= ext2fs_get_mem(fs
->blocksize
* 2, &buf
);
162 if (block
< EXT2_NDIR_BLOCKS
) {
163 if (bmap_flags
& BMAP_SET
) {
166 if ((fs
->flags
& EXT2_FLAG_SWAP_BYTES
) ||
167 (fs
->flags
& EXT2_FLAG_SWAP_BYTES_READ
))
168 b
= ext2fs_swab32(b
);
170 inode_bmap(inode
, block
) = b
;
175 *phys_blk
= inode_bmap(inode
, block
);
176 b
= block
? inode_bmap(inode
, block
-1) : 0;
178 if ((*phys_blk
== 0) && (bmap_flags
& BMAP_ALLOC
)) {
179 retval
= ext2fs_alloc_block(fs
, b
, block_buf
, &b
);
182 inode_bmap(inode
, block
) = b
;
190 block
-= EXT2_NDIR_BLOCKS
;
191 if (block
< addr_per_block
) {
192 b
= inode_bmap(inode
, EXT2_IND_BLOCK
);
194 if (!(bmap_flags
& BMAP_ALLOC
)) {
195 if (bmap_flags
& BMAP_SET
)
196 retval
= EXT2_ET_SET_BMAP_NO_IND
;
200 b
= inode_bmap(inode
, EXT2_IND_BLOCK
-1);
201 retval
= ext2fs_alloc_block(fs
, b
, block_buf
, &b
);
204 inode_bmap(inode
, EXT2_IND_BLOCK
) = b
;
207 retval
= block_ind_bmap(fs
, bmap_flags
, b
, block_buf
,
208 &blocks_alloc
, block
, phys_blk
);
212 /* Doubly indirect block */
213 block
-= addr_per_block
;
214 if (block
< addr_per_block
* addr_per_block
) {
215 b
= inode_bmap(inode
, EXT2_DIND_BLOCK
);
217 if (!(bmap_flags
& BMAP_ALLOC
)) {
218 if (bmap_flags
& BMAP_SET
)
219 retval
= EXT2_ET_SET_BMAP_NO_IND
;
223 b
= inode_bmap(inode
, EXT2_IND_BLOCK
);
224 retval
= ext2fs_alloc_block(fs
, b
, block_buf
, &b
);
227 inode_bmap(inode
, EXT2_DIND_BLOCK
) = b
;
230 retval
= block_dind_bmap(fs
, bmap_flags
, b
, block_buf
,
231 &blocks_alloc
, block
, phys_blk
);
235 /* Triply indirect block */
236 block
-= addr_per_block
* addr_per_block
;
237 b
= inode_bmap(inode
, EXT2_TIND_BLOCK
);
239 if (!(bmap_flags
& BMAP_ALLOC
)) {
240 if (bmap_flags
& BMAP_SET
)
241 retval
= EXT2_ET_SET_BMAP_NO_IND
;
245 b
= inode_bmap(inode
, EXT2_DIND_BLOCK
);
246 retval
= ext2fs_alloc_block(fs
, b
, block_buf
, &b
);
249 inode_bmap(inode
, EXT2_TIND_BLOCK
) = b
;
252 retval
= block_tind_bmap(fs
, bmap_flags
, b
, block_buf
,
253 &blocks_alloc
, block
, phys_blk
);
255 ext2fs_free_mem(&buf
);
256 if ((retval
== 0) && (blocks_alloc
|| inode_dirty
)) {
257 inode
->i_blocks
+= (blocks_alloc
* fs
->blocksize
) / 512;
258 retval
= ext2fs_write_inode(fs
, ino
, inode
);