blob: e4846e81eb499cbc5dd1acddfd50935331805a28 [file] [log] [blame]
Theodore Ts'o30fab291997-10-25 22:37:42 +00001/*
2 * bmap.c --- logical to phiscal block mapping
3 *
4 * Copyright (C) 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
Theodore Ts'o30fab291997-10-25 22:37:42 +000017
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000018#if EXT2_FLAT_INCLUDES
19#include "ext2_fs.h"
20#else
Theodore Ts'o30fab291997-10-25 22:37:42 +000021#include <linux/ext2_fs.h>
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000022#endif
Theodore Ts'o30fab291997-10-25 22:37:42 +000023
24#include "ext2fs.h"
25
Theodore Ts'o78d8f901997-10-26 01:53:39 +000026#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
Theodore Ts'o30fab291997-10-25 22:37:42 +000027#define _BMAP_INLINE_ __inline__
28#else
29#define _BMAP_INLINE_
30#endif
31
32extern 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);
36
37#define BMAP_ALLOC 1
38
39#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
40
41static blk_t _BMAP_INLINE_ block_bmap(ext2_filsys fs, char *buf, blk_t nr)
42{
43 blk_t tmp;
44
45 tmp = ((blk_t *) buf)[nr];
46
47 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
48 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
49 return ext2fs_swab32(tmp);
50
51 return tmp;
52}
53
54static errcode_t _BMAP_INLINE_ block_ind_bmap(ext2_filsys fs, int flags,
55 blk_t ind, char *block_buf,
56 int *blocks_alloc,
57 blk_t nr, blk_t *ret_blk)
58{
59 errcode_t retval;
60 blk_t b;
61
62 if (!ind) {
63 *ret_blk = 0;
64 return 0;
65 }
66 retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
67 if (retval)
68 return retval;
69
70 b = ((blk_t *) block_buf)[nr];
71
72 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
73 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
74 b = ext2fs_swab32(b);
75
76 if (!b && (flags & BMAP_ALLOC)) {
77 b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
78 retval = ext2fs_alloc_block(fs, b,
79 block_buf + fs->blocksize, &b);
80 if (retval)
81 return retval;
82
83 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
84 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
85 ((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
86 else
87 ((blk_t *) block_buf)[nr] = b;
88
89 retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
90 if (retval)
91 return retval;
92
93 (*blocks_alloc)++;
94 }
95
96 *ret_blk = b;
97 return 0;
98}
99
100static errcode_t _BMAP_INLINE_ block_dind_bmap(ext2_filsys fs, int flags,
101 blk_t dind, char *block_buf,
102 int *blocks_alloc,
103 blk_t nr, blk_t *ret_blk)
104{
105 blk_t b;
106 errcode_t retval;
107 int addr_per_block;
108
109 addr_per_block = fs->blocksize >> 2;
110
111 retval = block_ind_bmap(fs, flags, dind, block_buf, blocks_alloc,
112 nr / addr_per_block, &b);
113 if (retval)
114 return retval;
115 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
116 nr % addr_per_block, ret_blk);
117 return retval;
118}
119
120static errcode_t _BMAP_INLINE_ block_tind_bmap(ext2_filsys fs, int flags,
121 blk_t tind, char *block_buf,
122 int *blocks_alloc,
123 blk_t nr, blk_t *ret_blk)
124{
125 blk_t b;
126 errcode_t retval;
127 int addr_per_block;
128
129 addr_per_block = fs->blocksize >> 2;
130
131 retval = block_dind_bmap(fs, flags, tind, block_buf, blocks_alloc,
132 nr / addr_per_block, &b);
133 if (retval)
134 return retval;
135 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
136 nr % addr_per_block, ret_blk);
137 return retval;
138}
139
140errcode_t ext2fs_bmap(ext2_filsys fs, ino_t ino, struct ext2_inode *inode,
141 char *block_buf, int bmap_flags, blk_t block,
142 blk_t *phys_blk)
143{
144 struct ext2_inode inode_buf;
145 int addr_per_block;
146 blk_t b;
147 char *buf = 0;
148 errcode_t retval = 0;
149 int blocks_alloc = 0;
150
151 *phys_blk = 0;
152
153 /* Read inode structure if necessary */
154 if (!inode) {
155 retval = ext2fs_read_inode(fs, ino, &inode_buf);
156 if (!retval)
157 return retval;
158 inode = &inode_buf;
159 }
160 addr_per_block = fs->blocksize >> 2;
161
162 if (!block_buf) {
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000163 retval = ext2fs_get_mem(fs->blocksize * 2, (void **) &buf);
164 if (retval)
165 return retval;
Theodore Ts'o30fab291997-10-25 22:37:42 +0000166 block_buf = buf;
167 }
168
169 if (block < EXT2_NDIR_BLOCKS) {
170 *phys_blk = inode_bmap(inode, block);
171 b = block ? inode_bmap(inode, block-1) : 0;
172
173 if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
174 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
175 if (retval)
176 goto done;
177 inode_bmap(inode, block) = b;
178 blocks_alloc++;
179 *phys_blk = b;
180 }
181 goto done;
182 }
183
184 /* Indirect block */
185 block -= EXT2_NDIR_BLOCKS;
186 if (block < addr_per_block) {
187 b = inode_bmap(inode, EXT2_IND_BLOCK);
188 if (!b) {
189 if (!(bmap_flags & BMAP_ALLOC))
190 goto done;
191
192 b = inode_bmap(inode, EXT2_IND_BLOCK-1);
193 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
194 if (retval)
195 goto done;
196 inode_bmap(inode, EXT2_IND_BLOCK) = b;
197 blocks_alloc++;
198 }
199 retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
200 &blocks_alloc, block, phys_blk);
201 goto done;
202 }
203
204 /* Doubly indirect block */
205 block -= addr_per_block;
206 if (block < addr_per_block * addr_per_block) {
207 b = inode_bmap(inode, EXT2_DIND_BLOCK);
208 if (!b) {
209 if (!(bmap_flags & BMAP_ALLOC))
210 goto done;
211
212 b = inode_bmap(inode, EXT2_IND_BLOCK);
213 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
214 if (retval)
215 goto done;
216 inode_bmap(inode, EXT2_DIND_BLOCK) = b;
217 blocks_alloc++;
218 }
219 retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
220 &blocks_alloc, block, phys_blk);
221 goto done;
222 }
223
224 /* Triply indirect block */
225 block -= addr_per_block * addr_per_block;
226 b = inode_bmap(inode, EXT2_TIND_BLOCK);
227 if (!b) {
228 if (!(bmap_flags & BMAP_ALLOC))
229 goto done;
230
231 b = inode_bmap(inode, EXT2_DIND_BLOCK);
232 retval = ext2fs_alloc_block(fs, b, block_buf, &b);
233 if (retval)
234 goto done;
235 inode_bmap(inode, EXT2_TIND_BLOCK) = b;
236 blocks_alloc++;
237 }
238 retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
239 &blocks_alloc, block, phys_blk);
240done:
241 if (buf)
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000242 ext2fs_free_mem((void **) &buf);
Theodore Ts'o30fab291997-10-25 22:37:42 +0000243 if ((retval == 0) && blocks_alloc) {
244 inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
245 retval = ext2fs_write_inode(fs, ino, inode);
246 }
247 return retval;
248}
249
250
251