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>
43 #include "ext4_common.h"
45 int ext4fs_symlinknest
;
46 struct ext_filesystem ext_fs
;
48 struct ext_filesystem
*get_fs(void)
53 void ext4fs_free_node(struct ext2fs_node
*node
, struct ext2fs_node
*currroot
)
55 if ((node
!= &ext4fs_root
->diropen
) && (node
!= currroot
))
60 * Taken from openmoko-kernel mailing list: By Andy green
61 * Optimized read file API : collects and defers contiguous sector
62 * reads into one potentially more efficient larger sequential read action
64 int ext4fs_read_file(struct ext2fs_node
*node
, int pos
,
65 unsigned int len
, char *buf
)
69 int log2blocksize
= LOG2_EXT2_BLOCK_SIZE(node
->data
);
70 int blocksize
= 1 << (log2blocksize
+ DISK_SECTOR_BITS
);
71 unsigned int filesize
= __le32_to_cpu(node
->inode
.size
);
72 int previous_block_number
= -1;
73 int delayed_start
= 0;
74 int delayed_extent
= 0;
75 int delayed_skipfirst
= 0;
77 char *delayed_buf
= NULL
;
80 /* Adjust len so it we can't read past the end of the file. */
84 blockcnt
= ((len
+ pos
) + blocksize
- 1) / blocksize
;
86 for (i
= pos
/ blocksize
; i
< blockcnt
; i
++) {
88 int blockoff
= pos
% blocksize
;
89 int blockend
= blocksize
;
91 blknr
= read_allocated_block(&(node
->inode
), i
);
95 blknr
= blknr
<< log2blocksize
;
98 if (i
== blockcnt
- 1) {
99 blockend
= (len
+ pos
) % blocksize
;
101 /* The last portion is exactly blocksize. */
103 blockend
= blocksize
;
107 if (i
== pos
/ blocksize
) {
108 skipfirst
= blockoff
;
109 blockend
-= skipfirst
;
114 if (previous_block_number
!= -1) {
115 if (delayed_next
== blknr
) {
116 delayed_extent
+= blockend
;
117 delayed_next
+= blockend
>> SECTOR_BITS
;
119 status
= ext4fs_devread(delayed_start
,
125 previous_block_number
= blknr
;
126 delayed_start
= blknr
;
127 delayed_extent
= blockend
;
128 delayed_skipfirst
= skipfirst
;
130 delayed_next
= blknr
+
131 (blockend
>> SECTOR_BITS
);
134 previous_block_number
= blknr
;
135 delayed_start
= blknr
;
136 delayed_extent
= blockend
;
137 delayed_skipfirst
= skipfirst
;
139 delayed_next
= blknr
+
140 (blockend
>> SECTOR_BITS
);
143 if (previous_block_number
!= -1) {
145 status
= ext4fs_devread(delayed_start
,
151 previous_block_number
= -1;
153 memset(buf
, 0, blocksize
- skipfirst
);
155 buf
+= blocksize
- skipfirst
;
157 if (previous_block_number
!= -1) {
159 status
= ext4fs_devread(delayed_start
,
160 delayed_skipfirst
, delayed_extent
,
164 previous_block_number
= -1;
170 int ext4fs_ls(const char *dirname
)
172 struct ext2fs_node
*dirnode
;
178 status
= ext4fs_find_file(dirname
, &ext4fs_root
->diropen
, &dirnode
,
181 printf("** Can not find directory. **\n");
185 ext4fs_iterate_dir(dirnode
, NULL
, NULL
, NULL
);
186 ext4fs_free_node(dirnode
, &ext4fs_root
->diropen
);
191 int ext4fs_read(char *buf
, unsigned len
)
193 if (ext4fs_root
== NULL
|| ext4fs_file
== NULL
)
196 return ext4fs_read_file(ext4fs_file
, 0, len
, buf
);
199 #if defined(CONFIG_CMD_EXT4_WRITE)
200 static void ext4fs_update(void)
203 ext4fs_update_journal();
204 struct ext_filesystem
*fs
= get_fs();
206 /* update super block */
207 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
208 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
210 /* update block groups */
211 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
212 fs
->gd
[i
].bg_checksum
= ext4fs_checksum_update(i
);
213 put_ext4((uint64_t)(fs
->gd
[i
].block_id
* fs
->blksz
),
214 fs
->blk_bmaps
[i
], fs
->blksz
);
217 /* update inode table groups */
218 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
219 put_ext4((uint64_t) (fs
->gd
[i
].inode_id
* fs
->blksz
),
220 fs
->inode_bmaps
[i
], fs
->blksz
);
223 /* update the block group descriptor table */
224 put_ext4((uint64_t)(fs
->gdtable_blkno
* fs
->blksz
),
225 (struct ext2_block_group
*)fs
->gdtable
,
226 (fs
->blksz
* fs
->no_blk_pergdt
));
228 ext4fs_dump_metadata();
234 int ext4fs_get_bgdtable(void)
238 struct ext_filesystem
*fs
= get_fs();
239 grp_desc_size
= sizeof(struct ext2_block_group
);
240 fs
->no_blk_pergdt
= (fs
->no_blkgrp
* grp_desc_size
) / fs
->blksz
;
241 if ((fs
->no_blkgrp
* grp_desc_size
) % fs
->blksz
)
244 /* allocate memory for gdtable */
245 fs
->gdtable
= zalloc(fs
->blksz
* fs
->no_blk_pergdt
);
248 /* read the group descriptor table */
249 status
= ext4fs_devread(fs
->gdtable_blkno
* fs
->sect_perblk
, 0,
250 fs
->blksz
* fs
->no_blk_pergdt
, fs
->gdtable
);
254 if (ext4fs_log_gdt(fs
->gdtable
)) {
255 printf("Error in ext4fs_log_gdt\n");
267 static void delete_single_indirect_block(struct ext2_inode
*inode
)
269 struct ext2_block_group
*gd
= NULL
;
270 static int prev_bg_bmap_idx
= -1;
275 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
276 struct ext_filesystem
*fs
= get_fs();
277 char *journal_buffer
= zalloc(fs
->blksz
);
278 if (!journal_buffer
) {
279 printf("No memory\n");
282 /* get block group descriptor table */
283 gd
= (struct ext2_block_group
*)fs
->gdtable
;
285 /* deleting the single indirect block associated with inode */
286 if (inode
->b
.blocks
.indir_block
!= 0) {
287 debug("SIPB releasing %u\n", inode
->b
.blocks
.indir_block
);
288 blknr
= inode
->b
.blocks
.indir_block
;
289 if (fs
->blksz
!= 1024) {
290 bg_idx
= blknr
/ blk_per_grp
;
292 bg_idx
= blknr
/ blk_per_grp
;
293 remainder
= blknr
% blk_per_grp
;
297 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
298 gd
[bg_idx
].free_blocks
++;
299 fs
->sb
->free_blocks
++;
301 if (prev_bg_bmap_idx
!= bg_idx
) {
303 ext4fs_devread(gd
[bg_idx
].block_id
*
304 fs
->sect_perblk
, 0, fs
->blksz
,
308 if (ext4fs_log_journal
309 (journal_buffer
, gd
[bg_idx
].block_id
))
311 prev_bg_bmap_idx
= bg_idx
;
315 free(journal_buffer
);
318 static void delete_double_indirect_block(struct ext2_inode
*inode
)
322 static int prev_bg_bmap_idx
= -1;
326 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
327 unsigned int *di_buffer
= NULL
;
328 unsigned int *DIB_start_addr
= NULL
;
329 struct ext2_block_group
*gd
= NULL
;
330 struct ext_filesystem
*fs
= get_fs();
331 char *journal_buffer
= zalloc(fs
->blksz
);
332 if (!journal_buffer
) {
333 printf("No memory\n");
336 /* get the block group descriptor table */
337 gd
= (struct ext2_block_group
*)fs
->gdtable
;
339 if (inode
->b
.blocks
.double_indir_block
!= 0) {
340 di_buffer
= zalloc(fs
->blksz
);
342 printf("No memory\n");
345 DIB_start_addr
= (unsigned int *)di_buffer
;
346 blknr
= inode
->b
.blocks
.double_indir_block
;
347 status
= ext4fs_devread(blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
349 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
353 debug("DICB releasing %u\n", *di_buffer
);
354 if (fs
->blksz
!= 1024) {
355 bg_idx
= (*di_buffer
) / blk_per_grp
;
357 bg_idx
= (*di_buffer
) / blk_per_grp
;
358 remainder
= (*di_buffer
) % blk_per_grp
;
362 ext4fs_reset_block_bmap(*di_buffer
,
363 fs
->blk_bmaps
[bg_idx
], bg_idx
);
365 gd
[bg_idx
].free_blocks
++;
366 fs
->sb
->free_blocks
++;
368 if (prev_bg_bmap_idx
!= bg_idx
) {
369 status
= ext4fs_devread(gd
[bg_idx
].block_id
370 * fs
->sect_perblk
, 0,
376 if (ext4fs_log_journal(journal_buffer
,
377 gd
[bg_idx
].block_id
))
379 prev_bg_bmap_idx
= bg_idx
;
383 /* removing the parent double indirect block */
384 blknr
= inode
->b
.blocks
.double_indir_block
;
385 if (fs
->blksz
!= 1024) {
386 bg_idx
= blknr
/ blk_per_grp
;
388 bg_idx
= blknr
/ blk_per_grp
;
389 remainder
= blknr
% blk_per_grp
;
393 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
394 gd
[bg_idx
].free_blocks
++;
395 fs
->sb
->free_blocks
++;
397 if (prev_bg_bmap_idx
!= bg_idx
) {
398 memset(journal_buffer
, '\0', fs
->blksz
);
399 status
= ext4fs_devread(gd
[bg_idx
].block_id
*
400 fs
->sect_perblk
, 0, fs
->blksz
,
405 if (ext4fs_log_journal(journal_buffer
,
406 gd
[bg_idx
].block_id
))
408 prev_bg_bmap_idx
= bg_idx
;
410 debug("DIPB releasing %ld\n", blknr
);
413 free(DIB_start_addr
);
414 free(journal_buffer
);
417 static void delete_triple_indirect_block(struct ext2_inode
*inode
)
421 static int prev_bg_bmap_idx
= -1;
425 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
426 unsigned int *tigp_buffer
= NULL
;
427 unsigned int *tib_start_addr
= NULL
;
428 unsigned int *tip_buffer
= NULL
;
429 unsigned int *tipb_start_addr
= NULL
;
430 struct ext2_block_group
*gd
= NULL
;
431 struct ext_filesystem
*fs
= get_fs();
432 char *journal_buffer
= zalloc(fs
->blksz
);
433 if (!journal_buffer
) {
434 printf("No memory\n");
437 /* get block group descriptor table */
438 gd
= (struct ext2_block_group
*)fs
->gdtable
;
440 if (inode
->b
.blocks
.triple_indir_block
!= 0) {
441 tigp_buffer
= zalloc(fs
->blksz
);
443 printf("No memory\n");
446 tib_start_addr
= (unsigned int *)tigp_buffer
;
447 blknr
= inode
->b
.blocks
.triple_indir_block
;
448 status
= ext4fs_devread(blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
449 (char *)tigp_buffer
);
450 for (i
= 0; i
< fs
->blksz
/ sizeof(int); i
++) {
451 if (*tigp_buffer
== 0)
453 debug("tigp buffer releasing %u\n", *tigp_buffer
);
455 tip_buffer
= zalloc(fs
->blksz
);
458 tipb_start_addr
= (unsigned int *)tip_buffer
;
459 status
= ext4fs_devread((*tigp_buffer
) *
460 fs
->sect_perblk
, 0, fs
->blksz
,
462 for (j
= 0; j
< fs
->blksz
/ sizeof(int); j
++) {
463 if (*tip_buffer
== 0)
465 if (fs
->blksz
!= 1024) {
466 bg_idx
= (*tip_buffer
) / blk_per_grp
;
468 bg_idx
= (*tip_buffer
) / blk_per_grp
;
470 remainder
= (*tip_buffer
) % blk_per_grp
;
475 ext4fs_reset_block_bmap(*tip_buffer
,
476 fs
->blk_bmaps
[bg_idx
],
480 gd
[bg_idx
].free_blocks
++;
481 fs
->sb
->free_blocks
++;
483 if (prev_bg_bmap_idx
!= bg_idx
) {
485 ext4fs_devread(gd
[bg_idx
].block_id
*
492 if (ext4fs_log_journal(journal_buffer
,
496 prev_bg_bmap_idx
= bg_idx
;
499 free(tipb_start_addr
);
500 tipb_start_addr
= NULL
;
503 * removing the grand parent blocks
504 * which is connected to inode
506 if (fs
->blksz
!= 1024) {
507 bg_idx
= (*tigp_buffer
) / blk_per_grp
;
509 bg_idx
= (*tigp_buffer
) / blk_per_grp
;
511 remainder
= (*tigp_buffer
) % blk_per_grp
;
515 ext4fs_reset_block_bmap(*tigp_buffer
,
516 fs
->blk_bmaps
[bg_idx
], bg_idx
);
519 gd
[bg_idx
].free_blocks
++;
520 fs
->sb
->free_blocks
++;
522 if (prev_bg_bmap_idx
!= bg_idx
) {
523 memset(journal_buffer
, '\0', fs
->blksz
);
525 ext4fs_devread(gd
[bg_idx
].block_id
*
527 fs
->blksz
, journal_buffer
);
531 if (ext4fs_log_journal(journal_buffer
,
532 gd
[bg_idx
].block_id
))
534 prev_bg_bmap_idx
= bg_idx
;
538 /* removing the grand parent triple indirect block */
539 blknr
= inode
->b
.blocks
.triple_indir_block
;
540 if (fs
->blksz
!= 1024) {
541 bg_idx
= blknr
/ blk_per_grp
;
543 bg_idx
= blknr
/ blk_per_grp
;
544 remainder
= blknr
% blk_per_grp
;
548 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
], bg_idx
);
549 gd
[bg_idx
].free_blocks
++;
550 fs
->sb
->free_blocks
++;
552 if (prev_bg_bmap_idx
!= bg_idx
) {
553 memset(journal_buffer
, '\0', fs
->blksz
);
554 status
= ext4fs_devread(gd
[bg_idx
].block_id
*
555 fs
->sect_perblk
, 0, fs
->blksz
,
560 if (ext4fs_log_journal(journal_buffer
,
561 gd
[bg_idx
].block_id
))
563 prev_bg_bmap_idx
= bg_idx
;
565 debug("tigp buffer itself releasing %ld\n", blknr
);
568 free(tib_start_addr
);
569 free(tipb_start_addr
);
570 free(journal_buffer
);
573 static int ext4fs_delete_file(int inodeno
)
575 struct ext2_inode inode
;
582 char *read_buffer
= NULL
;
583 char *start_block_address
= NULL
;
584 unsigned int no_blocks
;
586 static int prev_bg_bmap_idx
= -1;
587 unsigned int inodes_per_block
;
590 unsigned int blk_per_grp
= ext4fs_root
->sblock
.blocks_per_group
;
591 unsigned int inode_per_grp
= ext4fs_root
->sblock
.inodes_per_group
;
592 struct ext2_inode
*inode_buffer
= NULL
;
593 struct ext2_block_group
*gd
= NULL
;
594 struct ext_filesystem
*fs
= get_fs();
595 char *journal_buffer
= zalloc(fs
->blksz
);
598 /* get the block group descriptor table */
599 gd
= (struct ext2_block_group
*)fs
->gdtable
;
600 status
= ext4fs_read_inode(ext4fs_root
, inodeno
, &inode
);
604 /* read the block no allocated to a file */
605 no_blocks
= inode
.size
/ fs
->blksz
;
606 if (inode
.size
% fs
->blksz
)
609 if (le32_to_cpu(inode
.flags
) & EXT4_EXTENTS_FL
) {
610 struct ext2fs_node
*node_inode
=
611 zalloc(sizeof(struct ext2fs_node
));
614 node_inode
->data
= ext4fs_root
;
615 node_inode
->ino
= inodeno
;
616 node_inode
->inode_read
= 0;
617 memcpy(&(node_inode
->inode
), &inode
, sizeof(struct ext2_inode
));
619 for (i
= 0; i
< no_blocks
; i
++) {
620 blknr
= read_allocated_block(&(node_inode
->inode
), i
);
621 if (fs
->blksz
!= 1024) {
622 bg_idx
= blknr
/ blk_per_grp
;
624 bg_idx
= blknr
/ blk_per_grp
;
625 remainder
= blknr
% blk_per_grp
;
629 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
631 debug("EXT4_EXTENTS Block releasing %ld: %d\n",
634 gd
[bg_idx
].free_blocks
++;
635 fs
->sb
->free_blocks
++;
638 if (prev_bg_bmap_idx
!= bg_idx
) {
640 ext4fs_devread(gd
[bg_idx
].block_id
*
642 fs
->blksz
, journal_buffer
);
645 if (ext4fs_log_journal(journal_buffer
,
646 gd
[bg_idx
].block_id
))
648 prev_bg_bmap_idx
= bg_idx
;
657 delete_single_indirect_block(&inode
);
658 delete_double_indirect_block(&inode
);
659 delete_triple_indirect_block(&inode
);
661 /* read the block no allocated to a file */
662 no_blocks
= inode
.size
/ fs
->blksz
;
663 if (inode
.size
% fs
->blksz
)
665 for (i
= 0; i
< no_blocks
; i
++) {
666 blknr
= read_allocated_block(&inode
, i
);
667 if (fs
->blksz
!= 1024) {
668 bg_idx
= blknr
/ blk_per_grp
;
670 bg_idx
= blknr
/ blk_per_grp
;
671 remainder
= blknr
% blk_per_grp
;
675 ext4fs_reset_block_bmap(blknr
, fs
->blk_bmaps
[bg_idx
],
677 debug("ActualB releasing %ld: %d\n", blknr
, bg_idx
);
679 gd
[bg_idx
].free_blocks
++;
680 fs
->sb
->free_blocks
++;
682 if (prev_bg_bmap_idx
!= bg_idx
) {
683 memset(journal_buffer
, '\0', fs
->blksz
);
684 status
= ext4fs_devread(gd
[bg_idx
].block_id
690 if (ext4fs_log_journal(journal_buffer
,
691 gd
[bg_idx
].block_id
))
693 prev_bg_bmap_idx
= bg_idx
;
698 /* from the inode no to blockno */
699 inodes_per_block
= fs
->blksz
/ fs
->inodesz
;
700 ibmap_idx
= inodeno
/ inode_per_grp
;
702 /* get the block no */
704 blkno
= __le32_to_cpu(gd
[ibmap_idx
].inode_table_id
) +
705 (inodeno
% __le32_to_cpu(inode_per_grp
)) / inodes_per_block
;
707 /* get the offset of the inode */
708 blkoff
= ((inodeno
) % inodes_per_block
) * fs
->inodesz
;
710 /* read the block no containing the inode */
711 read_buffer
= zalloc(fs
->blksz
);
714 start_block_address
= read_buffer
;
715 status
= ext4fs_devread(blkno
* fs
->sect_perblk
,
716 0, fs
->blksz
, read_buffer
);
720 if (ext4fs_log_journal(read_buffer
, blkno
))
723 read_buffer
= read_buffer
+ blkoff
;
724 inode_buffer
= (struct ext2_inode
*)read_buffer
;
725 memset(inode_buffer
, '\0', sizeof(struct ext2_inode
));
727 /* write the inode to original position in inode table */
728 if (ext4fs_put_metadata(start_block_address
, blkno
))
731 /* update the respective inode bitmaps */
733 ext4fs_reset_inode_bmap(inodeno
, fs
->inode_bmaps
[ibmap_idx
], ibmap_idx
);
734 gd
[ibmap_idx
].free_inodes
++;
735 fs
->sb
->free_inodes
++;
737 memset(journal_buffer
, '\0', fs
->blksz
);
738 status
= ext4fs_devread(gd
[ibmap_idx
].inode_id
*
739 fs
->sect_perblk
, 0, fs
->blksz
, journal_buffer
);
742 if (ext4fs_log_journal(journal_buffer
, gd
[ibmap_idx
].inode_id
))
748 if (ext4fs_init() != 0) {
749 printf("error in File System init\n");
753 free(start_block_address
);
754 free(journal_buffer
);
758 free(start_block_address
);
759 free(journal_buffer
);
764 int ext4fs_init(void)
768 unsigned int real_free_blocks
= 0;
769 struct ext_filesystem
*fs
= get_fs();
772 fs
->blksz
= EXT2_BLOCK_SIZE(ext4fs_root
);
773 fs
->inodesz
= INODE_SIZE_FILESYSTEM(ext4fs_root
);
774 fs
->sect_perblk
= fs
->blksz
/ SECTOR_SIZE
;
776 /* get the superblock */
777 fs
->sb
= zalloc(SUPERBLOCK_SIZE
);
780 if (!ext4fs_devread(SUPERBLOCK_SECTOR
, 0, SUPERBLOCK_SIZE
,
785 if (ext4fs_init_journal())
788 /* get total no of blockgroups */
789 fs
->no_blkgrp
= (uint32_t)ext4fs_div_roundup(
790 (ext4fs_root
->sblock
.total_blocks
-
791 ext4fs_root
->sblock
.first_data_block
),
792 ext4fs_root
->sblock
.blocks_per_group
);
794 /* get the block group descriptor table */
795 fs
->gdtable_blkno
= ((EXT2_MIN_BLOCK_SIZE
== fs
->blksz
) + 1);
796 if (ext4fs_get_bgdtable() == -1) {
797 printf("Error in getting the block group descriptor table\n");
800 fs
->gd
= (struct ext2_block_group
*)fs
->gdtable
;
802 /* load all the available bitmap block of the partition */
803 fs
->blk_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(char *));
806 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
807 fs
->blk_bmaps
[i
] = zalloc(fs
->blksz
);
808 if (!fs
->blk_bmaps
[i
])
812 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
814 ext4fs_devread(fs
->gd
[i
].block_id
* fs
->sect_perblk
, 0,
815 fs
->blksz
, (char *)fs
->blk_bmaps
[i
]);
820 /* load all the available inode bitmap of the partition */
821 fs
->inode_bmaps
= zalloc(fs
->no_blkgrp
* sizeof(unsigned char *));
822 if (!fs
->inode_bmaps
)
824 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
825 fs
->inode_bmaps
[i
] = zalloc(fs
->blksz
);
826 if (!fs
->inode_bmaps
[i
])
830 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
831 status
= ext4fs_devread(fs
->gd
[i
].inode_id
* fs
->sect_perblk
,
833 (char *)fs
->inode_bmaps
[i
]);
839 * check filesystem consistency with free blocks of file system
840 * some time we observed that superblock freeblocks does not match
841 * with the blockgroups freeblocks when improper
842 * reboot of a linux kernel
844 for (i
= 0; i
< fs
->no_blkgrp
; i
++)
845 real_free_blocks
= real_free_blocks
+ fs
->gd
[i
].free_blocks
;
846 if (real_free_blocks
!= fs
->sb
->free_blocks
)
847 fs
->sb
->free_blocks
= real_free_blocks
;
856 void ext4fs_deinit(void)
859 struct ext2_inode inode_journal
;
860 struct journal_superblock_t
*jsb
;
862 struct ext_filesystem
*fs
= get_fs();
865 char *temp_buff
= zalloc(fs
->blksz
);
867 ext4fs_read_inode(ext4fs_root
, EXT2_JOURNAL_INO
,
869 blknr
= read_allocated_block(&inode_journal
,
870 EXT2_JOURNAL_SUPERBLOCK
);
871 ext4fs_devread(blknr
* fs
->sect_perblk
, 0, fs
->blksz
,
873 jsb
= (struct journal_superblock_t
*)temp_buff
;
874 jsb
->s_start
= cpu_to_be32(0);
875 put_ext4((uint64_t) (blknr
* fs
->blksz
),
876 (struct journal_superblock_t
*)temp_buff
, fs
->blksz
);
879 ext4fs_free_journal();
881 /* get the superblock */
882 ext4fs_devread(SUPERBLOCK_SECTOR
, 0, SUPERBLOCK_SIZE
, (char *)fs
->sb
);
883 fs
->sb
->feature_incompat
&= ~EXT3_FEATURE_INCOMPAT_RECOVER
;
884 put_ext4((uint64_t)(SUPERBLOCK_SIZE
),
885 (struct ext2_sblock
*)fs
->sb
, (uint32_t)SUPERBLOCK_SIZE
);
890 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
891 free(fs
->blk_bmaps
[i
]);
892 fs
->blk_bmaps
[i
] = NULL
;
895 fs
->blk_bmaps
= NULL
;
898 if (fs
->inode_bmaps
) {
899 for (i
= 0; i
< fs
->no_blkgrp
; i
++) {
900 free(fs
->inode_bmaps
[i
]);
901 fs
->inode_bmaps
[i
] = NULL
;
903 free(fs
->inode_bmaps
);
904 fs
->inode_bmaps
= NULL
;
912 * reinitiliazed the global inode and
913 * block bitmap first execution check variables
915 fs
->first_pass_ibmap
= 0;
916 fs
->first_pass_bbmap
= 0;
917 fs
->curr_inode_no
= 0;
921 static int ext4fs_write_file(struct ext2_inode
*file_inode
,
922 int pos
, unsigned int len
, char *buf
)
926 int log2blocksize
= LOG2_EXT2_BLOCK_SIZE(ext4fs_root
);
927 unsigned int filesize
= __le32_to_cpu(file_inode
->size
);
928 struct ext_filesystem
*fs
= get_fs();
929 int previous_block_number
= -1;
930 int delayed_start
= 0;
931 int delayed_extent
= 0;
932 int delayed_skipfirst
= 0;
933 int delayed_next
= 0;
934 char *delayed_buf
= NULL
;
936 /* Adjust len so it we can't read past the end of the file. */
940 blockcnt
= ((len
+ pos
) + fs
->blksz
- 1) / fs
->blksz
;
942 for (i
= pos
/ fs
->blksz
; i
< blockcnt
; i
++) {
944 int blockend
= fs
->blksz
;
946 blknr
= read_allocated_block(file_inode
, i
);
950 blknr
= blknr
<< log2blocksize
;
953 if (previous_block_number
!= -1) {
954 if (delayed_next
== blknr
) {
955 delayed_extent
+= blockend
;
956 delayed_next
+= blockend
>> SECTOR_BITS
;
958 put_ext4((uint64_t) (delayed_start
*
961 (uint32_t) delayed_extent
);
962 previous_block_number
= blknr
;
963 delayed_start
= blknr
;
964 delayed_extent
= blockend
;
965 delayed_skipfirst
= skipfirst
;
967 delayed_next
= blknr
+
968 (blockend
>> SECTOR_BITS
);
971 previous_block_number
= blknr
;
972 delayed_start
= blknr
;
973 delayed_extent
= blockend
;
974 delayed_skipfirst
= skipfirst
;
976 delayed_next
= blknr
+
977 (blockend
>> SECTOR_BITS
);
980 if (previous_block_number
!= -1) {
982 put_ext4((uint64_t) (delayed_start
*
983 SECTOR_SIZE
), delayed_buf
,
984 (uint32_t) delayed_extent
);
985 previous_block_number
= -1;
987 memset(buf
, 0, fs
->blksz
- skipfirst
);
989 buf
+= fs
->blksz
- skipfirst
;
991 if (previous_block_number
!= -1) {
993 put_ext4((uint64_t) (delayed_start
* SECTOR_SIZE
),
994 delayed_buf
, (uint32_t) delayed_extent
);
995 previous_block_number
= -1;
1001 int ext4fs_write(const char *fname
, unsigned char *buffer
,
1002 unsigned long sizebytes
)
1005 struct ext2_inode
*file_inode
= NULL
;
1006 unsigned char *inode_buffer
= NULL
;
1009 time_t timestamp
= 0;
1011 uint64_t bytes_reqd_for_file
;
1012 unsigned int blks_reqd_for_file
;
1013 unsigned int blocks_remaining
;
1014 int existing_file_inodeno
;
1017 char *temp_ptr
= NULL
;
1018 long int itable_blkno
;
1019 long int parent_itable_blkno
;
1021 struct ext2_sblock
*sblock
= &(ext4fs_root
->sblock
);
1022 unsigned int inodes_per_block
;
1023 unsigned int ibmap_idx
;
1024 struct ext_filesystem
*fs
= get_fs();
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
= bytes_reqd_for_file
/ fs
->blksz
;
1054 if (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
->gd
[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
->gd
[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
;