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

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

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 36.9 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 <time.h>
47#include "ext4/superblock.h"
48
49/** Get number of i-nodes in the whole filesystem.
50 *
51 * @param sb Superblock
52 *
53 * @return Number of i-nodes
54 *
55 */
56uint32_t ext4_superblock_get_inodes_count(ext4_superblock_t *sb)
57{
58 return uint32_t_le2host(sb->inodes_count);
59}
60
61/** Set number of i-nodes in the whole filesystem.
62 *
63 * @param sb Superblock
64 * @param count Number of i-nodes
65 *
66 */
67void ext4_superblock_set_inodes_count(ext4_superblock_t *sb, uint32_t count)
68{
69 sb->inodes_count = host2uint32_t_le(count);
70}
71
72/** Get number of data blocks in the whole filesystem.
73 *
74 * @param sb Superblock
75 *
76 * @return Number of data blocks
77 *
78 */
79uint64_t ext4_superblock_get_blocks_count(ext4_superblock_t *sb)
80{
81 return ((uint64_t) uint32_t_le2host(sb->blocks_count_hi) << 32) |
82 uint32_t_le2host(sb->blocks_count_lo);
83}
84
85/** Set number of data blocks in the whole filesystem.
86 *
87 * @param sb Superblock
88 * @param count Number of data blocks
89 *
90 */
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
97/** Get number of reserved data blocks in the whole filesystem.
98 *
99 * @param sb Superblock
100 *
101 * @return Number of reserved data blocks
102 *
103 */
104uint64_t ext4_superblock_get_reserved_blocks_count(ext4_superblock_t *sb)
105{
106 return ((uint64_t)
107 uint32_t_le2host(sb->reserved_blocks_count_hi) << 32) |
108 uint32_t_le2host(sb->reserved_blocks_count_lo);
109}
110
111/** Set number of reserved data blocks in the whole filesystem.
112 *
113 * @param sb Superblock
114 * @param count Number of reserved data blocks
115 *
116 */
117void ext4_superblock_set_reserved_blocks_count(ext4_superblock_t *sb,
118 uint64_t count)
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
124/** Get number of free data blocks in the whole filesystem.
125 *
126 * @param sb Superblock
127 *
128 * @return Number of free data blocks
129 *
130 */
131uint64_t ext4_superblock_get_free_blocks_count(ext4_superblock_t *sb)
132{
133 return ((uint64_t)
134 uint32_t_le2host(sb->free_blocks_count_hi) << 32) |
135 uint32_t_le2host(sb->free_blocks_count_lo);
136}
137
138/** Set number of free data blocks in the whole filesystem.
139 *
140 * @param sb Superblock
141 * @param count Number of free data blocks
142 *
143 */
144void ext4_superblock_set_free_blocks_count(ext4_superblock_t *sb,
145 uint64_t count)
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
151/** Get number of free i-nodes in the whole filesystem.
152 *
153 * @param sb Superblock
154 *
155 * @return Number of free i-nodes
156 *
157 */
158uint32_t ext4_superblock_get_free_inodes_count(ext4_superblock_t *sb)
159{
160 return uint32_t_le2host(sb->free_inodes_count);
161}
162
163/** Set number of free i-nodes in the whole filesystem.
164 *
165 * @param sb Superblock
166 * @param count Number of free i-nodes
167 *
168 */
169void ext4_superblock_set_free_inodes_count(ext4_superblock_t *sb,
170 uint32_t count)
171{
172 sb->free_inodes_count = host2uint32_t_le(count);
173}
174
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
180 *
181 */
182uint32_t ext4_superblock_get_first_data_block(ext4_superblock_t *sb)
183{
184 return uint32_t_le2host(sb->first_data_block);
185}
186
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
191 *
192 */
193void ext4_superblock_set_first_data_block(ext4_superblock_t *sb,
194 uint32_t first)
195{
196 sb->first_data_block = host2uint32_t_le(first);
197}
198
199/** Get logarithmic block size (1024 << size == block_size)
200 *
201 * @param sb Superblock
202 *
203 * @return Logarithmic block size
204 *
205 */
206uint32_t ext4_superblock_get_log_block_size(ext4_superblock_t *sb)
207{
208 return uint32_t_le2host(sb->log_block_size);
209}
210
211/** Set logarithmic block size (1024 << size == block_size)
212 *
213 * @param sb Superblock
214 *
215 * @return Logarithmic block size
216 *
217 */
218void ext4_superblock_set_log_block_size(ext4_superblock_t *sb,
219 uint32_t log_size)
220{
221 sb->log_block_size = host2uint32_t_le(log_size);
222}
223
224/** Get size of data block (in bytes).
225 *
226 * @param sb Superblock
227 *
228 * @return Size of data block
229 *
230 */
231uint32_t ext4_superblock_get_block_size(ext4_superblock_t *sb)
232{
233 return 1024 << ext4_superblock_get_log_block_size(sb);
234}
235
236/** Set size of data block (in bytes).
237 *
238 * @param sb Superblock
239 * @param size Size of data block (must be power of 2, at least 1024)
240 *
241 */
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;
246
247 tmp >>= 1;
248 while (tmp) {
249 log++;
250 tmp >>= 1;
251 }
252
253 ext4_superblock_set_log_block_size(sb, log);
254}
255
256/** Get logarithmic fragment size (1024 << size)
257 *
258 * @param sb Superblock
259 *
260 * @return Logarithmic fragment size
261 *
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 *
270 * @param sb Superblock
271 * @param frag_size Logarithmic fragment size
272 *
273 */
274void ext4_superblock_set_log_frag_size(ext4_superblock_t *sb,
275 uint32_t frag_size)
276{
277 sb->log_frag_size = host2uint32_t_le(frag_size);
278}
279
280/** Get size of fragment (in bytes).
281 *
282 * @param sb Superblock
283 *
284 * @return Size of fragment
285 *
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 *
294 * @param sb Superblock
295 * @param size Size of fragment (must be power of 2, at least 1024)
296 *
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;
302
303 tmp >>= 1;
304 while (tmp) {
305 log++;
306 tmp >>= 1;
307 }
308
309 ext4_superblock_set_log_frag_size(sb, log);
310}
311
312/** Get number of data blocks per block group (except last BG)
313 *
314 * @param sb Superblock
315 *
316 * @return Data blocks per block group
317 *
318 */
319uint32_t ext4_superblock_get_blocks_per_group(ext4_superblock_t *sb)
320{
321 return uint32_t_le2host(sb->blocks_per_group);
322}
323
324/** Set number of data blocks per block group (except last BG)
325 *
326 * @param sb Superblock
327 * @param blocks Data blocks per block group
328 *
329 */
330void ext4_superblock_set_blocks_per_group(ext4_superblock_t *sb,
331 uint32_t blocks)
332{
333 sb->blocks_per_group = host2uint32_t_le(blocks);
334}
335
336/** Get number of fragments per block group (except last BG)
337 *
338 * @param sb Superblock
339 *
340 * @return Fragments per block group
341 *
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 *
350 * @param sb Superblock
351 * @param frags Fragments per block group
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
358/** Get number of i-nodes per block group (except last BG)
359 *
360 * @param sb Superblock
361 *
362 * @return I-nodes per block group
363 *
364 */
365uint32_t ext4_superblock_get_inodes_per_group(ext4_superblock_t *sb)
366{
367 return uint32_t_le2host(sb->inodes_per_group);
368}
369
370/** Set number of i-nodes per block group (except last BG)
371 *
372 * @param sb Superblock
373 * @param inodes I-nodes per block group
374 *
375 */
376void ext4_superblock_set_inodes_per_group(ext4_superblock_t *sb,
377 uint32_t inodes)
378{
379 sb->inodes_per_group = host2uint32_t_le(inodes);
380}
381
382/** Get time when filesystem was mounted (POSIX time).
383 *
384 * @param sb Superblock
385 *
386 * @return Mount time
387 *
388 */
389uint32_t ext4_superblock_get_mount_time(ext4_superblock_t *sb)
390{
391 return uint32_t_le2host(sb->mount_time);
392}
393
394/** Set time when filesystem was mounted (POSIX time).
395 *
396 * @param sb Superblock
397 * @param time Mount time
398 *
399 */
400void ext4_superblock_set_mount_time(ext4_superblock_t *sb, uint32_t time)
401{
402 sb->mount_time = host2uint32_t_le(time);
403}
404
405/** Get time when filesystem was last accesed by write operation (POSIX time).
406 *
407 * @param sb Superblock
408 *
409 * @return Write time
410 *
411 */
412uint32_t ext4_superblock_get_write_time(ext4_superblock_t *sb)
413{
414 return uint32_t_le2host(sb->write_time);
415}
416
417/** Set time when filesystem was last accesed by write operation (POSIX time).
418 *
419 * @param sb Superblock
420 * @param time Write time
421 *
422 */
423void ext4_superblock_set_write_time(ext4_superblock_t *sb, uint32_t time)
424{
425 sb->write_time = host2uint32_t_le(time);
426}
427
428/** Get number of mount from last filesystem check.
429 *
430 * @param sb Superblock
431 *
432 * @return Number of mounts
433 *
434 */
435uint16_t ext4_superblock_get_mount_count(ext4_superblock_t *sb)
436{
437 return uint16_t_le2host(sb->mount_count);
438}
439
440/** Set number of mount from last filesystem check.
441 *
442 * @param sb Superblock
443 * @param count Number of mounts
444 *
445 */
446void ext4_superblock_set_mount_count(ext4_superblock_t *sb, uint16_t count)
447{
448 sb->mount_count = host2uint16_t_le(count);
449}
450
451/** Get maximum number of mount from last filesystem check.
452 *
453 * @param sb Superblock
454 *
455 * @return Maximum number of mounts
456 *
457 */
458uint16_t ext4_superblock_get_max_mount_count(ext4_superblock_t *sb)
459{
460 return uint16_t_le2host(sb->max_mount_count);
461}
462
463/** Set maximum number of mount from last filesystem check.
464 *
465 * @param sb Superblock
466 * @param count Maximum number of mounts
467 *
468 */
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
474/** Get superblock magic value.
475 *
476 * @param sb Superblock
477 *
478 * @return Magic value
479 *
480 */
481uint16_t ext4_superblock_get_magic(ext4_superblock_t *sb)
482{
483 return uint16_t_le2host(sb->magic);
484}
485
486/** Set superblock magic value.
487 *
488 * @param sb Superblock
489 * @param magic Magic value
490 *
491 */
492void ext4_superblock_set_magic(ext4_superblock_t *sb, uint16_t magic)
493{
494 sb->magic = host2uint16_t_le(magic);
495}
496
497/** Get filesystem state.
498 *
499 * @param sb Superblock
500 *
501 * @return Filesystem state
502 *
503 */
504uint16_t ext4_superblock_get_state(ext4_superblock_t *sb)
505{
506 return uint16_t_le2host(sb->state);
507}
508
509/** Set filesystem state.
510 *
511 * @param sb Superblock
512 * @param state Filesystem state
513 *
514 */
515void ext4_superblock_set_state(ext4_superblock_t *sb, uint16_t state)
516{
517 sb->state = host2uint16_t_le(state);
518}
519
520/** Get behavior code when errors detected.
521 *
522 * @param sb Superblock
523 *
524 * @return Behavior code
525 *
526 */
527uint16_t ext4_superblock_get_errors(ext4_superblock_t *sb)
528{
529 return uint16_t_le2host(sb->errors);
530}
531
532/** Set behavior code when errors detected.
533 *
534 * @param sb Superblock
535 * @param errors Behavior code
536 *
537 */
538void ext4_superblock_set_errors(ext4_superblock_t *sb, uint16_t errors)
539{
540 sb->errors = host2uint16_t_le(errors);
541}
542
543/** Get minor revision level of the filesystem.
544 *
545 * @param sb Superblock
546 *
547 * @return Minor revision level
548 *
549 */
550uint16_t ext4_superblock_get_minor_rev_level(ext4_superblock_t *sb)
551{
552 return uint16_t_le2host(sb->minor_rev_level);
553}
554
555/** Set minor revision level of the filesystem.
556 *
557 * @param sb Superblock
558 * @param level Minor revision level
559 *
560 */
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
566/** Get time of the last filesystem check.
567 *
568 * @param sb Superblock
569 *
570 * @return Time of the last check (POSIX)
571 *
572 */
573uint32_t ext4_superblock_get_last_check_time(ext4_superblock_t *sb)
574{
575 return uint32_t_le2host(sb->last_check_time);
576}
577
578/** Set time of the last filesystem check.
579 *
580 * @param sb Superblock
581 * @param time Time of the last check (POSIX)
582 *
583 */
584void ext4_superblock_set_last_check_time(ext4_superblock_t *sb, uint32_t time)
585{
586 sb->last_check_time = host2uint32_t_le(time);
587}
588
589/** Get maximum time interval between two filesystem checks.
590 *
591 * @param sb Superblock
592 *
593 * @return Time interval between two check (POSIX)
594 *
595 */
596uint32_t ext4_superblock_get_check_interval(ext4_superblock_t *sb)
597{
598 return uint32_t_le2host(sb->check_interval);
599}
600
601/** Set maximum time interval between two filesystem checks.
602 *
603 * @param sb Superblock
604 * @param interval Time interval between two check (POSIX)
605 *
606 */
607void ext4_superblock_set_check_interval(ext4_superblock_t *sb, uint32_t interval)
608{
609 sb->check_interval = host2uint32_t_le(interval);
610}
611
612/** Get operation system identifier, on which the filesystem was created.
613 *
614 * @param sb Superblock
615 *
616 * @return Operation system identifier
617 *
618 */
619uint32_t ext4_superblock_get_creator_os(ext4_superblock_t *sb)
620{
621 return uint32_t_le2host(sb->creator_os);
622}
623
624/** Set operation system identifier, on which the filesystem was created.
625 *
626 * @param sb Superblock
627 * @param os Operation system identifier
628 *
629 */
630void ext4_superblock_set_creator_os(ext4_superblock_t *sb, uint32_t os)
631{
632 sb->creator_os = host2uint32_t_le(os);
633}
634
635/** Get revision level of the filesystem.
636 *
637 * @param sb Superblock
638 *
639 * @return Revision level
640 *
641 */
642uint32_t ext4_superblock_get_rev_level(ext4_superblock_t *sb)
643{
644 return uint32_t_le2host(sb->rev_level);
645}
646
647/** Set revision level of the filesystem.
648 *
649 * @param sb Superblock
650 * @param level Revision level
651 *
652 */
653void ext4_superblock_set_rev_level(ext4_superblock_t *sb, uint32_t level)
654{
655 sb->rev_level = host2uint32_t_le(level);
656}
657
658/** Get default user id for reserved blocks.
659 *
660 * @param sb Superblock
661 *
662 * @return Default user id for reserved blocks.
663 *
664 */
665uint16_t ext4_superblock_get_def_resuid(ext4_superblock_t *sb)
666{
667 return uint16_t_le2host(sb->def_resuid);
668}
669
670/** Set default user id for reserved blocks.
671 *
672 * @param sb Superblock
673 * @param uid Default user id for reserved blocks.
674 *
675 */
676void ext4_superblock_set_def_resuid(ext4_superblock_t *sb, uint16_t uid)
677{
678 sb->def_resuid = host2uint16_t_le(uid);
679}
680
681/** Get default group id for reserved blocks.
682 *
683 * @param sb Superblock
684 *
685 * @return Default group id for reserved blocks.
686 *
687 */
688uint16_t ext4_superblock_get_def_resgid(ext4_superblock_t *sb)
689{
690 return uint16_t_le2host(sb->def_resgid);
691}
692
693/** Set default group id for reserved blocks.
694 *
695 * @param sb Superblock
696 * @param gid Default group id for reserved blocks.
697 *
698 */
699void ext4_superblock_set_def_resgid(ext4_superblock_t *sb, uint16_t gid)
700{
701 sb->def_resgid = host2uint16_t_le(gid);
702}
703
704/** Get index of the first i-node, which can be used for allocation.
705 *
706 * @param sb Superblock
707 *
708 * @return I-node index
709 *
710 */
711uint32_t ext4_superblock_get_first_inode(ext4_superblock_t *sb)
712{
713 if (ext4_superblock_get_rev_level(sb) == 0)
714 return EXT4_REV0_FIRST_INO;
715
716 return uint32_t_le2host(sb->first_inode);
717}
718
719/** Set index of the first i-node, which can be used for allocation.
720 *
721 * @param sb Superblock
722 * @param first_inode I-node index
723 *
724 */
725void ext4_superblock_set_first_inode(ext4_superblock_t *sb,
726 uint32_t first_inode)
727{
728 sb->first_inode = host2uint32_t_le(first_inode);
729}
730
731/** Get size of i-node structure.
732 *
733 * For the oldest revision return constant number.
734 *
735 * @param sb Superblock
736 *
737 * @return Size of i-node structure
738 *
739 */
740uint16_t ext4_superblock_get_inode_size(ext4_superblock_t *sb)
741{
742 if (ext4_superblock_get_rev_level(sb) == 0)
743 return EXT4_REV0_INODE_SIZE;
744
745 return uint16_t_le2host(sb->inode_size);
746}
747
748/** Set size of i-node structure.
749 *
750 * @param sb Superblock
751 * @param size Size of i-node structure
752 *
753 */
754void ext4_superblock_set_inode_size(ext4_superblock_t *sb, uint16_t size)
755{
756 sb->inode_size = host2uint16_t_le(size);
757}
758
759/** Get index of block group, where superblock copy is located.
760 *
761 * @param sb Superblock
762 *
763 * @return Block group index
764 *
765 */
766uint16_t ext4_superblock_get_block_group_index(ext4_superblock_t *sb)
767{
768 return uint16_t_le2host(sb->block_group_index);
769}
770
771/** Set index of block group, where superblock copy is located.
772 *
773 * @param sb Superblock
774 * @param bgid Block group index
775 *
776 */
777void ext4_superblock_set_block_group_index(ext4_superblock_t *sb, uint16_t bgid)
778{
779 sb->block_group_index = host2uint16_t_le(bgid);
780}
781
782/** Get compatible features supported by the filesystem.
783 *
784 * @param sb Superblock
785 *
786 * @return Compatible features bitmap
787 *
788 */
789uint32_t ext4_superblock_get_features_compatible(ext4_superblock_t *sb)
790{
791 return uint32_t_le2host(sb->features_compatible);
792}
793
794/** Set compatible features supported by the filesystem.
795 *
796 * @param sb Superblock
797 * @param features Compatible features bitmap
798 *
799 */
800void ext4_superblock_set_features_compatible(ext4_superblock_t *sb,
801 uint32_t features)
802{
803 sb->features_compatible = host2uint32_t_le(features);
804}
805
806/** Get incompatible features supported by the filesystem.
807 *
808 * @param sb Superblock
809 *
810 * @return Incompatible features bitmap
811 *
812 */
813uint32_t ext4_superblock_get_features_incompatible(ext4_superblock_t *sb)
814{
815 return uint32_t_le2host(sb->features_incompatible);
816}
817
818/** Set incompatible features supported by the filesystem.
819 *
820 * @param sb Superblock
821 * @param features Incompatible features bitmap
822 *
823 */
824void ext4_superblock_set_features_incompatible(ext4_superblock_t *sb,
825 uint32_t features)
826{
827 sb->features_incompatible = host2uint32_t_le(features);
828}
829
830/** Get compatible features supported by the filesystem.
831 *
832 * @param sb Superblock
833 *
834 * @return Read-only compatible features bitmap
835 *
836 */
837uint32_t ext4_superblock_get_features_read_only(ext4_superblock_t *sb)
838{
839 return uint32_t_le2host(sb->features_read_only);
840}
841
842/** Set compatible features supported by the filesystem.
843 *
844 * @param sb Superblock
845 * @param feature Read-only compatible features bitmap
846 *
847 */
848void ext4_superblock_set_features_read_only(ext4_superblock_t *sb,
849 uint32_t features)
850{
851 sb->features_read_only = host2uint32_t_le(features);
852}
853
854/** Get UUID of the filesystem.
855 *
856 * @param sb superblock
857 *
858 * @return Pointer to UUID array
859 *
860 */
861void ext4_superblock_get_uuid(ext4_superblock_t *sb, uuid_t *uuid)
862{
863 uuid_decode(sb->uuid, uuid);
864}
865
866/** Set UUID of the filesystem.
867 *
868 * @param sb Superblock
869 * @param uuid Pointer to UUID
870 *
871 */
872void ext4_superblock_set_uuid(ext4_superblock_t *sb, uuid_t *uuid)
873{
874 uuid_encode(uuid, sb->uuid);
875}
876
877/** Get name of the filesystem volume.
878 *
879 * @param sb Superblock
880 *
881 * @return Name of the volume
882 *
883 */
884const char *ext4_superblock_get_volume_name(ext4_superblock_t *sb)
885{
886 return sb->volume_name;
887}
888
889/** Set name of the filesystem volume.
890 *
891 * @param sb Superblock
892 * @param name New name of the volume
893 */
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
899/** Get name of the directory, where this filesystem was mounted at last.
900 *
901 * @param sb Superblock
902 *
903 * @return Directory name
904 *
905 */
906const char *ext4_superblock_get_last_mounted(ext4_superblock_t *sb)
907{
908 return sb->last_mounted;
909}
910
911/** Set name of the directory, where this filesystem was mounted at last.
912 *
913 * @param sb Superblock
914 * @param last Directory name
915 *
916 */
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
922/** Get last orphaned i-node index.
923 *
924 * Orphans are stored in linked list.
925 *
926 * @param sb Superblock
927 *
928 * @return Last orphaned i-node index
929 *
930 */
931uint32_t ext4_superblock_get_last_orphan(ext4_superblock_t *sb)
932{
933 return uint32_t_le2host(sb->last_orphan);
934}
935
936/** Set last orphaned i-node index.
937 *
938 * Orphans are stored in linked list.
939 *
940 * @param sb Superblock
941 * @param last_orphan Last orphaned i-node index
942 *
943 */
944void ext4_superblock_set_last_orphan(ext4_superblock_t *sb,
945 uint32_t last_orphan)
946{
947 sb->last_orphan = host2uint32_t_le(last_orphan);
948}
949
950/** Get hash seed for directory index hash function.
951 *
952 * @param sb Superblock
953 *
954 * @return Hash seed pointer
955 *
956 */
957const uint32_t *ext4_superblock_get_hash_seed(ext4_superblock_t *sb)
958{
959 return sb->hash_seed;
960}
961
962/** Set hash seed for directory index hash function.
963 *
964 * @param sb Superblock
965 * @param seed Hash seed pointer
966 *
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 *
975 * @param sb Superblock
976 *
977 * @return Default hash version
978 *
979 */
980uint8_t ext4_superblock_get_default_hash_version(ext4_superblock_t *sb)
981{
982 return sb->default_hash_version;
983}
984
985/** Set default version of the hash algorithm version for directory index.
986 *
987 * @param sb Superblock
988 * @param version Default hash version
989 *
990 */
991void ext4_superblock_set_default_hash_version(ext4_superblock_t *sb,
992 uint8_t version)
993{
994 sb->default_hash_version = version;
995}
996
997/** Get size of block group descriptor structure.
998 *
999 * Output value is checked for minimal size.
1000 *
1001 * @param sb Superblock
1002 *
1003 * @return Size of block group descriptor
1004 *
1005 */
1006uint16_t ext4_superblock_get_desc_size(ext4_superblock_t *sb)
1007{
1008 uint16_t size = uint16_t_le2host(sb->desc_size);
1009
1010 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
1011 size = EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE;
1012
1013 return size;
1014}
1015
1016/** Set size of block group descriptor structure.
1017 *
1018 * Input value is checked for minimal size.
1019 *
1020 * @param sb Superblock
1021 * @param size Size of block group descriptor
1022 *
1023 */
1024void ext4_superblock_set_desc_size(ext4_superblock_t *sb, uint16_t size)
1025{
1026 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
1027 sb->desc_size =
1028 host2uint16_t_le(EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE);
1029
1030 sb->desc_size = host2uint16_t_le(size);
1031}
1032
1033/** Get superblock flags.
1034 *
1035 * @param sb Superblock
1036 *
1037 * @return Flags from the superblock
1038 *
1039 */
1040uint32_t ext4_superblock_get_flags(ext4_superblock_t *sb)
1041{
1042 return uint32_t_le2host(sb->flags);
1043}
1044
1045/** Set superblock flags.
1046 *
1047 * @param sb Superblock
1048 * @param flags Flags for the superblock
1049 *
1050 */
1051void ext4_superblock_set_flags(ext4_superblock_t *sb, uint32_t flags)
1052{
1053 sb->flags = host2uint32_t_le(flags);
1054}
1055
1056/*
1057 * More complex superblock operations
1058 */
1059
1060/** Check if superblock has specified flag.
1061 *
1062 * @param sb Superblock
1063 * @param flag Flag to be checked
1064 *
1065 * @return True, if superblock has the flag
1066 *
1067 */
1068bool ext4_superblock_has_flag(ext4_superblock_t *sb, uint32_t flag)
1069{
1070 if (ext4_superblock_get_flags(sb) & flag)
1071 return true;
1072
1073 return false;
1074}
1075
1076/** Check if filesystem supports compatible feature.
1077 *
1078 * @param sb Superblock
1079 * @param feature Feature to be checked
1080 *
1081 * @return True, if filesystem supports the feature
1082 *
1083 */
1084bool ext4_superblock_has_feature_compatible(ext4_superblock_t *sb,
1085 uint32_t feature)
1086{
1087 if (ext4_superblock_get_features_compatible(sb) & feature)
1088 return true;
1089
1090 return false;
1091}
1092
1093/** Check if filesystem supports incompatible feature.
1094 *
1095 * @param sb Superblock
1096 * @param feature Feature to be checked
1097 *
1098 * @return True, if filesystem supports the feature
1099 *
1100 */
1101bool ext4_superblock_has_feature_incompatible(ext4_superblock_t *sb,
1102 uint32_t feature)
1103{
1104 if (ext4_superblock_get_features_incompatible(sb) & feature)
1105 return true;
1106
1107 return false;
1108}
1109
1110/** Check if filesystem supports read-only compatible feature.
1111 *
1112 * @param sb Superblock
1113 * @param feature Feature to be checked
1114 *
1115 * @return True, if filesystem supports the feature
1116 *
1117 */
1118bool ext4_superblock_has_feature_read_only(ext4_superblock_t *sb,
1119 uint32_t feature)
1120{
1121 if (ext4_superblock_get_features_read_only(sb) & feature)
1122 return true;
1123
1124 return false;
1125}
1126
1127/** Read superblock directly from block device.
1128 *
1129 * @param service_id Block device identifier
1130 * @param sb Output pointer to memory structure
1131 *
1132 * @return Eerror code.
1133 *
1134 */
1135errno_t ext4_superblock_read_direct(service_id_t service_id, ext4_superblock_t **sb)
1136{
1137 /* Allocated memory for superblock structure */
1138 void *data = malloc(EXT4_SUPERBLOCK_SIZE);
1139 if (data == NULL)
1140 return ENOMEM;
1141
1142 /* Read data from block device */
1143 errno_t rc = block_read_bytes_direct(service_id, EXT4_SUPERBLOCK_OFFSET,
1144 EXT4_SUPERBLOCK_SIZE, data);
1145
1146 if (rc != EOK) {
1147 free(data);
1148 return rc;
1149 }
1150
1151 /* Set output value */
1152 (*sb) = data;
1153
1154 return EOK;
1155}
1156
1157/** Write superblock structure directly to block device.
1158 *
1159 * @param service_id Block device identifier
1160 * @param sb Superblock to be written
1161 *
1162 * @return Error code
1163 *
1164 */
1165errno_t ext4_superblock_write_direct(service_id_t service_id, ext4_superblock_t *sb)
1166{
1167 /* Load physical block size from block device */
1168 size_t phys_block_size;
1169 errno_t rc = block_get_bsize(service_id, &phys_block_size);
1170 if (rc != EOK)
1171 return rc;
1172
1173 /* Compute address of the first block */
1174 uint64_t first_block = EXT4_SUPERBLOCK_OFFSET / phys_block_size;
1175
1176 /* Compute number of block to write */
1177 size_t block_count = EXT4_SUPERBLOCK_SIZE / phys_block_size;
1178
1179 /* Check alignment */
1180 if (EXT4_SUPERBLOCK_SIZE % phys_block_size)
1181 block_count++;
1182
1183 /* Write data */
1184 return block_write_direct(service_id, first_block, block_count, sb);
1185}
1186
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
1197/** Check sanity of the superblock.
1198 *
1199 * This check is performed at mount time.
1200 * Checks are described by one-line comments in the code.
1201 *
1202 * @param sb Superblock to check
1203 *
1204 * @return Error code
1205 *
1206 */
1207errno_t ext4_superblock_check_sanity(ext4_superblock_t *sb)
1208{
1209 if (ext4_superblock_get_magic(sb) != EXT4_SUPERBLOCK_MAGIC)
1210 return ENOTSUP;
1211
1212 if (ext4_superblock_get_inodes_count(sb) == 0)
1213 return ENOTSUP;
1214
1215 if (ext4_superblock_get_blocks_count(sb) == 0)
1216 return ENOTSUP;
1217
1218 if (ext4_superblock_get_blocks_per_group(sb) == 0)
1219 return ENOTSUP;
1220
1221 if (ext4_superblock_get_inodes_per_group(sb) == 0)
1222 return ENOTSUP;
1223
1224 if (ext4_superblock_get_inode_size(sb) < 128)
1225 return ENOTSUP;
1226
1227 if (ext4_superblock_get_first_inode(sb) < 11)
1228 return ENOTSUP;
1229
1230 if (ext4_superblock_get_desc_size(sb) <
1231 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
1232 return ENOTSUP;
1233
1234 if (ext4_superblock_get_desc_size(sb) >
1235 EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE)
1236 return ENOTSUP;
1237
1238 return EOK;
1239}
1240
1241/** Compute number of block groups in the filesystem.
1242 *
1243 * @param sb Superblock
1244 *
1245 * @return Number of block groups
1246 *
1247 */
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);
1252
1253 uint32_t block_groups_count = blocks_count / blocks_per_group;
1254
1255 if (blocks_count % blocks_per_group)
1256 block_groups_count++;
1257
1258 return block_groups_count;
1259}
1260
1261/** Compute number of blocks in specified block group.
1262 *
1263 * @param sb Superblock
1264 * @param bgid Block group index
1265 *
1266 * @return Number of blocks
1267 *
1268 */
1269uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *sb, uint32_t bgid)
1270{
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);
1277
1278 if (bgid < block_group_count - 1)
1279 return blocks_per_group;
1280 else
1281 return (total_blocks - ((block_group_count - 1) * blocks_per_group));
1282}
1283
1284/** Compute number of i-nodes in specified block group.
1285 *
1286 * @param sb Superblock
1287 * @param bgid Block group index
1288 *
1289 * @return Number of i-nodes
1290 *
1291 */
1292uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *sb, uint32_t bgid)
1293{
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);
1300
1301 if (bgid < block_group_count - 1)
1302 return inodes_per_group;
1303 else
1304 return (total_inodes - ((block_group_count - 1) * inodes_per_group));
1305}
1306
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
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/** Create superblock for new file system.
1453 *
1454 * @param dev_bsize Device block size
1455 * @param dev_bcnt Device number of blocks
1456 * @param rsb Place to store pointer to newly allocated superblock
1457 * @return EOK on success or error code
1458 */
1459errno_t ext4_superblock_create(size_t dev_bsize, uint64_t dev_bcnt,
1460 ext4_superblock_t **rsb)
1461{
1462 ext4_superblock_t *sb;
1463 uuid_t uuid;
1464 uint32_t cur_ts;
1465 uint64_t first_block;
1466 uint64_t fs_blocks;
1467 uint32_t blocks_count;
1468 uint32_t free_blocks;
1469 uint32_t inodes_count;
1470 uint64_t blocks_group;
1471 uint64_t inodes_group;
1472 uint32_t inodes_block;
1473 uint32_t inode_table_blocks;
1474 uint32_t res_blocks;
1475 uint32_t ngroups;
1476 uint32_t idx;
1477 size_t fs_bsize;
1478 errno_t rc;
1479 struct timespec ts;
1480
1481 sb = calloc(1, sizeof(ext4_superblock_t));
1482 if (sb == NULL)
1483 return ENOMEM;
1484
1485 rc = uuid_generate(&uuid);
1486 if (rc != EOK)
1487 goto error;
1488
1489 /* Current UNIX time */
1490 getrealtime(&ts); // XXX ISO C does not say what the epoch is
1491 cur_ts = ts.tv_sec;
1492
1493 fs_bsize = 1024;
1494 first_block = 1; /* 1 for 1k block size, 0 otherwise */
1495
1496 if (fs_bsize % dev_bsize == 0) {
1497 /* Small device blocks */
1498 fs_blocks = dev_bcnt / (fs_bsize / dev_bsize);
1499 } else {
1500 /* Large device blocks */
1501 fs_blocks = dev_bcnt * (dev_bsize / fs_bsize);
1502 }
1503
1504 /* FS blocks per group */
1505 blocks_group = 8 * fs_bsize;
1506
1507 /* Inodes per group */
1508 inodes_block = fs_bsize / EXT4_REV0_INODE_SIZE;
1509 inodes_group = min((fs_blocks - first_block) / 8,
1510 blocks_group / 4);
1511 if (inodes_group < 16)
1512 inodes_group = 16;
1513
1514 /* Align up to multiple of inodes_block */
1515 if (inodes_group % inodes_block != 0)
1516 inodes_group += inodes_block - inodes_group % inodes_block;
1517 inode_table_blocks = inodes_group / inodes_block;
1518
1519 /* Number of groups */
1520 ngroups = ((fs_blocks - first_block) + blocks_group - 1) / blocks_group;
1521
1522 /* Count of all blocks in groups */
1523 blocks_count = fs_blocks - first_block;
1524
1525 /* Count of all inodes */
1526 inodes_count = ngroups * inodes_group;
1527
1528 /* Count of blocks reserved for superuser */
1529 res_blocks = (blocks_count + 19) / 20;
1530
1531 free_blocks = blocks_count;
1532
1533 ext4_superblock_set_magic(sb, EXT4_SUPERBLOCK_MAGIC);
1534 ext4_superblock_set_inodes_count(sb, inodes_count);
1535 ext4_superblock_set_blocks_count(sb, blocks_count);
1536 ext4_superblock_set_reserved_blocks_count(sb, res_blocks);
1537 ext4_superblock_set_free_blocks_count(sb, free_blocks);
1538 ext4_superblock_set_free_inodes_count(sb, inodes_count);
1539 ext4_superblock_set_first_data_block(sb, first_block);
1540 /* Block size will be 1024 bytes */
1541 ext4_superblock_set_log_block_size(sb, 0);
1542 /* Fragment size should be equal to block size */
1543 ext4_superblock_set_log_frag_size(sb, 0);
1544 ext4_superblock_set_blocks_per_group(sb, blocks_group);
1545 /* Should be the same as blocks per group. */
1546 ext4_superblock_set_frags_per_group(sb, blocks_group);
1547 ext4_superblock_set_inodes_per_group(sb, inodes_group);
1548 ext4_superblock_set_mount_time(sb, 0);
1549 ext4_superblock_set_write_time(sb, cur_ts);
1550 ext4_superblock_set_mount_count(sb, 0);
1551 ext4_superblock_set_max_mount_count(sb, (uint16_t)-1);
1552 ext4_superblock_set_state(sb, EXT4_SUPERBLOCK_STATE_VALID_FS);
1553 ext4_superblock_set_errors(sb, EXT4_SUPERBLOCK_ERRORS_CONTINUE);
1554 ext4_superblock_set_minor_rev_level(sb, 0); // XXX
1555 ext4_superblock_set_last_check_time(sb, cur_ts);
1556 ext4_superblock_set_check_interval(sb, 0);
1557 ext4_superblock_set_creator_os(sb, EXT4_SUPERBLOCK_OS_LINUX);
1558 ext4_superblock_set_rev_level(sb, EXT4_GOOD_OLD_REV);
1559 ext4_superblock_set_def_resuid(sb, 0);
1560 ext4_superblock_set_def_resgid(sb, 0);
1561#if 0
1562 /* Dynamic rev */
1563 ext4_superblock_set_first_inode(sb, EXT4_REV0_FIRST_INO);
1564 ext4_superblock_set_inode_size(sb, EXT4_REV0_INODE_SIZE);
1565 ext4_superblock_set_block_group_index(sb, 0); // XXX
1566 ext4_superblock_set_features_compatible(sb, 0);
1567 ext4_superblock_set_features_incompatible(sb, 0);
1568 ext4_superblock_set_features_read_only(sb, 0);
1569
1570 ext4_superblock_set_uuid(sb, &uuid);
1571 /* 16-byte Latin-1 string padded with null characters */
1572 ext4_superblock_set_volume_name(sb, "HelenOS-Ext4\0\0\0\0");
1573 /* 64-byte Latin-1 string padded with null characters */
1574 ext4_superblock_set_last_mounted(sb,
1575 "\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"
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 sb->algorithm_usage_bitmap = 0;
1578
1579 /* Journalling */
1580 ext4_superblock_set_desc_size(sb, EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE);
1581#endif
1582
1583 /* Compute free blocks */
1584 free_blocks = blocks_count;
1585 for (idx = 0; idx < ngroups; idx++) {
1586 free_blocks -= ext4_superblock_get_group_backup_blocks(sb, idx);
1587 /* One for block bitmap, one for inode bitamp */
1588 free_blocks -= 2;
1589 free_blocks -= inode_table_blocks;
1590 }
1591
1592 ext4_superblock_set_free_blocks_count(sb, free_blocks);
1593
1594 *rsb = sb;
1595 return EOK;
1596error:
1597 free(sb);
1598 return rc;
1599}
1600
1601/**
1602 * @}
1603 */
Note: See TracBrowser for help on using the repository browser.