/** * nilfs_palloc_init_blockgroup - initialize private variables for allocator * @inode: inode of metadata file using this allocator * @entry_size: size of the persistent object */ int nilfs_palloc_init_blockgroup(struct inode *inode, unsigned int entry_size) { struct nilfs_mdt_info *mi = NILFS_MDT(inode); mi->mi_bgl = kmalloc(sizeof(*mi->mi_bgl), GFP_NOFS); if (!mi->mi_bgl) return -ENOMEM; bgl_lock_init(mi->mi_bgl); nilfs_mdt_set_entry_size(inode, entry_size, 0); mi->mi_blocks_per_group = DIV_ROUND_UP(nilfs_palloc_entries_per_group(inode), mi->mi_entries_per_block) + 1; /* * Number of blocks in a group including entry blocks * and a bitmap block */ mi->mi_blocks_per_desc_block = nilfs_palloc_groups_per_desc_block(inode) * mi->mi_blocks_per_group + 1; /* * Number of blocks per descriptor including the * descriptor block */ return 0; }
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; }
/* ================================================================================== Function :me2fsFillSuperBlock Input :struct super_block *sb < vfs super block object > void *data < user data > int silent < silent flag > Output :void Return :void Description :fill my ext2 super block object ================================================================================== */ static int me2fsFillSuperBlock( struct super_block *sb, void *data, int silent ) { struct buffer_head *bh; struct ext2_super_block *esb; struct me2fs_sb_info *msi; struct inode *root; int block_size; int ret = -EINVAL; int i; int err; unsigned long sb_block = 1; /* ------------------------------------------------------------------------ */ /* allocate memory to me2fs_sb_info */ /* ------------------------------------------------------------------------ */ msi = kzalloc( sizeof( struct me2fs_sb_info ), GFP_KERNEL ); if( !msi ) { ME2FS_ERROR( "<ME2FS>error: unable to alloc me2fs_sb_info\n" ); ret = -ENOMEM; return( ret ); } /* set me2fs information to vfs super block */ sb->s_fs_info = ( void* )msi; /* ------------------------------------------------------------------------ */ /* allocate memory to spin locks for block group */ /* ------------------------------------------------------------------------ */ msi->s_blockgroup_lock = kzalloc( sizeof( struct blockgroup_lock ), GFP_KERNEL ); if( !msi->s_blockgroup_lock ) { ME2FS_ERROR( "<ME2FS>error: unabel to alloc s_blockgroup_lock\n" ); kfree( msi ); return( -ENOMEM ); } /* ------------------------------------------------------------------------ */ /* set device's block size and size bits to super block */ /* ------------------------------------------------------------------------ */ block_size = sb_min_blocksize( sb, BLOCK_SIZE ); DBGPRINT( "<ME2FS>Fill Super! block_size = %d\n", block_size ); DBGPRINT( "<ME2FS>s_blocksize_bits = %d\n", sb->s_blocksize_bits ); DBGPRINT( "<ME2FS>default block size is : %d\n", BLOCK_SIZE ); if( !block_size ) { ME2FS_ERROR( "<ME2FS>error: unable to set blocksize\n" ); goto error_read_sb; } /* ------------------------------------------------------------------------ */ /* read super block */ /* ------------------------------------------------------------------------ */ if( !( bh = sb_bread( sb, sb_block ) ) ) { ME2FS_ERROR( "<ME2FS>failed to bread super block\n" ); goto error_read_sb; } esb = ( struct ext2_super_block* )( bh->b_data ); /* ------------------------------------------------------------------------ */ /* check magic number */ /* ------------------------------------------------------------------------ */ sb->s_magic = le16_to_cpu( esb->s_magic ); if( sb->s_magic != ME2FS_SUPER_MAGIC ) { ME2FS_ERROR( "<ME2FS>error : magic of super block is %lu\n", sb->s_magic ); goto error_mount; } /* ------------------------------------------------------------------------ */ /* check revison */ /* ------------------------------------------------------------------------ */ if( ME2FS_OLD_REV == le32_to_cpu( esb->s_rev_level ) ) { ME2FS_ERROR( "<ME2FS>error : cannot mount old revision\n" ); goto error_mount; } dbgPrintExt2SB( esb ); /* ------------------------------------------------------------------------ */ /* set up me2fs super block information */ /* ------------------------------------------------------------------------ */ /* buffer cache information */ msi->s_esb = esb; msi->s_sbh = bh; /* super block(disk information cache) */ msi->s_sb_block = sb_block; msi->s_mount_opt = le32_to_cpu( esb->s_default_mount_opts ); msi->s_mount_state = le16_to_cpu( esb->s_state ); if( msi->s_mount_state != EXT2_VALID_FS ) { ME2FS_ERROR( "<ME2FS>error : cannot mount invalid fs\n" ); goto error_mount; } if( le16_to_cpu( esb->s_errors ) == EXT2_ERRORS_CONTINUE ) { DBGPRINT( "<ME2FS>s_errors : CONTINUE\n" ); } else if( le16_to_cpu( esb->s_errors ) == EXT2_ERRORS_PANIC ) { DBGPRINT( "<ME2FS>s_errors : PANIC\n" ); } else { DBGPRINT( "<ME2FS>s_errors : READ ONLY\n" ); } if( le32_to_cpu( esb->s_rev_level ) != EXT2_DYNAMIC_REV ) { ME2FS_ERROR( "<ME2FS>error : cannot mount unsupported revision\n" ); goto error_mount; } /* inode(disk information cache) */ msi->s_inode_size = le16_to_cpu( esb->s_inode_size ); if( ( msi->s_inode_size < 128 ) || !is_power_of_2( msi->s_inode_size ) || ( block_size < msi->s_inode_size ) ) { ME2FS_ERROR( "<ME2FS>error : cannot mount unsupported inode size %u\n", msi->s_inode_size ); goto error_mount; } msi->s_first_ino = le32_to_cpu( esb->s_first_ino ); msi->s_inodes_per_group = le32_to_cpu( esb->s_inodes_per_group ); msi->s_inodes_per_block = sb->s_blocksize / msi->s_inode_size; if( msi->s_inodes_per_block == 0 ) { ME2FS_ERROR( "<ME2FS>error : bad inodes per block\n" ); goto error_mount; } msi->s_itb_per_group = msi->s_inodes_per_group / msi->s_inodes_per_block; /* group(disk information cache) */ msi->s_blocks_per_group = le32_to_cpu( esb->s_blocks_per_group ); if( msi->s_blocks_per_group == 0 ) { ME2FS_ERROR( "<ME2FS>eroor : bad blocks per group\n" ); goto error_mount; } msi->s_groups_count = ( ( le32_to_cpu( esb->s_blocks_count ) - le32_to_cpu( esb->s_first_data_block ) - 1 ) / msi->s_blocks_per_group ) + 1; msi->s_desc_per_block = sb->s_blocksize / sizeof( struct ext2_group_desc ); msi->s_gdb_count = ( msi->s_groups_count + msi->s_desc_per_block - 1 ) / msi->s_desc_per_block; /* fragment(disk information cache) */ msi->s_frag_size = 1024 << le32_to_cpu( esb->s_log_frag_size ); if( msi->s_frag_size == 0 ) { ME2FS_ERROR( "<ME2FS>eroor : bad fragment size\n" ); goto error_mount; } msi->s_frags_per_block = sb->s_blocksize / msi->s_frag_size; msi->s_frags_per_group = le32_to_cpu( esb->s_frags_per_group ); /* deaults(disk information cache) */ msi->s_resuid = make_kuid( &init_user_ns, le16_to_cpu( esb->s_def_resuid ) ); msi->s_resgid = make_kgid( &init_user_ns, le16_to_cpu( esb->s_def_resgid ) ); dbgPrintMe2fsInfo( msi ); /* ------------------------------------------------------------------------ */ /* read block group descriptor table */ /* ------------------------------------------------------------------------ */ msi->s_group_desc = kmalloc( msi->s_gdb_count * sizeof( struct buffer_head* ), GFP_KERNEL ); if( !msi->s_group_desc ) { ME2FS_ERROR( "<ME2FS>error : alloc memory for group desc is failed\n" ); goto error_mount; } for( i = 0 ; i < msi->s_gdb_count ; i++ ) { unsigned long block; block = getDescriptorLocation( sb, sb_block, i ); if( !( msi->s_group_desc[ i ] = sb_bread( sb, block ) ) ) //if( !( msi->s_group_desc[ i ] = sb_bread( sb, sb_block + i + 1 ) ) ) { ME2FS_ERROR( "<ME2FS>error : cannot read " ); ME2FS_ERROR( "block group descriptor[ group=%d ]\n", i ); goto error_mount_phase2; } } /* ------------------------------------------------------------------------ */ /* sanity check for group descriptors */ /* ------------------------------------------------------------------------ */ for( i = 0 ; i < msi->s_groups_count ; i++ ) { struct ext2_group_desc *gdesc; unsigned long first_block; unsigned long last_block; unsigned long ar_block; DBGPRINT( "<ME2FS>Block Count %d\n", i ); if( !( gdesc = me2fsGetGroupDescriptor( sb, i ) ) ) { /* corresponding group descriptor does not exist */ goto error_mount_phase2; } first_block = ext2GetFirstBlockNum( sb, i ); if( i == ( msi->s_groups_count - 1 ) ) { last_block = le32_to_cpu( esb->s_blocks_count ) - 1; } else { last_block = first_block + ( esb->s_blocks_per_group - 1 ); } DBGPRINT( "<ME2FS>first = %lu, last = %lu\n", first_block, last_block ); ar_block = le32_to_cpu( gdesc->bg_block_bitmap ); if( ( ar_block < first_block ) || ( last_block < ar_block ) ) { ME2FS_ERROR( "<ME2FS>error : block num of block bitmap is " ); ME2FS_ERROR( "insanity [ group=%d, first=%lu, block=%lu, last=%lu ]\n", i, first_block, ar_block, last_block ); goto error_mount_phase2; } ar_block = le32_to_cpu( gdesc->bg_inode_bitmap ); if( ( ar_block < first_block ) || ( last_block < ar_block ) ) { ME2FS_ERROR( "<ME2FS>error : block num of inode bitmap is " ); ME2FS_ERROR( "insanity [ group=%d, first=%lu, block=%lu, last=%lu ]\n", i, first_block, ar_block, last_block ); goto error_mount_phase2; } ar_block = le32_to_cpu( gdesc->bg_inode_table ); if( ( ar_block < first_block ) || ( last_block < ar_block ) ) { ME2FS_ERROR( "<ME2FS>error : block num of inode table is " ); ME2FS_ERROR( "insanity [ group=%d, first=%lu, block=%lu, last=%lu ]\n", i, first_block, ar_block, last_block ); goto error_mount_phase2; } dbgPrintExt2Bgd( gdesc, i ); } /* ------------------------------------------------------------------------ */ /* initialize exclusive locks */ /* ------------------------------------------------------------------------ */ spin_lock_init( &msi->s_lock ); bgl_lock_init( msi->s_blockgroup_lock ); err = percpu_counter_init( &msi->s_freeblocks_counter, me2fsCountFreeBlocks( sb ) ); if( err ) { ME2FS_ERROR( "<ME2FS>cannot allocate memory for percpu counter" ); ME2FS_ERROR( "[s_freeblocks_counter]\n" ); goto error_mount_phase3; } err = percpu_counter_init( &msi->s_freeinodes_counter, me2fsCountFreeInodes( sb ) ); if( err ) { ME2FS_ERROR( "<ME2FS>cannot allocate memory for percpu counter" ); ME2FS_ERROR( "[s_freeinodes_counter]\n" ); goto error_mount_phase3; } err = percpu_counter_init( &msi->s_dirs_counter, me2fsCountDirectories( sb ) ); if( err ) { ME2FS_ERROR( "<ME2FS>cannot allocate memory for percpu counter" ); ME2FS_ERROR( "[s_dirs_counter]\n" ); goto error_mount_phase3; } /* ------------------------------------------------------------------------ */ /* set up vfs super block */ /* ------------------------------------------------------------------------ */ sb->s_op = &me2fs_super_ops; //sb->s_export_op = &me2fs_export_ops; //sb->s_xattr = me2fs_xattr_handler; sb->s_maxbytes = me2fsMaxFileSize( sb ); sb->s_max_links = ME2FS_LINK_MAX; DBGPRINT( "<ME2FS>max file size = %lld\n", sb->s_maxbytes ); root = me2fsGetVfsInode( sb, ME2FS_EXT2_ROOT_INO ); //root = iget_locked( sb, ME2FS_EXT2_ROOT_INO ); if( IS_ERR( root ) ) { ME2FS_ERROR( "<ME2FS>error : failed to get root inode\n" ); ret = PTR_ERR( root ); goto error_mount_phase3; } if( !S_ISDIR( root->i_mode ) ) { ME2FS_ERROR( "<ME2FS>root is not directory!!!!\n" ); } sb->s_root = d_make_root( root ); //sb->s_root = d_alloc_root( root_ino ); if( !sb->s_root ) { ME2FS_ERROR( "<ME2FS>error : failed to make root\n" ); ret = -ENOMEM; goto error_mount_phase3; } le16_add_cpu( &esb->s_mnt_count, 1 ); me2fsWriteSuper( sb ); DBGPRINT( "<ME2FS> me2fs is mounted !\n" ); return( 0 ); /* ------------------------------------------------------------------------ */ /* destroy percpu counter */ /* ------------------------------------------------------------------------ */ error_mount_phase3: percpu_counter_destroy( &msi->s_freeblocks_counter ); percpu_counter_destroy( &msi->s_freeinodes_counter ); percpu_counter_destroy( &msi->s_dirs_counter ); /* ------------------------------------------------------------------------ */ /* release buffer for group descriptors */ /* ------------------------------------------------------------------------ */ error_mount_phase2: for( i = 0 ; i < msi->s_gdb_count ; i++ ) { brelse( msi->s_group_desc[ i ] ); } kfree( msi->s_group_desc ); /* ------------------------------------------------------------------------ */ /* release buffer cache for read super block */ /* ------------------------------------------------------------------------ */ error_mount: brelse( bh ); /* ------------------------------------------------------------------------ */ /* release me2fs super block information */ /* ------------------------------------------------------------------------ */ error_read_sb: sb->s_fs_info = NULL; kfree( msi->s_blockgroup_lock ); kfree( msi ); return( ret ); }
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; err = -ENOMEM; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) goto failed; sbi->s_blockgroup_lock = kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); if (!sbi->s_blockgroup_lock) { kfree(sbi); goto failed; } sb->s_fs_info = sbi; sbi->s_sb_block = sb_block; spin_lock_init(&sbi->s_lock); /* * 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) { ext2_msg(sb, KERN_ERR, "error: unable to set blocksize"); 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))) { ext2_msg(sb, KERN_ERR, "error: unable to read superblock"); 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 = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); set_opt(sbi->s_mount_opt, RESERVATION); if (!parse_options((char *) data, sb)) goto failed_mount; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); sb->s_iflags |= SB_I_CGROUPWB; 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))) ext2_msg(sb, KERN_WARNING, "warning: feature flags set on rev 0 fs, " "running e2fsck is recommended"); /* * 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) { ext2_msg(sb, KERN_ERR, "error: couldn't mount because of " "unsupported optional features (%x)", 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))){ ext2_msg(sb, KERN_ERR, "error: couldn't mount RDWR because of " "unsupported optional features (%x)", le32_to_cpu(features)); goto failed_mount; } blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); if (sbi->s_mount_opt & EXT2_MOUNT_DAX) { struct blk_dax_ctl dax = { .sector = 0, .size = PAGE_SIZE, }; if (blocksize != PAGE_SIZE) { ext2_msg(sb, KERN_ERR, "error: unsupported blocksize for dax"); goto failed_mount; } err = bdev_direct_access(sb->s_bdev, &dax); if (err < 0) { switch (err) { case -EOPNOTSUPP: ext2_msg(sb, KERN_ERR, "error: device does not support dax"); break; case -EINVAL: ext2_msg(sb, KERN_ERR, "error: unaligned partition for dax"); break; default: ext2_msg(sb, KERN_ERR, "error: dax access failed (%d)", err); break; } 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)) { ext2_msg(sb, KERN_ERR, "error: bad blocksize %d", blocksize); 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) { ext2_msg(sb, KERN_ERR, "error: couldn't read" "superblock on 2nd try"); 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)) { ext2_msg(sb, KERN_ERR, "error: magic mismatch"); goto failed_mount; } } sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); sb->s_max_links = EXT2_LINK_MAX; 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)) { ext2_msg(sb, KERN_ERR, "error: unsupported inode size: %d", 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) ext2_msg(sb, KERN_ERR, "error: unsupported blocksize"); goto failed_mount; } if (sb->s_blocksize != sbi->s_frag_size) { ext2_msg(sb, KERN_ERR, "error: fragsize %lu != blocksize %lu" "(not supported yet)", sbi->s_frag_size, sb->s_blocksize); goto failed_mount; } if (sbi->s_blocks_per_group > sb->s_blocksize * 8) { ext2_msg(sb, KERN_ERR, "error: #blocks per group too big: %lu", sbi->s_blocks_per_group); goto failed_mount; } if (sbi->s_frags_per_group > sb->s_blocksize * 8) { ext2_msg(sb, KERN_ERR, "error: #fragments per group too big: %lu", sbi->s_frags_per_group); goto failed_mount; } if (sbi->s_inodes_per_group > sb->s_blocksize * 8) { ext2_msg(sb, KERN_ERR, "error: #inodes per group too big: %lu", 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) { ext2_msg(sb, KERN_ERR, "error: not enough memory"); 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) { ext2_msg(sb, KERN_ERR, "error: not enough memory"); 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]); ext2_msg(sb, KERN_ERR, "error: unable to read group descriptors"); goto failed_mount_group_desc; } } if (!ext2_check_descriptors (sb)) { ext2_msg(sb, KERN_ERR, "group descriptors corrupted"); 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), GFP_KERNEL); if (!err) { err = percpu_counter_init(&sbi->s_freeinodes_counter, ext2_count_free_inodes(sb), GFP_KERNEL); } if (!err) { err = percpu_counter_init(&sbi->s_dirs_counter, ext2_count_dirs(sb), GFP_KERNEL); } if (err) { ext2_msg(sb, KERN_ERR, "error: insufficient memory"); goto failed_mount3; } #ifdef CONFIG_EXT2_FS_XATTR sbi->s_mb_cache = ext2_xattr_create_cache(); if (!sbi->s_mb_cache) { ext2_msg(sb, KERN_ERR, "Failed to create an mb_cache"); goto failed_mount3; } #endif /* * 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; #ifdef CONFIG_QUOTA sb->dq_op = &dquot_operations; sb->s_qcop = &dquot_quotactl_ops; sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP; #endif 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); ext2_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck"); goto failed_mount3; } sb->s_root = d_make_root(root); if (!sb->s_root) { ext2_msg(sb, KERN_ERR, "error: get root inode failed"); ret = -ENOMEM; goto failed_mount3; } if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) ext2_msg(sb, KERN_WARNING, "warning: mounting ext3 filesystem as ext2"); if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY)) sb->s_flags |= MS_RDONLY; ext2_write_super(sb); return 0; cantfind_ext2: if (!silent) ext2_msg(sb, KERN_ERR, "error: can't find an ext2 filesystem on dev %s.", sb->s_id); goto failed_mount; failed_mount3: if (sbi->s_mb_cache) ext2_xattr_destroy_cache(sbi->s_mb_cache); 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); failed: return ret; } static void ext2_clear_super_error(struct super_block *sb) { struct buffer_head *sbh = EXT2_SB(sb)->s_sbh; if (buffer_write_io_error(sbh)) { /* * Oh, dear. A previous attempt to write the * superblock failed. This could happen because the * USB device was yanked out. Or it could happen to * be a transient write error and maybe the block will * be remapped. Nothing we can do but to retry the * write and hope for the best. */ ext2_msg(sb, KERN_ERR, "previous I/O error to superblock detected\n"); clear_buffer_write_io_error(sbh); set_buffer_uptodate(sbh); } } static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es, int wait) { ext2_clear_super_error(sb); spin_lock(&EXT2_SB(sb)->s_lock); es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); es->s_wtime = cpu_to_le32(get_seconds()); /* unlock before we do IO */ spin_unlock(&EXT2_SB(sb)->s_lock); mark_buffer_dirty(EXT2_SB(sb)->s_sbh); if (wait) sync_dirty_buffer(EXT2_SB(sb)->s_sbh); }