/* * Stupid algorithm --- we now just search forward starting from the * goal. Should put in a smarter one someday.... */ errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, ext2fs_block_bitmap map, blk64_t *ret) { blk64_t i; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (!map) map = fs->block_map; if (!map) return EXT2_ET_NO_BLOCK_BITMAP; if (!goal || (goal >= fs->super->s_blocks_count)) goal = fs->super->s_first_data_block; i = goal; check_block_uninit(fs, map, (i - fs->super->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(fs->super)); do { if (((i - fs->super->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(fs->super)) == 0) check_block_uninit(fs, map, (i - fs->super->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(fs->super)); if (!ext2fs_fast_test_block_bitmap2(map, i)) { *ret = i; return 0; } i++; if (i >= fs->super->s_blocks_count) i = fs->super->s_first_data_block; } while (i != goal); return EXT2_ET_BLOCK_ALLOC_FAIL; }
/* * Initialize an ext2 partition starting at offset P_OFFSET; this is * sort-of the same idea as "mounting" it. Read in the relevant * control structures and make them available to the user. Returns 0 * if successful, -1 on failure. */ static int ext2_mount(long cons_dev, long p_offset, long quiet) { long sb_block = 1; long sb_offset; int i; dev = cons_dev; partition_offset = p_offset; /* initialize the inode table */ for (i = 0; i < MAX_OPEN_FILES; i++) { inode_table[i].free = 1; inode_table[i].inumber = 0; } /* clear the root inode pointer (very important!) */ root_inode = NULL; /* read in the first superblock */ sb_offset = sb_block * EXT2_MIN_BLOCK_SIZE; if (cons_read(dev, &sb, sizeof(sb), partition_offset + sb_offset) != sizeof(sb)) { printf("ext2 sb read failed\n"); return -1; } if (sb.s_magic != EXT2_SUPER_MAGIC) { if (!quiet) { printf("ext2_init: bad magic 0x%x\n", sb.s_magic); } return -1; } ngroups = (sb.s_blocks_count - sb.s_first_data_block + EXT2_BLOCKS_PER_GROUP(&sb) - 1) / EXT2_BLOCKS_PER_GROUP(&sb); gds = (struct ext2_group_desc *) malloc((size_t)(ngroups * sizeof(struct ext2_group_desc))); ext2fs.blocksize = EXT2_BLOCK_SIZE(&sb); /* read in the group descriptors (immediately follows superblock) */ cons_read(dev, gds, ngroups * sizeof(struct ext2_group_desc), partition_offset + ext2fs.blocksize * (EXT2_MIN_BLOCK_SIZE/ext2fs.blocksize + 1)); /* * Calculate direct/indirect block limits for this file system * (blocksize dependent): */ ext2fs.blocksize = EXT2_BLOCK_SIZE(&sb); directlim = EXT2_NDIR_BLOCKS - 1; ptrs_per_blk = ext2fs.blocksize/sizeof(unsigned int); ind1lim = ptrs_per_blk + directlim; ind2lim = (ptrs_per_blk * ptrs_per_blk) + directlim; return 0; }
static inline int load_block_bitmap(struct vnode *vnode ,unsigned int blk_group) { struct bcache tmp_bitmap ,*block_bitmap; ; unsigned int totblkgroup ,tmp; int i ,k ; struct ext2_super_block *sblock sb = vnode->vfsp->ext2sb; totblkgroup = sb->s_blocks_count - sb->s_first_data_block + EXT2_BLOCKS_PER_GROUP(sb) - 1 / EXT2_BLOCKS_PER_GROUP(sb); if(blk_group > totblkgroup) printf("out of limit"); if(index_block_group[0] == blk_group) return 0; if(totblkgroup <= EXT_BITMAP_CACHE) { if(block_bitmap[blk_group]) { if(index_block_group[blk_group] == blk_group) { return blk_group; } else printf("error"); } else { read_block_bitmap(vnode,blk_group ,blk_group) return blk_group; } } /* If the known block group number is within the given array of index_block_group * then the known block group is removed from the location of array and place * to the front of the array * */ for(i = 0; index_block_group[i] != blk_group;i++); if(index_block_group[i] == blk_group) { tmp = index_block_group[i]; tmp_bitmap = block_bitmap [i]; for( k = i ;k > 0 k--) { index_block_group [k] = index_block_group[k-1]; block_bitmap[k] = block_bitmap[k-1]; } block_bitmap[0] = tmp_bitmap ; index_block_group[0] = tmp; brelse(&tmp_bitmap); }
errcode_t ext2fs_write_block_bitmap (ext2_filsys fs) { dgrp_t i; unsigned int j; int nbytes; unsigned int nbits; errcode_t retval; char * block_bitmap = fs->block_map->bitmap; char * bitmap_block = NULL; blk_t blk; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (!(fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; if (!block_bitmap) return 0; nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; bitmap_block = memalign(getpagesize(), fs->blocksize); memset(bitmap_block, 0xff, fs->blocksize); retval = io_channel_reopen(fs->io, O_RDWR | O_DIRECT); if (retval) return retval; for (i = 0; i < fs->group_desc_count; i++) { memcpy(bitmap_block, block_bitmap, nbytes); if (i == fs->group_desc_count - 1) { /* Force bitmap padding for the last group */ nbits = ((fs->super->s_blocks_count - fs->super->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(fs->super)); if (nbits) for (j = nbits; j < fs->blocksize * 8; j++) ext2fs_set_bit(j, bitmap_block); } blk = fs->group_desc[i].bg_block_bitmap; if (blk) { #ifdef EXT2_BIG_ENDIAN_BITMAPS if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) ext2fs_swap_bitmap(fs, bitmap_block, nbytes); #endif retval = io_channel_write_blk(fs->io, blk, 1, bitmap_block); if (retval) return EXT2_ET_BLOCK_BITMAP_WRITE; } block_bitmap += nbytes; } io_channel_reopen(fs->io, O_RDWR); fs->flags &= ~EXT2_FLAG_BB_DIRTY; free(bitmap_block); return 0; }
/* * init. the fs meta data, return the block size bits. */ static int ext2_fs_init(struct fs_info *fs) { struct disk *disk = fs->fs_dev->disk; struct ext2_sb_info *sbi; struct ext2_super_block sb; struct cache *cs; /* read the super block */ disk->rdwr_sectors(disk, &sb, 2, 2, 0); /* check if it is ext2, since we also support btrfs now */ if (sb.s_magic != EXT2_SUPER_MAGIC) return -1; sbi = malloc(sizeof(*sbi)); if (!sbi) { malloc_error("ext2_sb_info structure"); return -1; } fs->fs_info = sbi; if (sb.s_magic != EXT2_SUPER_MAGIC) { printf("ext2 mount error: it's not a EXT2/3/4 file system!\n"); return 0; } fs->sector_shift = disk->sector_shift; fs->block_shift = sb.s_log_block_size + 10; fs->sector_size = 1 << fs->sector_shift; fs->block_size = 1 << fs->block_shift; sbi->s_inodes_per_group = sb.s_inodes_per_group; sbi->s_blocks_per_group = sb.s_blocks_per_group; sbi->s_inodes_per_block = BLOCK_SIZE(fs) / sb.s_inode_size; if (sb.s_desc_size < sizeof(struct ext2_group_desc)) sb.s_desc_size = sizeof(struct ext2_group_desc); sbi->s_desc_per_block = BLOCK_SIZE(fs) / sb.s_desc_size; sbi->s_groups_count = (sb.s_blocks_count - sb.s_first_data_block + EXT2_BLOCKS_PER_GROUP(fs) - 1) / EXT2_BLOCKS_PER_GROUP(fs); sbi->s_first_data_block = sb.s_first_data_block; sbi->s_inode_size = sb.s_inode_size; /* Volume UUID */ memcpy(sbi->s_uuid, sb.s_uuid, sizeof(sbi->s_uuid)); /* Initialize the cache, and force block zero to all zero */ cache_init(fs->fs_dev, fs->block_shift); cs = _get_cache_block(fs->fs_dev, 0); memset(cs->data, 0, fs->block_size); cache_lock_block(cs); return fs->block_shift; }
static int ext2_check_descriptors (struct super_block * sb) { int i; int desc_block = 0; struct ext2_sb_info *sbi = EXT2_SB(sb); unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block); unsigned long last_block; struct ext2_group_desc * gdp = NULL; ext2_debug ("Checking group descriptors"); for (i = 0; i < sbi->s_groups_count; i++) { if (i == sbi->s_groups_count - 1) last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; else last_block = first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0) gdp = (struct ext2_group_desc *) sbi->s_group_desc[desc_block++]->b_data; if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) { ext2_error (sb, "ext2_check_descriptors", "Block bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); return 0; } if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || le32_to_cpu(gdp->bg_inode_bitmap) > last_block) { ext2_error (sb, "ext2_check_descriptors", "Inode bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); return 0; } if (le32_to_cpu(gdp->bg_inode_table) < first_block || le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group - 1 > last_block) { ext2_error (sb, "ext2_check_descriptors", "Inode table for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); return 0; } first_block += EXT2_BLOCKS_PER_GROUP(sb); gdp++; } return 1; }
/* * Checks that the data in the descriptor blocks make sense. */ int ext2_check_descriptors(struct ext2_sb_info *sb) { int i; int desc_block = 0; unsigned long block = sb->s_es->s_first_data_block; struct ext2_group_desc *gdp = NULL; /* ext2_debug ("Checking group descriptors"); */ for (i = 0; i < sb->s_groups_count; i++) { /* examine next descriptor block */ if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0) gdp = (struct ext2_group_desc *) sb->s_group_desc[desc_block++]->b_data; if (gdp->bg_block_bitmap < block || gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) { kprintf ("ext2_check_descriptors: " "Block bitmap for group %d" " not in group (block %lu)!\n", i, (unsigned long) gdp->bg_block_bitmap); return 0; } if (gdp->bg_inode_bitmap < block || gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) { kprintf ("ext2_check_descriptors: " "Inode bitmap for group %d" " not in group (block %lu)!\n", i, (unsigned long) gdp->bg_inode_bitmap); return 0; } if (gdp->bg_inode_table < block || gdp->bg_inode_table + sb->s_itb_per_group >= block + EXT2_BLOCKS_PER_GROUP(sb)) { kprintf ("ext2_check_descriptors: " "Inode table for group %d" " not in group (block %lu)!\n", i, (unsigned long) gdp->bg_inode_table); return 0; } block += EXT2_BLOCKS_PER_GROUP(sb); gdp++; } return 1; }
errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags) { char *ptr; int c, size; char zero_buf[1024]; ssize_t actual; errcode_t retval; if (flags & IMAGER_FLAG_INODEMAP) { if (!fs->inode_map) { retval = ext2fs_read_inode_bitmap(fs); if (retval) return retval; } ptr = fs->inode_map->bitmap; size = (EXT2_INODES_PER_GROUP(fs->super) / 8); } else { if (!fs->block_map) { retval = ext2fs_read_block_bitmap(fs); if (retval) return retval; } ptr = fs->block_map->bitmap; size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; } size = size * fs->group_desc_count; actual = write(fd, ptr, size); if (actual == -1) { retval = errno; goto errout; } if (actual != size) { retval = EXT2_ET_SHORT_WRITE; goto errout; } size = size % fs->blocksize; memset(zero_buf, 0, sizeof(zero_buf)); if (size) { size = fs->blocksize - size; while (size) { c = size; if (c > (int) sizeof(zero_buf)) c = sizeof(zero_buf); actual = write(fd, zero_buf, c); if (actual == -1) { retval = errno; goto errout; } if (actual != c) { retval = EXT2_ET_SHORT_WRITE; goto errout; } size -= c; } } retval = 0; errout: return (retval); }
/* * Select the desired position for the next block in a file. * * we try to mimic what Remy does in inode_getblk/block_getblk * * we note: blocknr == 0 means that we're about to allocate either * a direct block or a pointer block at the first level of indirection * (In other words, stuff that will go in i_db[] or i_ib[]) * * blocknr != 0 means that we're allocating a block that is none * of the above. Then, blocknr tells us the number of the block * that will hold the pointer */ daddr_t ext2_blkpref(struct inode *ip, daddr_t lbn, int indx, daddr_t *bap, daddr_t blocknr) { int tmp; /* * if the next block is actually what we thought it is, * then set the goal to what we thought it should be */ if (ip->i_next_alloc_block == lbn && ip->i_next_alloc_goal != 0) return ip->i_next_alloc_goal; /* now check whether we were provided with an array that basically tells us previous blocks to which we want to stay closeby */ if(bap) for (tmp = indx - 1; tmp >= 0; tmp--) if (bap[tmp]) return bap[tmp]; /* * else let's fall back to the blocknr, or, if there is none, * follow the rule that a block should be allocated near its inode */ return blocknr ? blocknr : (daddr_t)(ip->i_block_group * EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) + ip->i_e2fs->s_es->s_first_data_block; }
errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, const char *descr, ext2fs_block_bitmap *ret) { __u64 start, end, real_end; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); fs->write_bitmaps = ext2fs_write_bitmaps; start = fs->super->s_first_data_block; end = ext2fs_blocks_count(fs->super)-1; real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super) * (__u64) fs->group_desc_count)-1 + start; if (fs->flags & EXT2_FLAG_64BITS) return (ext2fs_alloc_generic_bmap(fs, EXT2_ET_MAGIC_BLOCK_BITMAP64, EXT2FS_BMAP64_BITARRAY, start, end, real_end, descr, ret)); if ((end > ~0U) || (real_end > ~0U)) return EXT2_ET_CANT_USE_LEGACY_BITMAPS; return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs, start, end, real_end, descr, 0, (ext2fs_generic_bitmap *) ret)); }
/* * ext2fs_allocate_block_bitmap() really allocates a per-cluster * bitmap for backwards compatibility. This function allocates a * block bitmap which is truly per-block, even if clusters/bigalloc * are enabled. mke2fs and e2fsck need this for tracking the * allocation of the file system metadata blocks. */ errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs, const char *descr, ext2fs_block_bitmap *ret) { __u64 start, end, real_end; ext2fs_generic_bitmap bmap; errcode_t retval; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); fs->write_bitmaps = ext2fs_write_bitmaps; if (!fs->cluster_ratio_bits) return ext2fs_allocate_block_bitmap(fs, descr, ret); if ((fs->flags & EXT2_FLAG_64BITS) == 0) return EXT2_ET_CANT_USE_LEGACY_BITMAPS; start = fs->super->s_first_data_block; end = ext2fs_blocks_count(fs->super)-1; real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super) * (__u64) fs->group_desc_count)-1 + start; retval = ext2fs_alloc_generic_bmap(fs, EXT2_ET_MAGIC_BLOCK_BITMAP64, fs->default_bitmap_type, start, end, real_end, descr, &bmap); if (retval) return retval; bmap->cluster_bits = 0; *ret = bmap; return 0; }
errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, const char *descr, ext2fs_block_bitmap *ret) { ext2fs_block_bitmap bitmap; errcode_t retval; __u32 start, end, real_end; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); fs->write_bitmaps = ext2fs_write_bitmaps; start = fs->super->s_first_data_block; end = fs->super->s_blocks_count-1; real_end = (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count)-1 + start; retval = ext2fs_allocate_generic_bitmap(start, end, real_end, descr, &bitmap); if (retval) return retval; bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP; bitmap->fs = fs; bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; *ret = bitmap; return 0; }
static int ext2_check_descriptors (struct super_block * sb) { int i; int desc_block = 0; unsigned long block = sb->u.ext2_sb.s_es->s_first_data_block; struct ext2_group_desc * gdp = NULL; ext2_debug ("Checking group descriptors"); for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0) gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[desc_block++]->b_data; if (gdp->bg_block_bitmap < block || gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) { ext2_error (sb, "ext2_check_desciptors", "Block bitmap for group %d" " not in group (block %lu)!", i, gdp->bg_block_bitmap); return 0; } if (gdp->bg_inode_bitmap < block || gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) { ext2_error (sb, "ext2_check_desciptors", "Inode bitmap for group %d" " not in group (block %lu)!", i, gdp->bg_inode_bitmap); return 0; } if (gdp->bg_inode_table < block || gdp->bg_inode_table + sb->u.ext2_sb.s_itb_per_group >= block + EXT2_BLOCKS_PER_GROUP(sb)) { ext2_error (sb, "ext2_check_desciptors", "Inode table for group %d" " not in group (block %lu)!", i, gdp->bg_inode_table); return 0; } block += EXT2_BLOCKS_PER_GROUP(sb); gdp++; } return 1; }
int Ext2Partition::mount() { EXT2_SUPER_BLOCK sblock; int gSizes, gSizeb; /* Size of total group desc in sectors */ char *tmpbuf; read_disk(handle, &sblock, relative_sect + 2, 2, sect_size); /* read superBlock of root */ if(sblock.s_magic != EXT2_SUPER_MAGIC) { LOG("Bad Super Block. The drive %s is not ext2 formatted.\n", linux_name.c_str()); return -1; } if(sblock.s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) { LOG("File system compression is used which is not supported.\n"); } blocksize = EXT2_BLOCK_SIZE(&sblock); inodes_per_group = EXT2_INODES_PER_GROUP(&sblock); inode_size = EXT2_INODE_SIZE(&sblock); LOG("Block size %d, inp %d, inodesize %d\n", blocksize, inodes_per_group, inode_size); totalGroups = (sblock.s_blocks_count)/EXT2_BLOCKS_PER_GROUP(&sblock); gSizeb = (sizeof(EXT2_GROUP_DESC) * totalGroups); gSizes = (gSizeb / sect_size)+1; desc = (EXT2_GROUP_DESC *) calloc(totalGroups, sizeof(EXT2_GROUP_DESC)); if(desc == NULL) { LOG("Not enough Memory: mount: desc: Exiting\n"); exit(1); } if((tmpbuf = (char *) malloc(gSizes * sect_size)) == NULL) { LOG("Not enough Memory: mount: tmpbuf: Exiting\n"); exit(1); } /* Read all Group descriptors and store in buffer */ /* I really dont know the official start location of Group Descriptor array */ if((blocksize/sect_size) <= 2) read_disk(handle, tmpbuf, relative_sect + ((blocksize/sect_size) + 2), gSizes, sect_size); else read_disk(handle, tmpbuf, relative_sect + (blocksize/sect_size), gSizes, sect_size); memcpy(desc, tmpbuf, gSizeb); free(tmpbuf); return 0; }
static int ext2_setup_super (struct super_block * sb, struct ext2_super_block * es, int read_only) { int res = 0; struct ext2_sb_info *sbi = EXT2_SB(sb); if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) { ext2_msg(sb, KERN_ERR, "error: revision level too high, " "forcing read-only mode"); res = MS_RDONLY; } if (read_only) return res; #ifndef MY_ABC_HERE if (!(sbi->s_mount_state & EXT2_VALID_FS)) ext2_msg(sb, KERN_WARNING, "warning: mounting unchecked fs, " "running e2fsck is recommended"); else if ((sbi->s_mount_state & EXT2_ERROR_FS)) ext2_msg(sb, KERN_WARNING, "warning: mounting fs with errors, " "running e2fsck is recommended"); else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && le16_to_cpu(es->s_mnt_count) >= (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) ext2_msg(sb, KERN_WARNING, "warning: maximal mount count reached, " "running e2fsck is recommended"); else if (le32_to_cpu(es->s_checkinterval) && (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= get_seconds())) ext2_msg(sb, KERN_WARNING, "warning: checktime reached, " "running e2fsck is recommended"); #endif if (!le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); le16_add_cpu(&es->s_mnt_count, 1); if (test_opt (sb, DEBUG)) ext2_msg(sb, KERN_INFO, "%s, %s, bs=%lu, fs=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]", EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, sbi->s_frag_size, sbi->s_groups_count, EXT2_BLOCKS_PER_GROUP(sb), EXT2_INODES_PER_GROUP(sb), sbi->s_mount_opt); return res; }
/* * Stupid algorithm --- we now just search forward starting from the * goal. Should put in a smarter one someday.... */ errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, ext2fs_block_bitmap map, blk64_t *ret) { blk64_t i; int c_ratio; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (!map) map = fs->block_map; if (!map) return EXT2_ET_NO_BLOCK_BITMAP; if (!goal || (goal >= ext2fs_blocks_count(fs->super))) goal = fs->super->s_first_data_block; i = goal; c_ratio = 1 << ext2fs_get_bitmap_granularity(map); if (c_ratio > 1) goal &= ~EXT2FS_CLUSTER_MASK(fs); check_block_uninit(fs, map, (i - fs->super->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(fs->super)); do { if (((i - fs->super->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(fs->super)) == 0) check_block_uninit(fs, map, (i - fs->super->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(fs->super)); if (!ext2fs_fast_test_block_bitmap2(map, i)) { *ret = i; return 0; } i = (i + c_ratio) & ~(c_ratio - 1); if (i >= ext2fs_blocks_count(fs->super)) i = fs->super->s_first_data_block; } while (i != goal); return EXT2_ET_BLOCK_ALLOC_FAIL; }
int Partition::Mount() { EXT2_SUPER_BLOCK sblock; int gSizes, gSizeb; char *tmpbuf; ReadDisk(handle, &sblock, relative_sect + 2, 2, sect_size); if(sblock.s_magic != EXT2_SUPER_MAGIC) { LOG("Bad Super Block. The drive %s is not ext2 formatted.\n", linux_name.c_str()); return -1; } if(sblock.s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) { LOG("File system compression is used which is not supported.\n"); } blocksize = EXT2_BLOCK_SIZE(&sblock); inodes_per_group = EXT2_INODES_PER_GROUP(&sblock); inode_size = EXT2_INODE_SIZE(&sblock); LOG(" Розмір блоку: %d\n", blocksize); totalGroups = (sblock.s_blocks_count)/EXT2_BLOCKS_PER_GROUP(&sblock); gSizeb = (sizeof(EXT2_GROUP_DESC) * totalGroups); gSizes = (gSizeb / sect_size)+1; desc = (EXT2_GROUP_DESC *) calloc(totalGroups, sizeof(EXT2_GROUP_DESC)); if(desc == NULL) { LOG("Not enough Memory: mount: desc: Exiting\n"); exit(1); } if((tmpbuf = (char *) malloc(gSizes * sect_size)) == NULL) { LOG("Not enough Memory: mount: tmpbuf: Exiting\n"); exit(1); } if((blocksize/sect_size) <= 2) ReadDisk(handle, tmpbuf, relative_sect + ((blocksize/sect_size) + 2), gSizes, sect_size); else ReadDisk(handle, tmpbuf, relative_sect + (blocksize/sect_size), gSizes, sect_size); memcpy(desc, tmpbuf, gSizeb); free(tmpbuf); return 0; }
static int ext2_setup_super (struct super_block * sb, struct ext2_super_block * es, int read_only) { int res = 0; struct ext2_sb_info *sbi = EXT2_SB(sb); if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) { printk ("EXT2-fs warning: revision level too high, " "forcing read-only mode\n"); res = MS_RDONLY; } if (read_only) return res; if (!(sbi->s_mount_state & EXT2_VALID_FS)) printk ("EXT2-fs warning: mounting unchecked fs, " "running e2fsck is recommended\n"); else if ((sbi->s_mount_state & EXT2_ERROR_FS)) printk ("EXT2-fs warning: mounting fs with errors, " "running e2fsck is recommended\n"); else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && le16_to_cpu(es->s_mnt_count) >= (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) printk ("EXT2-fs warning: maximal mount count reached, " "running e2fsck is recommended\n"); else if (le32_to_cpu(es->s_checkinterval) && (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= get_seconds())) printk ("EXT2-fs warning: checktime reached, " "running e2fsck is recommended\n"); if (!le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); ext2_write_super(sb); if (test_opt (sb, DEBUG)) printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]\n", EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, sbi->s_frag_size, sbi->s_groups_count, EXT2_BLOCKS_PER_GROUP(sb), EXT2_INODES_PER_GROUP(sb), sbi->s_mount_opt); #ifdef CONFIG_EXT2_CHECK if (test_opt (sb, CHECK)) { ext2_check_blocks_bitmap (sb); ext2_check_inodes_bitmap (sb); } #endif return res; }
static int ext2_check_descriptors(struct super_block *sb) { int i; struct ext2_sb_info *sbi = EXT2_SB(sb); ext2_debug ("Checking group descriptors"); for (i = 0; i < sbi->s_groups_count; i++) { struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL); ext2_fsblk_t first_block = ext2_group_first_block_no(sb, i); ext2_fsblk_t last_block; if (i == sbi->s_groups_count - 1) last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; else last_block = first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) { ext2_error (sb, "ext2_check_descriptors", "Block bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); return 0; } if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || le32_to_cpu(gdp->bg_inode_bitmap) > last_block) { ext2_error (sb, "ext2_check_descriptors", "Inode bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); return 0; } if (le32_to_cpu(gdp->bg_inode_table) < first_block || le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group - 1 > last_block) { ext2_error (sb, "ext2_check_descriptors", "Inode table for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); return 0; } } return 1; }
errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) { char *ptr, *buf = 0; int size; ssize_t actual; errcode_t retval; if (flags & IMAGER_FLAG_INODEMAP) { if (!fs->inode_map) { retval = ext2fs_read_inode_bitmap(fs); if (retval) return retval; } ptr = fs->inode_map->bitmap; size = (EXT2_INODES_PER_GROUP(fs->super) / 8); } else { if (!fs->block_map) { retval = ext2fs_read_block_bitmap(fs); if (retval) return retval; } ptr = fs->block_map->bitmap; size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; } size = size * fs->group_desc_count; buf = malloc(size); if (!buf) return ENOMEM; actual = read(fd, buf, size); if (actual == -1) { retval = errno; goto errout; } if (actual != size) { retval = EXT2_ET_SHORT_WRITE; goto errout; } memcpy(ptr, buf, size); retval = 0; errout: if (buf) free(buf); return (retval); }
/** * goal_in_my_reservation() * @rsv: inode's reservation window * @grp_goal: given goal block relative to the allocation block group * @group: the current allocation block group * @sb: filesystem super block * * Test if the given goal block (group relative) is within the file's * own block reservation window range. * * If the reservation window is outside the goal allocation group, return 0; * grp_goal (given goal block) could be -1, which means no specific * goal block. In this case, always return 1. * If the goal block is within the reservation window, return 1; * otherwise, return 0; */ static int goal_in_my_reservation(struct ext2_reserve_window *rsv, ext2_grpblk_t grp_goal, unsigned int group, struct super_block * sb) { ext2_fsblk_t group_first_block, group_last_block; group_first_block = ext2_group_first_block_no(sb, group); group_last_block = group_first_block + EXT2_BLOCKS_PER_GROUP(sb) - 1; if ((rsv->_rsv_start > group_last_block) || (rsv->_rsv_end < group_first_block)) return 0; if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start) || (grp_goal + group_first_block > rsv->_rsv_end))) return 0; return 1; }
static void ext2_setup_super (struct super_block * sb, struct ext2_super_block * es) { if (swab32(es->s_rev_level) > EXT2_MAX_SUPP_REV) { printk ("EXT2-fs warning: revision level too high, " "forcing read/only mode\n"); sb->s_flags |= MS_RDONLY; } if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) printk ("EXT2-fs warning: mounting unchecked fs, " "running e2fsck is recommended\n"); else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) printk ("EXT2-fs warning: mounting fs with errors, " "running e2fsck is recommended\n"); else if ((__s16) swab16(es->s_max_mnt_count) >= 0 && swab16(es->s_mnt_count) >= (unsigned short) (__s16) swab16(es->s_max_mnt_count)) printk ("EXT2-fs warning: maximal mount count reached, " "running e2fsck is recommended\n"); else if (swab32(es->s_checkinterval) && (swab32(es->s_lastcheck) + swab32(es->s_checkinterval) <= CURRENT_TIME)) printk ("EXT2-fs warning: checktime reached, " "running e2fsck is recommended\n"); es->s_state = swab16(swab16(es->s_state) & ~EXT2_VALID_FS); if (!(__s16) swab16(es->s_max_mnt_count)) es->s_max_mnt_count = (__s16) swab16(EXT2_DFL_MAX_MNT_COUNT); es->s_mnt_count=swab16(swab16(es->s_mnt_count) + 1); es->s_mtime = swab32(CURRENT_TIME); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; if (test_opt (sb, DEBUG)) printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]\n", EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, sb->u.ext2_sb.s_frag_size, sb->u.ext2_sb.s_groups_count, EXT2_BLOCKS_PER_GROUP(sb), EXT2_INODES_PER_GROUP(sb), sb->u.ext2_sb.s_mount_opt); if (test_opt (sb, CHECK)) { ext2_check_blocks_bitmap (sb); ext2_check_inodes_bitmap (sb); } } }
static void check_block_end(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; blk_t end, save_blocks_count, i; struct problem_context pctx; clear_problem_context(&pctx); end = fs->block_map->start + (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1; pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end, &save_blocks_count); if (pctx.errcode) { pctx.num = 3; fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ return; } if (save_blocks_count == end) return; /* Protect loop from wrap-around if end is maxed */ for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) { if (!ext2fs_test_block_bitmap(fs->block_map, i)) { if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) { for (i = save_blocks_count + 1; i <= end; i++) ext2fs_mark_block_bitmap(fs->block_map, i); ext2fs_mark_bb_dirty(fs); } else ext2fs_unmark_valid(fs); break; } } pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, save_blocks_count, 0); if (pctx.errcode) { pctx.num = 4; fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ return; } }
static errcode_t adjust_fs_size(ext2_filsys fs, long long *new_size) { errcode_t retval; int overhead = 0; int rem; fs->super->s_blocks_count = (unsigned int)(*new_size / fs->blocksize); retry: fs->group_desc_count = ext2fs_div_ceil(fs->super->s_blocks_count - fs->super->s_first_data_block, EXT2_BLOCKS_PER_GROUP(fs->super)); if (fs->group_desc_count == 0) return EXT2_ET_TOOSMALL; fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count, EXT2_DESC_PER_BLOCK(fs->super)); /* * Overhead is the number of bookkeeping blocks per group. It * includes the superblock backup, the group descriptor * backups, the inode bitmap, the block bitmap, and the inode * table. */ overhead = (int) (2 + fs->inode_blocks_per_group); if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1)) overhead += 1 + fs->desc_blocks + fs->super->s_reserved_gdt_blocks; /* * See if the last group is big enough to support the * necessary data structures. If not, we need to get rid of * it. */ rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) % fs->super->s_blocks_per_group; if ((fs->group_desc_count == 1) && rem && (rem < overhead)) return EXT2_ET_TOOSMALL; if (rem && (rem < overhead+50)) { fs->super->s_blocks_count -= rem; goto retry; } *new_size = ((long long)fs->super->s_blocks_count * (long long)fs->blocksize); return 0; }
static void ext2_setup_super (struct super_block * sb, struct ext2_super_block * es) { if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) printk ("EXT2-fs warning: mounting unchecked fs, " "running e2fsck is recommended\n"); else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) printk ("EXT2-fs warning: mounting fs with errors, " "running e2fsck is recommended\n"); else if (es->s_max_mnt_count >= 0 && es->s_mnt_count >= (unsigned short) es->s_max_mnt_count) printk ("EXT2-fs warning: maximal mount count reached, " "running e2fsck is recommended\n"); else if (es->s_checkinterval && (es->s_lastcheck + es->s_checkinterval <= CURRENT_TIME)) printk ("EXT2-fs warning: checktime reached, " "running e2fsck is recommended\n"); es->s_state &= ~EXT2_VALID_FS; if (!es->s_max_mnt_count) es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; es->s_mnt_count++; es->s_mtime = CURRENT_TIME; sb->u.ext2_sb.s_sbh->b_dirt = 1; sb->s_dirt = 1; if (test_opt (sb, DEBUG)) printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]\n", EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, sb->u.ext2_sb.s_frag_size, sb->u.ext2_sb.s_groups_count, EXT2_BLOCKS_PER_GROUP(sb), EXT2_INODES_PER_GROUP(sb), sb->u.ext2_sb.s_mount_opt); if (test_opt (sb, CHECK)) { ext2_check_blocks_bitmap (sb); ext2_check_inodes_bitmap (sb); } } }
static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block) { dgrp_t i; unsigned int j; int block_nbytes, inode_nbytes; unsigned int nbits; errcode_t retval; char *block_buf = NULL, *inode_buf = NULL; int csum_flag = 0; blk64_t blk; blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); ext2_ino_t ino_itr = 1; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (!(fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) csum_flag = 1; inode_nbytes = block_nbytes = 0; if (do_block) { block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; retval = io_channel_alloc_buf(fs->io, 0, &block_buf); if (retval) goto errout; memset(block_buf, 0xff, fs->blocksize); } if (do_inode) { inode_nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); retval = io_channel_alloc_buf(fs->io, 0, &inode_buf); if (retval) goto errout; memset(inode_buf, 0xff, fs->blocksize); } for (i = 0; i < fs->group_desc_count; i++) { if (!do_block) goto skip_block_bitmap; if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) ) goto skip_this_block_bitmap; retval = ext2fs_get_block_bitmap_range2(fs->block_map, blk_itr, block_nbytes << 3, block_buf); if (retval) goto errout; if (i == fs->group_desc_count - 1) { /* Force bitmap padding for the last group */ nbits = EXT2FS_NUM_B2C(fs, ((ext2fs_blocks_count(fs->super) - (__u64) fs->super->s_first_data_block) % (__u64) EXT2_BLOCKS_PER_GROUP(fs->super))); if (nbits) for (j = nbits; j < fs->blocksize * 8; j++) ext2fs_set_bit(j, block_buf); } blk = ext2fs_block_bitmap_loc(fs, i); if (blk) { retval = io_channel_write_blk64(fs->io, blk, 1, block_buf); if (retval) { retval = EXT2_ET_BLOCK_BITMAP_WRITE; goto errout; } } skip_this_block_bitmap: blk_itr += block_nbytes << 3; skip_block_bitmap: if (!do_inode) continue; if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) ) goto skip_this_inode_bitmap; retval = ext2fs_get_inode_bitmap_range2(fs->inode_map, ino_itr, inode_nbytes << 3, inode_buf); if (retval) goto errout; blk = ext2fs_inode_bitmap_loc(fs, i); if (blk) { retval = io_channel_write_blk64(fs->io, blk, 1, inode_buf); if (retval) { retval = EXT2_ET_INODE_BITMAP_WRITE; goto errout; } } skip_this_inode_bitmap: ino_itr += inode_nbytes << 3; } if (do_block) { fs->flags &= ~EXT2_FLAG_BB_DIRTY; ext2fs_free_mem(&block_buf); } if (do_inode) { fs->flags &= ~EXT2_FLAG_IB_DIRTY; ext2fs_free_mem(&inode_buf); } return 0; errout: if (inode_buf) ext2fs_free_mem(&inode_buf); if (block_buf) ext2fs_free_mem(&block_buf); return retval; }
static int ext2_fill_super(struct super_block *sb, void *data, int silent) { struct buffer_head * bh; struct ext2_sb_info * sbi; struct ext2_super_block * es; struct inode *root; unsigned long block; unsigned long sb_block = get_sb_block(&data); unsigned long logic_sb_block; unsigned long offset = 0; unsigned long def_mount_opts; long ret = -EINVAL; int blocksize = BLOCK_SIZE; int db_count; int i, j; __le32 features; int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) return -ENOMEM; sbi->s_blockgroup_lock = kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); if (!sbi->s_blockgroup_lock) { kfree(sbi); return -ENOMEM; } sb->s_fs_info = sbi; sbi->s_sb_block = sb_block; /* * See what the current blocksize for the device is, and * use that as the blocksize. Otherwise (or if the blocksize * is smaller than the default) use the default. * This is important for devices that have a hardware * sectorsize that is larger than the default. */ blocksize = sb_min_blocksize(sb, BLOCK_SIZE); if (!blocksize) { printk ("EXT2-fs: unable to set blocksize\n"); goto failed_sbi; } /* * If the superblock doesn't start on a hardware sector boundary, * calculate the offset. */ if (blocksize != BLOCK_SIZE) { logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; offset = (sb_block*BLOCK_SIZE) % blocksize; } else { logic_sb_block = sb_block; } if (!(bh = sb_bread(sb, logic_sb_block))) { printk ("EXT2-fs: unable to read superblock\n"); goto failed_sbi; } /* * Note: s_es must be initialized as soon as possible because * some ext2 macro-instructions depend on its value */ es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); sbi->s_es = es; sb->s_magic = le16_to_cpu(es->s_magic); if (sb->s_magic != EXT2_SUPER_MAGIC) goto cantfind_ext2; /* Set defaults before we parse the mount options */ def_mount_opts = le32_to_cpu(es->s_default_mount_opts); if (def_mount_opts & EXT2_DEFM_DEBUG) set_opt(sbi->s_mount_opt, DEBUG); if (def_mount_opts & EXT2_DEFM_BSDGROUPS) set_opt(sbi->s_mount_opt, GRPID); if (def_mount_opts & EXT2_DEFM_UID16) set_opt(sbi->s_mount_opt, NO_UID32); #ifdef CONFIG_EXT2_FS_XATTR if (def_mount_opts & EXT2_DEFM_XATTR_USER) set_opt(sbi->s_mount_opt, XATTR_USER); #endif #ifdef CONFIG_EXT2_FS_POSIX_ACL if (def_mount_opts & EXT2_DEFM_ACL) set_opt(sbi->s_mount_opt, POSIX_ACL); #endif if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC) set_opt(sbi->s_mount_opt, ERRORS_PANIC); else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE) set_opt(sbi->s_mount_opt, ERRORS_CONT); else set_opt(sbi->s_mount_opt, ERRORS_RO); sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); set_opt(sbi->s_mount_opt, RESERVATION); if (!parse_options ((char *) data, sbi)) goto failed_mount; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset EXT2_MOUNT_XIP if not */ if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || EXT2_HAS_INCOMPAT_FEATURE(sb, ~0U))) printk("EXT2-fs warning: feature flags set on rev 0 fs, " "running e2fsck is recommended\n"); /* * Check feature flags regardless of the revision level, since we * previously didn't change the revision level when setting the flags, * so there is a chance incompat flags are set on a rev 0 filesystem. */ features = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP); if (features) { printk("EXT2-fs: %s: couldn't mount because of " "unsupported optional features (%x).\n", sb->s_id, le32_to_cpu(features)); goto failed_mount; } if (!(sb->s_flags & MS_RDONLY) && (features = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){ printk("EXT2-fs: %s: couldn't mount RDWR because of " "unsupported optional features (%x).\n", sb->s_id, le32_to_cpu(features)); goto failed_mount; } blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) { if (!silent) printk("XIP: Unsupported blocksize\n"); goto failed_mount; } /* If the blocksize doesn't match, re-read the thing.. */ if (sb->s_blocksize != blocksize) { brelse(bh); if (!sb_set_blocksize(sb, blocksize)) { printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n"); goto failed_sbi; } logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; offset = (sb_block*BLOCK_SIZE) % blocksize; bh = sb_bread(sb, logic_sb_block); if(!bh) { printk("EXT2-fs: Couldn't read superblock on " "2nd try.\n"); goto failed_sbi; } es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); sbi->s_es = es; if (es->s_magic != cpu_to_le16(EXT2_SUPER_MAGIC)) { printk ("EXT2-fs: Magic mismatch, very weird !\n"); goto failed_mount; } } sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; sbi->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; } else { sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) || !is_power_of_2(sbi->s_inode_size) || (sbi->s_inode_size > blocksize)) { printk ("EXT2-fs: unsupported inode size: %d\n", sbi->s_inode_size); goto failed_mount; } } sbi->s_frag_size = EXT2_MIN_FRAG_SIZE << le32_to_cpu(es->s_log_frag_size); if (sbi->s_frag_size == 0) goto cantfind_ext2; sbi->s_frags_per_block = sb->s_blocksize / sbi->s_frag_size; sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); if (EXT2_INODE_SIZE(sb) == 0) goto cantfind_ext2; sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb); if (sbi->s_inodes_per_block == 0 || sbi->s_inodes_per_group == 0) goto cantfind_ext2; sbi->s_itb_per_group = sbi->s_inodes_per_group / sbi->s_inodes_per_block; sbi->s_desc_per_block = sb->s_blocksize / sizeof (struct ext2_group_desc); sbi->s_sbh = bh; sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_addr_per_block_bits = ilog2 (EXT2_ADDR_PER_BLOCK(sb)); sbi->s_desc_per_block_bits = ilog2 (EXT2_DESC_PER_BLOCK(sb)); if (sb->s_magic != EXT2_SUPER_MAGIC) goto cantfind_ext2; if (sb->s_blocksize != bh->b_size) { if (!silent) printk ("VFS: Unsupported blocksize on dev " "%s.\n", sb->s_id); goto failed_mount; } if (sb->s_blocksize != sbi->s_frag_size) { printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n", sbi->s_frag_size, sb->s_blocksize); goto failed_mount; } if (sbi->s_blocks_per_group > sb->s_blocksize * 8) { printk ("EXT2-fs: #blocks per group too big: %lu\n", sbi->s_blocks_per_group); goto failed_mount; } if (sbi->s_frags_per_group > sb->s_blocksize * 8) { printk ("EXT2-fs: #fragments per group too big: %lu\n", sbi->s_frags_per_group); goto failed_mount; } if (sbi->s_inodes_per_group > sb->s_blocksize * 8) { printk ("EXT2-fs: #inodes per group too big: %lu\n", sbi->s_inodes_per_group); goto failed_mount; } if (EXT2_BLOCKS_PER_GROUP(sb) == 0) goto cantfind_ext2; sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - le32_to_cpu(es->s_first_data_block) - 1) / EXT2_BLOCKS_PER_GROUP(sb)) + 1; db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / EXT2_DESC_PER_BLOCK(sb); sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL); if (sbi->s_group_desc == NULL) { printk ("EXT2-fs: not enough memory\n"); goto failed_mount; } bgl_lock_init(sbi->s_blockgroup_lock); sbi->s_debts = kcalloc(sbi->s_groups_count, sizeof(*sbi->s_debts), GFP_KERNEL); if (!sbi->s_debts) { printk ("EXT2-fs: not enough memory\n"); goto failed_mount_group_desc; } for (i = 0; i < db_count; i++) { block = descriptor_loc(sb, logic_sb_block, i); sbi->s_group_desc[i] = sb_bread(sb, block); if (!sbi->s_group_desc[i]) { for (j = 0; j < i; j++) brelse (sbi->s_group_desc[j]); printk ("EXT2-fs: unable to read group descriptors\n"); goto failed_mount_group_desc; } } if (!ext2_check_descriptors (sb)) { printk ("EXT2-fs: group descriptors corrupted!\n"); goto failed_mount2; } sbi->s_gdb_count = db_count; get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); /* per fileystem reservation list head & lock */ spin_lock_init(&sbi->s_rsv_window_lock); sbi->s_rsv_window_root = RB_ROOT; /* * Add a single, static dummy reservation to the start of the * reservation window list --- it gives us a placeholder for * append-at-start-of-list which makes the allocation logic * _much_ simpler. */ sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; sbi->s_rsv_window_head.rsv_alloc_hit = 0; sbi->s_rsv_window_head.rsv_goal_size = 0; ext2_rsv_window_add(sb, &sbi->s_rsv_window_head); err = percpu_counter_init(&sbi->s_freeblocks_counter, ext2_count_free_blocks(sb)); if (!err) { err = percpu_counter_init(&sbi->s_freeinodes_counter, ext2_count_free_inodes(sb)); } if (!err) { err = percpu_counter_init(&sbi->s_dirs_counter, ext2_count_dirs(sb)); } if (err) { printk(KERN_ERR "EXT2-fs: insufficient memory\n"); goto failed_mount3; } /* * set up enough so that it can read an inode */ sb->s_op = &ext2_sops; sb->s_export_op = &ext2_export_ops; sb->s_xattr = ext2_xattr_handlers; root = ext2_iget(sb, EXT2_ROOT_INO); if (IS_ERR(root)) { ret = PTR_ERR(root); goto failed_mount3; } if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { iput(root); printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n"); goto failed_mount3; } sb->s_root = d_alloc_root(root); if (!sb->s_root) { iput(root); printk(KERN_ERR "EXT2-fs: get root inode failed\n"); ret = -ENOMEM; goto failed_mount3; } if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) ext2_warning(sb, __func__, "mounting ext3 filesystem as ext2"); ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); return 0; cantfind_ext2: if (!silent) printk("VFS: Can't find an ext2 filesystem on dev %s.\n", sb->s_id); goto failed_mount; failed_mount3: percpu_counter_destroy(&sbi->s_freeblocks_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_dirs_counter); failed_mount2: for (i = 0; i < db_count; i++) brelse(sbi->s_group_desc[i]); failed_mount_group_desc: kfree(sbi->s_group_desc); kfree(sbi->s_debts); failed_mount: brelse(bh); failed_sbi: sb->s_fs_info = NULL; kfree(sbi->s_blockgroup_lock); kfree(sbi); return ret; }
struct super_block * ext2_read_super (struct super_block * sb, void * data, int silent) { struct buffer_head * bh; struct ext2_sb_info * sbi = EXT2_SB(sb); struct ext2_super_block * es; unsigned long sb_block = 1; unsigned short resuid = EXT2_DEF_RESUID; unsigned short resgid = EXT2_DEF_RESGID; unsigned long block; unsigned long logic_sb_block; unsigned long offset = 0; kdev_t dev = sb->s_dev; int blocksize = BLOCK_SIZE; int db_count; int i, j; /* * See what the current blocksize for the device is, and * use that as the blocksize. Otherwise (or if the blocksize * is smaller than the default) use the default. * This is important for devices that have a hardware * sectorsize that is larger than the default. */ blocksize = get_hardsect_size(dev); if(blocksize < BLOCK_SIZE ) blocksize = BLOCK_SIZE; sb->u.ext2_sb.s_mount_opt = 0; if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, &sb->u.ext2_sb.s_mount_opt)) { return NULL; } if (set_blocksize(dev, blocksize) < 0) { printk ("EXT2-fs: unable to set blocksize %d\n", blocksize); return NULL; } sb->s_blocksize = blocksize; /* * If the superblock doesn't start on a sector boundary, * calculate the offset. FIXME(eric) this doesn't make sense * that we would have to do this. */ if (blocksize != BLOCK_SIZE) { logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; offset = (sb_block*BLOCK_SIZE) % blocksize; } else { logic_sb_block = sb_block; } if (!(bh = sb_bread(sb, logic_sb_block))) { printk ("EXT2-fs: unable to read superblock\n"); return NULL; } /* * Note: s_es must be initialized as soon as possible because * some ext2 macro-instructions depend on its value */ es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); sb->u.ext2_sb.s_es = es; sb->s_magic = le16_to_cpu(es->s_magic); if (sb->s_magic != EXT2_SUPER_MAGIC) { if (!silent) printk ("VFS: Can't find ext2 filesystem on dev %s.\n", bdevname(dev)); goto failed_mount; } if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || EXT2_HAS_INCOMPAT_FEATURE(sb, ~0U))) printk("EXT2-fs warning: feature flags set on rev 0 fs, " "running e2fsck is recommended\n"); /* * Check feature flags regardless of the revision level, since we * previously didn't change the revision level when setting the flags, * so there is a chance incompat flags are set on a rev 0 filesystem. */ if ((i = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP))) { printk("EXT2-fs: %s: couldn't mount because of " "unsupported optional features (%x).\n", bdevname(dev), i); goto failed_mount; } if (!(sb->s_flags & MS_RDONLY) && (i = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){ printk("EXT2-fs: %s: couldn't mount RDWR because of " "unsupported optional features (%x).\n", bdevname(dev), i); goto failed_mount; } if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) ext2_warning(sb, __FUNCTION__, "mounting ext3 filesystem as ext2\n"); sb->s_blocksize_bits = le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size) + 10; sb->s_blocksize = 1 << sb->s_blocksize_bits; sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); /* If the blocksize doesn't match, re-read the thing.. */ if (sb->s_blocksize != blocksize) { blocksize = sb->s_blocksize; brelse(bh); if (set_blocksize(dev, blocksize) < 0) { printk(KERN_ERR "EXT2-fs: blocksize too small for device.\n"); return NULL; } logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; offset = (sb_block*BLOCK_SIZE) % blocksize; bh = sb_bread(sb, logic_sb_block); if(!bh) { printk("EXT2-fs: Couldn't read superblock on " "2nd try.\n"); goto failed_mount; } es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); sb->u.ext2_sb.s_es = es; if (es->s_magic != le16_to_cpu(EXT2_SUPER_MAGIC)) { printk ("EXT2-fs: Magic mismatch, very weird !\n"); goto failed_mount; } } if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; sbi->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; } else { sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) || (sbi->s_inode_size & (sbi->s_inode_size - 1)) || (sbi->s_inode_size > blocksize)) { printk ("EXT2-fs: unsupported inode size: %d\n", sbi->s_inode_size); goto failed_mount; } } sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE << le32_to_cpu(es->s_log_frag_size); if (sb->u.ext2_sb.s_frag_size) sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize / sb->u.ext2_sb.s_frag_size; else sb->s_magic = 0; sb->u.ext2_sb.s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); sb->u.ext2_sb.s_frags_per_group = le32_to_cpu(es->s_frags_per_group); sb->u.ext2_sb.s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb); sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group / sb->u.ext2_sb.s_inodes_per_block; sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize / sizeof (struct ext2_group_desc); sb->u.ext2_sb.s_sbh = bh; if (resuid != EXT2_DEF_RESUID) sb->u.ext2_sb.s_resuid = resuid; else sb->u.ext2_sb.s_resuid = le16_to_cpu(es->s_def_resuid); if (resgid != EXT2_DEF_RESGID) sb->u.ext2_sb.s_resgid = resgid; else sb->u.ext2_sb.s_resgid = le16_to_cpu(es->s_def_resgid); sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state); sb->u.ext2_sb.s_addr_per_block_bits = log2 (EXT2_ADDR_PER_BLOCK(sb)); sb->u.ext2_sb.s_desc_per_block_bits = log2 (EXT2_DESC_PER_BLOCK(sb)); if (sb->s_magic != EXT2_SUPER_MAGIC) { if (!silent) printk ("VFS: Can't find an ext2 filesystem on dev " "%s.\n", bdevname(dev)); goto failed_mount; } if (sb->s_blocksize != bh->b_size) { if (!silent) printk ("VFS: Unsupported blocksize on dev " "%s.\n", bdevname(dev)); goto failed_mount; } if (sb->s_blocksize != sb->u.ext2_sb.s_frag_size) { printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n", sb->u.ext2_sb.s_frag_size, sb->s_blocksize); goto failed_mount; } if (sb->u.ext2_sb.s_blocks_per_group > sb->s_blocksize * 8) { printk ("EXT2-fs: #blocks per group too big: %lu\n", sb->u.ext2_sb.s_blocks_per_group); goto failed_mount; } if (sb->u.ext2_sb.s_frags_per_group > sb->s_blocksize * 8) { printk ("EXT2-fs: #fragments per group too big: %lu\n", sb->u.ext2_sb.s_frags_per_group); goto failed_mount; } if (sb->u.ext2_sb.s_inodes_per_group > sb->s_blocksize * 8) { printk ("EXT2-fs: #inodes per group too big: %lu\n", sb->u.ext2_sb.s_inodes_per_group); goto failed_mount; } sb->u.ext2_sb.s_groups_count = (le32_to_cpu(es->s_blocks_count) - le32_to_cpu(es->s_first_data_block) + EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb); db_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / EXT2_DESC_PER_BLOCK(sb); sb->u.ext2_sb.s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL); if (sb->u.ext2_sb.s_group_desc == NULL) { printk ("EXT2-fs: not enough memory\n"); goto failed_mount; } for (i = 0; i < db_count; i++) { block = descriptor_loc(sb, logic_sb_block, i); sbi->s_group_desc[i] = sb_bread(sb, block); if (!sbi->s_group_desc[i]) { for (j = 0; j < i; j++) brelse (sbi->s_group_desc[j]); kfree(sbi->s_group_desc); printk ("EXT2-fs: unable to read group descriptors\n"); goto failed_mount; } } if (!ext2_check_descriptors (sb)) { printk ("EXT2-fs: group descriptors corrupted!\n"); db_count = i; goto failed_mount2; } for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) { sb->u.ext2_sb.s_inode_bitmap_number[i] = 0; sb->u.ext2_sb.s_inode_bitmap[i] = NULL; sb->u.ext2_sb.s_block_bitmap_number[i] = 0; sb->u.ext2_sb.s_block_bitmap[i] = NULL; } sb->u.ext2_sb.s_loaded_inode_bitmaps = 0; sb->u.ext2_sb.s_loaded_block_bitmaps = 0; sb->u.ext2_sb.s_gdb_count = db_count; /* * set up enough so that it can read an inode */ sb->s_op = &ext2_sops; sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO)); if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) || !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) { if (sb->s_root) { dput(sb->s_root); sb->s_root = NULL; printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n"); } else printk(KERN_ERR "EXT2-fs: get root inode failed\n"); goto failed_mount2; } ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); return sb; failed_mount2: for (i = 0; i < db_count; i++) brelse(sb->u.ext2_sb.s_group_desc[i]); kfree(sb->u.ext2_sb.s_group_desc); failed_mount: brelse(bh); return NULL; }
/* * Note: if superblock is non-zero, block-size must also be non-zero. * Superblock and block_size can be zero to use the default size. * * Valid flags for ext2fs_open() * * EXT2_FLAG_RW - Open the filesystem for read/write. * EXT2_FLAG_FORCE - Open the filesystem even if some of the * features aren't supported. * EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device * EXT2_FLAG_SKIP_MMP - Open without multi-mount protection check. * EXT2_FLAG_64BITS - Allow 64-bit bitfields (needed for large * filesystems) */ errcode_t ext2fs_open2(const char *name, const char *io_options, int flags, int superblock, unsigned int block_size, io_manager manager, ext2_filsys *ret_fs) { ext2_filsys fs; errcode_t retval; unsigned long i, first_meta_bg; __u32 features; unsigned int blocks_per_group, io_flags; blk64_t group_block, blk; char *dest, *cp; int group_zero_adjust = 0; #ifdef WORDS_BIGENDIAN unsigned int groups_per_block; struct ext2_group_desc *gdp; int j; #endif char *time_env; EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER); retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs); if (retval) return retval; memset(fs, 0, sizeof(struct struct_ext2_filsys)); fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS; fs->flags = flags; /* don't overwrite sb backups unless flag is explicitly cleared */ fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; fs->umask = 022; time_env = getenv("E2FSPROGS_FAKE_TIME"); if (time_env) fs->now = strtoul(time_env, NULL, 0); retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name); if (retval) goto cleanup; strcpy(fs->device_name, name); cp = strchr(fs->device_name, '?'); if (!io_options && cp) { *cp++ = 0; io_options = cp; } io_flags = 0; if (flags & EXT2_FLAG_RW) io_flags |= IO_FLAG_RW; if (flags & EXT2_FLAG_EXCLUSIVE) io_flags |= IO_FLAG_EXCLUSIVE; if (flags & EXT2_FLAG_DIRECT_IO) io_flags |= IO_FLAG_DIRECT_IO; retval = manager->open(fs->device_name, io_flags, &fs->io); if (retval) goto cleanup; if (io_options && (retval = io_channel_set_options(fs->io, io_options))) goto cleanup; fs->image_io = fs->io; fs->io->app_data = fs; retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super); if (retval) goto cleanup; if (flags & EXT2_FLAG_IMAGE_FILE) { retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr), &fs->image_header); if (retval) goto cleanup; retval = io_channel_read_blk(fs->io, 0, -(int)sizeof(struct ext2_image_hdr), fs->image_header); if (retval) goto cleanup; if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE) return EXT2_ET_MAGIC_E2IMAGE; superblock = 1; block_size = fs->image_header->fs_blocksize; } /* * If the user specifies a specific block # for the * superblock, then he/she must also specify the block size! * Otherwise, read the master superblock located at offset * SUPERBLOCK_OFFSET from the start of the partition. * * Note: we only save a backup copy of the superblock if we * are reading the superblock from the primary superblock location. */ if (superblock) { if (!block_size) { retval = EXT2_ET_INVALID_ARGUMENT; goto cleanup; } io_channel_set_blksize(fs->io, block_size); group_block = superblock; fs->orig_super = 0; } else { io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); superblock = 1; group_block = 0; retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super); if (retval) goto cleanup; } retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE, fs->super); if (retval) goto cleanup; if (fs->orig_super) memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE); if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) { retval = 0; if (!ext2fs_verify_csum_type(fs, fs->super)) retval = EXT2_ET_UNKNOWN_CSUM; if (!ext2fs_superblock_csum_verify(fs, fs->super)) retval = EXT2_ET_SB_CSUM_INVALID; } #ifdef WORDS_BIGENDIAN fs->flags |= EXT2_FLAG_SWAP_BYTES; ext2fs_swap_super(fs->super); #else if (fs->flags & EXT2_FLAG_SWAP_BYTES) { retval = EXT2_ET_UNIMPLEMENTED; goto cleanup; } #endif if (fs->super->s_magic != EXT2_SUPER_MAGIC) retval = EXT2_ET_BAD_MAGIC; if (retval) goto cleanup; if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) { retval = EXT2_ET_REV_TOO_HIGH; goto cleanup; } /* * Check for feature set incompatibility */ if (!(flags & EXT2_FLAG_FORCE)) { features = fs->super->s_feature_incompat; #ifdef EXT2_LIB_SOFTSUPP_INCOMPAT if (flags & EXT2_FLAG_SOFTSUPP_FEATURES) features &= ~EXT2_LIB_SOFTSUPP_INCOMPAT; #endif if (features & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) { retval = EXT2_ET_UNSUPP_FEATURE; goto cleanup; } features = fs->super->s_feature_ro_compat; #ifdef EXT2_LIB_SOFTSUPP_RO_COMPAT if (flags & EXT2_FLAG_SOFTSUPP_FEATURES) features &= ~EXT2_LIB_SOFTSUPP_RO_COMPAT; #endif if ((flags & EXT2_FLAG_RW) && (features & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) { retval = EXT2_ET_RO_UNSUPP_FEATURE; goto cleanup; } if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) && ext2fs_has_feature_journal_dev(fs->super)) { retval = EXT2_ET_UNSUPP_FEATURE; goto cleanup; } } if ((fs->super->s_log_block_size + EXT2_MIN_BLOCK_LOG_SIZE) > EXT2_MAX_BLOCK_LOG_SIZE) { retval = EXT2_ET_CORRUPT_SUPERBLOCK; goto cleanup; } /* * bigalloc requires cluster-aware bitfield operations, which at the * moment means we need EXT2_FLAG_64BITS. */ if (ext2fs_has_feature_bigalloc(fs->super) && !(flags & EXT2_FLAG_64BITS)) { retval = EXT2_ET_CANT_USE_LEGACY_BITMAPS; goto cleanup; } if (!ext2fs_has_feature_bigalloc(fs->super) && (fs->super->s_log_block_size != fs->super->s_log_cluster_size)) { retval = EXT2_ET_CORRUPT_SUPERBLOCK; goto cleanup; } fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(fs->super); if (EXT2_INODE_SIZE(fs->super) < EXT2_GOOD_OLD_INODE_SIZE) { retval = EXT2_ET_CORRUPT_SUPERBLOCK; goto cleanup; } /* Enforce the block group descriptor size */ if (ext2fs_has_feature_64bit(fs->super)) { if (fs->super->s_desc_size < EXT2_MIN_DESC_SIZE_64BIT) { retval = EXT2_ET_BAD_DESC_SIZE; goto cleanup; } } else { if (fs->super->s_desc_size && fs->super->s_desc_size != EXT2_MIN_DESC_SIZE) { retval = EXT2_ET_BAD_DESC_SIZE; goto cleanup; } } fs->cluster_ratio_bits = fs->super->s_log_cluster_size - fs->super->s_log_block_size; if (EXT2_BLOCKS_PER_GROUP(fs->super) != EXT2_CLUSTERS_PER_GROUP(fs->super) << fs->cluster_ratio_bits) { retval = EXT2_ET_CORRUPT_SUPERBLOCK; goto cleanup; } fs->inode_blocks_per_group = ((EXT2_INODES_PER_GROUP(fs->super) * EXT2_INODE_SIZE(fs->super) + EXT2_BLOCK_SIZE(fs->super) - 1) / EXT2_BLOCK_SIZE(fs->super)); if (block_size) { if (block_size != fs->blocksize) { retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE; goto cleanup; } } /* * Set the blocksize to the filesystem's blocksize. */ io_channel_set_blksize(fs->io, fs->blocksize); /* * If this is an external journal device, don't try to read * the group descriptors, because they're not there. */ if (ext2fs_has_feature_journal_dev(fs->super)) { fs->group_desc_count = 0; *ret_fs = fs; return 0; } if (EXT2_INODES_PER_GROUP(fs->super) == 0) { retval = EXT2_ET_CORRUPT_SUPERBLOCK; goto cleanup; } /* Precompute the FS UUID to seed other checksums */ ext2fs_init_csum_seed(fs); /* * Read group descriptors */ blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super); if (blocks_per_group == 0 || blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) || fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super) || EXT2_DESC_PER_BLOCK(fs->super) == 0 || fs->super->s_first_data_block >= ext2fs_blocks_count(fs->super)) { retval = EXT2_ET_CORRUPT_SUPERBLOCK; goto cleanup; } fs->group_desc_count = ext2fs_div64_ceil(ext2fs_blocks_count(fs->super) - fs->super->s_first_data_block, blocks_per_group); if (fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) != fs->super->s_inodes_count) { retval = EXT2_ET_CORRUPT_SUPERBLOCK; goto cleanup; } fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count, EXT2_DESC_PER_BLOCK(fs->super)); retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, &fs->group_desc); if (retval) goto cleanup; if (!group_block) group_block = fs->super->s_first_data_block; /* * On a FS with a 1K blocksize, block 0 is reserved for bootloaders * so we must increment block numbers to any group 0 items. * * However, we cannot touch group_block directly because in the meta_bg * case, the ext2fs_descriptor_block_loc2() function will interpret * group_block != s_first_data_block to mean that we want to access the * backup group descriptors. This is not what we want if the caller * set superblock == 0 (i.e. auto-detect the superblock), which is * what's going on here. */ if (group_block == 0 && fs->blocksize == 1024) group_zero_adjust = 1; dest = (char *) fs->group_desc; #ifdef WORDS_BIGENDIAN groups_per_block = EXT2_DESC_PER_BLOCK(fs->super); #endif if (ext2fs_has_feature_meta_bg(fs->super)) { first_meta_bg = fs->super->s_first_meta_bg; if (first_meta_bg > fs->desc_blocks) first_meta_bg = fs->desc_blocks; } else first_meta_bg = fs->desc_blocks; if (first_meta_bg) { retval = io_channel_read_blk(fs->io, group_block + group_zero_adjust + 1, first_meta_bg, dest); if (retval) goto cleanup; #ifdef WORDS_BIGENDIAN gdp = (struct ext2_group_desc *) dest; for (j=0; j < groups_per_block*first_meta_bg; j++) { gdp = ext2fs_group_desc(fs, fs->group_desc, j); ext2fs_swap_group_desc2(fs, gdp); } #endif dest += fs->blocksize*first_meta_bg; } for (i=first_meta_bg ; i < fs->desc_blocks; i++) { blk = ext2fs_descriptor_block_loc2(fs, group_block, i); retval = io_channel_read_blk64(fs->io, blk, 1, dest); if (retval) goto cleanup; #ifdef WORDS_BIGENDIAN for (j=0; j < groups_per_block; j++) { gdp = ext2fs_group_desc(fs, fs->group_desc, i * groups_per_block + j); ext2fs_swap_group_desc2(fs, gdp); } #endif dest += fs->blocksize; } fs->stride = fs->super->s_raid_stride; /* * If recovery is from backup superblock, Clear _UNININT flags & * reset bg_itable_unused to zero */ if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) { dgrp_t group; for (group = 0; group < fs->group_desc_count; group++) { ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); ext2fs_bg_itable_unused_set(fs, group, 0); /* The checksum will be reset later, but fix it here * anyway to avoid printing a lot of spurious errors. */ ext2fs_group_desc_csum_set(fs, group); } if (fs->flags & EXT2_FLAG_RW) ext2fs_mark_super_dirty(fs); } if (ext2fs_has_feature_mmp(fs->super) && !(flags & EXT2_FLAG_SKIP_MMP) && (flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) { retval = ext2fs_mmp_start(fs); if (retval) { fs->flags |= EXT2_FLAG_SKIP_MMP; /* just do cleanup */ ext2fs_mmp_stop(fs); goto cleanup; } } if (fs->flags & EXT2_FLAG_SHARE_DUP) { fs->block_sha_map = ext2fs_hashmap_create(ext2fs_djb2_hash, block_sha_map_free_entry, 4096); if (!fs->block_sha_map) { retval = EXT2_ET_NO_MEMORY; goto cleanup; } ext2fs_set_feature_shared_blocks(fs->super); } fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR; *ret_fs = fs; return 0; cleanup: if (!(flags & EXT2_FLAG_NOFREE_ON_ERROR)) { ext2fs_free(fs); fs = NULL; } *ret_fs = fs; return retval; }
static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block) { dgrp_t i; unsigned int j; int block_nbytes, inode_nbytes; unsigned int nbits; errcode_t retval; char *block_bitmap, *inode_bitmap; char *block_buf, *inode_buf; int lazy_flag = 0; blk_t blk; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (!(fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG)) lazy_flag = 1; inode_nbytes = block_nbytes = 0; block_bitmap = inode_bitmap = 0; if (do_block) { block_bitmap = fs->block_map->bitmap; block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; retval = ext2fs_get_mem(fs->blocksize, &block_buf); if (retval) return retval; memset(block_buf, 0xff, fs->blocksize); } if (do_inode) { inode_bitmap = fs->inode_map->bitmap; inode_nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); retval = ext2fs_get_mem(fs->blocksize, &inode_buf); if (retval) return retval; memset(inode_buf, 0xff, fs->blocksize); } for (i = 0; i < fs->group_desc_count; i++) { if (!block_bitmap || !do_block) goto skip_block_bitmap; if (lazy_flag && fs->group_desc[i].bg_flags & EXT2_BG_BLOCK_UNINIT) goto skip_this_block_bitmap; memcpy(block_buf, block_bitmap, block_nbytes); if (i == fs->group_desc_count - 1) { /* Force bitmap padding for the last group */ nbits = ((fs->super->s_blocks_count - fs->super->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(fs->super)); if (nbits) for (j = nbits; j < fs->blocksize * 8; j++) ext2fs_set_bit(j, block_buf); } blk = fs->group_desc[i].bg_block_bitmap; if (blk) { #ifdef EXT2_BIG_ENDIAN_BITMAPS if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) ext2fs_swap_bitmap(fs, block_buf, block_nbytes); #endif retval = io_channel_write_blk(fs->io, blk, 1, block_buf); if (retval) return EXT2_ET_BLOCK_BITMAP_WRITE; } skip_this_block_bitmap: block_bitmap += block_nbytes; skip_block_bitmap: if (!inode_bitmap || !do_inode) continue; if (lazy_flag && fs->group_desc[i].bg_flags & EXT2_BG_INODE_UNINIT) goto skip_this_inode_bitmap; memcpy(inode_buf, inode_bitmap, inode_nbytes); blk = fs->group_desc[i].bg_inode_bitmap; if (blk) { #ifdef EXT2_BIG_ENDIAN_BITMAPS if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) || (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))) ext2fs_swap_bitmap(fs, inode_buf, inode_nbytes); #endif retval = io_channel_write_blk(fs->io, blk, 1, inode_buf); if (retval) return EXT2_ET_INODE_BITMAP_WRITE; } skip_this_inode_bitmap: inode_bitmap += inode_nbytes; } if (do_block) { fs->flags &= ~EXT2_FLAG_BB_DIRTY; ext2fs_free_mem(&block_buf); } if (do_inode) { fs->flags &= ~EXT2_FLAG_IB_DIRTY; ext2fs_free_mem(&inode_buf); } return 0; }