]> git.sur5r.net Git - u-boot/blob - fs/ext4/ext4_write.c
ext4: Fix memory leak of journal buffer if block is updated multiple times
[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                 if (blknr == 0)
465                         continue;
466                 if (blknr < 0)
467                         goto fail;
468                 bg_idx = blknr / blk_per_grp;
469                 if (fs->blksz == 1024) {
470                         remainder = blknr % blk_per_grp;
471                         if (!remainder)
472                                 bg_idx--;
473                 }
474                 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx],
475                                         bg_idx);
476                 debug("EXT4 Block releasing %ld: %d\n", blknr, bg_idx);
477
478                 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]);
479                 ext4fs_sb_free_blocks_inc(fs->sb);
480                 /* journal backup */
481                 if (prev_bg_bmap_idx != bg_idx) {
482                         uint32_t bgd_blknr = le32_to_cpu(bgd[bg_idx].block_id);
483                         status = ext4fs_devread((lbaint_t)bgd_blknr *
484                                                 fs->sect_perblk,
485                                                 0, fs->blksz,
486                                                 journal_buffer);
487                         if (status == 0)
488                                 goto fail;
489                         if (ext4fs_log_journal(journal_buffer, bgd_blknr))
490                                 goto fail;
491                         prev_bg_bmap_idx = bg_idx;
492                 }
493         }
494
495         /* release inode */
496         /* from the inode no to blockno */
497         inodes_per_block = fs->blksz / fs->inodesz;
498         ibmap_idx = inodeno / inode_per_grp;
499
500         /* get the block no */
501         inodeno--;
502         blkno = le32_to_cpu(bgd[ibmap_idx].inode_table_id) +
503                 (inodeno % inode_per_grp) / inodes_per_block;
504
505         /* get the offset of the inode */
506         blkoff = ((inodeno) % inodes_per_block) * fs->inodesz;
507
508         /* read the block no containing the inode */
509         read_buffer = zalloc(fs->blksz);
510         if (!read_buffer)
511                 goto fail;
512         start_block_address = read_buffer;
513         status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk,
514                                 0, fs->blksz, read_buffer);
515         if (status == 0)
516                 goto fail;
517
518         if (ext4fs_log_journal(read_buffer, blkno))
519                 goto fail;
520
521         read_buffer = read_buffer + blkoff;
522         inode_buffer = (struct ext2_inode *)read_buffer;
523         memset(inode_buffer, '\0', fs->inodesz);
524
525         /* write the inode to original position in inode table */
526         if (ext4fs_put_metadata(start_block_address, blkno))
527                 goto fail;
528
529         /* update the respective inode bitmaps */
530         inodeno++;
531         ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx);
532         ext4fs_bg_free_inodes_inc(&bgd[ibmap_idx]);
533         ext4fs_sb_free_inodes_inc(fs->sb);
534         /* journal backup */
535         memset(journal_buffer, '\0', fs->blksz);
536         status = ext4fs_devread((lbaint_t)le32_to_cpu(bgd[ibmap_idx].inode_id) *
537                                 fs->sect_perblk, 0, fs->blksz, journal_buffer);
538         if (status == 0)
539                 goto fail;
540         if (ext4fs_log_journal(journal_buffer, le32_to_cpu(bgd[ibmap_idx].inode_id)))
541                 goto fail;
542
543         ext4fs_update();
544         ext4fs_deinit();
545         ext4fs_reinit_global();
546
547         if (ext4fs_init() != 0) {
548                 printf("error in File System init\n");
549                 goto fail;
550         }
551
552         free(start_block_address);
553         free(journal_buffer);
554
555         return 0;
556 fail:
557         free(start_block_address);
558         free(journal_buffer);
559
560         return -1;
561 }
562
563 int ext4fs_init(void)
564 {
565         short status;
566         int i;
567         uint32_t real_free_blocks = 0;
568         struct ext_filesystem *fs = get_fs();
569
570         /* populate fs */
571         fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root);
572         fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz;
573
574         /* get the superblock */
575         fs->sb = zalloc(SUPERBLOCK_SIZE);
576         if (!fs->sb)
577                 return -ENOMEM;
578         if (!ext4_read_superblock((char *)fs->sb))
579                 goto fail;
580
581         /* init journal */
582         if (ext4fs_init_journal())
583                 goto fail;
584
585         /* get total no of blockgroups */
586         fs->no_blkgrp = (uint32_t)ext4fs_div_roundup(
587                         le32_to_cpu(ext4fs_root->sblock.total_blocks)
588                         - le32_to_cpu(ext4fs_root->sblock.first_data_block),
589                         le32_to_cpu(ext4fs_root->sblock.blocks_per_group));
590
591         /* get the block group descriptor table */
592         fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1);
593         if (ext4fs_get_bgdtable() == -1) {
594                 printf("Error in getting the block group descriptor table\n");
595                 goto fail;
596         }
597         fs->bgd = (struct ext2_block_group *)fs->gdtable;
598
599         /* load all the available bitmap block of the partition */
600         fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *));
601         if (!fs->blk_bmaps)
602                 goto fail;
603         for (i = 0; i < fs->no_blkgrp; i++) {
604                 fs->blk_bmaps[i] = zalloc(fs->blksz);
605                 if (!fs->blk_bmaps[i])
606                         goto fail;
607         }
608
609         for (i = 0; i < fs->no_blkgrp; i++) {
610                 status =
611                     ext4fs_devread(
612                                    (lbaint_t)le32_to_cpu(fs->bgd[i].block_id) *
613                                    fs->sect_perblk, 0,
614                                    fs->blksz, (char *)fs->blk_bmaps[i]);
615                 if (status == 0)
616                         goto fail;
617         }
618
619         /* load all the available inode bitmap of the partition */
620         fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *));
621         if (!fs->inode_bmaps)
622                 goto fail;
623         for (i = 0; i < fs->no_blkgrp; i++) {
624                 fs->inode_bmaps[i] = zalloc(fs->blksz);
625                 if (!fs->inode_bmaps[i])
626                         goto fail;
627         }
628
629         for (i = 0; i < fs->no_blkgrp; i++) {
630                 status = ext4fs_devread(
631                                         (lbaint_t)le32_to_cpu(fs->bgd[i].inode_id) *
632                                         fs->sect_perblk,
633                                         0, fs->blksz,
634                                         (char *)fs->inode_bmaps[i]);
635                 if (status == 0)
636                         goto fail;
637         }
638
639         /*
640          * check filesystem consistency with free blocks of file system
641          * some time we observed that superblock freeblocks does not match
642          * with the  blockgroups freeblocks when improper
643          * reboot of a linux kernel
644          */
645         for (i = 0; i < fs->no_blkgrp; i++)
646                 real_free_blocks = real_free_blocks + le16_to_cpu(fs->bgd[i].free_blocks);
647         if (real_free_blocks != le32_to_cpu(fs->sb->free_blocks))
648                 fs->sb->free_blocks = cpu_to_le32(real_free_blocks);
649
650         return 0;
651 fail:
652         ext4fs_deinit();
653
654         return -1;
655 }
656
657 void ext4fs_deinit(void)
658 {
659         int i;
660         struct ext2_inode inode_journal;
661         struct journal_superblock_t *jsb;
662         uint32_t blknr;
663         struct ext_filesystem *fs = get_fs();
664         uint32_t new_feature_incompat;
665
666         /* free journal */
667         char *temp_buff = zalloc(fs->blksz);
668         if (temp_buff) {
669                 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO,
670                                   &inode_journal);
671                 blknr = read_allocated_block(&inode_journal,
672                                         EXT2_JOURNAL_SUPERBLOCK);
673                 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz,
674                                temp_buff);
675                 jsb = (struct journal_superblock_t *)temp_buff;
676                 jsb->s_start = 0;
677                 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz),
678                          (struct journal_superblock_t *)temp_buff, fs->blksz);
679                 free(temp_buff);
680         }
681         ext4fs_free_journal();
682
683         /* get the superblock */
684         ext4_read_superblock((char *)fs->sb);
685         new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat);
686         new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
687         fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat);
688         put_ext4((uint64_t)(SUPERBLOCK_SIZE),
689                  (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE);
690         free(fs->sb);
691         fs->sb = NULL;
692
693         if (fs->blk_bmaps) {
694                 for (i = 0; i < fs->no_blkgrp; i++) {
695                         free(fs->blk_bmaps[i]);
696                         fs->blk_bmaps[i] = NULL;
697                 }
698                 free(fs->blk_bmaps);
699                 fs->blk_bmaps = NULL;
700         }
701
702         if (fs->inode_bmaps) {
703                 for (i = 0; i < fs->no_blkgrp; i++) {
704                         free(fs->inode_bmaps[i]);
705                         fs->inode_bmaps[i] = NULL;
706                 }
707                 free(fs->inode_bmaps);
708                 fs->inode_bmaps = NULL;
709         }
710
711
712         free(fs->gdtable);
713         fs->gdtable = NULL;
714         fs->bgd = NULL;
715         /*
716          * reinitiliazed the global inode and
717          * block bitmap first execution check variables
718          */
719         fs->first_pass_ibmap = 0;
720         fs->first_pass_bbmap = 0;
721         fs->curr_inode_no = 0;
722         fs->curr_blkno = 0;
723 }
724
725 /*
726  * Write data to filesystem blocks. Uses same optimization for
727  * contigous sectors as ext4fs_read_file
728  */
729 static int ext4fs_write_file(struct ext2_inode *file_inode,
730                              int pos, unsigned int len, char *buf)
731 {
732         int i;
733         int blockcnt;
734         uint32_t filesize = le32_to_cpu(file_inode->size);
735         struct ext_filesystem *fs = get_fs();
736         int log2blksz = fs->dev_desc->log2blksz;
737         int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz;
738         int previous_block_number = -1;
739         int delayed_start = 0;
740         int delayed_extent = 0;
741         int delayed_next = 0;
742         char *delayed_buf = NULL;
743
744         /* Adjust len so it we can't read past the end of the file. */
745         if (len > filesize)
746                 len = filesize;
747
748         blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz;
749
750         for (i = pos / fs->blksz; i < blockcnt; i++) {
751                 long int blknr;
752                 int blockend = fs->blksz;
753                 int skipfirst = 0;
754                 blknr = read_allocated_block(file_inode, i);
755                 if (blknr <= 0)
756                         return -1;
757
758                 blknr = blknr << log2_fs_blocksize;
759
760                 if (blknr) {
761                         if (previous_block_number != -1) {
762                                 if (delayed_next == blknr) {
763                                         delayed_extent += blockend;
764                                         delayed_next += blockend >> log2blksz;
765                                 } else {        /* spill */
766                                         put_ext4((uint64_t)
767                                                  ((uint64_t)delayed_start << log2blksz),
768                                                  delayed_buf,
769                                                  (uint32_t) delayed_extent);
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                                 previous_block_number = blknr;
779                                 delayed_start = blknr;
780                                 delayed_extent = blockend;
781                                 delayed_buf = buf;
782                                 delayed_next = blknr +
783                                     (blockend >> log2blksz);
784                         }
785                 } else {
786                         if (previous_block_number != -1) {
787                                 /* spill */
788                                 put_ext4((uint64_t) ((uint64_t)delayed_start <<
789                                                      log2blksz),
790                                          delayed_buf,
791                                          (uint32_t) delayed_extent);
792                                 previous_block_number = -1;
793                         }
794                         memset(buf, 0, fs->blksz - skipfirst);
795                 }
796                 buf += fs->blksz - skipfirst;
797         }
798         if (previous_block_number != -1) {
799                 /* spill */
800                 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz),
801                          delayed_buf, (uint32_t) delayed_extent);
802                 previous_block_number = -1;
803         }
804
805         return len;
806 }
807
808 int ext4fs_write(const char *fname, unsigned char *buffer,
809                                         unsigned long sizebytes)
810 {
811         int ret = 0;
812         struct ext2_inode *file_inode = NULL;
813         unsigned char *inode_buffer = NULL;
814         int parent_inodeno;
815         int inodeno;
816         time_t timestamp = 0;
817
818         uint64_t bytes_reqd_for_file;
819         unsigned int blks_reqd_for_file;
820         unsigned int blocks_remaining;
821         int existing_file_inodeno;
822         char *temp_ptr = NULL;
823         long int itable_blkno;
824         long int parent_itable_blkno;
825         long int blkoff;
826         struct ext2_sblock *sblock = &(ext4fs_root->sblock);
827         unsigned int inodes_per_block;
828         unsigned int ibmap_idx;
829         struct ext_filesystem *fs = get_fs();
830         ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256);
831         memset(filename, 0x00, 256);
832
833         g_parent_inode = zalloc(fs->inodesz);
834         if (!g_parent_inode)
835                 goto fail;
836
837         if (ext4fs_init() != 0) {
838                 printf("error in File System init\n");
839                 return -1;
840         }
841         inodes_per_block = fs->blksz / fs->inodesz;
842         parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE);
843         if (parent_inodeno == -1)
844                 goto fail;
845         if (ext4fs_iget(parent_inodeno, g_parent_inode))
846                 goto fail;
847         /* do not mess up a directory using hash trees */
848         if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) {
849                 printf("hash tree directory\n");
850                 goto fail;
851         }
852         /* check if the filename is already present in root */
853         existing_file_inodeno = ext4fs_filename_unlink(filename);
854         if (existing_file_inodeno != -1) {
855                 ret = ext4fs_delete_file(existing_file_inodeno);
856                 fs->first_pass_bbmap = 0;
857                 fs->curr_blkno = 0;
858
859                 fs->first_pass_ibmap = 0;
860                 fs->curr_inode_no = 0;
861                 if (ret)
862                         goto fail;
863         }
864         /* calucalate how many blocks required */
865         bytes_reqd_for_file = sizebytes;
866         blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz);
867         if (do_div(bytes_reqd_for_file, fs->blksz) != 0) {
868                 blks_reqd_for_file++;
869                 debug("total bytes for a file %u\n", blks_reqd_for_file);
870         }
871         blocks_remaining = blks_reqd_for_file;
872         /* test for available space in partition */
873         if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) {
874                 printf("Not enough space on partition !!!\n");
875                 goto fail;
876         }
877
878         inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG);
879         if (inodeno == -1)
880                 goto fail;
881         /* prepare file inode */
882         inode_buffer = zalloc(fs->inodesz);
883         if (!inode_buffer)
884                 goto fail;
885         file_inode = (struct ext2_inode *)inode_buffer;
886         file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU |
887             S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH);
888         /* ToDo: Update correct time */
889         file_inode->mtime = cpu_to_le32(timestamp);
890         file_inode->atime = cpu_to_le32(timestamp);
891         file_inode->ctime = cpu_to_le32(timestamp);
892         file_inode->nlinks = cpu_to_le16(1);
893         file_inode->size = cpu_to_le32(sizebytes);
894
895         /* Allocate data blocks */
896         ext4fs_allocate_blocks(file_inode, blocks_remaining,
897                                &blks_reqd_for_file);
898         file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >>
899                 fs->dev_desc->log2blksz);
900
901         temp_ptr = zalloc(fs->blksz);
902         if (!temp_ptr)
903                 goto fail;
904         ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
905         inodeno--;
906         itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
907                         (inodeno % le32_to_cpu(sblock->inodes_per_group)) /
908                         inodes_per_block;
909         blkoff = (inodeno % inodes_per_block) * fs->inodesz;
910         ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz,
911                        temp_ptr);
912         if (ext4fs_log_journal(temp_ptr, itable_blkno))
913                 goto fail;
914
915         memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz);
916         if (ext4fs_put_metadata(temp_ptr, itable_blkno))
917                 goto fail;
918         /* copy the file content into data blocks */
919         if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) {
920                 printf("Error in copying content\n");
921                 /* FIXME: Deallocate data blocks */
922                 goto fail;
923         }
924         ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
925         parent_inodeno--;
926         parent_itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) +
927             (parent_inodeno %
928              le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
929         blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz;
930         if (parent_itable_blkno != itable_blkno) {
931                 memset(temp_ptr, '\0', fs->blksz);
932                 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk,
933                                0, fs->blksz, temp_ptr);
934                 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno))
935                         goto fail;
936
937                 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
938                 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno))
939                         goto fail;
940         } else {
941                 /*
942                  * If parent and child fall in same inode table block
943                  * both should be kept in 1 buffer
944                  */
945                 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz);
946                 gd_index--;
947                 if (ext4fs_put_metadata(temp_ptr, itable_blkno))
948                         goto fail;
949         }
950         ext4fs_update();
951         ext4fs_deinit();
952
953         fs->first_pass_bbmap = 0;
954         fs->curr_blkno = 0;
955         fs->first_pass_ibmap = 0;
956         fs->curr_inode_no = 0;
957         free(inode_buffer);
958         free(g_parent_inode);
959         free(temp_ptr);
960         g_parent_inode = NULL;
961
962         return 0;
963 fail:
964         ext4fs_deinit();
965         free(inode_buffer);
966         free(g_parent_inode);
967         free(temp_ptr);
968         g_parent_inode = NULL;
969
970         return -1;
971 }
972
973 int ext4_write_file(const char *filename, void *buf, loff_t offset,
974                     loff_t len, loff_t *actwrite)
975 {
976         int ret;
977
978         if (offset != 0) {
979                 printf("** Cannot support non-zero offset **\n");
980                 return -1;
981         }
982
983         ret = ext4fs_write(filename, buf, len);
984         if (ret) {
985                 printf("** Error ext4fs_write() **\n");
986                 goto fail;
987         }
988
989         *actwrite = len;
990
991         return 0;
992
993 fail:
994         *actwrite = 0;
995
996         return -1;
997 }