2 * bmap.c --- logical to phiscal block mapping
4 * Copyright (C) 1997 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Public
18 #if EXT2_FLAT_INCLUDES
21 #include <linux/ext2_fs.h>
26 #if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
27 #define _BMAP_INLINE_ __inline__
32 extern errcode_t ext2fs_bmap(ext2_filsys fs, ino_t ino,
33 struct ext2_inode *inode,
34 char *block_buf, int bmap_flags,
35 blk_t block, blk_t *phys_blk);
39 #define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
41 static errcode_t _BMAP_INLINE_ block_ind_bmap(ext2_filsys fs, int flags,
42 blk_t ind, char *block_buf,
44 blk_t nr, blk_t *ret_blk)
53 retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
57 b = ((blk_t *) block_buf)[nr];
59 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
60 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
63 if (!b && (flags & BMAP_ALLOC)) {
64 b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
65 retval = ext2fs_alloc_block(fs, b,
66 block_buf + fs->blocksize, &b);
70 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
71 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
72 ((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
74 ((blk_t *) block_buf)[nr] = b;
76 retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
87 static errcode_t _BMAP_INLINE_ block_dind_bmap(ext2_filsys fs, int flags,
88 blk_t dind, char *block_buf,
90 blk_t nr, blk_t *ret_blk)
96 addr_per_block = (blk_t) fs->blocksize >> 2;
98 retval = block_ind_bmap(fs, flags, dind, block_buf, blocks_alloc,
99 nr / addr_per_block, &b);
102 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
103 nr % addr_per_block, ret_blk);
107 static errcode_t _BMAP_INLINE_ block_tind_bmap(ext2_filsys fs, int flags,
108 blk_t tind, char *block_buf,
110 blk_t nr, blk_t *ret_blk)
114 blk_t addr_per_block;
116 addr_per_block = (blk_t) fs->blocksize >> 2;
118 retval = block_dind_bmap(fs, flags, tind, block_buf, blocks_alloc,
119 nr / addr_per_block, &b);
122 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
123 nr % addr_per_block, ret_blk);
127 errcode_t ext2fs_bmap(ext2_filsys fs, ino_t ino, struct ext2_inode *inode,
128 char *block_buf, int bmap_flags, blk_t block,
131 struct ext2_inode inode_buf;
132 blk_t addr_per_block;
135 errcode_t retval = 0;
136 int blocks_alloc = 0;
140 /* Read inode structure if necessary */
142 retval = ext2fs_read_inode(fs, ino, &inode_buf);
147 addr_per_block = (blk_t) fs->blocksize >> 2;
150 retval = ext2fs_get_mem(fs->blocksize * 2, (void **) &buf);
156 if (block < EXT2_NDIR_BLOCKS) {
157 *phys_blk = inode_bmap(inode, block);
158 b = block ? inode_bmap(inode, block-1) : 0;
160 if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
161 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
164 inode_bmap(inode, block) = b;
172 block -= EXT2_NDIR_BLOCKS;
173 if (block < addr_per_block) {
174 b = inode_bmap(inode, EXT2_IND_BLOCK);
176 if (!(bmap_flags & BMAP_ALLOC))
179 b = inode_bmap(inode, EXT2_IND_BLOCK-1);
180 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
183 inode_bmap(inode, EXT2_IND_BLOCK) = b;
186 retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
187 &blocks_alloc, block, phys_blk);
191 /* Doubly indirect block */
192 block -= addr_per_block;
193 if (block < addr_per_block * addr_per_block) {
194 b = inode_bmap(inode, EXT2_DIND_BLOCK);
196 if (!(bmap_flags & BMAP_ALLOC))
199 b = inode_bmap(inode, EXT2_IND_BLOCK);
200 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
203 inode_bmap(inode, EXT2_DIND_BLOCK) = b;
206 retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
207 &blocks_alloc, block, phys_blk);
211 /* Triply indirect block */
212 block -= addr_per_block * addr_per_block;
213 b = inode_bmap(inode, EXT2_TIND_BLOCK);
215 if (!(bmap_flags & BMAP_ALLOC))
218 b = inode_bmap(inode, EXT2_DIND_BLOCK);
219 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
222 inode_bmap(inode, EXT2_TIND_BLOCK) = b;
225 retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
226 &blocks_alloc, block, phys_blk);
229 ext2fs_free_mem((void **) &buf);
230 if ((retval == 0) && blocks_alloc) {
231 inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
232 retval = ext2fs_write_inode(fs, ino, inode);