/* given logical block number, allocate a new physical block, if it does not * exist already, and return the physical block number that is allocated. * returns negative value on error. */ static int testfs_allocate_block(struct inode *in, int log_block_nr, char *block) { if (log_block_nr>4196361) return -EFBIG; // //printf("log_block_nr:%d\n",log_block_nr); // } int phy_block_nr; char indirect[BLOCK_SIZE]; char dindirect[BLOCK_SIZE]; char dindirect2[BLOCK_SIZE]; int indirect_allocated = 0; //int dindirect_allocated = 0; assert(log_block_nr >= 0); phy_block_nr = testfs_read_block(in, log_block_nr, block); /* phy_block_nr > 0: block exists, so we don't need to allocate it, phy_block_nr < 0: some error */ if (phy_block_nr != 0) return phy_block_nr; /* allocate a direct block */ if (log_block_nr < NR_DIRECT_BLOCKS) { assert(in->in.i_block_nr[log_block_nr] == 0); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr >= 0) { in->in.i_block_nr[log_block_nr] = phy_block_nr; } return phy_block_nr; } log_block_nr -= NR_DIRECT_BLOCKS; if (log_block_nr >= NR_INDIRECT_BLOCKS) { log_block_nr -= NR_INDIRECT_BLOCKS; //log block ranges from 0 ~ 4194303 int level1_block = DIVROUNDUP(log_block_nr+1,2048) - 1; // ranges 0~2047 int level2_block= log_block_nr % 2048; /* allocate an dindirect block */ if (in->in.i_dindirect == 0) { bzero(dindirect, BLOCK_SIZE); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr < 0) return phy_block_nr; //dindirect_allocated = 1; in->in.i_dindirect = phy_block_nr; //printf("dindirect block #:%d\n",phy_block_nr); } else /* read dindirect block */ { read_blocks(in->sb, dindirect, in->in.i_dindirect, 1); } // Allocate 2nd level indirect block if (((int *)dindirect)[level1_block] == 0) { bzero(dindirect2, BLOCK_SIZE); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr < 0) return phy_block_nr; ((int*)dindirect)[level1_block]=phy_block_nr; //printf("2nd dindirect block #:%d\n", ((int*)dindirect)[level1_block]); write_blocks(in->sb, dindirect, in->in.i_dindirect,1); } // error here.... // Read 2nd level indirect block else { read_blocks(in->sb, dindirect2, ((int*)dindirect)[level1_block], 1); } // allocate direct block */ phy_block_nr=testfs_alloc_block_for_inode(in); if (phy_block_nr >=0) // update 2nd level indirect block { ((int*)dindirect2)[level2_block]=phy_block_nr; //printf("Last direct block #:%d\n", ((int*)dindirect2)[level2_block]); write_blocks(in->sb, dindirect2, ((int*)dindirect)[level1_block], 1); } return phy_block_nr; // Allocate 2nd-level indirect block } /**** Allocating in 1st level indirect blocks ****/ if (in->in.i_indirect == 0) /* allocate an indirect block */ { bzero(indirect, BLOCK_SIZE); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr < 0) return phy_block_nr; indirect_allocated = 1; in->in.i_indirect = phy_block_nr; } else { /* read indirect block */ read_blocks(in->sb, indirect, in->in.i_indirect, 1); } /* allocate direct block */ assert(((int *)indirect)[log_block_nr] == 0); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr >= 0) { /* update indirect block */ ((int *)indirect)[log_block_nr] = phy_block_nr; write_blocks(in->sb, indirect, in->in.i_indirect, 1); } else if (indirect_allocated) { /* free the indirect block that was allocated */ testfs_free_block_from_inode(in, in->in.i_indirect); } return phy_block_nr; }
/* given logical block number, allocate a new physical block, if it does not * exist already, and return the physical block number that is allocated. * returns negative value on error. */ static int testfs_allocate_block(struct inode *in, int log_block_nr, char *block) { int phy_block_nr; char indirect[BLOCK_SIZE]; int indirect_allocated = 0; assert(log_block_nr >= 0); phy_block_nr = testfs_read_block(in, log_block_nr, block); /* phy_block_nr > 0: block exists, so we don't need to allocate it, phy_block_nr < 0: some error */ if (phy_block_nr != 0) return phy_block_nr; /* allocate a direct block */ if (log_block_nr < NR_DIRECT_BLOCKS) { assert(in->in.i_block_nr[log_block_nr] == 0); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr >= 0) { in->in.i_block_nr[log_block_nr] = phy_block_nr; } return phy_block_nr; } log_block_nr -= NR_DIRECT_BLOCKS; if (log_block_nr >= NR_INDIRECT_BLOCKS) { log_block_nr -= NR_INDIRECT_BLOCKS; char dindirect[BLOCK_SIZE]; int dindirect_allocated = 0; int position = log_block_nr/NR_INDIRECT_BLOCKS; if (log_block_nr >= NR_INDIRECT_BLOCKS * NR_INDIRECT_BLOCKS) { return -EFBIG; } //get the double indirect block first if(in->in.i_dindirect == 0){ bzero(dindirect, BLOCK_SIZE); phy_block_nr = testfs_alloc_block_for_inode(in); if(phy_block_nr < 0) return phy_block_nr; dindirect_allocated = 1; in->in.i_dindirect = phy_block_nr; } else{ read_blocks(in->sb, dindirect, in->in.i_dindirect, 1); } //get the indirect block in double indirect block if(((int*) dindirect)[position] == 0) { bzero(indirect, BLOCK_SIZE); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr < 0){ if (dindirect_allocated) { testfs_free_block_from_inode(in, in->in.i_dindirect); return phy_block_nr; } } else{ indirect_allocated = 1; ((int *) dindirect)[position] = phy_block_nr; write_blocks(in->sb, dindirect, in->in.i_dindirect, 1); } }else{ read_blocks(in->sb, indirect, ((int*) dindirect)[position], 1); } //get the direct block assert(((int *) indirect)[log_block_nr % NR_INDIRECT_BLOCKS] == 0); phy_block_nr = testfs_alloc_block_for_inode(in); if(phy_block_nr < 0){ if(dindirect_allocated){ testfs_free_block_from_inode(in, ((int *)dindirect)[position]); testfs_free_block_from_inode(in, in->in.i_dindirect); }else if(indirect_allocated) testfs_free_block_from_inode(in, ((int *)dindirect)[position]); return phy_block_nr; } else if (phy_block_nr >= 0) { ((int *) indirect)[log_block_nr % NR_INDIRECT_BLOCKS] = phy_block_nr; write_blocks(in->sb, indirect, ((int *)dindirect)[position], 1); } return phy_block_nr; } if (in->in.i_indirect == 0) { /* allocate an indirect block */ bzero(indirect, BLOCK_SIZE); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr < 0) return phy_block_nr; indirect_allocated = 1; in->in.i_indirect = phy_block_nr; } else { /* read indirect block */ read_blocks(in->sb, indirect, in->in.i_indirect, 1); } /* allocate direct block */ assert(((int *) indirect)[log_block_nr] == 0); phy_block_nr = testfs_alloc_block_for_inode(in); if (phy_block_nr >= 0) { /* update indirect block */ ((int *) indirect)[log_block_nr] = phy_block_nr; write_blocks(in->sb, indirect, in->in.i_indirect, 1); } else if (indirect_allocated) { /* free the indirect block that was allocated */ testfs_free_block_from_inode(in, in->in.i_indirect); } return phy_block_nr; }