diff options
Diffstat (limited to 'ext2fs')
-rw-r--r-- | ext2fs/getblk.c | 765 |
1 files changed, 391 insertions, 374 deletions
diff --git a/ext2fs/getblk.c b/ext2fs/getblk.c index 3972694e..e67494d2 100644 --- a/ext2fs/getblk.c +++ b/ext2fs/getblk.c @@ -15,17 +15,11 @@ * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 */ -#define inode_bmap(inode, nr) ((inode)->u.ext2_i.i_data[(nr)]) - -static int block_bmap (char * bh, int nr) +#define inode_bmap(node, nr) ((node)->dn.info.i_data[(nr)]) +static inline int +block_bmap (char *bh, int nr) { - int tmp; - - if (!bh) - return 0; - tmp = ((u32 *) bh)[nr]; - brelse (bh); - return tmp; + return bh ? ((u32 *) bh)[nr] : 0; } /* @@ -35,408 +29,431 @@ static int block_bmap (char * bh, int nr) * here, since ext2_new_block will do the necessary locking and we * can't block until then. */ -void ext2_discard_prealloc (struct inode * inode) +void +ext2_discard_prealloc (struct inode *inode) { #ifdef EXT2_PREALLOCATE - if (inode->u.ext2_i.i_prealloc_count) { - int i = inode->u.ext2_i.i_prealloc_count; - inode->u.ext2_i.i_prealloc_count = 0; - ext2_free_blocks (inode->i_sb, - inode->u.ext2_i.i_prealloc_block, - i); - } + if (node->dn->info.i_prealloc_count) + { + int i = node->dn->info.i_prealloc_count; + node->dn->info.i_prealloc_count = 0; + ext2_free_blocks (node->dn->info.i_prealloc_block, i); + } #endif } -static int ext2_alloc_block (struct inode * inode, unsigned long goal) +static int +ext2_alloc_block (struct inode *inode, unsigned long goal) { #ifdef EXT2FS_DEBUG - static unsigned long alloc_hits = 0, alloc_attempts = 0; + static unsigned long alloc_hits = 0, alloc_attempts = 0; #endif - unsigned long result; - char * bh; + unsigned long result; + char *bh; - wait_on_super (inode->i_sb); + wait_on_super (sblock); #ifdef EXT2_PREALLOCATE - if (inode->u.ext2_i.i_prealloc_count && - (goal == inode->u.ext2_i.i_prealloc_block || - goal + 1 == inode->u.ext2_i.i_prealloc_block)) - { - result = inode->u.ext2_i.i_prealloc_block++; - inode->u.ext2_i.i_prealloc_count--; - ext2_debug ("preallocation hit (%lu/%lu).\n", - ++alloc_hits, ++alloc_attempts); - - /* It doesn't matter if we block in getblk() since - we have already atomically allocated the block, and - are only clearing it now. */ - if (!(bh = getblk (inode->i_sb->s_dev, result, - inode->i_sb->s_blocksize))) { - ext2_error (inode->i_sb, "ext2_alloc_block", - "cannot get block %lu", result); - return 0; - } - memset(bh, 0, inode->i_sb->s_blocksize); - brelse (bh); - } else { - ext2_discard_prealloc (inode); - ext2_debug ("preallocation miss (%lu/%lu).\n", - alloc_hits, ++alloc_attempts); - if (S_ISREG(inode->i_mode)) - result = ext2_new_block - (inode->i_sb, goal, - &inode->u.ext2_i.i_prealloc_count, - &inode->u.ext2_i.i_prealloc_block); - else - result = ext2_new_block (inode->i_sb, goal, 0, 0); + if (node->dn->info.i_prealloc_count && + (goal == node->dn->info.i_prealloc_block || + goal + 1 == node->dn->info.i_prealloc_block)) + { + result = node->dn->info.i_prealloc_block++; + node->dn->info.i_prealloc_count--; + ext2_debug ("preallocation hit (%lu/%lu).\n", + ++alloc_hits, ++alloc_attempts); + + /* It doesn't matter if we block in getblk() since + we have already atomically allocated the block, and + are only clearing it now. */ + if (!(bh = getblk (result, block_size))) + { + ext2_error ("ext2_alloc_block", "cannot get block %lu", result); + return 0; } + memset (bh, 0, block_size); + } + else + { + ext2_discard_prealloc (inode); + ext2_debug ("preallocation miss (%lu/%lu).\n", + alloc_hits, ++alloc_attempts); + if (S_ISREG (node->dn_stat.mode)) + result = ext2_new_block + (goal, + &node->dn->info.i_prealloc_count, + &node->dn->info.i_prealloc_block); + else + result = ext2_new_block (goal, 0, 0); + } #else - result = ext2_new_block (inode->i_sb, goal, 0, 0); + result = ext2_new_block (goal, 0, 0); #endif - return result; + return result; } -int ext2_bmap (struct inode * inode, int block) +int +ext2_bmap (struct inode *inode, int block) { - int i; - int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - - if (block < 0) { - ext2_warning (inode->i_sb, "ext2_bmap", "block < 0"); - return 0; - } - if (block >= EXT2_NDIR_BLOCKS + addr_per_block + - addr_per_block * addr_per_block + - addr_per_block * addr_per_block * addr_per_block) { - ext2_warning (inode->i_sb, "ext2_bmap", "block > big"); - return 0; - } - if (block < EXT2_NDIR_BLOCKS) - return inode_bmap (inode, block); - block -= EXT2_NDIR_BLOCKS; - if (block < addr_per_block) { - i = inode_bmap (inode, EXT2_IND_BLOCK); - if (!i) - return 0; - return block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), block); - } - block -= addr_per_block; - if (block < addr_per_block * addr_per_block) { - i = inode_bmap (inode, EXT2_DIND_BLOCK); - if (!i) - return 0; - i = block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), - block / addr_per_block); - if (!i) - return 0; - return block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), - block & (addr_per_block - 1)); - } - block -= addr_per_block * addr_per_block; - i = inode_bmap (inode, EXT2_TIND_BLOCK); - if (!i) - return 0; - i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - block / (addr_per_block * addr_per_block)); - if (!i) - return 0; - i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - (block / addr_per_block) & (addr_per_block - 1)); - if (!i) - return 0; - return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - block & (addr_per_block - 1)); + int i; + int addr_per_block = EXT2_ADDR_PER_BLOCK (sblock); + + if (block < 0) + { + ext2_warning ("ext2_bmap", "block < 0"); + return 0; + } + if (block >= EXT2_NDIR_BLOCKS + addr_per_block + + addr_per_block * addr_per_block + + addr_per_block * addr_per_block * addr_per_block) + { + ext2_warning ("ext2_bmap", "block > big"); + return 0; + } + if (block < EXT2_NDIR_BLOCKS) + return inode_bmap (inode, block); + block -= EXT2_NDIR_BLOCKS; + if (block < addr_per_block) + { + i = inode_bmap (inode, EXT2_IND_BLOCK); + if (!i) + return 0; + return block_bmap (baddr (i), block); + } + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) + { + i = inode_bmap (inode, EXT2_DIND_BLOCK); + if (!i) + return 0; + i = block_bmap (baddr (i), block / addr_per_block); + if (!i) + return 0; + return block_bmap (baddr (i), block & (addr_per_block - 1)); + } + block -= addr_per_block * addr_per_block; + i = inode_bmap (inode, EXT2_TIND_BLOCK); + if (!i) + return 0; + i = block_bmap (baddr (i), block / (addr_per_block * addr_per_block)); + if (!i) + return 0; + i = block_bmap (baddr (i), (block / addr_per_block) & (addr_per_block - 1)); + if (!i) + return 0; + return block_bmap (baddr (i), block & (addr_per_block - 1)); } -static char * inode_getblk (struct inode * inode, int nr, - int create, int new_block, int * err) +static char * +inode_getblk (struct inode *inode, int nr, + int create, int new_block, int *err) { - u32 * p; - int tmp, goal = 0; - char * result; - int blocks = inode->i_sb->s_blocksize / 512; + u32 *p; + int tmp, goal = 0; + char *result; + int blocks = block_size / 512; - p = inode->u.ext2_i.i_data + nr; + p = node->dn->info.i_data + nr; repeat: - tmp = *p; - if (tmp) { - result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (tmp == *p) - return result; - brelse (result); - goto repeat; - } - if (!create || new_block >= - (current->rlim[RLIMIT_FSIZE].rlim_cur >> - EXT2_BLOCK_SIZE_BITS(inode->i_sb))) { - *err = -EFBIG; - return NULL; - } - if (inode->u.ext2_i.i_next_alloc_block == new_block) - goal = inode->u.ext2_i.i_next_alloc_goal; - - ext2_debug ("hint = %d,", goal); - - if (!goal) { - for (tmp = nr - 1; tmp >= 0; tmp--) { - if (inode->u.ext2_i.i_data[tmp]) { - goal = inode->u.ext2_i.i_data[tmp]; - break; - } - } - if (!goal) - goal = (inode->u.ext2_i.i_block_group * - EXT2_BLOCKS_PER_GROUP(inode->i_sb)) + - inode->i_sb->u.ext2_sb.s_es->s_first_data_block; - } - - ext2_debug ("goal = %d.\n", goal); - - tmp = ext2_alloc_block (inode, goal); - if (!tmp) - return NULL; - result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (*p) { - ext2_free_blocks (inode->i_sb, tmp, 1); - brelse (result); - goto repeat; - } - *p = tmp; - inode->u.ext2_i.i_next_alloc_block = new_block; - inode->u.ext2_i.i_next_alloc_goal = tmp; - inode->i_ctime = CURRENT_TIME; - inode->i_blocks += blocks; - if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) - ext2_sync_inode (inode); - else - inode->i_dirt = 1; + tmp = *p; + if (tmp) + { + result = getblk (tmp, block_size); + if (tmp == *p) return result; + goto repeat; + } + if (!create || new_block >= + (current->rlim[RLIMIT_FSIZE].rlim_cur >> + EXT2_BLOCK_SIZE_BITS (sblock))) + { + *err = -EFBIG; + return NULL; + } + if (node->dn->info.i_next_alloc_block == new_block) + goal = node->dn->info.i_next_alloc_goal; + + ext2_debug ("hint = %d,", goal); + + if (!goal) + { + for (tmp = nr - 1; tmp >= 0; tmp--) + { + if (node->dn->info.i_data[tmp]) + { + goal = node->dn->info.i_data[tmp]; + break; + } + } + if (!goal) + goal = + (node->dn->info.i_block_group * EXT2_BLOCKS_PER_GROUP (sblock)) + + sblock->s_first_data_block; + } + + ext2_debug ("goal = %d.\n", goal); + + tmp = ext2_alloc_block (inode, goal); + if (!tmp) + return NULL; + result = getblk (tmp, block_size); + if (*p) + { + ext2_free_blocks (tmp, 1); + goto repeat; + } + *p = tmp; + node->dn->info.i_next_alloc_block = new_block; + node->dn->info.i_next_alloc_goal = tmp; + node->dn_set_ctime = 1; + node->dn_stat.st_blocks += blocks; + if (IS_SYNC (inode) || node->dn->info.i_osync) + ext2_sync_inode (inode); + else + node->dirty = 1; + return result; } -static char * block_getblk (struct inode * inode, - char * bh, int nr, - int create, int blocksize, - int new_block, int * err) +static char * +block_getblk (struct inode *inode, + char *bh, int nr, + int create, int blocksize, + int new_block, int *err) { - int tmp, goal = 0; - u32 * p; - char * result; - int blocks = inode->i_sb->s_blocksize / 512; - - if (!bh) - return NULL; - if (!bh->b_uptodate) { - ll_rw_block (READ, 1, &bh); - wait_on_buffer (bh); - if (!bh->b_uptodate) { - brelse (bh); - return NULL; - } - } - p = (u32 *) bh + nr; + int tmp, goal = 0; + u32 *p; + char *result; + int blocks = block_size / 512; + + if (!bh) + return NULL; + if (!bh->b_uptodate) + { + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (!bh->b_uptodate) + return NULL; + } + p = (u32 *) bh + nr; repeat: - tmp = *p; - if (tmp) { - result = getblk (bh->b_dev, tmp, blocksize); - if (tmp == *p) { - brelse (bh); - return result; - } - brelse (result); - goto repeat; - } - if (!create || new_block >= - (current->rlim[RLIMIT_FSIZE].rlim_cur >> - EXT2_BLOCK_SIZE_BITS(inode->i_sb))) { - brelse (bh); - *err = -EFBIG; - return NULL; - } - if (inode->u.ext2_i.i_next_alloc_block == new_block) - goal = inode->u.ext2_i.i_next_alloc_goal; - if (!goal) { - for (tmp = nr - 1; tmp >= 0; tmp--) { - if (((u32 *) bh)[tmp]) { - goal = ((u32 *)bh)[tmp]; - break; - } - } - if (!goal) - goal = bh->b_blocknr; - } - tmp = ext2_alloc_block (inode, goal); - if (!tmp) { - brelse (bh); - return NULL; - } - result = getblk (bh->b_dev, tmp, blocksize); - if (*p) { - ext2_free_blocks (inode->i_sb, tmp, 1); - brelse (result); - goto repeat; - } - *p = tmp; - mark_buffer_dirty(bh, 1); - if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) { - ll_rw_block (WRITE, 1, &bh); - wait_on_buffer (bh); - } - inode->i_ctime = CURRENT_TIME; - inode->i_blocks += blocks; - inode->i_dirt = 1; - inode->u.ext2_i.i_next_alloc_block = new_block; - inode->u.ext2_i.i_next_alloc_goal = tmp; - brelse (bh); + tmp = *p; + if (tmp) + { + result = getblk (bh->b_dev, tmp, blocksize); + if (tmp == *p) return result; + goto repeat; + } + if (!create || new_block >= + (current->rlim[RLIMIT_FSIZE].rlim_cur >> + EXT2_BLOCK_SIZE_BITS (sblock))) + { + *err = -EFBIG; + return NULL; + } + if (node->dn->info.i_next_alloc_block == new_block) + goal = node->dn->info.i_next_alloc_goal; + if (!goal) + { + for (tmp = nr - 1; tmp >= 0; tmp--) + { + if (((u32 *) bh)[tmp]) + { + goal = ((u32 *) bh)[tmp]; + break; + } + } + if (!goal) + goal = bh->b_blocknr; + } + tmp = ext2_alloc_block (inode, goal); + if (!tmp) + return NULL; + + result = getblk (bh->b_dev, tmp, blocksize); + if (*p) + { + ext2_free_blocks (tmp, 1); + goto repeat; + } + *p = tmp; + mark_buffer_dirty (bh, 1); + if (IS_SYNC (inode) || node->dn->info.i_osync) + { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + node->dn_set_ctime = 1; + node->dn_stat.st_blocks += blocks; + node->dirty = 1; + node->dn->info.i_next_alloc_block = new_block; + node->dn->info.i_next_alloc_goal = tmp; + + return result; } -static int block_getcluster (struct inode * inode, char * bh, - int nr, - int blocksize) +static int +block_getcluster (struct inode *inode, char *bh, + int nr, + int blocksize) { - u32 * p; - int firstblock = 0; - int result = 0; - int i; - - /* Check to see if clustering possible here. */ - - if(!bh) return 0; - - if(nr % (PAGE_SIZE / inode->i_sb->s_blocksize) != 0) goto out; - if(nr + 3 > EXT2_ADDR_PER_BLOCK(inode->i_sb)) goto out; - - for(i=0; i< (PAGE_SIZE / inode->i_sb->s_blocksize); i++) { - p = (u32 *) bh + nr + i; - - /* All blocks in cluster must already be allocated */ - if(*p == 0) goto out; - - /* See if aligned correctly */ - if(i==0) firstblock = *p; - else if(*p != firstblock + i) goto out; - } - - p = (u32 *) bh + nr; - result = generate_cluster(bh->b_dev, (int *) p, blocksize); + u32 *p; + int firstblock = 0; + int result = 0; + int i; - out: - brelse(bh); - return result; -} + /* Check to see if clustering possible here. */ -char * ext2_getblk (struct inode * inode, long block, - int create, int * err) -{ - char * bh; - unsigned long b; - unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - - *err = -EIO; - if (block < 0) { - ext2_warning (inode->i_sb, "ext2_getblk", "block < 0"); - return NULL; - } - if (block > EXT2_NDIR_BLOCKS + addr_per_block + - addr_per_block * addr_per_block + - addr_per_block * addr_per_block * addr_per_block) { - ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); - return NULL; - } - /* - * If this is a sequential block allocation, set the next_alloc_block - * to this block now so that all the indblock and data block - * allocations use the same goal zone - */ - - ext2_debug ("block %lu, next %lu, goal %lu.\n", block, - inode->u.ext2_i.i_next_alloc_block, - inode->u.ext2_i.i_next_alloc_goal); - - if (block == inode->u.ext2_i.i_next_alloc_block + 1) { - inode->u.ext2_i.i_next_alloc_block++; - inode->u.ext2_i.i_next_alloc_goal++; - } + if (!bh) + return 0; - *err = -ENOSPC; - b = block; - if (block < EXT2_NDIR_BLOCKS) - return inode_getblk (inode, block, create, b, err); - block -= EXT2_NDIR_BLOCKS; - if (block < addr_per_block) { - bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err); - return block_getblk (inode, bh, block, create, - inode->i_sb->s_blocksize, b, err); - } - block -= addr_per_block; - if (block < addr_per_block * addr_per_block) { - bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err); - bh = block_getblk (inode, bh, block / addr_per_block, create, - inode->i_sb->s_blocksize, b, err); - return block_getblk (inode, bh, block & (addr_per_block - 1), - create, inode->i_sb->s_blocksize, b, err); - } - block -= addr_per_block * addr_per_block; - bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err); - bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block), - create, inode->i_sb->s_blocksize, b, err); - bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1), - create, inode->i_sb->s_blocksize, b, err); - return block_getblk (inode, bh, block & (addr_per_block - 1), create, - inode->i_sb->s_blocksize, b, err); -} + if (nr % (PAGE_SIZE / block_size) != 0) + goto out; + if (nr + 3 > EXT2_ADDR_PER_BLOCK (sblock)) + goto out; -int ext2_getcluster (struct inode * inode, long block) -{ - char * bh; - int err, create; - unsigned long b; - unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - - create = 0; - err = -EIO; - if (block < 0) { - ext2_warning (inode->i_sb, "ext2_getblk", "block < 0"); - return 0; - } - if (block > EXT2_NDIR_BLOCKS + addr_per_block + - addr_per_block * addr_per_block + - addr_per_block * addr_per_block * addr_per_block) { - ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); - return 0; - } + for (i = 0; i < (PAGE_SIZE / block_size); i++) + { + p = (u32 *) bh + nr + i; - err = -ENOSPC; - b = block; - if (block < EXT2_NDIR_BLOCKS) return 0; + /* All blocks in cluster must already be allocated */ + if (*p == 0) + goto out; - block -= EXT2_NDIR_BLOCKS; + /* See if aligned correctly */ + if (i == 0) + firstblock = *p; + else if (*p != firstblock + i) + goto out; + } - if (block < addr_per_block) { - bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, &err); - return block_getcluster (inode, bh, block, - inode->i_sb->s_blocksize); - } - block -= addr_per_block; - if (block < addr_per_block * addr_per_block) { - bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, &err); - bh = block_getblk (inode, bh, block / addr_per_block, create, - inode->i_sb->s_blocksize, b, &err); - return block_getcluster (inode, bh, block & (addr_per_block - 1), - inode->i_sb->s_blocksize); - } - block -= addr_per_block * addr_per_block; - bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, &err); - bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block), - create, inode->i_sb->s_blocksize, b, &err); - bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1), - create, inode->i_sb->s_blocksize, b, &err); - return block_getcluster (inode, bh, block & (addr_per_block - 1), - inode->i_sb->s_blocksize); + p = (u32 *) bh + nr; + result = generate_cluster (bh->b_dev, (int *) p, blocksize); + +out: + return result; +} + +char * +ext2_getblk (struct inode *inode, long block, + int create, int *err) +{ + char *bh; + unsigned long b; + unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK (sblock); + + *err = -EIO; + if (block < 0) + { + ext2_warning ("ext2_getblk", "block < 0"); + return NULL; + } + if (block > EXT2_NDIR_BLOCKS + addr_per_block + + addr_per_block * addr_per_block + + addr_per_block * addr_per_block * addr_per_block) + { + ext2_warning ("ext2_getblk", "block > big"); + return NULL; + } + /* + * If this is a sequential block allocation, set the next_alloc_block + * to this block now so that all the indblock and data block + * allocations use the same goal zone + */ + + ext2_debug ("block %lu, next %lu, goal %lu.\n", block, + node->dn->info.i_next_alloc_block, + node->dn->info.i_next_alloc_goal); + + if (block == node->dn->info.i_next_alloc_block + 1) + { + node->dn->info.i_next_alloc_block++; + node->dn->info.i_next_alloc_goal++; + } + + *err = -ENOSPC; + b = block; + if (block < EXT2_NDIR_BLOCKS) + return inode_getblk (inode, block, create, b, err); + block -= EXT2_NDIR_BLOCKS; + if (block < addr_per_block) + { + bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err); + return block_getblk (inode, bh, block, create, + block_size, b, err); + } + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) + { + bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err); + bh = block_getblk (inode, bh, block / addr_per_block, create, + block_size, b, err); + return block_getblk (inode, bh, block & (addr_per_block - 1), + create, block_size, b, err); + } + block -= addr_per_block * addr_per_block; + bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err); + bh = block_getblk (inode, bh, block / (addr_per_block * addr_per_block), + create, block_size, b, err); + bh = block_getblk (inode, bh, (block / addr_per_block) & (addr_per_block - 1), + create, block_size, b, err); + return block_getblk (inode, bh, block & (addr_per_block - 1), create, + block_size, b, err); +} + +int +ext2_getcluster (struct inode *inode, long block) +{ + char *bh; + int err, create; + unsigned long b; + unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK (sblock); + + create = 0; + err = -EIO; + if (block < 0) + { + ext2_warning ("ext2_getblk", "block < 0"); + return 0; + } + if (block > EXT2_NDIR_BLOCKS + addr_per_block + + addr_per_block * addr_per_block + + addr_per_block * addr_per_block * addr_per_block) + { + ext2_warning ("ext2_getblk", "block > big"); + return 0; + } + + err = -ENOSPC; + b = block; + if (block < EXT2_NDIR_BLOCKS) + return 0; + + block -= EXT2_NDIR_BLOCKS; + + if (block < addr_per_block) + { + bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, &err); + return block_getcluster (inode, bh, block, + block_size); + } + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) + { + bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, &err); + bh = block_getblk (inode, bh, block / addr_per_block, create, + block_size, b, &err); + return block_getcluster (inode, bh, block & (addr_per_block - 1), + block_size); + } + block -= addr_per_block * addr_per_block; + bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, &err); + bh = block_getblk (inode, bh, block / (addr_per_block * addr_per_block), + create, block_size, b, &err); + bh = block_getblk (inode, bh, (block / addr_per_block) & (addr_per_block - 1), + create, block_size, b, &err); + return block_getcluster (inode, bh, block & (addr_per_block - 1), + block_size); } |