source: mainline/uspace/srv/fs/mfs/mfs_rw.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.7 KB
Line 
1/*
2 * Copyright (c) 2011 Maurizio Lombardi
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
31 */
32
33#include <align.h>
34#include "mfs.h"
35
36static errno_t
37rw_map_ondisk(uint32_t *b, const struct mfs_node *mnode, int rblock,
38 bool write_mode, uint32_t w_block);
39
40static errno_t
41reset_zone_content(struct mfs_instance *inst, uint32_t zone);
42
43static errno_t
44alloc_zone_and_clear(struct mfs_instance *inst, uint32_t *zone);
45
46static errno_t
47read_ind_zone(struct mfs_instance *inst, uint32_t zone, uint32_t **ind_zone);
48
49static errno_t
50write_ind_zone(struct mfs_instance *inst, uint32_t zone, uint32_t *ind_zone);
51
52
53/**Given the position in the file expressed in
54 *bytes, this function returns the on-disk block
55 *relative to that position.
56 *
57 * @param b Pointer to a 32bit number where the block number will be stored
58 * @param mnode Pointer to a generic MINIX inode in memory.
59 * @param pos Position in file.
60 *
61 * @return EOK on success or an error code.
62 */
63errno_t
64mfs_read_map(uint32_t *b, const struct mfs_node *mnode, uint32_t pos)
65{
66 errno_t r;
67 const struct mfs_sb_info *sbi = mnode->instance->sbi;
68 const int block_size = sbi->block_size;
69
70 /* Compute relative block number in file */
71 int rblock = pos / block_size;
72
73 if (ROUND_UP(mnode->ino_i->i_size, sbi->block_size) < pos) {
74 /* Trying to read beyond the end of file */
75 r = EOK;
76 *b = 0;
77 goto out;
78 }
79
80 r = rw_map_ondisk(b, mnode, rblock, false, 0);
81out:
82 return r;
83}
84
85errno_t
86mfs_write_map(struct mfs_node *mnode, const uint32_t pos, uint32_t new_zone,
87 uint32_t *old_zone)
88{
89 const struct mfs_sb_info *sbi = mnode->instance->sbi;
90
91 if (pos >= sbi->max_file_size) {
92 /* Can't write beyond the maximum file size */
93 return EINVAL;
94 }
95
96 /* Compute the relative block number in file */
97 int rblock = pos / sbi->block_size;
98
99 return rw_map_ondisk(old_zone, mnode, rblock, true, new_zone);
100}
101
102static errno_t
103rw_map_ondisk(uint32_t *b, const struct mfs_node *mnode, int rblock,
104 bool write_mode, uint32_t w_block)
105{
106 int nr_direct;
107 int ptrs_per_block;
108 uint32_t *ind_zone = NULL, *ind2_zone = NULL;
109 errno_t r = EOK;
110
111 struct mfs_ino_info *ino_i = mnode->ino_i;
112 struct mfs_instance *inst = mnode->instance;
113 struct mfs_sb_info *sbi = inst->sbi;
114
115 const mfs_version_t fs_version = sbi->fs_version;
116 const bool deleting = write_mode && (w_block == 0);
117
118 if (fs_version == MFS_VERSION_V1) {
119 nr_direct = V1_NR_DIRECT_ZONES;
120 ptrs_per_block = MFS_BLOCKSIZE / sizeof(uint16_t);
121 } else {
122 nr_direct = V2_NR_DIRECT_ZONES;
123 ptrs_per_block = sbi->block_size / sizeof(uint32_t);
124 }
125
126 /* Check if the wanted block is in the direct zones */
127 if (rblock < nr_direct) {
128 *b = ino_i->i_dzone[rblock];
129 if (write_mode) {
130 ino_i->i_dzone[rblock] = w_block;
131 ino_i->dirty = true;
132 }
133 goto out;
134 }
135
136 rblock -= nr_direct;
137
138 if (rblock < ptrs_per_block) {
139 /* The wanted block is in the single indirect zone chain */
140 if (ino_i->i_izone[0] == 0) {
141 if (write_mode && !deleting) {
142 uint32_t zone;
143 r = alloc_zone_and_clear(inst, &zone);
144 if (r != EOK)
145 goto out;
146
147 ino_i->i_izone[0] = zone;
148 ino_i->dirty = true;
149 } else {
150 /* Sparse block */
151 *b = 0;
152 goto out;
153 }
154 }
155
156 r = read_ind_zone(inst, ino_i->i_izone[0], &ind_zone);
157 if (r != EOK)
158 goto out;
159
160 *b = ind_zone[rblock];
161 if (write_mode) {
162 ind_zone[rblock] = w_block;
163 write_ind_zone(inst, ino_i->i_izone[0], ind_zone);
164 }
165
166 goto out;
167 }
168
169 rblock -= ptrs_per_block;
170
171 /* The wanted block is in the double indirect zone chain */
172
173 /* Read the first indirect zone of the chain */
174 if (ino_i->i_izone[1] == 0) {
175 if (write_mode && !deleting) {
176 uint32_t zone;
177 r = alloc_zone_and_clear(inst, &zone);
178 if (r != EOK)
179 goto out;
180
181 ino_i->i_izone[1] = zone;
182 ino_i->dirty = true;
183 } else {
184 /* Sparse block */
185 *b = 0;
186 goto out;
187 }
188 }
189
190 r = read_ind_zone(inst, ino_i->i_izone[1], &ind_zone);
191 if (r != EOK)
192 goto out;
193
194 /*
195 * Compute the position of the second indirect
196 * zone pointer in the chain.
197 */
198 uint32_t ind2_off = rblock / ptrs_per_block;
199
200 /* read the second indirect zone of the chain */
201 if (ind_zone[ind2_off] == 0) {
202 if (write_mode && !deleting) {
203 uint32_t zone;
204 r = alloc_zone_and_clear(inst, &zone);
205 if (r != EOK)
206 goto out;
207
208 ind_zone[ind2_off] = zone;
209 write_ind_zone(inst, ino_i->i_izone[1], ind_zone);
210 } else {
211 /* Sparse block */
212 *b = 0;
213 goto out;
214 }
215 }
216
217 r = read_ind_zone(inst, ind_zone[ind2_off], &ind2_zone);
218 if (r != EOK)
219 goto out;
220
221 *b = ind2_zone[rblock - (ind2_off * ptrs_per_block)];
222 if (write_mode) {
223 ind2_zone[rblock - (ind2_off * ptrs_per_block)] = w_block;
224 write_ind_zone(inst, ind_zone[ind2_off], ind2_zone);
225 }
226
227out:
228 free(ind2_zone);
229 free(ind_zone);
230 return r;
231}
232
233/**Free unused indirect zones from a MINIX inode according to its new size.
234 *
235 * @param mnode Pointer to a generic MINIX inode in memory.
236 * @param new_size The new size of the inode.
237 *
238 * @return EOK on success or an error code.
239 */
240errno_t
241mfs_prune_ind_zones(struct mfs_node *mnode, size_t new_size)
242{
243 struct mfs_instance *inst = mnode->instance;
244 struct mfs_sb_info *sbi = inst->sbi;
245 struct mfs_ino_info *ino_i = mnode->ino_i;
246 int nr_direct, ptrs_per_block, rblock;
247 errno_t r;
248 int i;
249
250 mfs_version_t fs_version = sbi->fs_version;
251
252 assert(new_size <= ino_i->i_size);
253
254 if (fs_version == MFS_VERSION_V1) {
255 nr_direct = V1_NR_DIRECT_ZONES;
256 ptrs_per_block = MFS_BLOCKSIZE / sizeof(uint16_t);
257 } else {
258 nr_direct = V2_NR_DIRECT_ZONES;
259 ptrs_per_block = sbi->block_size / sizeof(uint32_t);
260 }
261
262 rblock = new_size / sbi->block_size;
263
264 if (rblock < nr_direct) {
265 /* Free the single indirect zone */
266 if (ino_i->i_izone[0]) {
267 r = mfs_free_zone(inst, ino_i->i_izone[0]);
268 if (r != EOK)
269 return r;
270
271 ino_i->i_izone[0] = 0;
272 ino_i->dirty = true;
273 }
274 }
275
276 rblock -= nr_direct + ptrs_per_block;
277
278 int fzone_to_free = (rblock < 0 ? 0 : rblock) / ptrs_per_block;
279
280 if ((fzone_to_free % ptrs_per_block) != 0)
281 ++fzone_to_free;
282
283 /* Free the entire double indirect zone */
284 uint32_t *dbl_zone;
285
286 if (ino_i->i_izone[1] == 0) {
287 /* Nothing to be done */
288 return EOK;
289 }
290
291 r = read_ind_zone(inst, ino_i->i_izone[1], &dbl_zone);
292 if (r != EOK)
293 return r;
294
295 for (i = fzone_to_free; i < ptrs_per_block; ++i) {
296 if (dbl_zone[i] == 0)
297 continue;
298
299 r = mfs_free_zone(inst, dbl_zone[i]);
300 if (r != EOK)
301 goto out;
302 }
303
304 if (fzone_to_free == 0) {
305 r = mfs_free_zone(inst, ino_i->i_izone[1]);
306 ino_i->i_izone[1] = 0;
307 ino_i->dirty = true;
308 }
309out:
310 free(dbl_zone);
311 return r;
312}
313
314static errno_t
315reset_zone_content(struct mfs_instance *inst, uint32_t zone)
316{
317 block_t *b;
318 errno_t r;
319
320 r = block_get(&b, inst->service_id, zone, BLOCK_FLAGS_NOREAD);
321 if (r != EOK)
322 return r;
323
324 memset(b->data, 0, b->size);
325 b->dirty = true;
326
327 return block_put(b);
328}
329
330static errno_t
331alloc_zone_and_clear(struct mfs_instance *inst, uint32_t *zone)
332{
333 errno_t r;
334
335 r = mfs_alloc_zone(inst, zone);
336 if (r != EOK)
337 return r;
338
339 r = reset_zone_content(inst, *zone);
340 return r;
341}
342
343static errno_t
344read_ind_zone(struct mfs_instance *inst, uint32_t zone, uint32_t **ind_zone)
345{
346 struct mfs_sb_info *sbi = inst->sbi;
347 errno_t r;
348 unsigned i;
349 block_t *b;
350 const int max_ind_zone_ptrs = (MFS_MAX_BLOCKSIZE / sizeof(uint16_t)) *
351 sizeof(uint32_t);
352
353 *ind_zone = malloc(max_ind_zone_ptrs);
354 if (*ind_zone == NULL)
355 return ENOMEM;
356
357 r = block_get(&b, inst->service_id, zone, BLOCK_FLAGS_NONE);
358 if (r != EOK) {
359 free(*ind_zone);
360 return r;
361 }
362
363 if (sbi->fs_version == MFS_VERSION_V1) {
364 uint16_t *src_ptr = b->data;
365
366 for (i = 0; i < sbi->block_size / sizeof(uint16_t); ++i)
367 (*ind_zone)[i] = conv16(sbi->native, src_ptr[i]);
368 } else {
369 uint32_t *src_ptr = b->data;
370
371 for (i = 0; i < sbi->block_size / sizeof(uint32_t); ++i)
372 (*ind_zone)[i] = conv32(sbi->native, src_ptr[i]);
373 }
374
375 return block_put(b);
376}
377
378static errno_t
379write_ind_zone(struct mfs_instance *inst, uint32_t zone, uint32_t *ind_zone)
380{
381 struct mfs_sb_info *sbi = inst->sbi;
382 errno_t r;
383 unsigned i;
384 block_t *b;
385
386 r = block_get(&b, inst->service_id, zone, BLOCK_FLAGS_NOREAD);
387 if (r != EOK)
388 return r;
389
390 if (sbi->fs_version == MFS_VERSION_V1) {
391 uint16_t *dest_ptr = b->data;
392
393 for (i = 0; i < sbi->block_size / sizeof(uint16_t); ++i)
394 dest_ptr[i] = conv16(sbi->native, ind_zone[i]);
395 } else {
396 uint32_t *dest_ptr = b->data;
397
398 for (i = 0; i < sbi->block_size / sizeof(uint32_t); ++i)
399 dest_ptr[i] = conv32(sbi->native, ind_zone[i]);
400
401 }
402 b->dirty = true;
403
404 return block_put(b);
405}
406
407
408/**
409 * @}
410 */
411
Note: See TracBrowser for help on using the repository browser.