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