xref: /rk3399_rockchip-uboot/fs/ext4/ext4_write.c (revision b779e0290a4a6ac589bfac7192b4f8e677d3bf8a)
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 }
989