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

Last change on this file since cb747b3 was cb747b3, checked in by Miroslav Cimerman <mc@…>, 5 months ago

ext4: support bigger blkdev block size

Allows ext4 to be used with block devices that have
block size > EXT4_SUPERBLOCK_SIZE (1K).

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