source: mainline/uspace/lib/ext4/src/superblock.c@ aab85d90

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since aab85d90 was aab85d90, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Basic Ext4 filesystem creation (can only create Ext2-old, 1K blocks).

  • Property mode set to 100644
File size: 36.9 KB
RevLine 
[eb91db7]1/*
[aab85d90]2 * Copyright (c) 2018 Jiri Svoboda
[d1538a1]3 * Copyright (c) 2011 Martin Sucha
[f22d5ef0]4 * Copyright (c) 2012 Frantisek Princ
[eb91db7]5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup libext4
32 * @{
[38542dc]33 */
[eb91db7]34
35/**
[4bfad34]36 * @file superblock.c
[38542dc]37 * @brief Ext4 superblock operations.
[eb91db7]38 */
39
[aab85d90]40#include <align.h>
[fcb0d76]41#include <block.h>
[01ab41b]42#include <byteorder.h>
43#include <errno.h>
[fcb0d76]44#include <mem.h>
[38d150e]45#include <stdlib.h>
[aab85d90]46#include <time.h>
[fcb0d76]47#include "ext4/superblock.h"
[eb91db7]48
[9fc72fb3]49/** Get number of i-nodes in the whole filesystem.
50 *
[38542dc]51 * @param sb Superblock
52 *
53 * @return Number of i-nodes
54 *
[9fc72fb3]55 */
[3712434]56uint32_t ext4_superblock_get_inodes_count(ext4_superblock_t *sb)
[01ab41b]57{
[3712434]58 return uint32_t_le2host(sb->inodes_count);
[01ab41b]59}
60
[9fc72fb3]61/** Set number of i-nodes in the whole filesystem.
62 *
[38542dc]63 * @param sb Superblock
64 * @param count Number of i-nodes
65 *
[9fc72fb3]66 */
[fe27eb4]67void ext4_superblock_set_inodes_count(ext4_superblock_t *sb, uint32_t count)
68{
69 sb->inodes_count = host2uint32_t_le(count);
70}
71
[9fc72fb3]72/** Get number of data blocks in the whole filesystem.
73 *
[38542dc]74 * @param sb Superblock
75 *
76 * @return Number of data blocks
77 *
[9fc72fb3]78 */
[3712434]79uint64_t ext4_superblock_get_blocks_count(ext4_superblock_t *sb)
80{
[38542dc]81 return ((uint64_t) uint32_t_le2host(sb->blocks_count_hi) << 32) |
82 uint32_t_le2host(sb->blocks_count_lo);
[3712434]83}
84
[9fc72fb3]85/** Set number of data blocks in the whole filesystem.
86 *
[38542dc]87 * @param sb Superblock
88 * @param count Number of data blocks
89 *
[9fc72fb3]90 */
[fe27eb4]91void ext4_superblock_set_blocks_count(ext4_superblock_t *sb, uint64_t count)
92{
93 sb->blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
94 sb->blocks_count_hi = host2uint32_t_le(count >> 32);
95}
96
[9fc72fb3]97/** Get number of reserved data blocks in the whole filesystem.
98 *
[38542dc]99 * @param sb Superblock
100 *
101 * @return Number of reserved data blocks
102 *
[9fc72fb3]103 */
[3712434]104uint64_t ext4_superblock_get_reserved_blocks_count(ext4_superblock_t *sb)
105{
[38542dc]106 return ((uint64_t)
107 uint32_t_le2host(sb->reserved_blocks_count_hi) << 32) |
108 uint32_t_le2host(sb->reserved_blocks_count_lo);
[3712434]109}
110
[9fc72fb3]111/** Set number of reserved data blocks in the whole filesystem.
112 *
[38542dc]113 * @param sb Superblock
114 * @param count Number of reserved data blocks
115 *
[9fc72fb3]116 */
[38542dc]117void ext4_superblock_set_reserved_blocks_count(ext4_superblock_t *sb,
118 uint64_t count)
[fe27eb4]119{
120 sb->reserved_blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
121 sb->reserved_blocks_count_hi = host2uint32_t_le(count >> 32);
122}
123
[9fc72fb3]124/** Get number of free data blocks in the whole filesystem.
125 *
[38542dc]126 * @param sb Superblock
127 *
128 * @return Number of free data blocks
129 *
[9fc72fb3]130 */
[3712434]131uint64_t ext4_superblock_get_free_blocks_count(ext4_superblock_t *sb)
132{
[38542dc]133 return ((uint64_t)
134 uint32_t_le2host(sb->free_blocks_count_hi) << 32) |
135 uint32_t_le2host(sb->free_blocks_count_lo);
[3712434]136}
137
[9fc72fb3]138/** Set number of free data blocks in the whole filesystem.
139 *
[38542dc]140 * @param sb Superblock
141 * @param count Number of free data blocks
142 *
[9fc72fb3]143 */
[38542dc]144void ext4_superblock_set_free_blocks_count(ext4_superblock_t *sb,
145 uint64_t count)
[ae3d4f8]146{
147 sb->free_blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
148 sb->free_blocks_count_hi = host2uint32_t_le(count >> 32);
149}
150
[9fc72fb3]151/** Get number of free i-nodes in the whole filesystem.
152 *
[38542dc]153 * @param sb Superblock
154 *
155 * @return Number of free i-nodes
156 *
[9fc72fb3]157 */
[3712434]158uint32_t ext4_superblock_get_free_inodes_count(ext4_superblock_t *sb)
159{
160 return uint32_t_le2host(sb->free_inodes_count);
161}
162
[9fc72fb3]163/** Set number of free i-nodes in the whole filesystem.
164 *
[38542dc]165 * @param sb Superblock
166 * @param count Number of free i-nodes
167 *
[9fc72fb3]168 */
[38542dc]169void ext4_superblock_set_free_inodes_count(ext4_superblock_t *sb,
170 uint32_t count)
[fe27eb4]171{
172 sb->free_inodes_count = host2uint32_t_le(count);
173}
174
[38542dc]175/** Get index of first data block (block where the superblock is located)
176 *
177 * @param sb Superblock
178 *
179 * @return Index of the first data block
[9fc72fb3]180 *
181 */
[3712434]182uint32_t ext4_superblock_get_first_data_block(ext4_superblock_t *sb)
[01ab41b]183{
[9c0c0e1]184 return uint32_t_le2host(sb->first_data_block);
[01ab41b]185}
186
[38542dc]187/** Set index of first data block (block where the superblock is located)
188 *
189 * @param sb Superblock
190 * @param first Index of the first data block
[9fc72fb3]191 *
192 */
[38542dc]193void ext4_superblock_set_first_data_block(ext4_superblock_t *sb,
194 uint32_t first)
[fe27eb4]195{
196 sb->first_data_block = host2uint32_t_le(first);
197}
198
[9fc72fb3]199/** Get logarithmic block size (1024 << size == block_size)
200 *
[38542dc]201 * @param sb Superblock
202 *
203 * @return Logarithmic block size
204 *
[9fc72fb3]205 */
[3712434]206uint32_t ext4_superblock_get_log_block_size(ext4_superblock_t *sb)
[01ab41b]207{
[9c0c0e1]208 return uint32_t_le2host(sb->log_block_size);
[01ab41b]209}
210
[9fc72fb3]211/** Set logarithmic block size (1024 << size == block_size)
212 *
[38542dc]213 * @param sb Superblock
214 *
215 * @return Logarithmic block size
216 *
[9fc72fb3]217 */
[38542dc]218void ext4_superblock_set_log_block_size(ext4_superblock_t *sb,
219 uint32_t log_size)
[fe27eb4]220{
221 sb->log_block_size = host2uint32_t_le(log_size);
222}
223
[9fc72fb3]224/** Get size of data block (in bytes).
225 *
[38542dc]226 * @param sb Superblock
227 *
228 * @return Size of data block
229 *
[9fc72fb3]230 */
[01ab41b]231uint32_t ext4_superblock_get_block_size(ext4_superblock_t *sb)
232{
[3712434]233 return 1024 << ext4_superblock_get_log_block_size(sb);
234}
235
[9fc72fb3]236/** Set size of data block (in bytes).
237 *
[38542dc]238 * @param sb Superblock
239 * @param size Size of data block (must be power of 2, at least 1024)
240 *
[9fc72fb3]241 */
[fe27eb4]242void ext4_superblock_set_block_size(ext4_superblock_t *sb, uint32_t size)
243{
244 uint32_t log = 0;
245 uint32_t tmp = size / EXT4_MIN_BLOCK_SIZE;
[a35b458]246
[fe27eb4]247 tmp >>= 1;
248 while (tmp) {
249 log++;
250 tmp >>= 1;
251 }
[a35b458]252
[fe27eb4]253 ext4_superblock_set_log_block_size(sb, log);
254}
[3712434]255
[fb04cd90]256/** Get logarithmic fragment size (1024 << size)
257 *
[38542dc]258 * @param sb Superblock
259 *
260 * @return Logarithmic fragment size
261 *
[fb04cd90]262 */
263uint32_t ext4_superblock_get_log_frag_size(ext4_superblock_t *sb)
264{
265 return uint32_t_le2host(sb->log_frag_size);
266}
267
268/** Set logarithmic fragment size (1024 << size)
269 *
[38542dc]270 * @param sb Superblock
271 * @param frag_size Logarithmic fragment size
272 *
[fb04cd90]273 */
[38542dc]274void ext4_superblock_set_log_frag_size(ext4_superblock_t *sb,
275 uint32_t frag_size)
[fb04cd90]276{
277 sb->log_frag_size = host2uint32_t_le(frag_size);
278}
279
280/** Get size of fragment (in bytes).
281 *
[38542dc]282 * @param sb Superblock
283 *
284 * @return Size of fragment
285 *
[fb04cd90]286 */
287uint32_t ext4_superblock_get_frag_size(ext4_superblock_t *sb)
288{
289 return 1024 << ext4_superblock_get_log_frag_size(sb);
290}
291
292/** Set size of fragment (in bytes).
293 *
[38542dc]294 * @param sb Superblock
295 * @param size Size of fragment (must be power of 2, at least 1024)
296 *
[fb04cd90]297 */
298void ext4_superblock_set_frag_size(ext4_superblock_t *sb, uint32_t size)
299{
300 uint32_t log = 0;
301 uint32_t tmp = size / EXT4_MIN_BLOCK_SIZE;
[a35b458]302
[fb04cd90]303 tmp >>= 1;
304 while (tmp) {
305 log++;
306 tmp >>= 1;
307 }
[a35b458]308
[fb04cd90]309 ext4_superblock_set_log_frag_size(sb, log);
310}
311
[9fc72fb3]312/** Get number of data blocks per block group (except last BG)
313 *
[38542dc]314 * @param sb Superblock
315 *
316 * @return Data blocks per block group
317 *
[9fc72fb3]318 */
[3712434]319uint32_t ext4_superblock_get_blocks_per_group(ext4_superblock_t *sb)
320{
321 return uint32_t_le2host(sb->blocks_per_group);
322}
323
[9fc72fb3]324/** Set number of data blocks per block group (except last BG)
325 *
[38542dc]326 * @param sb Superblock
327 * @param blocks Data blocks per block group
328 *
[9fc72fb3]329 */
[38542dc]330void ext4_superblock_set_blocks_per_group(ext4_superblock_t *sb,
331 uint32_t blocks)
[fe27eb4]332{
333 sb->blocks_per_group = host2uint32_t_le(blocks);
334}
335
[fb04cd90]336/** Get number of fragments per block group (except last BG)
337 *
[38542dc]338 * @param sb Superblock
339 *
340 * @return Fragments per block group
341 *
[fb04cd90]342 */
343uint32_t ext4_superblock_get_frags_per_group(ext4_superblock_t *sb)
344{
345 return uint32_t_le2host(sb->frags_per_group);
346}
347
348/** Set number of fragment per block group (except last BG)
349 *
[38542dc]350 * @param sb Superblock
351 * @param frags Fragments per block group
[fb04cd90]352 */
353void ext4_superblock_set_frags_per_group(ext4_superblock_t *sb, uint32_t frags)
354{
355 sb->frags_per_group = host2uint32_t_le(frags);
356}
357
[9fc72fb3]358/** Get number of i-nodes per block group (except last BG)
359 *
[38542dc]360 * @param sb Superblock
361 *
362 * @return I-nodes per block group
363 *
[9fc72fb3]364 */
[3712434]365uint32_t ext4_superblock_get_inodes_per_group(ext4_superblock_t *sb)
366{
367 return uint32_t_le2host(sb->inodes_per_group);
368}
369
[9fc72fb3]370/** Set number of i-nodes per block group (except last BG)
371 *
[38542dc]372 * @param sb Superblock
373 * @param inodes I-nodes per block group
374 *
[9fc72fb3]375 */
[38542dc]376void ext4_superblock_set_inodes_per_group(ext4_superblock_t *sb,
377 uint32_t inodes)
[fe27eb4]378{
379 sb->inodes_per_group = host2uint32_t_le(inodes);
380}
381
[9fc72fb3]382/** Get time when filesystem was mounted (POSIX time).
383 *
[38542dc]384 * @param sb Superblock
385 *
386 * @return Mount time
387 *
[9fc72fb3]388 */
[3712434]389uint32_t ext4_superblock_get_mount_time(ext4_superblock_t *sb)
390{
391 return uint32_t_le2host(sb->mount_time);
392}
393
[9fc72fb3]394/** Set time when filesystem was mounted (POSIX time).
395 *
[38542dc]396 * @param sb Superblock
397 * @param time Mount time
398 *
[9fc72fb3]399 */
[fe27eb4]400void ext4_superblock_set_mount_time(ext4_superblock_t *sb, uint32_t time)
401{
402 sb->mount_time = host2uint32_t_le(time);
403}
404
[9fc72fb3]405/** Get time when filesystem was last accesed by write operation (POSIX time).
406 *
[38542dc]407 * @param sb Superblock
408 *
409 * @return Write time
410 *
[9fc72fb3]411 */
[3712434]412uint32_t ext4_superblock_get_write_time(ext4_superblock_t *sb)
413{
414 return uint32_t_le2host(sb->write_time);
415}
416
[9fc72fb3]417/** Set time when filesystem was last accesed by write operation (POSIX time).
418 *
[38542dc]419 * @param sb Superblock
420 * @param time Write time
421 *
[9fc72fb3]422 */
[fe27eb4]423void ext4_superblock_set_write_time(ext4_superblock_t *sb, uint32_t time)
424{
425 sb->write_time = host2uint32_t_le(time);
426}
427
[9fc72fb3]428/** Get number of mount from last filesystem check.
429 *
[38542dc]430 * @param sb Superblock
431 *
432 * @return Number of mounts
433 *
[9fc72fb3]434 */
[3712434]435uint16_t ext4_superblock_get_mount_count(ext4_superblock_t *sb)
436{
437 return uint16_t_le2host(sb->mount_count);
438}
439
[9fc72fb3]440/** Set number of mount from last filesystem check.
441 *
[38542dc]442 * @param sb Superblock
443 * @param count Number of mounts
444 *
[9fc72fb3]445 */
[fe27eb4]446void ext4_superblock_set_mount_count(ext4_superblock_t *sb, uint16_t count)
447{
448 sb->mount_count = host2uint16_t_le(count);
449}
450
[9fc72fb3]451/** Get maximum number of mount from last filesystem check.
452 *
[38542dc]453 * @param sb Superblock
454 *
455 * @return Maximum number of mounts
456 *
[9fc72fb3]457 */
[3712434]458uint16_t ext4_superblock_get_max_mount_count(ext4_superblock_t *sb)
459{
460 return uint16_t_le2host(sb->max_mount_count);
461}
462
[9fc72fb3]463/** Set maximum number of mount from last filesystem check.
464 *
[38542dc]465 * @param sb Superblock
466 * @param count Maximum number of mounts
467 *
[9fc72fb3]468 */
[fe27eb4]469void ext4_superblock_set_max_mount_count(ext4_superblock_t *sb, uint16_t count)
470{
471 sb->max_mount_count = host2uint16_t_le(count);
472}
473
[9fc72fb3]474/** Get superblock magic value.
475 *
[38542dc]476 * @param sb Superblock
477 *
478 * @return Magic value
479 *
[9fc72fb3]480 */
[3712434]481uint16_t ext4_superblock_get_magic(ext4_superblock_t *sb)
482{
483 return uint16_t_le2host(sb->magic);
484}
485
[9fc72fb3]486/** Set superblock magic value.
487 *
[38542dc]488 * @param sb Superblock
489 * @param magic Magic value
490 *
[9fc72fb3]491 */
492void ext4_superblock_set_magic(ext4_superblock_t *sb, uint16_t magic)
493{
494 sb->magic = host2uint16_t_le(magic);
495}
496
[2226cc3]497/** Get filesystem state.
[9fc72fb3]498 *
[38542dc]499 * @param sb Superblock
500 *
501 * @return Filesystem state
502 *
[9fc72fb3]503 */
[3712434]504uint16_t ext4_superblock_get_state(ext4_superblock_t *sb)
505{
506 return uint16_t_le2host(sb->state);
507}
508
[2226cc3]509/** Set filesystem state.
[9fc72fb3]510 *
[38542dc]511 * @param sb Superblock
512 * @param state Filesystem state
513 *
[9fc72fb3]514 */
[fe27eb4]515void ext4_superblock_set_state(ext4_superblock_t *sb, uint16_t state)
516{
517 sb->state = host2uint16_t_le(state);
518}
519
[2226cc3]520/** Get behavior code when errors detected.
[9fc72fb3]521 *
[38542dc]522 * @param sb Superblock
523 *
524 * @return Behavior code
525 *
[9fc72fb3]526 */
[3712434]527uint16_t ext4_superblock_get_errors(ext4_superblock_t *sb)
528{
529 return uint16_t_le2host(sb->errors);
530}
531
[2226cc3]532/** Set behavior code when errors detected.
[9fc72fb3]533 *
[38542dc]534 * @param sb Superblock
535 * @param errors Behavior code
536 *
[9fc72fb3]537 */
[fe27eb4]538void ext4_superblock_set_errors(ext4_superblock_t *sb, uint16_t errors)
539{
540 sb->errors = host2uint16_t_le(errors);
541}
[3712434]542
[2226cc3]543/** Get minor revision level of the filesystem.
[9fc72fb3]544 *
[38542dc]545 * @param sb Superblock
546 *
547 * @return Minor revision level
548 *
[9fc72fb3]549 */
[3712434]550uint16_t ext4_superblock_get_minor_rev_level(ext4_superblock_t *sb)
551{
552 return uint16_t_le2host(sb->minor_rev_level);
553}
554
[2226cc3]555/** Set minor revision level of the filesystem.
[9fc72fb3]556 *
[38542dc]557 * @param sb Superblock
558 * @param level Minor revision level
559 *
[9fc72fb3]560 */
[fe27eb4]561void ext4_superblock_set_minor_rev_level(ext4_superblock_t *sb, uint16_t level)
562{
563 sb->minor_rev_level = host2uint16_t_le(level);
564}
565
[2226cc3]566/** Get time of the last filesystem check.
[9fc72fb3]567 *
[38542dc]568 * @param sb Superblock
569 *
570 * @return Time of the last check (POSIX)
571 *
[9fc72fb3]572 */
[3712434]573uint32_t ext4_superblock_get_last_check_time(ext4_superblock_t *sb)
574{
575 return uint32_t_le2host(sb->last_check_time);
576}
577
[2226cc3]578/** Set time of the last filesystem check.
[9fc72fb3]579 *
[38542dc]580 * @param sb Superblock
581 * @param time Time of the last check (POSIX)
582 *
[9fc72fb3]583 */
[fe27eb4]584void ext4_superblock_set_last_check_time(ext4_superblock_t *sb, uint32_t time)
585{
[aab85d90]586 sb->last_check_time = host2uint32_t_le(time);
[fe27eb4]587}
588
[2226cc3]589/** Get maximum time interval between two filesystem checks.
[9fc72fb3]590 *
[38542dc]591 * @param sb Superblock
592 *
593 * @return Time interval between two check (POSIX)
594 *
[9fc72fb3]595 */
[38542dc]596uint32_t ext4_superblock_get_check_interval(ext4_superblock_t *sb)
597{
[3712434]598 return uint32_t_le2host(sb->check_interval);
599}
600
[2226cc3]601/** Set maximum time interval between two filesystem checks.
[9fc72fb3]602 *
[38542dc]603 * @param sb Superblock
604 * @param interval Time interval between two check (POSIX)
605 *
[9fc72fb3]606 */
[fe27eb4]607void ext4_superblock_set_check_interval(ext4_superblock_t *sb, uint32_t interval)
608{
609 sb->check_interval = host2uint32_t_le(interval);
610}
611
[2226cc3]612/** Get operation system identifier, on which the filesystem was created.
[9fc72fb3]613 *
[38542dc]614 * @param sb Superblock
615 *
616 * @return Operation system identifier
617 *
[9fc72fb3]618 */
[3712434]619uint32_t ext4_superblock_get_creator_os(ext4_superblock_t *sb)
620{
621 return uint32_t_le2host(sb->creator_os);
[01ab41b]622}
623
[2226cc3]624/** Set operation system identifier, on which the filesystem was created.
[9fc72fb3]625 *
[38542dc]626 * @param sb Superblock
627 * @param os Operation system identifier
628 *
[9fc72fb3]629 */
[fe27eb4]630void ext4_superblock_set_creator_os(ext4_superblock_t *sb, uint32_t os)
631{
632 sb->creator_os = host2uint32_t_le(os);
633}
634
[2226cc3]635/** Get revision level of the filesystem.
[9fc72fb3]636 *
[38542dc]637 * @param sb Superblock
638 *
639 * @return Revision level
640 *
[9fc72fb3]641 */
[9c0c0e1]642uint32_t ext4_superblock_get_rev_level(ext4_superblock_t *sb)
643{
644 return uint32_t_le2host(sb->rev_level);
645}
646
[2226cc3]647/** Set revision level of the filesystem.
[9fc72fb3]648 *
[38542dc]649 * @param sb Superblock
650 * @param level Revision level
651 *
[9fc72fb3]652 */
[fe27eb4]653void ext4_superblock_set_rev_level(ext4_superblock_t *sb, uint32_t level)
654{
655 sb->rev_level = host2uint32_t_le(level);
656}
657
[2226cc3]658/** Get default user id for reserved blocks.
[9fc72fb3]659 *
[38542dc]660 * @param sb Superblock
661 *
662 * @return Default user id for reserved blocks.
663 *
[9fc72fb3]664 */
[fe27eb4]665uint16_t ext4_superblock_get_def_resuid(ext4_superblock_t *sb)
666{
667 return uint16_t_le2host(sb->def_resuid);
668}
669
[2226cc3]670/** Set default user id for reserved blocks.
[9fc72fb3]671 *
[38542dc]672 * @param sb Superblock
673 * @param uid Default user id for reserved blocks.
674 *
[9fc72fb3]675 */
[fe27eb4]676void ext4_superblock_set_def_resuid(ext4_superblock_t *sb, uint16_t uid)
677{
678 sb->def_resuid = host2uint16_t_le(uid);
679}
680
[2226cc3]681/** Get default group id for reserved blocks.
[9fc72fb3]682 *
[38542dc]683 * @param sb Superblock
684 *
685 * @return Default group id for reserved blocks.
686 *
[9fc72fb3]687 */
[fe27eb4]688uint16_t ext4_superblock_get_def_resgid(ext4_superblock_t *sb)
689{
690 return uint16_t_le2host(sb->def_resgid);
691}
692
[2226cc3]693/** Set default group id for reserved blocks.
[9fc72fb3]694 *
[38542dc]695 * @param sb Superblock
696 * @param gid Default group id for reserved blocks.
697 *
[9fc72fb3]698 */
[fe27eb4]699void ext4_superblock_set_def_resgid(ext4_superblock_t *sb, uint16_t gid)
700{
701 sb->def_resgid = host2uint16_t_le(gid);
702}
703
[2226cc3]704/** Get index of the first i-node, which can be used for allocation.
[9fc72fb3]705 *
[38542dc]706 * @param sb Superblock
707 *
708 * @return I-node index
709 *
[9fc72fb3]710 */
[fe27eb4]711uint32_t ext4_superblock_get_first_inode(ext4_superblock_t *sb)
712{
[aab85d90]713 if (ext4_superblock_get_rev_level(sb) == 0)
714 return EXT4_REV0_FIRST_INO;
715
[fe27eb4]716 return uint32_t_le2host(sb->first_inode);
717}
718
[2226cc3]719/** Set index of the first i-node, which can be used for allocation.
[9fc72fb3]720 *
[38542dc]721 * @param sb Superblock
722 * @param first_inode I-node index
723 *
[9fc72fb3]724 */
[38542dc]725void ext4_superblock_set_first_inode(ext4_superblock_t *sb,
726 uint32_t first_inode)
[fe27eb4]727{
728 sb->first_inode = host2uint32_t_le(first_inode);
729}
730
[2226cc3]731/** Get size of i-node structure.
732 *
733 * For the oldest revision return constant number.
[9fc72fb3]734 *
[38542dc]735 * @param sb Superblock
736 *
737 * @return Size of i-node structure
738 *
[9fc72fb3]739 */
[3711e7e]740uint16_t ext4_superblock_get_inode_size(ext4_superblock_t *sb)
741{
[38542dc]742 if (ext4_superblock_get_rev_level(sb) == 0)
[3711e7e]743 return EXT4_REV0_INODE_SIZE;
[a35b458]744
[3711e7e]745 return uint16_t_le2host(sb->inode_size);
746}
747
[2226cc3]748/** Set size of i-node structure.
[9fc72fb3]749 *
[38542dc]750 * @param sb Superblock
751 * @param size Size of i-node structure
752 *
[9fc72fb3]753 */
[fe27eb4]754void ext4_superblock_set_inode_size(ext4_superblock_t *sb, uint16_t size)
755{
756 sb->inode_size = host2uint16_t_le(size);
757}
758
[2226cc3]759/** Get index of block group, where superblock copy is located.
[9fc72fb3]760 *
[38542dc]761 * @param sb Superblock
762 *
763 * @return Block group index
764 *
[9fc72fb3]765 */
[2226cc3]766uint16_t ext4_superblock_get_block_group_index(ext4_superblock_t *sb)
[3711e7e]767{
[2226cc3]768 return uint16_t_le2host(sb->block_group_index);
[3711e7e]769}
770
[2226cc3]771/** Set index of block group, where superblock copy is located.
[9fc72fb3]772 *
[38542dc]773 * @param sb Superblock
774 * @param bgid Block group index
775 *
[9fc72fb3]776 */
[2226cc3]777void ext4_superblock_set_block_group_index(ext4_superblock_t *sb, uint16_t bgid)
[fe27eb4]778{
[2226cc3]779 sb->block_group_index = host2uint16_t_le(bgid);
[fe27eb4]780}
781
[2226cc3]782/** Get compatible features supported by the filesystem.
[9fc72fb3]783 *
[38542dc]784 * @param sb Superblock
785 *
786 * @return Compatible features bitmap
787 *
[9fc72fb3]788 */
[9c0c0e1]789uint32_t ext4_superblock_get_features_compatible(ext4_superblock_t *sb)
790{
791 return uint32_t_le2host(sb->features_compatible);
792}
793
[2226cc3]794/** Set compatible features supported by the filesystem.
[9fc72fb3]795 *
[38542dc]796 * @param sb Superblock
797 * @param features Compatible features bitmap
798 *
[9fc72fb3]799 */
[38542dc]800void ext4_superblock_set_features_compatible(ext4_superblock_t *sb,
801 uint32_t features)
[fe27eb4]802{
803 sb->features_compatible = host2uint32_t_le(features);
804}
805
[2226cc3]806/** Get incompatible features supported by the filesystem.
[9fc72fb3]807 *
[38542dc]808 * @param sb Superblock
809 *
810 * @return Incompatible features bitmap
811 *
[9fc72fb3]812 */
[9c0c0e1]813uint32_t ext4_superblock_get_features_incompatible(ext4_superblock_t *sb)
814{
815 return uint32_t_le2host(sb->features_incompatible);
816}
817
[2226cc3]818/** Set incompatible features supported by the filesystem.
[9fc72fb3]819 *
[38542dc]820 * @param sb Superblock
821 * @param features Incompatible features bitmap
822 *
[9fc72fb3]823 */
[38542dc]824void ext4_superblock_set_features_incompatible(ext4_superblock_t *sb,
825 uint32_t features)
[fe27eb4]826{
827 sb->features_incompatible = host2uint32_t_le(features);
828}
829
[2226cc3]830/** Get compatible features supported by the filesystem.
[9fc72fb3]831 *
[38542dc]832 * @param sb Superblock
833 *
834 * @return Read-only compatible features bitmap
835 *
[9fc72fb3]836 */
[9c0c0e1]837uint32_t ext4_superblock_get_features_read_only(ext4_superblock_t *sb)
838{
839 return uint32_t_le2host(sb->features_read_only);
840}
841
[2226cc3]842/** Set compatible features supported by the filesystem.
[9fc72fb3]843 *
[38542dc]844 * @param sb Superblock
845 * @param feature Read-only compatible features bitmap
846 *
[9fc72fb3]847 */
[38542dc]848void ext4_superblock_set_features_read_only(ext4_superblock_t *sb,
849 uint32_t features)
[fe27eb4]850{
851 sb->features_read_only = host2uint32_t_le(features);
852}
[01ab41b]853
[2226cc3]854/** Get UUID of the filesystem.
[9fc72fb3]855 *
[38542dc]856 * @param sb superblock
857 *
858 * @return Pointer to UUID array
859 *
[9fc72fb3]860 */
[aab85d90]861void ext4_superblock_get_uuid(ext4_superblock_t *sb, uuid_t *uuid)
[291af81]862{
[aab85d90]863 uuid_decode(sb->uuid, uuid);
[291af81]864}
865
[2226cc3]866/** Set UUID of the filesystem.
[9fc72fb3]867 *
[38542dc]868 * @param sb Superblock
[aab85d90]869 * @param uuid Pointer to UUID
[38542dc]870 *
[9fc72fb3]871 */
[aab85d90]872void ext4_superblock_set_uuid(ext4_superblock_t *sb, uuid_t *uuid)
[291af81]873{
[aab85d90]874 uuid_encode(uuid, sb->uuid);
[291af81]875}
876
[2226cc3]877/** Get name of the filesystem volume.
878 *
[38542dc]879 * @param sb Superblock
880 *
881 * @return Name of the volume
882 *
[2226cc3]883 */
[38542dc]884const char *ext4_superblock_get_volume_name(ext4_superblock_t *sb)
[291af81]885{
886 return sb->volume_name;
887}
888
[2226cc3]889/** Set name of the filesystem volume.
[9fc72fb3]890 *
[38542dc]891 * @param sb Superblock
892 * @param name New name of the volume
[9fc72fb3]893 */
[291af81]894void ext4_superblock_set_volume_name(ext4_superblock_t *sb, const char *name)
895{
896 memcpy(sb->volume_name, name, sizeof(sb->volume_name));
897}
898
[2226cc3]899/** Get name of the directory, where this filesystem was mounted at last.
[9fc72fb3]900 *
[38542dc]901 * @param sb Superblock
902 *
903 * @return Directory name
904 *
[9fc72fb3]905 */
[38542dc]906const char *ext4_superblock_get_last_mounted(ext4_superblock_t *sb)
[291af81]907{
908 return sb->last_mounted;
909}
910
[2226cc3]911/** Set name of the directory, where this filesystem was mounted at last.
[9fc72fb3]912 *
[38542dc]913 * @param sb Superblock
914 * @param last Directory name
915 *
[9fc72fb3]916 */
[291af81]917void ext4_superblock_set_last_mounted(ext4_superblock_t *sb, const char *last)
918{
919 memcpy(sb->last_mounted, last, sizeof(sb->last_mounted));
920}
921
[2226cc3]922/** Get last orphaned i-node index.
923 *
924 * Orphans are stored in linked list.
[9fc72fb3]925 *
[38542dc]926 * @param sb Superblock
927 *
928 * @return Last orphaned i-node index
929 *
[9fc72fb3]930 */
[ebcaff4]931uint32_t ext4_superblock_get_last_orphan(ext4_superblock_t *sb)
932{
933 return uint32_t_le2host(sb->last_orphan);
934}
935
[2226cc3]936/** Set last orphaned i-node index.
937 *
938 * Orphans are stored in linked list.
[9fc72fb3]939 *
[38542dc]940 * @param sb Superblock
941 * @param last_orphan Last orphaned i-node index
942 *
[9fc72fb3]943 */
[38542dc]944void ext4_superblock_set_last_orphan(ext4_superblock_t *sb,
945 uint32_t last_orphan)
[ebcaff4]946{
947 sb->last_orphan = host2uint32_t_le(last_orphan);
948}
949
[2226cc3]950/** Get hash seed for directory index hash function.
[9fc72fb3]951 *
[38542dc]952 * @param sb Superblock
953 *
954 * @return Hash seed pointer
955 *
[9fc72fb3]956 */
[38542dc]957const uint32_t *ext4_superblock_get_hash_seed(ext4_superblock_t *sb)
[7bc4508]958{
959 return sb->hash_seed;
960}
961
[2226cc3]962/** Set hash seed for directory index hash function.
[9fc72fb3]963 *
[38542dc]964 * @param sb Superblock
965 * @param seed Hash seed pointer
966 *
[2226cc3]967 */
968void ext4_superblock_set_hash_seed(ext4_superblock_t *sb, const uint32_t *seed)
969{
970 memcpy(sb->hash_seed, seed, sizeof(sb->hash_seed));
971}
972
973/** Get default version of the hash algorithm version for directory index.
974 *
[38542dc]975 * @param sb Superblock
976 *
977 * @return Default hash version
978 *
[9fc72fb3]979 */
[7eb033ce]980uint8_t ext4_superblock_get_default_hash_version(ext4_superblock_t *sb)
981{
982 return sb->default_hash_version;
983}
984
[2226cc3]985/** Set default version of the hash algorithm version for directory index.
[9fc72fb3]986 *
[38542dc]987 * @param sb Superblock
988 * @param version Default hash version
989 *
[9fc72fb3]990 */
[38542dc]991void ext4_superblock_set_default_hash_version(ext4_superblock_t *sb,
992 uint8_t version)
[7eb033ce]993{
994 sb->default_hash_version = version;
995}
996
[2226cc3]997/** Get size of block group descriptor structure.
[9fc72fb3]998 *
[2226cc3]999 * Output value is checked for minimal size.
1000 *
[38542dc]1001 * @param sb Superblock
1002 *
1003 * @return Size of block group descriptor
1004 *
[9fc72fb3]1005 */
[c25e39b]1006uint16_t ext4_superblock_get_desc_size(ext4_superblock_t *sb)
1007{
1008 uint16_t size = uint16_t_le2host(sb->desc_size);
[a35b458]1009
[38542dc]1010 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
[fb04cd90]1011 size = EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE;
[a35b458]1012
[c25e39b]1013 return size;
1014}
1015
[2226cc3]1016/** Set size of block group descriptor structure.
1017 *
1018 * Input value is checked for minimal size.
[9fc72fb3]1019 *
[38542dc]1020 * @param sb Superblock
1021 * @param size Size of block group descriptor
1022 *
[9fc72fb3]1023 */
[fe27eb4]1024void ext4_superblock_set_desc_size(ext4_superblock_t *sb, uint16_t size)
1025{
[38542dc]1026 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
1027 sb->desc_size =
1028 host2uint16_t_le(EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE);
[a35b458]1029
[fe27eb4]1030 sb->desc_size = host2uint16_t_le(size);
1031}
1032
[2226cc3]1033/** Get superblock flags.
[9fc72fb3]1034 *
[38542dc]1035 * @param sb Superblock
1036 *
1037 * @return Flags from the superblock
1038 *
[9fc72fb3]1039 */
[7bc4508]1040uint32_t ext4_superblock_get_flags(ext4_superblock_t *sb)
1041{
1042 return uint32_t_le2host(sb->flags);
1043}
1044
[2226cc3]1045/** Set superblock flags.
[9fc72fb3]1046 *
[38542dc]1047 * @param sb Superblock
1048 * @param flags Flags for the superblock
1049 *
[9fc72fb3]1050 */
[fe27eb4]1051void ext4_superblock_set_flags(ext4_superblock_t *sb, uint32_t flags)
1052{
1053 sb->flags = host2uint32_t_le(flags);
1054}
1055
[3712434]1056/*
[c25e39b]1057 * More complex superblock operations
[01ab41b]1058 */
[3712434]1059
[2226cc3]1060/** Check if superblock has specified flag.
[9fc72fb3]1061 *
[38542dc]1062 * @param sb Superblock
1063 * @param flag Flag to be checked
1064 *
1065 * @return True, if superblock has the flag
1066 *
[9fc72fb3]1067 */
[7bc4508]1068bool ext4_superblock_has_flag(ext4_superblock_t *sb, uint32_t flag)
1069{
[38542dc]1070 if (ext4_superblock_get_flags(sb) & flag)
[7bc4508]1071 return true;
[a35b458]1072
[7bc4508]1073 return false;
1074}
1075
[2226cc3]1076/** Check if filesystem supports compatible feature.
[9fc72fb3]1077 *
[38542dc]1078 * @param sb Superblock
1079 * @param feature Feature to be checked
1080 *
1081 * @return True, if filesystem supports the feature
1082 *
[9fc72fb3]1083 */
[38542dc]1084bool ext4_superblock_has_feature_compatible(ext4_superblock_t *sb,
1085 uint32_t feature)
[c25e39b]1086{
[38542dc]1087 if (ext4_superblock_get_features_compatible(sb) & feature)
[c25e39b]1088 return true;
[a35b458]1089
[c25e39b]1090 return false;
1091}
1092
[2226cc3]1093/** Check if filesystem supports incompatible feature.
[9fc72fb3]1094 *
[38542dc]1095 * @param sb Superblock
1096 * @param feature Feature to be checked
1097 *
1098 * @return True, if filesystem supports the feature
1099 *
[9fc72fb3]1100 */
[38542dc]1101bool ext4_superblock_has_feature_incompatible(ext4_superblock_t *sb,
1102 uint32_t feature)
[c25e39b]1103{
[38542dc]1104 if (ext4_superblock_get_features_incompatible(sb) & feature)
[c25e39b]1105 return true;
[a35b458]1106
[c25e39b]1107 return false;
1108}
1109
[2226cc3]1110/** Check if filesystem supports read-only compatible feature.
[9fc72fb3]1111 *
[38542dc]1112 * @param sb Superblock
1113 * @param feature Feature to be checked
1114 *
1115 * @return True, if filesystem supports the feature
1116 *
[9fc72fb3]1117 */
[38542dc]1118bool ext4_superblock_has_feature_read_only(ext4_superblock_t *sb,
1119 uint32_t feature)
[c25e39b]1120{
[38542dc]1121 if (ext4_superblock_get_features_read_only(sb) & feature)
[c25e39b]1122 return true;
[a35b458]1123
[c25e39b]1124 return false;
1125}
1126
[2226cc3]1127/** Read superblock directly from block device.
[9fc72fb3]1128 *
[38542dc]1129 * @param service_id Block device identifier
1130 * @param sb Output pointer to memory structure
1131 *
1132 * @return Eerror code.
1133 *
[9fc72fb3]1134 */
[b7fd2a0]1135errno_t ext4_superblock_read_direct(service_id_t service_id, ext4_superblock_t **sb)
[01ab41b]1136{
[06d85e5]1137 /* Allocated memory for superblock structure */
[d9bbe45]1138 void *data = malloc(EXT4_SUPERBLOCK_SIZE);
[38542dc]1139 if (data == NULL)
[01ab41b]1140 return ENOMEM;
[a35b458]1141
[06d85e5]1142 /* Read data from block device */
[b7fd2a0]1143 errno_t rc = block_read_bytes_direct(service_id, EXT4_SUPERBLOCK_OFFSET,
[01ab41b]1144 EXT4_SUPERBLOCK_SIZE, data);
[a35b458]1145
[01ab41b]1146 if (rc != EOK) {
1147 free(data);
1148 return rc;
1149 }
[a35b458]1150
[06d85e5]1151 /* Set output value */
[2226cc3]1152 (*sb) = data;
[a35b458]1153
[01ab41b]1154 return EOK;
1155}
1156
[2226cc3]1157/** Write superblock structure directly to block device.
[9fc72fb3]1158 *
[38542dc]1159 * @param service_id Block device identifier
1160 * @param sb Superblock to be written
1161 *
1162 * @return Error code
1163 *
[9fc72fb3]1164 */
[b7fd2a0]1165errno_t ext4_superblock_write_direct(service_id_t service_id, ext4_superblock_t *sb)
[ae3d4f8]1166{
[06d85e5]1167 /* Load physical block size from block device */
[38542dc]1168 size_t phys_block_size;
[b7fd2a0]1169 errno_t rc = block_get_bsize(service_id, &phys_block_size);
[38542dc]1170 if (rc != EOK)
[ae3d4f8]1171 return rc;
[a35b458]1172
[06d85e5]1173 /* Compute address of the first block */
[d9bbe45]1174 uint64_t first_block = EXT4_SUPERBLOCK_OFFSET / phys_block_size;
[a35b458]1175
[06d85e5]1176 /* Compute number of block to write */
[80bd676]1177 size_t block_count = EXT4_SUPERBLOCK_SIZE / phys_block_size;
[a35b458]1178
[06d85e5]1179 /* Check alignment */
[38542dc]1180 if (EXT4_SUPERBLOCK_SIZE % phys_block_size)
[ae3d4f8]1181 block_count++;
[a35b458]1182
[06d85e5]1183 /* Write data */
[ae3d4f8]1184 return block_write_direct(service_id, first_block, block_count, sb);
1185}
1186
[eb94d84]1187/** Release the memory allocated for the superblock structure
1188 *
1189 * @param sb Superblock to be freed
1190 *
1191 */
1192void ext4_superblock_release(ext4_superblock_t *sb)
1193{
1194 free(sb);
1195}
1196
[5b26747]1197/** Check sanity of the superblock.
[9fc72fb3]1198 *
[5b26747]1199 * This check is performed at mount time.
1200 * Checks are described by one-line comments in the code.
1201 *
[38542dc]1202 * @param sb Superblock to check
1203 *
1204 * @return Error code
1205 *
[9fc72fb3]1206 */
[b7fd2a0]1207errno_t ext4_superblock_check_sanity(ext4_superblock_t *sb)
[01ab41b]1208{
[38542dc]1209 if (ext4_superblock_get_magic(sb) != EXT4_SUPERBLOCK_MAGIC)
[9c0c0e1]1210 return ENOTSUP;
[a35b458]1211
[38542dc]1212 if (ext4_superblock_get_inodes_count(sb) == 0)
[fb04cd90]1213 return ENOTSUP;
[a35b458]1214
[38542dc]1215 if (ext4_superblock_get_blocks_count(sb) == 0)
[fb04cd90]1216 return ENOTSUP;
[a35b458]1217
[38542dc]1218 if (ext4_superblock_get_blocks_per_group(sb) == 0)
[fb04cd90]1219 return ENOTSUP;
[a35b458]1220
[38542dc]1221 if (ext4_superblock_get_inodes_per_group(sb) == 0)
[fb04cd90]1222 return ENOTSUP;
[a35b458]1223
[38542dc]1224 if (ext4_superblock_get_inode_size(sb) < 128)
[fb04cd90]1225 return ENOTSUP;
[a35b458]1226
[38542dc]1227 if (ext4_superblock_get_first_inode(sb) < 11)
[fb04cd90]1228 return ENOTSUP;
[a35b458]1229
[38542dc]1230 if (ext4_superblock_get_desc_size(sb) <
1231 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
[fb04cd90]1232 return ENOTSUP;
[a35b458]1233
[38542dc]1234 if (ext4_superblock_get_desc_size(sb) >
1235 EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE)
[fb04cd90]1236 return ENOTSUP;
[a35b458]1237
[01ab41b]1238 return EOK;
1239}
[eb91db7]1240
[2226cc3]1241/** Compute number of block groups in the filesystem.
[9fc72fb3]1242 *
[38542dc]1243 * @param sb Superblock
1244 *
1245 * @return Number of block groups
1246 *
[9fc72fb3]1247 */
[b12ca16]1248uint32_t ext4_superblock_get_block_group_count(ext4_superblock_t *sb)
1249{
1250 uint64_t blocks_count = ext4_superblock_get_blocks_count(sb);
1251 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
[a35b458]1252
[b12ca16]1253 uint32_t block_groups_count = blocks_count / blocks_per_group;
[a35b458]1254
[38542dc]1255 if (blocks_count % blocks_per_group)
[b12ca16]1256 block_groups_count++;
[a35b458]1257
[b12ca16]1258 return block_groups_count;
1259}
1260
[2226cc3]1261/** Compute number of blocks in specified block group.
[9fc72fb3]1262 *
[38542dc]1263 * @param sb Superblock
1264 * @param bgid Block group index
1265 *
1266 * @return Number of blocks
1267 *
[9fc72fb3]1268 */
[b12ca16]1269uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *sb, uint32_t bgid)
1270{
[38542dc]1271 uint32_t block_group_count =
1272 ext4_superblock_get_block_group_count(sb);
1273 uint32_t blocks_per_group =
1274 ext4_superblock_get_blocks_per_group(sb);
1275 uint64_t total_blocks =
1276 ext4_superblock_get_blocks_count(sb);
[a35b458]1277
[38542dc]1278 if (bgid < block_group_count - 1)
[b12ca16]1279 return blocks_per_group;
[38542dc]1280 else
[b12ca16]1281 return (total_blocks - ((block_group_count - 1) * blocks_per_group));
1282}
1283
[2226cc3]1284/** Compute number of i-nodes in specified block group.
[9fc72fb3]1285 *
[38542dc]1286 * @param sb Superblock
1287 * @param bgid Block group index
1288 *
1289 * @return Number of i-nodes
1290 *
[9fc72fb3]1291 */
[b12ca16]1292uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *sb, uint32_t bgid)
1293{
[38542dc]1294 uint32_t block_group_count =
1295 ext4_superblock_get_block_group_count(sb);
1296 uint32_t inodes_per_group =
1297 ext4_superblock_get_inodes_per_group(sb);
1298 uint32_t total_inodes =
1299 ext4_superblock_get_inodes_count(sb);
[a35b458]1300
[38542dc]1301 if (bgid < block_group_count - 1)
[b12ca16]1302 return inodes_per_group;
[38542dc]1303 else
[b12ca16]1304 return (total_inodes - ((block_group_count - 1) * inodes_per_group));
1305}
1306
[6dd7f65]1307/** Get the backup groups used with SPARSE_SUPER2
1308 *
1309 * @param sb Pointer to the superblock
1310 * @param g1 Output pointer to the first backup group
1311 * @param g2 Output pointer to the second backup group
1312 */
1313void ext4_superblock_get_backup_groups_sparse2(ext4_superblock_t *sb,
1314 uint32_t *g1, uint32_t *g2)
1315{
1316 *g1 = uint32_t_le2host(sb->backup_bgs[0]);
1317 *g2 = uint32_t_le2host(sb->backup_bgs[1]);
1318}
1319
1320/** Set the backup groups (SPARSE SUPER2)
1321 *
1322 * @param sb Pointer to the superblock
1323 * @param g1 Index of the first group
1324 * @param g2 Index of the second group
1325 */
1326void ext4_superblock_set_backup_groups_sparse2(ext4_superblock_t *sb,
1327 uint32_t g1, uint32_t g2)
1328{
1329 sb->backup_bgs[0] = host2uint32_t_le(g1);
1330 sb->backup_bgs[1] = host2uint32_t_le(g2);
1331}
1332
1333/** Get the number of blocks (per group) reserved to GDT expansion
1334 *
1335 * @param sb Pointer to the superblock
1336 *
1337 * @return Number of blocks
1338 */
1339uint32_t ext4_superblock_get_reserved_gdt_blocks(ext4_superblock_t *sb)
1340{
1341 return uint32_t_le2host(sb->reserved_gdt_blocks);
1342}
1343
1344/** Set the number of blocks (per group) reserved to GDT expansion
1345 *
1346 * @param sb Pointer to the superblock
1347 * @param n Number of reserved blocks
1348 */
1349void ext4_superblock_set_reserved_gdt_blocks(ext4_superblock_t *sb,
1350 uint32_t n)
1351{
1352 sb->reserved_gdt_blocks = host2uint32_t_le(n);
1353}
1354
[aab85d90]1355/* Check if n is a power of p */
1356static bool is_power_of(uint32_t n, unsigned p)
1357{
1358 if (p == 1 && n != p)
1359 return false;
1360
1361 while (n != p) {
1362 if (n < p)
1363 return false;
1364 else if ((n % p) != 0)
1365 return false;
1366
1367 n /= p;
1368 }
1369
1370 return true;
1371}
1372
1373/** Get the number of blocks used by superblock + gdt + reserved gdt backups
1374 *
1375 * @param sb Superblock
1376 * @param idx Block group index
1377 *
1378 * @return Number of blocks
1379 */
1380uint32_t ext4_superblock_get_group_backup_blocks(ext4_superblock_t *sb,
1381 uint32_t idx)
1382{
1383 uint32_t r = 0;
1384 bool has_backups = false;
1385
1386 /* First step: determine if the block group contains the backups */
1387
1388 if (idx <= 1)
1389 has_backups = true;
1390 else {
1391 if (ext4_superblock_has_feature_compatible(sb,
1392 EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
1393 uint32_t g1, g2;
1394
1395 ext4_superblock_get_backup_groups_sparse2(sb,
1396 &g1, &g2);
1397
1398 if (idx == g1 || idx == g2)
1399 has_backups = true;
1400 } else if (!ext4_superblock_has_feature_read_only(sb,
1401 EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
1402 /*
1403 * Very old fs were all block groups have
1404 * superblock and block descriptors backups.
1405 */
1406 has_backups = true;
1407 } else {
1408 if ((idx & 1) && (is_power_of(idx, 3) ||
1409 is_power_of(idx, 5) || is_power_of(idx, 7)))
1410 has_backups = true;
1411 }
1412 }
1413
1414 if (has_backups) {
1415 uint32_t bg_count;
1416 uint32_t bg_desc_sz;
1417 uint32_t gdt_table; /* Size of the GDT in blocks */
1418 uint32_t block_size = ext4_superblock_get_block_size(sb);
1419
1420 /*
1421 * Now we know that this block group has backups,
1422 * we have to compute how many blocks are reserved
1423 * for them
1424 */
1425
1426 if (idx == 0 && block_size == 1024) {
1427 /*
1428 * Special case for first group were the boot block
1429 * resides
1430 */
1431 r++;
1432 }
1433
1434 /* This accounts for the superblock */
1435 r++;
1436
1437 /* Add the number of blocks used for the GDT */
1438 bg_count = ext4_superblock_get_block_group_count(sb);
1439 bg_desc_sz = ext4_superblock_get_desc_size(sb);
1440 gdt_table = ROUND_UP(bg_count * bg_desc_sz, block_size) /
1441 block_size;
1442
1443 r += gdt_table;
1444
1445 /* And now the number of reserved GDT blocks */
1446 r += ext4_superblock_get_reserved_gdt_blocks(sb);
1447 }
1448
1449 return r;
1450}
1451
1452
1453/** Create superblock for new file system.
1454 *
1455 * @param dev_bsize Device block size
1456 * @param dev_bcnt Device number of blocks
1457 * @param rsb Place to store pointer to newly allocated superblock
1458 * @return EOK on success or error code
1459 */
1460errno_t ext4_superblock_create(size_t dev_bsize, uint64_t dev_bcnt,
1461 ext4_superblock_t **rsb)
1462{
1463 ext4_superblock_t *sb;
1464 uuid_t uuid;
1465 uint32_t cur_ts;
1466 uint64_t first_block;
1467 uint64_t fs_blocks;
1468 uint32_t blocks_count;
1469 uint32_t free_blocks;
1470 uint32_t inodes_count;
1471 uint64_t blocks_group;
1472 uint64_t inodes_group;
1473 uint32_t inodes_block;
1474 uint32_t inode_table_blocks;
1475 uint32_t res_blocks;
1476 uint32_t ngroups;
1477 uint32_t idx;
1478 size_t fs_bsize;
1479 errno_t rc;
1480 struct timespec ts;
1481
1482 sb = calloc(1, sizeof(ext4_superblock_t));
1483 if (sb == NULL)
1484 return ENOMEM;
1485
1486 rc = uuid_generate(&uuid);
1487 if (rc != EOK)
1488 goto error;
1489
1490 /* Current UNIX time */
1491 getrealtime(&ts); // XXX ISO C does not say what the epoch is
1492 cur_ts = ts.tv_sec;
1493
1494 fs_bsize = 1024;
1495 first_block = 1; /* 1 for 1k block size, 0 otherwise */
1496
1497 if (fs_bsize % dev_bsize == 0) {
1498 /* Small device blocks */
1499 fs_blocks = dev_bcnt / (fs_bsize / dev_bsize);
1500 } else {
1501 /* Large device blocks */
1502 fs_blocks = dev_bcnt * (dev_bsize / fs_bsize);
1503 }
1504
1505 /* FS blocks per group */
1506 blocks_group = 8 * fs_bsize;
1507
1508 /* Inodes per group */
1509 inodes_block = fs_bsize / EXT4_REV0_INODE_SIZE;
1510 inodes_group = min((fs_blocks - first_block) / 8,
1511 blocks_group / 4);
1512 if (inodes_group < 16)
1513 inodes_group = 16;
1514
1515 /* Align up to multiple of inodes_block */
1516 if (inodes_group % inodes_block != 0)
1517 inodes_group += inodes_block - inodes_group % inodes_block;
1518 inode_table_blocks = inodes_group / inodes_block;
1519
1520 /* Number of groups */
1521 ngroups = ((fs_blocks - first_block) + blocks_group - 1) / blocks_group;
1522
1523 /* Count of all blocks in groups */
1524 blocks_count = fs_blocks - first_block;
1525
1526 /* Count of all inodes */
1527 inodes_count = ngroups * inodes_group;
1528
1529 /* Count of blocks reserved for superuser */
1530 res_blocks = (blocks_count + 19) / 20;
1531
1532 free_blocks = blocks_count;
1533
1534 ext4_superblock_set_magic(sb, EXT4_SUPERBLOCK_MAGIC);
1535 ext4_superblock_set_inodes_count(sb, inodes_count);
1536 ext4_superblock_set_blocks_count(sb, blocks_count);
1537 ext4_superblock_set_reserved_blocks_count(sb, res_blocks);
1538 ext4_superblock_set_free_blocks_count(sb, free_blocks);
1539 ext4_superblock_set_free_inodes_count(sb, inodes_count);
1540 ext4_superblock_set_first_data_block(sb, first_block);
1541 /* Block size will be 1024 bytes */
1542 ext4_superblock_set_log_block_size(sb, 0);
1543 /* Fragment size should be equal to block size */
1544 ext4_superblock_set_log_frag_size(sb, 0);
1545 ext4_superblock_set_blocks_per_group(sb, blocks_group);
1546 /* Should be the same as blocks per group. */
1547 ext4_superblock_set_frags_per_group(sb, blocks_group);
1548 ext4_superblock_set_inodes_per_group(sb, inodes_group);
1549 ext4_superblock_set_mount_time(sb, 0);
1550 ext4_superblock_set_write_time(sb, cur_ts);
1551 ext4_superblock_set_mount_count(sb, 0);
1552 ext4_superblock_set_max_mount_count(sb, (uint16_t)-1);
1553 ext4_superblock_set_state(sb, EXT4_SUPERBLOCK_STATE_VALID_FS);
1554 ext4_superblock_set_errors(sb, EXT4_SUPERBLOCK_ERRORS_CONTINUE);
1555 ext4_superblock_set_minor_rev_level(sb, 0); // XXX
1556 ext4_superblock_set_last_check_time(sb, cur_ts);
1557 ext4_superblock_set_check_interval(sb, 0);
1558 ext4_superblock_set_creator_os(sb, EXT4_SUPERBLOCK_OS_LINUX);
1559 ext4_superblock_set_rev_level(sb, EXT4_GOOD_OLD_REV);
1560 ext4_superblock_set_def_resuid(sb, 0);
1561 ext4_superblock_set_def_resgid(sb, 0);
1562#if 0
1563 /* Dynamic rev */
1564 ext4_superblock_set_first_inode(sb, EXT4_REV0_FIRST_INO);
1565 ext4_superblock_set_inode_size(sb, EXT4_REV0_INODE_SIZE);
1566 ext4_superblock_set_block_group_index(sb, 0); // XXX
1567 ext4_superblock_set_features_compatible(sb, 0);
1568 ext4_superblock_set_features_incompatible(sb, 0);
1569 ext4_superblock_set_features_read_only(sb, 0);
1570
1571 ext4_superblock_set_uuid(sb, &uuid);
1572 /* 16-byte Latin-1 string padded with null characters */
1573 ext4_superblock_set_volume_name(sb, "HelenOS-Ext4\0\0\0\0");
1574 /* 64-byte Latin-1 string padded with null characters */
1575 ext4_superblock_set_last_mounted(sb,
1576 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1577 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
1578 sb->algorithm_usage_bitmap = 0;
1579
1580 /* Journalling */
1581 ext4_superblock_set_desc_size(sb, EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE);
1582#endif
1583
1584 /* Compute free blocks */
1585 free_blocks = blocks_count;
1586 for (idx = 0; idx < ngroups; idx++) {
1587 free_blocks -= ext4_superblock_get_group_backup_blocks(sb, idx);
1588 /* One for block bitmap, one for inode bitamp */
1589 free_blocks -= 2;
1590 free_blocks -= inode_table_blocks;
1591 }
1592
1593 ext4_superblock_set_free_blocks_count(sb, free_blocks);
1594
1595 *rsb = sb;
1596 return EOK;
1597error:
1598 free(sb);
1599 return rc;
1600}
1601
[eb91db7]1602/**
1603 * @}
[38542dc]1604 */
Note: See TracBrowser for help on using the repository browser.