2 * (C) Copyright 2011 - 2012 Samsung Electronics
3 * EXT4 filesystem implementation in Uboot by
4 * Uma Shankar <uma.shankar@samsung.com>
5 * Manjunatha C Achar <a.manjunatha@samsung.com>
7 * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
8 * Ext4 read optimization taken from Open-Moko
12 * esd gmbh <www.esd-electronics.com>
13 * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
15 * based on code from grub2 fs/ext2.c and fs/fshelp.c by
16 * GRUB -- GRand Unified Bootloader
17 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
19 * ext4write : Based on generic ext4 protocol.
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38 #include <ext_common.h>
40 #include <linux/stat.h>
41 #include <linux/time.h>
42 #include <asm/byteorder.h>
44 #include "ext4_common.h"
46 int ext4fs_symlinknest
;
47 struct ext_filesystem ext_fs
;
49 struct ext_filesystem
*get_fs(void)
54 void ext4fs_free_node(struct ext2fs_node
*node
, struct ext2fs_node
*currroot
)
56 if ((node
!= &ext4fs_root
->diropen
) && (node
!= currroot
))
61 * Taken from openmoko-kernel mailing list: By Andy green
62 * Optimized read file API : collects and defers contiguous sector
63 * reads into one potentially more efficient larger sequential read action
65 int ext4fs_read_file(struct ext2fs_node
*node
, int pos
,
66 unsigned int len
, char *buf
)
70 int log2blocksize
= LOG2_EXT2_BLOCK_SIZE(node
->data
);
71 int blocksize
= 1 << (log2blocksize
+ DISK_SECTOR_BITS
);
72 unsigned int filesize
= __le32_to_cpu(node
->inode
.size
);
73 int previous_block_number
= -1;
74 int delayed_start
= 0;
75 int delayed_extent
= 0;
76 int delayed_skipfirst
= 0;
78 char *delayed_buf
= NULL
;
81 /* Adjust len so it we can't read past the end of the file. */
85 blockcnt
= ((len
+ pos
) + blocksize
- 1) / blocksize
;
87 for (i
= pos
/ blocksize
; i
< blockcnt
; i
++) {
89 int blockoff
= pos
% blocksize
;
90 int blockend
= blocksize
;
92 blknr
= read_allocated_block(&(node
->inode
), i
);
96 blknr
= blknr
<< log2blocksize
;
99 if (i
== blockcnt
- 1) {
100 blockend
= (len
+ pos
) % blocksize
;
102 /* The last portion is exactly blocksize. */
104 blockend
= blocksize
;
108 if (i
== pos
/ blocksize
) {
109 skipfirst
= blockoff
;
110 blockend
-= skipfirst
;
115 if (previous_block_number
!= -1) {
116 if (delayed_next
== blknr
) {
117 delayed_extent
+= blockend
;
118 delayed_next
+= blockend
>> SECTOR_BITS
;
120 status
= ext4fs_devread(delayed_start
,
126 previous_block_number
= blknr
;
127 delayed_start
= blknr
;
128 delayed_extent
= blockend
;
129 delayed_skipfirst
= skipfirst
;
131 delayed_next
= blknr
+
132 (blockend
>> SECTOR_BITS
);
135 previous_block_number
= blknr
;
136 delayed_start
= blknr
;
137 delayed_extent
= blockend
;
138 delayed_skipfirst
= skipfirst
;
140 delayed_next
= blknr
+
141 (blockend
>> SECTOR_BITS
);
144 if (previous_block_number
!= -1) {
146 status
= ext4fs_devread(delayed_start
,
152 previous_block_number
= -1;
154 memset(buf
, 0, blocksize
- skipfirst
);
156 buf
+= blocksize
- skipfirst
;
158 if (previous_block_number
!= -1) {
160 status
= ext4fs_devread(delayed_start
,
161 delayed_skipfirst
, delayed_extent
,
165 previous_block_number
= -1;
171 int ext4fs_ls(const char *dirname
)
173 struct ext2fs_node
*dirnode
;
179 status
= ext4fs_find_file(dirname
, &ext4fs_root
->diropen
, &dirnode
,
182 printf("** Can not find directory. **\n");
186 ext4fs_iterate_dir(dirnode
, NULL
, NULL
, NULL
);
187 ext4fs_free_node(dirnode
, &ext4fs_root
->diropen
);
192 int ext4fs_read(char *buf
, unsigned len
)
194 if (ext4fs_root
== NULL
|| ext4fs_file
== NULL
)
197 return ext4fs_read_file(ext4fs_file
, 0, len
, buf
);
200 #if defined(CONFIG_EXT4_WRITE)
201 static void ext4fs_update(void)
204 ext4fs_update_journal();
205 struct ext_filesystem
*fs
= get_fs();
207 /* update super block */
208 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
209 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
211 /* update block groups */
212 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
213 fs
->bgd
[i
].bg_checksum
= ext4fs_checksum_update(i
);
214 put_ext4((uint64_t)(fs
->bgd
[i
].block_id
* fs
->blksz
),
215 fs
->blk_bmaps
[i
], fs
->blksz
);
218 /* update inode table groups */
219 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
220 put_ext4((uint64_t) (fs
->bgd
[i
].inode_id
* fs
->blksz
),
221 fs
->inode_bmaps
[i
], fs
->blksz
);
224 /* update the block group descriptor table */
225 put_ext4((uint64_t)(fs
->gdtable_blkno
* fs
->blksz
),
226 (struct ext2_block_group
*)fs
->gdtable
,
227 (fs
->blksz
* fs
->no_blk_pergdt
));
229 ext4fs_dump_metadata();
235 int ext4fs_get_bgdtable(void)
239 struct ext_filesystem
*fs
= get_fs();
240 grp_desc_size
= sizeof(struct ext2_block_group
);
241 fs
->no_blk_pergdt
= (fs
->no_blkgrp
* grp_desc_size
) / fs
->blksz
;
242 if ((fs
->no_blkgrp
* grp_desc_size
) % fs
->blksz
)
245 /* allocate memory for gdtable */
246 fs
->gdtable
= zalloc(fs
->blksz
* fs
->no_blk_pergdt
);
249 /* read the group descriptor table */
250 status
= ext4fs_devread(fs
->gdtable_blkno
* fs
->sect_perblk
, 0,
251 fs
->blksz
* fs
->no_blk_pergdt
, fs
->gdtable
);
255 if (ext4fs_log_gdt(fs
->gdtable
)) {
256 printf("Error in ext4fs_log_gdt\n");
268 static void delete_single_indirect_block(struct ext2_inode
*inode
)
270 struct ext2_block_group
*bgd
= NULL
;
271 static int prev_bg_bmap_idx
= -1;
276 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
277 struct ext_filesystem
*fs
= get_fs();
278 char *journal_buffer
= zalloc(fs
->blksz
);
279 if (!journal_buffer
) {
280 printf("No memory\n");
283 /* get block group descriptor table */
284 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
286 /* deleting the single indirect block associated with inode */
287 if (inode
->b
.blocks
.indir_block
!= 0) {
288 debug("SIPB releasing %u\n", inode
->b
.blocks
.indir_block
);
289 blknr
= inode
->b
.blocks
.indir_block
;
290 if (fs
->blksz
!= 1024) {
291 bg_idx
= blknr
/ blk_per_grp
;
293 bg_idx
= blknr
/ blk_per_grp
;
294 remainder
= blknr
% blk_per_grp
;
298 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
299 bgd
[bg_idx
].free_blocks
++;
300 fs
->sb
->free_blocks
++;
302 if (prev_bg_bmap_idx
!= bg_idx
) {
304 ext4fs_devread(bgd
[bg_idx
].block_id
*
305 fs
->sect_perblk
, 0, fs
->blksz
,
309 if (ext4fs_log_journal
310 (journal_buffer
, bgd
[bg_idx
].block_id
))
312 prev_bg_bmap_idx
= bg_idx
;
316 free(journal_buffer
);
319 static void delete_double_indirect_block(struct ext2_inode
*inode
)
323 static int prev_bg_bmap_idx
= -1;
327 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
328 unsigned int *di_buffer
= NULL
;
329 unsigned int *DIB_start_addr
= NULL
;
330 struct ext2_block_group
*bgd
= NULL
;
331 struct ext_filesystem
*fs
= get_fs();
332 char *journal_buffer
= zalloc(fs
->blksz
);
333 if (!journal_buffer
) {
334 printf("No memory\n");
337 /* get the block group descriptor table */
338 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
340 if (inode
->b
.blocks
.double_indir_block
!= 0) {
341 di_buffer
= zalloc(fs
->blksz
);
343 printf("No memory\n");
346 DIB_start_addr
= (unsigned int *)di_buffer
;
347 blknr
= inode
->b
.blocks
.double_indir_block
;
348 status
= ext4fs_devread(blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
350 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
354 debug("DICB releasing %u\n", *di_buffer
);
355 if (fs
->blksz
!= 1024) {
356 bg_idx
= (*di_buffer
) / blk_per_grp
;
358 bg_idx
= (*di_buffer
) / blk_per_grp
;
359 remainder
= (*di_buffer
) % blk_per_grp
;
363 ext4fs_reset_block_bmap(*di_buffer
,
364 fs
->blk_bmaps
[bg_idx
], bg_idx
);
366 bgd
[bg_idx
].free_blocks
++;
367 fs
->sb
->free_blocks
++;
369 if (prev_bg_bmap_idx
!= bg_idx
) {
370 status
= ext4fs_devread(bgd
[bg_idx
].block_id
371 * fs
->sect_perblk
, 0,
377 if (ext4fs_log_journal(journal_buffer
,
378 bgd
[bg_idx
].block_id
))
380 prev_bg_bmap_idx
= bg_idx
;
384 /* removing the parent double indirect block */
385 blknr
= inode
->b
.blocks
.double_indir_block
;
386 if (fs
->blksz
!= 1024) {
387 bg_idx
= blknr
/ blk_per_grp
;
389 bg_idx
= blknr
/ blk_per_grp
;
390 remainder
= blknr
% blk_per_grp
;
394 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
395 bgd
[bg_idx
].free_blocks
++;
396 fs
->sb
->free_blocks
++;
398 if (prev_bg_bmap_idx
!= bg_idx
) {
399 memset(journal_buffer
, '\0', fs
->blksz
);
400 status
= ext4fs_devread(bgd
[bg_idx
].block_id
*
401 fs
->sect_perblk
, 0, fs
->blksz
,
406 if (ext4fs_log_journal(journal_buffer
,
407 bgd
[bg_idx
].block_id
))
409 prev_bg_bmap_idx
= bg_idx
;
411 debug("DIPB releasing %ld\n", blknr
);
414 free(DIB_start_addr
);
415 free(journal_buffer
);
418 static void delete_triple_indirect_block(struct ext2_inode
*inode
)
422 static int prev_bg_bmap_idx
= -1;
426 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
427 unsigned int *tigp_buffer
= NULL
;
428 unsigned int *tib_start_addr
= NULL
;
429 unsigned int *tip_buffer
= NULL
;
430 unsigned int *tipb_start_addr
= NULL
;
431 struct ext2_block_group
*bgd
= NULL
;
432 struct ext_filesystem
*fs
= get_fs();
433 char *journal_buffer
= zalloc(fs
->blksz
);
434 if (!journal_buffer
) {
435 printf("No memory\n");
438 /* get block group descriptor table */
439 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
441 if (inode
->b
.blocks
.triple_indir_block
!= 0) {
442 tigp_buffer
= zalloc(fs
->blksz
);
444 printf("No memory\n");
447 tib_start_addr
= (unsigned int *)tigp_buffer
;
448 blknr
= inode
->b
.blocks
.triple_indir_block
;
449 status
= ext4fs_devread(blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
450 (char *)tigp_buffer
);
451 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
452 if (*tigp_buffer
== 0)
454 debug("tigp buffer releasing %u\n", *tigp_buffer
);
456 tip_buffer
= zalloc(fs
->blksz
);
459 tipb_start_addr
= (unsigned int *)tip_buffer
;
460 status
= ext4fs_devread((*tigp_buffer
) *
461 fs
->sect_perblk
, 0, fs
->blksz
,
463 for (j
= 0; j
< fs
->blksz
/ sizeof(int); j
++) {
464 if (*tip_buffer
== 0)
466 if (fs
->blksz
!= 1024) {
467 bg_idx
= (*tip_buffer
) / blk_per_grp
;
469 bg_idx
= (*tip_buffer
) / blk_per_grp
;
471 remainder
= (*tip_buffer
) % blk_per_grp
;
476 ext4fs_reset_block_bmap(*tip_buffer
,
477 fs
->blk_bmaps
[bg_idx
],
481 bgd
[bg_idx
].free_blocks
++;
482 fs
->sb
->free_blocks
++;
484 if (prev_bg_bmap_idx
!= bg_idx
) {
487 bgd
[bg_idx
].block_id
*
494 if (ext4fs_log_journal(journal_buffer
,
498 prev_bg_bmap_idx
= bg_idx
;
501 free(tipb_start_addr
);
502 tipb_start_addr
= NULL
;
505 * removing the grand parent blocks
506 * which is connected to inode
508 if (fs
->blksz
!= 1024) {
509 bg_idx
= (*tigp_buffer
) / blk_per_grp
;
511 bg_idx
= (*tigp_buffer
) / blk_per_grp
;
513 remainder
= (*tigp_buffer
) % blk_per_grp
;
517 ext4fs_reset_block_bmap(*tigp_buffer
,
518 fs
->blk_bmaps
[bg_idx
], bg_idx
);
521 bgd
[bg_idx
].free_blocks
++;
522 fs
->sb
->free_blocks
++;
524 if (prev_bg_bmap_idx
!= bg_idx
) {
525 memset(journal_buffer
, '\0', fs
->blksz
);
527 ext4fs_devread(bgd
[bg_idx
].block_id
*
529 fs
->blksz
, journal_buffer
);
533 if (ext4fs_log_journal(journal_buffer
,
534 bgd
[bg_idx
].block_id
))
536 prev_bg_bmap_idx
= bg_idx
;
540 /* removing the grand parent triple indirect block */
541 blknr
= inode
->b
.blocks
.triple_indir_block
;
542 if (fs
->blksz
!= 1024) {
543 bg_idx
= blknr
/ blk_per_grp
;
545 bg_idx
= blknr
/ blk_per_grp
;
546 remainder
= blknr
% blk_per_grp
;
550 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
551 bgd
[bg_idx
].free_blocks
++;
552 fs
->sb
->free_blocks
++;
554 if (prev_bg_bmap_idx
!= bg_idx
) {
555 memset(journal_buffer
, '\0', fs
->blksz
);
556 status
= ext4fs_devread(bgd
[bg_idx
].block_id
*
557 fs
->sect_perblk
, 0, fs
->blksz
,
562 if (ext4fs_log_journal(journal_buffer
,
563 bgd
[bg_idx
].block_id
))
565 prev_bg_bmap_idx
= bg_idx
;
567 debug("tigp buffer itself releasing %ld\n", blknr
);
570 free(tib_start_addr
);
571 free(tipb_start_addr
);
572 free(journal_buffer
);
575 static int ext4fs_delete_file(int inodeno
)
577 struct ext2_inode inode
;
584 char *read_buffer
= NULL
;
585 char *start_block_address
= NULL
;
586 unsigned int no_blocks
;
588 static int prev_bg_bmap_idx
= -1;
589 unsigned int inodes_per_block
;
592 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
593 unsigned int inode_per_grp
= ext4fs_root
->sblock
.inodes_per_group
;
594 struct ext2_inode
*inode_buffer
= NULL
;
595 struct ext2_block_group
*bgd
= NULL
;
596 struct ext_filesystem
*fs
= get_fs();
597 char *journal_buffer
= zalloc(fs
->blksz
);
600 /* get the block group descriptor table */
601 bgd
= (struct ext2_block_group
*)fs
->gdtable
;
602 status
= ext4fs_read_inode(ext4fs_root
, inodeno
, &inode
);
606 /* read the block no allocated to a file */
607 no_blocks
= inode
.size
/ fs
->blksz
;
608 if (inode
.size
% fs
->blksz
)
611 if (le32_to_cpu(inode
.flags
) & EXT4_EXTENTS_FL
) {
612 struct ext2fs_node
*node_inode
=
613 zalloc(sizeof(struct ext2fs_node
));
616 node_inode
->data
= ext4fs_root
;
617 node_inode
->ino
= inodeno
;
618 node_inode
->inode_read
= 0;
619 memcpy(&(node_inode
->inode
), &inode
, sizeof(struct ext2_inode
));
621 for (i
= 0; i
< no_blocks
; i
++) {
622 blknr
= read_allocated_block(&(node_inode
->inode
), i
);
623 if (fs
->blksz
!= 1024) {
624 bg_idx
= blknr
/ blk_per_grp
;
626 bg_idx
= blknr
/ blk_per_grp
;
627 remainder
= blknr
% blk_per_grp
;
631 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
633 debug("EXT4_EXTENTS Block releasing %ld: %d\n",
636 bgd
[bg_idx
].free_blocks
++;
637 fs
->sb
->free_blocks
++;
640 if (prev_bg_bmap_idx
!= bg_idx
) {
642 ext4fs_devread(bgd
[bg_idx
].block_id
*
644 fs
->blksz
, journal_buffer
);
647 if (ext4fs_log_journal(journal_buffer
,
648 bgd
[bg_idx
].block_id
))
650 prev_bg_bmap_idx
= bg_idx
;
659 delete_single_indirect_block(&inode
);
660 delete_double_indirect_block(&inode
);
661 delete_triple_indirect_block(&inode
);
663 /* read the block no allocated to a file */
664 no_blocks
= inode
.size
/ fs
->blksz
;
665 if (inode
.size
% fs
->blksz
)
667 for (i
= 0; i
< no_blocks
; i
++) {
668 blknr
= read_allocated_block(&inode
, i
);
669 if (fs
->blksz
!= 1024) {
670 bg_idx
= blknr
/ blk_per_grp
;
672 bg_idx
= blknr
/ blk_per_grp
;
673 remainder
= blknr
% blk_per_grp
;
677 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
679 debug("ActualB releasing %ld: %d\n", blknr
, bg_idx
);
681 bgd
[bg_idx
].free_blocks
++;
682 fs
->sb
->free_blocks
++;
684 if (prev_bg_bmap_idx
!= bg_idx
) {
685 memset(journal_buffer
, '\0', fs
->blksz
);
686 status
= ext4fs_devread(bgd
[bg_idx
].block_id
692 if (ext4fs_log_journal(journal_buffer
,
693 bgd
[bg_idx
].block_id
))
695 prev_bg_bmap_idx
= bg_idx
;
700 /* from the inode no to blockno */
701 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
702 ibmap_idx
= inodeno
/ inode_per_grp
;
704 /* get the block no */
706 blkno
= __le32_to_cpu(bgd
[ibmap_idx
].inode_table_id
) +
707 (inodeno
% __le32_to_cpu(inode_per_grp
)) / inodes_per_block
;
709 /* get the offset of the inode */
710 blkoff
= ((inodeno
) % inodes_per_block
) * fs
->inodesz
;
712 /* read the block no containing the inode */
713 read_buffer
= zalloc(fs
->blksz
);
716 start_block_address
= read_buffer
;
717 status
= ext4fs_devread(blkno
* fs
->sect_perblk
,
718 0, fs
->blksz
, read_buffer
);
722 if (ext4fs_log_journal(read_buffer
, blkno
))
725 read_buffer
= read_buffer
+ blkoff
;
726 inode_buffer
= (struct ext2_inode
*)read_buffer
;
727 memset(inode_buffer
, '\0', sizeof(struct ext2_inode
));
729 /* write the inode to original position in inode table */
730 if (ext4fs_put_metadata(start_block_address
, blkno
))
733 /* update the respective inode bitmaps */
735 ext4fs_reset_inode_bmap(inodeno
, fs
->inode_bmaps
[ibmap_idx
], ibmap_idx
);
736 bgd
[ibmap_idx
].free_inodes
++;
737 fs
->sb
->free_inodes
++;
739 memset(journal_buffer
, '\0', fs
->blksz
);
740 status
= ext4fs_devread(bgd
[ibmap_idx
].inode_id
*
741 fs
->sect_perblk
, 0, fs
->blksz
, journal_buffer
);
744 if (ext4fs_log_journal(journal_buffer
, bgd
[ibmap_idx
].inode_id
))
750 if (ext4fs_init() != 0) {
751 printf("error in File System init\n");
755 free(start_block_address
);
756 free(journal_buffer
);
760 free(start_block_address
);
761 free(journal_buffer
);
766 int ext4fs_init(void)
770 unsigned int real_free_blocks
= 0;
771 struct ext_filesystem
*fs
= get_fs();
774 fs
->blksz
= EXT2_BLOCK_SIZE(ext4fs_root
);
775 fs
->inodesz
= INODE_SIZE_FILESYSTEM(ext4fs_root
);
776 fs
->sect_perblk
= fs
->blksz
/ SECTOR_SIZE
;
778 /* get the superblock */
779 fs
->sb
= zalloc(SUPERBLOCK_SIZE
);
782 if (!ext4fs_devread(SUPERBLOCK_SECTOR
, 0, SUPERBLOCK_SIZE
,
787 if (ext4fs_init_journal())
790 /* get total no of blockgroups */
791 fs
->no_blkgrp
= (uint32_t)ext4fs_div_roundup(
792 (ext4fs_root
->sblock
.total_blocks
-
793 ext4fs_root
->sblock
.first_data_block
),
794 ext4fs_root
->sblock
.blocks_per_group
);
796 /* get the block group descriptor table */
797 fs
->gdtable_blkno
= ((EXT2_MIN_BLOCK_SIZE
== fs
->blksz
) + 1);
798 if (ext4fs_get_bgdtable() == -1) {
799 printf("Error in getting the block group descriptor table\n");
802 fs
->bgd
= (struct ext2_block_group
*)fs
->gdtable
;
804 /* load all the available bitmap block of the partition */
805 fs
->blk_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(char *));
808 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
809 fs
->blk_bmaps
[i
] = zalloc(fs
->blksz
);
810 if (!fs
->blk_bmaps
[i
])
814 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
816 ext4fs_devread(fs
->bgd
[i
].block_id
* fs
->sect_perblk
, 0,
817 fs
->blksz
, (char *)fs
->blk_bmaps
[i
]);
822 /* load all the available inode bitmap of the partition */
823 fs
->inode_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(unsigned char *));
824 if (!fs
->inode_bmaps
)
826 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
827 fs
->inode_bmaps
[i
] = zalloc(fs
->blksz
);
828 if (!fs
->inode_bmaps
[i
])
832 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
833 status
= ext4fs_devread(fs
->bgd
[i
].inode_id
* fs
->sect_perblk
,
835 (char *)fs
->inode_bmaps
[i
]);
841 * check filesystem consistency with free blocks of file system
842 * some time we observed that superblock freeblocks does not match
843 * with the blockgroups freeblocks when improper
844 * reboot of a linux kernel
846 for (i
= 0; i
< fs
->no_blkgrp
; i
++)
847 real_free_blocks
= real_free_blocks
+ fs
->bgd
[i
].free_blocks
;
848 if (real_free_blocks
!= fs
->sb
->free_blocks
)
849 fs
->sb
->free_blocks
= real_free_blocks
;
858 void ext4fs_deinit(void)
861 struct ext2_inode inode_journal
;
862 struct journal_superblock_t
*jsb
;
864 struct ext_filesystem
*fs
= get_fs();
867 char *temp_buff
= zalloc(fs
->blksz
);
869 ext4fs_read_inode(ext4fs_root
, EXT2_JOURNAL_INO
,
871 blknr
= read_allocated_block(&inode_journal
,
872 EXT2_JOURNAL_SUPERBLOCK
);
873 ext4fs_devread(blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
875 jsb
= (struct journal_superblock_t
*)temp_buff
;
876 jsb
->s_start
= cpu_to_be32(0);
877 put_ext4((uint64_t) (blknr
* fs
->blksz
),
878 (struct journal_superblock_t
*)temp_buff
, fs
->blksz
);
881 ext4fs_free_journal();
883 /* get the superblock */
884 ext4fs_devread(SUPERBLOCK_SECTOR
, 0, SUPERBLOCK_SIZE
, (char *)fs
->sb
);
885 fs
->sb
->feature_incompat
&= ~EXT3_FEATURE_INCOMPAT_RECOVER
;
886 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
887 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
892 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
893 free(fs
->blk_bmaps
[i
]);
894 fs
->blk_bmaps
[i
] = NULL
;
897 fs
->blk_bmaps
= NULL
;
900 if (fs
->inode_bmaps
) {
901 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
902 free(fs
->inode_bmaps
[i
]);
903 fs
->inode_bmaps
[i
] = NULL
;
905 free(fs
->inode_bmaps
);
906 fs
->inode_bmaps
= NULL
;
914 * reinitiliazed the global inode and
915 * block bitmap first execution check variables
917 fs
->first_pass_ibmap
= 0;
918 fs
->first_pass_bbmap
= 0;
919 fs
->curr_inode_no
= 0;
923 static int ext4fs_write_file(struct ext2_inode
*file_inode
,
924 int pos
, unsigned int len
, char *buf
)
928 int log2blocksize
= LOG2_EXT2_BLOCK_SIZE(ext4fs_root
);
929 unsigned int filesize
= __le32_to_cpu(file_inode
->size
);
930 struct ext_filesystem
*fs
= get_fs();
931 int previous_block_number
= -1;
932 int delayed_start
= 0;
933 int delayed_extent
= 0;
934 int delayed_next
= 0;
935 char *delayed_buf
= NULL
;
937 /* Adjust len so it we can't read past the end of the file. */
941 blockcnt
= ((len
+ pos
) + fs
->blksz
- 1) / fs
->blksz
;
943 for (i
= pos
/ fs
->blksz
; i
< blockcnt
; i
++) {
945 int blockend
= fs
->blksz
;
947 blknr
= read_allocated_block(file_inode
, i
);
951 blknr
= blknr
<< log2blocksize
;
954 if (previous_block_number
!= -1) {
955 if (delayed_next
== blknr
) {
956 delayed_extent
+= blockend
;
957 delayed_next
+= blockend
>> SECTOR_BITS
;
959 put_ext4((uint64_t) (delayed_start
*
962 (uint32_t) delayed_extent
);
963 previous_block_number
= blknr
;
964 delayed_start
= blknr
;
965 delayed_extent
= blockend
;
967 delayed_next
= blknr
+
968 (blockend
>> SECTOR_BITS
);
971 previous_block_number
= blknr
;
972 delayed_start
= blknr
;
973 delayed_extent
= blockend
;
975 delayed_next
= blknr
+
976 (blockend
>> SECTOR_BITS
);
979 if (previous_block_number
!= -1) {
981 put_ext4((uint64_t) (delayed_start
*
982 SECTOR_SIZE
), delayed_buf
,
983 (uint32_t) delayed_extent
);
984 previous_block_number
= -1;
986 memset(buf
, 0, fs
->blksz
- skipfirst
);
988 buf
+= fs
->blksz
- skipfirst
;
990 if (previous_block_number
!= -1) {
992 put_ext4((uint64_t) (delayed_start
* SECTOR_SIZE
),
993 delayed_buf
, (uint32_t) delayed_extent
);
994 previous_block_number
= -1;
1000 int ext4fs_write(const char *fname
, unsigned char *buffer
,
1001 unsigned long sizebytes
)
1004 struct ext2_inode
*file_inode
= NULL
;
1005 unsigned char *inode_buffer
= NULL
;
1008 time_t timestamp
= 0;
1010 uint64_t bytes_reqd_for_file
;
1011 unsigned int blks_reqd_for_file
;
1012 unsigned int blocks_remaining
;
1013 int existing_file_inodeno
;
1014 char *temp_ptr
= NULL
;
1015 long int itable_blkno
;
1016 long int parent_itable_blkno
;
1018 struct ext2_sblock
*sblock
= &(ext4fs_root
->sblock
);
1019 unsigned int inodes_per_block
;
1020 unsigned int ibmap_idx
;
1021 struct ext_filesystem
*fs
= get_fs();
1022 ALLOC_CACHE_ALIGN_BUFFER(char, filename
, 256);
1023 memset(filename
, 0x00, sizeof(filename
));
1025 g_parent_inode
= zalloc(sizeof(struct ext2_inode
));
1026 if (!g_parent_inode
)
1029 if (ext4fs_init() != 0) {
1030 printf("error in File System init\n");
1033 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
1034 parent_inodeno
= ext4fs_get_parent_inode_num(fname
, filename
, F_FILE
);
1035 if (parent_inodeno
== -1)
1037 if (ext4fs_iget(parent_inodeno
, g_parent_inode
))
1039 /* check if the filename is already present in root */
1040 existing_file_inodeno
= ext4fs_filename_check(filename
);
1041 if (existing_file_inodeno
!= -1) {
1042 ret
= ext4fs_delete_file(existing_file_inodeno
);
1043 fs
->first_pass_bbmap
= 0;
1046 fs
->first_pass_ibmap
= 0;
1047 fs
->curr_inode_no
= 0;
1051 /* calucalate how many blocks required */
1052 bytes_reqd_for_file
= sizebytes
;
1053 blks_reqd_for_file
= lldiv(bytes_reqd_for_file
, fs
->blksz
);
1054 if (do_div(bytes_reqd_for_file
, fs
->blksz
) != 0) {
1055 blks_reqd_for_file
++;
1056 debug("total bytes for a file %u\n", blks_reqd_for_file
);
1058 blocks_remaining
= blks_reqd_for_file
;
1059 /* test for available space in partition */
1060 if (fs
->sb
->free_blocks
< blks_reqd_for_file
) {
1061 printf("Not enough space on partition !!!\n");
1065 ext4fs_update_parent_dentry(filename
, &inodeno
, FILETYPE_REG
);
1066 /* prepare file inode */
1067 inode_buffer
= zalloc(fs
->inodesz
);
1070 file_inode
= (struct ext2_inode
*)inode_buffer
;
1071 file_inode
->mode
= S_IFREG
| S_IRWXU
|
1072 S_IRGRP
| S_IROTH
| S_IXGRP
| S_IXOTH
;
1073 /* ToDo: Update correct time */
1074 file_inode
->mtime
= timestamp
;
1075 file_inode
->atime
= timestamp
;
1076 file_inode
->ctime
= timestamp
;
1077 file_inode
->nlinks
= 1;
1078 file_inode
->size
= sizebytes
;
1080 /* Allocate data blocks */
1081 ext4fs_allocate_blocks(file_inode
, blocks_remaining
,
1082 &blks_reqd_for_file
);
1083 file_inode
->blockcnt
= (blks_reqd_for_file
* fs
->blksz
) / SECTOR_SIZE
;
1085 temp_ptr
= zalloc(fs
->blksz
);
1088 ibmap_idx
= inodeno
/ ext4fs_root
->sblock
.inodes_per_group
;
1090 itable_blkno
= __le32_to_cpu(fs
->bgd
[ibmap_idx
].inode_table_id
) +
1091 (inodeno
% __le32_to_cpu(sblock
->inodes_per_group
)) /
1093 blkoff
= (inodeno
% inodes_per_block
) * fs
->inodesz
;
1094 ext4fs_devread(itable_blkno
* fs
->sect_perblk
, 0, fs
->blksz
, temp_ptr
);
1095 if (ext4fs_log_journal(temp_ptr
, itable_blkno
))
1098 memcpy(temp_ptr
+ blkoff
, inode_buffer
, fs
->inodesz
);
1099 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
1101 /* copy the file content into data blocks */
1102 if (ext4fs_write_file(file_inode
, 0, sizebytes
, (char *)buffer
) == -1) {
1103 printf("Error in copying content\n");
1106 ibmap_idx
= parent_inodeno
/ ext4fs_root
->sblock
.inodes_per_group
;
1108 parent_itable_blkno
= __le32_to_cpu(fs
->bgd
[ibmap_idx
].inode_table_id
) +
1110 __le32_to_cpu(sblock
->inodes_per_group
)) / inodes_per_block
;
1111 blkoff
= (parent_inodeno
% inodes_per_block
) * fs
->inodesz
;
1112 if (parent_itable_blkno
!= itable_blkno
) {
1113 memset(temp_ptr
, '\0', fs
->blksz
);
1114 ext4fs_devread(parent_itable_blkno
* fs
->sect_perblk
,
1115 0, fs
->blksz
, temp_ptr
);
1116 if (ext4fs_log_journal(temp_ptr
, parent_itable_blkno
))
1119 memcpy(temp_ptr
+ blkoff
, g_parent_inode
,
1120 sizeof(struct ext2_inode
));
1121 if (ext4fs_put_metadata(temp_ptr
, parent_itable_blkno
))
1126 * If parent and child fall in same inode table block
1127 * both should be kept in 1 buffer
1129 memcpy(temp_ptr
+ blkoff
, g_parent_inode
,
1130 sizeof(struct ext2_inode
));
1132 if (ext4fs_put_metadata(temp_ptr
, itable_blkno
))
1139 fs
->first_pass_bbmap
= 0;
1141 fs
->first_pass_ibmap
= 0;
1142 fs
->curr_inode_no
= 0;
1144 free(g_parent_inode
);
1145 g_parent_inode
= NULL
;
1151 free(g_parent_inode
);
1152 g_parent_inode
= NULL
;