]> git.sur5r.net Git - u-boot/blob - fs/ext4/ext4_write.c
ext4: remove duplicated block release code for extents
[u-boot] / fs / ext4 / ext4_write.c
1 /*
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>
6  *
7  * ext4ls and ext4load : Based on ext2 ls and load support in Uboot.
8  *                     Ext4 read optimization taken from Open-Moko
9  *                     Qi bootloader
10  *
11  * (C) Copyright 2004
12  * esd gmbh <www.esd-electronics.com>
13  * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
14  *
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.
18  *
19  * ext4write : Based on generic ext4 protocol.
20  *
21  * SPDX-License-Identifier:     GPL-2.0+
22  */
23
24
25 #include <common.h>
26 #include <memalign.h>
27 #include <linux/stat.h>
28 #include <div64.h>
29 #include "ext4_common.h"
30
31 static inline void ext4fs_sb_free_inodes_inc(struct ext2_sblock *sb)
32 {
33         sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) + 1);
34 }
35
36 static inline void ext4fs_sb_free_blocks_inc(struct ext2_sblock *sb)
37 {
38         sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) + 1);
39 }
40
41 static inline void ext4fs_bg_free_inodes_inc(struct ext2_block_group *bg)
42 {
43         bg->free_inodes = cpu_to_le16(le16_to_cpu(bg->free_inodes) + 1);
44 }
45
46 static inline void ext4fs_bg_free_blocks_inc(struct ext2_block_group *bg)
47 {
48         bg->free_blocks = cpu_to_le16(le16_to_cpu(bg->free_blocks) + 1);
49 }
50
51 static void ext4fs_update(void)
52 {
53         short i;
54         ext4fs_update_journal();
55         struct ext_filesystem *fs = get_fs();
56
57         /* update  super block */
58         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
59                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
60
61         /* update block groups */
62         for (i = 0; i < fs->no_blkgrp; i++) {
63                 fs->bgd[i].bg_checksum = cpu_to_le16(ext4fs_checksum_update(i));
64                 put_ext4((uint64_t)le32_to_cpu(fs->bgd[i].block_id) * fs->blksz,
65                          fs->blk_bmaps[i], fs->blksz);
66         }
67
68         /* update inode table groups */
69         for (i = 0; i < fs->no_blkgrp; i++) {
70                 put_ext4((uint64_t)le32_to_cpu(fs->bgd[i].inode_id) * fs->blksz,
71                          fs->inode_bmaps[i], fs->blksz);
72         }
73
74         /* update the block group descriptor table */
75         put_ext4((uint64_t)((uint64_t)fs->gdtable_blkno * (uint64_t)fs->blksz),
76                  (struct ext2_block_group *)fs->gdtable,
77                  (fs->blksz * fs->no_blk_pergdt));
78
79         ext4fs_dump_metadata();
80
81         gindex = 0;
82         gd_index = 0;
83 }
84
85 int ext4fs_get_bgdtable(void)
86 {
87         int status;
88         int grp_desc_size;
89         struct ext_filesystem *fs = get_fs();
90         grp_desc_size = sizeof(struct ext2_block_group);
91         fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz;
92         if ((fs->no_blkgrp * grp_desc_size) % fs->blksz)
93                 fs->no_blk_pergdt++;
94
95         /* allocate memory for gdtable */
96         fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt);
97         if (!fs->gdtable)
98                 return -ENOMEM;
99         /* read the group descriptor table */
100         status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk,
101                                 0, fs->blksz * fs->no_blk_pergdt, fs->gdtable);
102         if (status == 0)
103                 goto fail;
104
105         if (ext4fs_log_gdt(fs->gdtable)) {
106                 printf("Error in ext4fs_log_gdt\n");
107                 return -1;
108         }
109
110         return 0;
111 fail:
112         free(fs->gdtable);
113         fs->gdtable = NULL;
114
115         return -1;
116 }
117
118 static void delete_single_indirect_block(struct ext2_inode *inode)
119 {
120         struct ext2_block_group *bgd = NULL;
121         static int prev_bg_bmap_idx = -1;
122         uint32_t blknr;
123         int remainder;
124         int bg_idx;
125         int status;
126         uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
127         struct ext_filesystem *fs = get_fs();
128         char *journal_buffer = zalloc(fs->blksz);
129         if (!journal_buffer) {
130                 printf("No memory\n");
131                 return;
132         }
133         /* get  block group descriptor table */
134         bgd = (struct ext2_block_group *)fs->gdtable;
135
136         /* deleting the single indirect block associated with inode */
137         if (inode->b.blocks.indir_block != 0) {
138                 blknr = le32_to_cpu(inode->b.blocks.indir_block);
139                 debug("SIPB releasing %u\n", blknr);
140                 bg_idx = blknr / blk_per_grp;
141                 if (fs->blksz == 1024) {
142                         remainder = blknr % blk_per_grp;
143                         if (!remainder)
144                                 bg_idx--;
145                 }
146                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
147                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
148                 ext4fs_sb_free_blocks_inc(fs->sb);
149                 /* journal backup */
150                 if (prev_bg_bmap_idx != bg_idx) {
151                         status = ext4fs_devread(
152                                            (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
153                                            fs->sect_perblk, 0, fs->blksz,
154                                            journal_buffer);
155                         if (status == 0)
156                                 goto fail;
157                         if (ext4fs_log_journal
158                             (journal_buffer, le32_to_cpu(bgd[bg_idx].block_id)))
159                                 goto fail;
160                         prev_bg_bmap_idx = bg_idx;
161                 }
162         }
163 fail:
164         free(journal_buffer);
165 }
166
167 static void delete_double_indirect_block(struct ext2_inode *inode)
168 {
169         int i;
170         short status;
171         static int prev_bg_bmap_idx = -1;
172         uint32_t blknr;
173         int remainder;
174         int bg_idx;
175         uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
176         __le32 *di_buffer = NULL;
177         void *dib_start_addr = NULL;
178         struct ext2_block_group *bgd = NULL;
179         struct ext_filesystem *fs = get_fs();
180         char *journal_buffer = zalloc(fs->blksz);
181         if (!journal_buffer) {
182                 printf("No memory\n");
183                 return;
184         }
185         /* get the block group descriptor table */
186         bgd = (struct ext2_block_group *)fs->gdtable;
187
188         if (inode->b.blocks.double_indir_block != 0) {
189                 di_buffer = zalloc(fs->blksz);
190                 if (!di_buffer) {
191                         printf("No memory\n");
192                         return;
193                 }
194                 dib_start_addr = di_buffer;
195                 blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
196                 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
197                                         fs->blksz, (char *)di_buffer);
198                 for (i = 0; i < fs->blksz / sizeof(int); i++) {
199                         if (*di_buffer == 0)
200                                 break;
201
202                         debug("DICB releasing %u\n", *di_buffer);
203                         bg_idx = le32_to_cpu(*di_buffer) / blk_per_grp;
204                         if (fs->blksz == 1024) {
205                                 remainder = le32_to_cpu(*di_buffer) % blk_per_grp;
206                                 if (!remainder)
207                                         bg_idx--;
208                         }
209                         ext4fs_reset_block_bmap(le32_to_cpu(*di_buffer),
210                                         fs->blk_bmaps[bg_idx], bg_idx);
211                         di_buffer++;
212                         ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
213                         ext4fs_sb_free_blocks_inc(fs->sb);
214                         /* journal backup */
215                         if (prev_bg_bmap_idx != bg_idx) {
216                                 status = ext4fs_devread(
217                                                         (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id)
218                                                         * fs->sect_perblk, 0,
219                                                         fs->blksz,
220                                                         journal_buffer);
221                                 if (status == 0)
222                                         goto fail;
223
224                                 if (ext4fs_log_journal(journal_buffer,
225                                                         le32_to_cpu(bgd[bg_idx].block_id)))
226                                         goto fail;
227                                 prev_bg_bmap_idx = bg_idx;
228                         }
229                 }
230
231                 /* removing the parent double indirect block */
232                 blknr = le32_to_cpu(inode->b.blocks.double_indir_block);
233                 bg_idx = blknr / blk_per_grp;
234                 if (fs->blksz == 1024) {
235                         remainder = blknr % blk_per_grp;
236                         if (!remainder)
237                                 bg_idx--;
238                 }
239                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
240                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
241                 ext4fs_sb_free_blocks_inc(fs->sb);
242                 /* journal backup */
243                 if (prev_bg_bmap_idx != bg_idx) {
244                         memset(journal_buffer, '\0', fs->blksz);
245                         status = ext4fs_devread((lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
246                                                 fs->sect_perblk, 0, fs->blksz,
247                                                 journal_buffer);
248                         if (status == 0)
249                                 goto fail;
250
251                         if (ext4fs_log_journal(journal_buffer,
252                                                 le32_to_cpu(bgd[bg_idx].block_id)))
253                                 goto fail;
254                         prev_bg_bmap_idx = bg_idx;
255                 }
256                 debug("DIPB releasing %d\n", blknr);
257         }
258 fail:
259         free(dib_start_addr);
260         free(journal_buffer);
261 }
262
263 static void delete_triple_indirect_block(struct ext2_inode *inode)
264 {
265         int i, j;
266         short status;
267         static int prev_bg_bmap_idx = -1;
268         uint32_t blknr;
269         int remainder;
270         int bg_idx;
271         uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
272         __le32 *tigp_buffer = NULL;
273         void *tib_start_addr = NULL;
274         __le32 *tip_buffer = NULL;
275         void *tipb_start_addr = NULL;
276         struct ext2_block_group *bgd = NULL;
277         struct ext_filesystem *fs = get_fs();
278         char *journal_buffer = zalloc(fs->blksz);
279         if (!journal_buffer) {
280                 printf("No memory\n");
281                 return;
282         }
283         /* get block group descriptor table */
284         bgd = (struct ext2_block_group *)fs->gdtable;
285
286         if (inode->b.blocks.triple_indir_block != 0) {
287                 tigp_buffer = zalloc(fs->blksz);
288                 if (!tigp_buffer) {
289                         printf("No memory\n");
290                         return;
291                 }
292                 tib_start_addr = tigp_buffer;
293                 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
294                 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
295                                         fs->blksz, (char *)tigp_buffer);
296                 for (i = 0; i < fs->blksz / sizeof(int); i++) {
297                         if (*tigp_buffer == 0)
298                                 break;
299                         debug("tigp buffer releasing %u\n", *tigp_buffer);
300
301                         tip_buffer = zalloc(fs->blksz);
302                         if (!tip_buffer)
303                                 goto fail;
304                         tipb_start_addr = tip_buffer;
305                         status = ext4fs_devread((lbaint_t)le32_to_cpu(*tigp_buffer) *
306                                                 fs->sect_perblk, 0, fs->blksz,
307                                                 (char *)tip_buffer);
308                         for (j = 0; j < fs->blksz / sizeof(int); j++) {
309                                 if (le32_to_cpu(*tip_buffer) == 0)
310                                         break;
311                                 bg_idx = le32_to_cpu(*tip_buffer) / blk_per_grp;
312                                 if (fs->blksz == 1024) {
313                                         remainder = le32_to_cpu(*tip_buffer) % blk_per_grp;
314                                         if (!remainder)
315                                                 bg_idx--;
316                                 }
317
318                                 ext4fs_reset_block_bmap(le32_to_cpu(*tip_buffer),
319                                                         fs->blk_bmaps[bg_idx],
320                                                         bg_idx);
321
322                                 tip_buffer++;
323                                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
324                                 ext4fs_sb_free_blocks_inc(fs->sb);
325                                 /* journal backup */
326                                 if (prev_bg_bmap_idx != bg_idx) {
327                                         status =
328                                             ext4fs_devread(
329                                                         (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
330                                                         fs->sect_perblk, 0,
331                                                         fs->blksz,
332                                                         journal_buffer);
333                                         if (status == 0)
334                                                 goto fail;
335
336                                         if (ext4fs_log_journal(journal_buffer,
337                                                                le32_to_cpu(bgd[bg_idx].block_id)))
338                                                 goto fail;
339                                         prev_bg_bmap_idx = bg_idx;
340                                 }
341                         }
342                         free(tipb_start_addr);
343                         tipb_start_addr = NULL;
344
345                         /*
346                          * removing the grand parent blocks
347                          * which is connected to inode
348                          */
349                         bg_idx = le32_to_cpu(*tigp_buffer) / blk_per_grp;
350                         if (fs->blksz == 1024) {
351                                 remainder = le32_to_cpu(*tigp_buffer) % blk_per_grp;
352                                 if (!remainder)
353                                         bg_idx--;
354                         }
355                         ext4fs_reset_block_bmap(le32_to_cpu(*tigp_buffer),
356                                                 fs->blk_bmaps[bg_idx], bg_idx);
357
358                         tigp_buffer++;
359                         ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
360                         ext4fs_sb_free_blocks_inc(fs->sb);
361                         /* journal backup */
362                         if (prev_bg_bmap_idx != bg_idx) {
363                                 memset(journal_buffer, '\0', fs->blksz);
364                                 status =
365                                     ext4fs_devread(
366                                                    (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
367                                                    fs->sect_perblk, 0,
368                                                    fs->blksz, journal_buffer);
369                                 if (status == 0)
370                                         goto fail;
371
372                                 if (ext4fs_log_journal(journal_buffer,
373                                                         le32_to_cpu(bgd[bg_idx].block_id)))
374                                         goto fail;
375                                 prev_bg_bmap_idx = bg_idx;
376                         }
377                 }
378
379                 /* removing the grand parent triple indirect block */
380                 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block);
381                 bg_idx = blknr / blk_per_grp;
382                 if (fs->blksz == 1024) {
383                         remainder = blknr % blk_per_grp;
384                         if (!remainder)
385                                 bg_idx--;
386                 }
387                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx);
388                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
389                 ext4fs_sb_free_blocks_inc(fs->sb);
390                 /* journal backup */
391                 if (prev_bg_bmap_idx != bg_idx) {
392                         memset(journal_buffer, '\0', fs->blksz);
393                         status = ext4fs_devread(
394                                                 (lbaint_t)le32_to_cpu(bgd[bg_idx].block_id) *
395                                                 fs->sect_perblk, 0, fs->blksz,
396                                                 journal_buffer);
397                         if (status == 0)
398                                 goto fail;
399
400                         if (ext4fs_log_journal(journal_buffer,
401                                                 le32_to_cpu(bgd[bg_idx].block_id)))
402                                 goto fail;
403                         prev_bg_bmap_idx = bg_idx;
404                 }
405                 debug("tigp buffer itself releasing %d\n", blknr);
406         }
407 fail:
408         free(tib_start_addr);
409         free(tipb_start_addr);
410         free(journal_buffer);
411 }
412
413 static int ext4fs_delete_file(int inodeno)
414 {
415         struct ext2_inode inode;
416         short status;
417         int i;
418         int remainder;
419         long int blknr;
420         int bg_idx;
421         int ibmap_idx;
422         char *read_buffer = NULL;
423         char *start_block_address = NULL;
424         uint32_t no_blocks;
425
426         static int prev_bg_bmap_idx = -1;
427         unsigned int inodes_per_block;
428         uint32_t blkno;
429         unsigned int blkoff;
430         uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
431         uint32_t inode_per_grp = le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
432         struct ext2_inode *inode_buffer = NULL;
433         struct ext2_block_group *bgd = NULL;
434         struct ext_filesystem *fs = get_fs();
435         char *journal_buffer = zalloc(fs->blksz);
436         if (!journal_buffer)
437                 return -ENOMEM;
438         /* get the block group descriptor table */
439         bgd = (struct ext2_block_group *)fs->gdtable;
440         status = ext4fs_read_inode(ext4fs_root, inodeno, &inode);
441         if (status == 0)
442                 goto fail;
443
444         /* read the block no allocated to a file */
445         no_blocks = le32_to_cpu(inode.size) / fs->blksz;
446         if (le32_to_cpu(inode.size) % fs->blksz)
447                 no_blocks++;
448
449         if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) {
450                 /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */
451                 struct ext4_extent_header *eh =
452                         (struct ext4_extent_header *)
453                                 inode.b.blocks.dir_blocks;
454                 debug("del: dep=%d entries=%d\n", eh->eh_depth, eh->eh_entries);
455         } else {
456                 delete_single_indirect_block(&inode);
457                 delete_double_indirect_block(&inode);
458                 delete_triple_indirect_block(&inode);
459         }
460
461         /* release data blocks */
462         for (i = 0; i < no_blocks; i++) {
463                 blknr = read_allocated_block(&inode, i);
464                 bg_idx = blknr / blk_per_grp;
465                 if (fs->blksz == 1024) {
466                         remainder = blknr % blk_per_grp;
467                         if (!remainder)
468                                 bg_idx--;
469                 }
470                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
471                                         bg_idx);
472                 debug("EXT4 Block releasing %ld: %d\n", blknr, bg_idx);
473
474                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
475                 ext4fs_sb_free_blocks_inc(fs->sb);
476                 /* journal backup */
477                 if (prev_bg_bmap_idx != bg_idx) {
478                         uint32_t bgd_blknr = le32_to_cpu(bgd[bg_idx].block_id);
479                         status = ext4fs_devread((lbaint_t)bgd_blknr *
480                                                 fs->sect_perblk,
481                                                 0, fs->blksz,
482                                                 journal_buffer);
483                         if (status == 0)
484                                 goto fail;
485                         if (ext4fs_log_journal(journal_buffer, bgd_blknr))
486                                 goto fail;
487                         prev_bg_bmap_idx = bg_idx;
488                 }
489         }
490
491         /* release inode */
492         /* from the inode no to blockno */
493         inodes_per_block = fs->blksz / fs->inodesz;
494         ibmap_idx = inodeno / inode_per_grp;
495
496         /* get the block no */
497         inodeno--;
498         blkno = le32_to_cpu(bgd[ibmap_idx].inode_table_id) +
499                 (inodeno % inode_per_grp) / inodes_per_block;
500
501         /* get the offset of the inode */
502         blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
503
504         /* read the block no containing the inode */
505         read_buffer = zalloc(fs->blksz);
506         if (!read_buffer)
507                 goto fail;
508         start_block_address = read_buffer;
509         status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk,
510                                 0, fs->blksz, read_buffer);
511         if (status == 0)
512                 goto fail;
513
514         if (ext4fs_log_journal(read_buffer, blkno))
515                 goto fail;
516
517         read_buffer = read_buffer + blkoff;
518         inode_buffer = (struct ext2_inode *)read_buffer;
519         memset(inode_buffer, '\0', fs->inodesz);
520
521         /* write the inode to original position in inode table */
522         if (ext4fs_put_metadata(start_block_address, blkno))
523                 goto fail;
524
525         /* update the respective inode bitmaps */
526         inodeno++;
527         ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
528         ext4fs_bg_free_inodes_inc(&bgd[ibmap_idx]);
529         ext4fs_sb_free_inodes_inc(fs->sb);
530         /* journal backup */
531         memset(journal_buffer, '\0', fs->blksz);
532         status = ext4fs_devread((lbaint_t)le32_to_cpu(bgd[ibmap_idx].inode_id) *
533                                 fs->sect_perblk, 0, fs->blksz, journal_buffer);
534         if (status == 0)
535                 goto fail;
536         if (ext4fs_log_journal(journal_buffer, le32_to_cpu(bgd[ibmap_idx].inode_id)))
537                 goto fail;
538
539         ext4fs_update();
540         ext4fs_deinit();
541         ext4fs_reinit_global();
542
543         if (ext4fs_init() != 0) {
544                 printf("error in File System init\n");
545                 goto fail;
546         }
547
548         free(start_block_address);
549         free(journal_buffer);
550
551         return 0;
552 fail:
553         free(start_block_address);
554         free(journal_buffer);
555
556         return -1;
557 }
558
559 int ext4fs_init(void)
560 {
561         short status;
562         int i;
563         uint32_t real_free_blocks = 0;
564         struct ext_filesystem *fs = get_fs();
565
566         /* populate fs */
567         fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
568         fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
569
570         /* get the superblock */
571         fs->sb = zalloc(SUPERBLOCK_SIZE);
572         if (!fs->sb)
573                 return -ENOMEM;
574         if (!ext4_read_superblock((char *)fs->sb))
575                 goto fail;
576
577         /* init journal */
578         if (ext4fs_init_journal())
579                 goto fail;
580
581         /* get total no of blockgroups */
582         fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
583                         le32_to_cpu(ext4fs_root->sblock.total_blocks)
584                         - le32_to_cpu(ext4fs_root->sblock.first_data_block),
585                         le32_to_cpu(ext4fs_root->sblock.blocks_per_group));
586
587         /* get the block group descriptor table */
588         fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
589         if (ext4fs_get_bgdtable() == -1) {
590                 printf("Error in getting the block group descriptor table\n");
591                 goto fail;
592         }
593         fs->bgd = (struct ext2_block_group *)fs->gdtable;
594
595         /* load all the available bitmap block of the partition */
596         fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
597         if (!fs->blk_bmaps)
598                 goto fail;
599         for (i = 0; i < fs->no_blkgrp; i++) {
600                 fs->blk_bmaps[i] = zalloc(fs->blksz);
601                 if (!fs->blk_bmaps[i])
602                         goto fail;
603         }
604
605         for (i = 0; i < fs->no_blkgrp; i++) {
606                 status =
607                     ext4fs_devread(
608                                    (lbaint_t)le32_to_cpu(fs->bgd[i].block_id) *
609                                    fs->sect_perblk, 0,
610                                    fs->blksz, (char *)fs->blk_bmaps[i]);
611                 if (status == 0)
612                         goto fail;
613         }
614
615         /* load all the available inode bitmap of the partition */
616         fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
617         if (!fs->inode_bmaps)
618                 goto fail;
619         for (i = 0; i < fs->no_blkgrp; i++) {
620                 fs->inode_bmaps[i] = zalloc(fs->blksz);
621                 if (!fs->inode_bmaps[i])
622                         goto fail;
623         }
624
625         for (i = 0; i < fs->no_blkgrp; i++) {
626                 status = ext4fs_devread(
627                                         (lbaint_t)le32_to_cpu(fs->bgd[i].inode_id) *
628                                         fs->sect_perblk,
629                                         0, fs->blksz,
630                                         (char *)fs->inode_bmaps[i]);
631                 if (status == 0)
632                         goto fail;
633         }
634
635         /*
636          * check filesystem consistency with free blocks of file system
637          * some time we observed that superblock freeblocks does not match
638          * with the  blockgroups freeblocks when improper
639          * reboot of a linux kernel
640          */
641         for (i = 0; i < fs->no_blkgrp; i++)
642                 real_free_blocks = real_free_blocks + le16_to_cpu(fs->bgd[i].free_blocks);
643         if (real_free_blocks != le32_to_cpu(fs->sb->free_blocks))
644                 fs->sb->free_blocks = cpu_to_le32(real_free_blocks);
645
646         return 0;
647 fail:
648         ext4fs_deinit();
649
650         return -1;
651 }
652
653 void ext4fs_deinit(void)
654 {
655         int i;
656         struct ext2_inode inode_journal;
657         struct journal_superblock_t *jsb;
658         uint32_t blknr;
659         struct ext_filesystem *fs = get_fs();
660         uint32_t new_feature_incompat;
661
662         /* free journal */
663         char *temp_buff = zalloc(fs->blksz);
664         if (temp_buff) {
665                 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
666                                   &inode_journal);
667                 blknr = read_allocated_block(&inode_journal,
668                                         EXT2_JOURNAL_SUPERBLOCK);
669                 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
670                                temp_buff);
671                 jsb = (struct journal_superblock_t *)temp_buff;
672                 jsb->s_start = 0;
673                 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
674                          (struct journal_superblock_t *)temp_buff, fs->blksz);
675                 free(temp_buff);
676         }
677         ext4fs_free_journal();
678
679         /* get the superblock */
680         ext4_read_superblock((char *)fs->sb);
681         new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
682         new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
683         fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
684         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
685                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
686         free(fs->sb);
687         fs->sb = NULL;
688
689         if (fs->blk_bmaps) {
690                 for (i = 0; i < fs->no_blkgrp; i++) {
691                         free(fs->blk_bmaps[i]);
692                         fs->blk_bmaps[i] = NULL;
693                 }
694                 free(fs->blk_bmaps);
695                 fs->blk_bmaps = NULL;
696         }
697
698         if (fs->inode_bmaps) {
699                 for (i = 0; i < fs->no_blkgrp; i++) {
700                         free(fs->inode_bmaps[i]);
701                         fs->inode_bmaps[i] = NULL;
702                 }
703                 free(fs->inode_bmaps);
704                 fs->inode_bmaps = NULL;
705         }
706
707
708         free(fs->gdtable);
709         fs->gdtable = NULL;
710         fs->bgd = NULL;
711         /*
712          * reinitiliazed the global inode and
713          * block bitmap first execution check variables
714          */
715         fs->first_pass_ibmap = 0;
716         fs->first_pass_bbmap = 0;
717         fs->curr_inode_no = 0;
718         fs->curr_blkno = 0;
719 }
720
721 static int ext4fs_write_file(struct ext2_inode *file_inode,
722                              int pos, unsigned int len, char *buf)
723 {
724         int i;
725         int blockcnt;
726         uint32_t filesize = le32_to_cpu(file_inode->size);
727         struct ext_filesystem *fs = get_fs();
728         int log2blksz = fs->dev_desc->log2blksz;
729         int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
730         int previous_block_number = -1;
731         int delayed_start = 0;
732         int delayed_extent = 0;
733         int delayed_next = 0;
734         char *delayed_buf = NULL;
735
736         /* Adjust len so it we can't read past the end of the file. */
737         if (len > filesize)
738                 len = filesize;
739
740         blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
741
742         for (i = pos / fs->blksz; i < blockcnt; i++) {
743                 long int blknr;
744                 int blockend = fs->blksz;
745                 int skipfirst = 0;
746                 blknr = read_allocated_block(file_inode, i);
747                 if (blknr < 0)
748                         return -1;
749
750                 blknr = blknr << log2_fs_blocksize;
751
752                 if (blknr) {
753                         if (previous_block_number != -1) {
754                                 if (delayed_next == blknr) {
755                                         delayed_extent += blockend;
756                                         delayed_next += blockend >> log2blksz;
757                                 } else {        /* spill */
758                                         put_ext4((uint64_t)
759                                                  ((uint64_t)delayed_start << log2blksz),
760                                                  delayed_buf,
761                                                  (uint32_t) delayed_extent);
762                                         previous_block_number = blknr;
763                                         delayed_start = blknr;
764                                         delayed_extent = blockend;
765                                         delayed_buf = buf;
766                                         delayed_next = blknr +
767                                             (blockend >> log2blksz);
768                                 }
769                         } else {
770                                 previous_block_number = blknr;
771                                 delayed_start = blknr;
772                                 delayed_extent = blockend;
773                                 delayed_buf = buf;
774                                 delayed_next = blknr +
775                                     (blockend >> log2blksz);
776                         }
777                 } else {
778                         if (previous_block_number != -1) {
779                                 /* spill */
780                                 put_ext4((uint64_t) ((uint64_t)delayed_start <<
781                                                      log2blksz),
782                                          delayed_buf,
783                                          (uint32_t) delayed_extent);
784                                 previous_block_number = -1;
785                         }
786                         memset(buf, 0, fs->blksz - skipfirst);
787                 }
788                 buf += fs->blksz - skipfirst;
789         }
790         if (previous_block_number != -1) {
791                 /* spill */
792                 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz),
793                          delayed_buf, (uint32_t) delayed_extent);
794                 previous_block_number = -1;
795         }
796
797         return len;
798 }
799
800 int ext4fs_write(const char *fname, unsigned char *buffer,
801                                         unsigned long sizebytes)
802 {
803         int ret = 0;
804         struct ext2_inode *file_inode = NULL;
805         unsigned char *inode_buffer = NULL;
806         int parent_inodeno;
807         int inodeno;
808         time_t timestamp = 0;
809
810         uint64_t bytes_reqd_for_file;
811         unsigned int blks_reqd_for_file;
812         unsigned int blocks_remaining;
813         int existing_file_inodeno;
814         char *temp_ptr = NULL;
815         long int itable_blkno;
816         long int parent_itable_blkno;
817         long int blkoff;
818         struct ext2_sblock *sblock = &(ext4fs_root->sblock);
819         unsigned int inodes_per_block;
820         unsigned int ibmap_idx;
821         struct ext_filesystem *fs = get_fs();
822         ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
823         memset(filename, 0x00, 256);
824
825         g_parent_inode = zalloc(fs->inodesz);
826         if (!g_parent_inode)
827                 goto fail;
828
829         if (ext4fs_init() != 0) {
830                 printf("error in File System init\n");
831                 return -1;
832         }
833         inodes_per_block = fs->blksz / fs->inodesz;
834         parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
835         if (parent_inodeno == -1)
836                 goto fail;
837         if (ext4fs_iget(parent_inodeno, g_parent_inode))
838                 goto fail;
839         /* do not mess up a directory using hash trees */
840         if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) {
841                 printf("hash tree directory\n");
842                 goto fail;
843         }
844         /* check if the filename is already present in root */
845         existing_file_inodeno = ext4fs_filename_unlink(filename);
846         if (existing_file_inodeno != -1) {
847                 ret = ext4fs_delete_file(existing_file_inodeno);
848                 fs->first_pass_bbmap = 0;
849                 fs->curr_blkno = 0;
850
851                 fs->first_pass_ibmap = 0;
852                 fs->curr_inode_no = 0;
853                 if (ret)
854                         goto fail;
855         }
856         /* calucalate how many blocks required */
857         bytes_reqd_for_file = sizebytes;
858         blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
859         if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
860                 blks_reqd_for_file++;
861                 debug("total bytes for a file %u\n", blks_reqd_for_file);
862         }
863         blocks_remaining = blks_reqd_for_file;
864         /* test for available space in partition */
865         if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) {
866                 printf("Not enough space on partition !!!\n");
867                 goto fail;
868         }
869
870         inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG);
871         if (inodeno == -1)
872                 goto fail;
873         /* prepare file inode */
874         inode_buffer = zalloc(fs->inodesz);
875         if (!inode_buffer)
876                 goto fail;
877         file_inode = (struct ext2_inode *)inode_buffer;
878         file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU |
879             S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
880         /* ToDo: Update correct time */
881         file_inode->mtime = cpu_to_le32(timestamp);
882         file_inode->atime = cpu_to_le32(timestamp);
883         file_inode->ctime = cpu_to_le32(timestamp);
884         file_inode->nlinks = cpu_to_le16(1);
885         file_inode->size = cpu_to_le32(sizebytes);
886
887         /* Allocate data blocks */
888         ext4fs_allocate_blocks(file_inode, blocks_remaining,
889                                &blks_reqd_for_file);
890         file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >>
891                 fs->dev_desc->log2blksz);
892
893         temp_ptr = zalloc(fs->blksz);
894         if (!temp_ptr)
895                 goto fail;
896         ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
897         inodeno--;
898         itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
899                         (inodeno % le32_to_cpu(sblock->inodes_per_group)) /
900                         inodes_per_block;
901         blkoff = (inodeno % inodes_per_block) * fs->inodesz;
902         ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
903                        temp_ptr);
904         if (ext4fs_log_journal(temp_ptr, itable_blkno))
905                 goto fail;
906
907         memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
908         if (ext4fs_put_metadata(temp_ptr, itable_blkno))
909                 goto fail;
910         /* copy the file content into data blocks */
911         if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
912                 printf("Error in copying content\n");
913                 goto fail;
914         }
915         ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
916         parent_inodeno--;
917         parent_itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
918             (parent_inodeno %
919              le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
920         blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
921         if (parent_itable_blkno != itable_blkno) {
922                 memset(temp_ptr, '\0', fs->blksz);
923                 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk,
924                                0, fs->blksz, temp_ptr);
925                 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
926                         goto fail;
927
928                 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
929                 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
930                         goto fail;
931         } else {
932                 /*
933                  * If parent and child fall in same inode table block
934                  * both should be kept in 1 buffer
935                  */
936                 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
937                 gd_index--;
938                 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
939                         goto fail;
940         }
941         ext4fs_update();
942         ext4fs_deinit();
943
944         fs->first_pass_bbmap = 0;
945         fs->curr_blkno = 0;
946         fs->first_pass_ibmap = 0;
947         fs->curr_inode_no = 0;
948         free(inode_buffer);
949         free(g_parent_inode);
950         free(temp_ptr);
951         g_parent_inode = NULL;
952
953         return 0;
954 fail:
955         ext4fs_deinit();
956         free(inode_buffer);
957         free(g_parent_inode);
958         free(temp_ptr);
959         g_parent_inode = NULL;
960
961         return -1;
962 }
963
964 int ext4_write_file(const char *filename, void *buf, loff_t offset,
965                     loff_t len, loff_t *actwrite)
966 {
967         int ret;
968
969         if (offset != 0) {
970                 printf("** Cannot support non-zero offset **\n");
971                 return -1;
972         }
973
974         ret = ext4fs_write(filename, buf, len);
975         if (ret) {
976                 printf("** Error ext4fs_write() **\n");
977                 goto fail;
978         }
979
980         *actwrite = len;
981
982         return 0;
983
984 fail:
985         *actwrite = 0;
986
987         return -1;
988 }