static int ocfs2_check_new_group(struct inode *inode, struct ocfs2_dinode *di, struct ocfs2_new_group_input *input, struct buffer_head *group_bh) { int ret; struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)group_bh->b_data; u16 cl_bpc = le16_to_cpu(di->id2.i_chain.cl_bpc); ret = ocfs2_check_group_descriptor(inode->i_sb, di, group_bh); if (ret) goto out; ret = -EINVAL; if (le16_to_cpu(gd->bg_chain) != input->chain) mlog(ML_ERROR, "Group descriptor # %llu has bad chain %u " "while input has %u set.\n", (unsigned long long)le64_to_cpu(gd->bg_blkno), le16_to_cpu(gd->bg_chain), input->chain); else if (le16_to_cpu(gd->bg_bits) != input->clusters * cl_bpc) mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but " "input has %u clusters set\n", (unsigned long long)le64_to_cpu(gd->bg_blkno), le16_to_cpu(gd->bg_bits), input->clusters); else if (le16_to_cpu(gd->bg_free_bits_count) != input->frees * cl_bpc) mlog(ML_ERROR, "Group descriptor # %llu has free bit count %u " "but it should have %u set\n", (unsigned long long)le64_to_cpu(gd->bg_blkno), le16_to_cpu(gd->bg_bits), input->frees * cl_bpc); else ret = 0; out: return ret; }
/* * expects the suballoc inode to already be locked. */ static int ocfs2_free_suballoc_bits(handle_t *handle, struct inode *alloc_inode, struct buffer_head *alloc_bh, unsigned int start_bit, u64 bg_blkno, unsigned int count) { int status = 0; u32 tmp_used; struct ocfs2_super *osb = OCFS2_SB(alloc_inode->i_sb); struct ocfs2_dinode *fe = (struct ocfs2_dinode *) alloc_bh->b_data; struct ocfs2_chain_list *cl = &fe->id2.i_chain; struct buffer_head *group_bh = NULL; struct ocfs2_group_desc *group; mlog_entry_void(); if (!OCFS2_IS_VALID_DINODE(fe)) { OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe); status = -EIO; goto bail; } BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl)); mlog(0, "%llu: freeing %u bits from group %llu, starting at %u\n", (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno, count, (unsigned long long)bg_blkno, start_bit); status = ocfs2_read_block(osb, bg_blkno, &group_bh, OCFS2_BH_CACHED, alloc_inode); if (status < 0) { mlog_errno(status); goto bail; } group = (struct ocfs2_group_desc *) group_bh->b_data; status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, group); if (status) { mlog_errno(status); goto bail; } BUG_ON((count + start_bit) > le16_to_cpu(group->bg_bits)); status = ocfs2_block_group_clear_bits(handle, alloc_inode, group, group_bh, start_bit, count); if (status < 0) { mlog_errno(status); goto bail; } status = ocfs2_journal_access(handle, alloc_inode, alloc_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } le32_add_cpu(&cl->cl_recs[le16_to_cpu(group->bg_chain)].c_free, count); tmp_used = le32_to_cpu(fe->id1.bitmap1.i_used); fe->id1.bitmap1.i_used = cpu_to_le32(tmp_used - count); status = ocfs2_journal_dirty(handle, alloc_bh); if (status < 0) { mlog_errno(status); goto bail; } bail: if (group_bh) brelse(group_bh); mlog_exit(status); return status; }
/* * Extend the filesystem to the new number of clusters specified. This entry * point is only used to extend the current filesystem to the end of the last * existing group. */ int ocfs2_group_extend(struct inode * inode, int new_clusters) { int ret; handle_t *handle; struct buffer_head *main_bm_bh = NULL; struct buffer_head *group_bh = NULL; struct inode *main_bm_inode = NULL; struct ocfs2_dinode *fe = NULL; struct ocfs2_group_desc *group = NULL; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); u16 cl_bpc; u32 first_new_cluster; u64 lgd_blkno; mlog_entry_void(); if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) return -EROFS; if (new_clusters < 0) return -EINVAL; else if (new_clusters == 0) return 0; main_bm_inode = ocfs2_get_system_file_inode(osb, GLOBAL_BITMAP_SYSTEM_INODE, OCFS2_INVALID_SLOT); if (!main_bm_inode) { ret = -EINVAL; mlog_errno(ret); goto out; } mutex_lock(&main_bm_inode->i_mutex); ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1); if (ret < 0) { mlog_errno(ret); goto out_mutex; } fe = (struct ocfs2_dinode *)main_bm_bh->b_data; if (le16_to_cpu(fe->id2.i_chain.cl_cpg) != ocfs2_group_bitmap_size(osb->sb) * 8) { mlog(ML_ERROR, "The disk is too old and small. " "Force to do offline resize."); ret = -EINVAL; goto out_unlock; } if (!OCFS2_IS_VALID_DINODE(fe)) { OCFS2_RO_ON_INVALID_DINODE(main_bm_inode->i_sb, fe); ret = -EIO; goto out_unlock; } first_new_cluster = le32_to_cpu(fe->i_clusters); lgd_blkno = ocfs2_which_cluster_group(main_bm_inode, first_new_cluster - 1); ret = ocfs2_read_block(main_bm_inode, lgd_blkno, &group_bh); if (ret < 0) { mlog_errno(ret); goto out_unlock; } group = (struct ocfs2_group_desc *)group_bh->b_data; ret = ocfs2_check_group_descriptor(inode->i_sb, fe, group); if (ret) { mlog_errno(ret); goto out_unlock; } cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); if (le16_to_cpu(group->bg_bits) / cl_bpc + new_clusters > le16_to_cpu(fe->id2.i_chain.cl_cpg)) { ret = -EINVAL; goto out_unlock; } mlog(0, "extend the last group at %llu, new clusters = %d\n", (unsigned long long)le64_to_cpu(group->bg_blkno), new_clusters); handle = ocfs2_start_trans(osb, OCFS2_GROUP_EXTEND_CREDITS); if (IS_ERR(handle)) { mlog_errno(PTR_ERR(handle)); ret = -EINVAL; goto out_unlock; } /* update the last group descriptor and inode. */ ret = ocfs2_update_last_group_and_inode(handle, main_bm_inode, main_bm_bh, group_bh, first_new_cluster, new_clusters); if (ret) { mlog_errno(ret); goto out_commit; } ocfs2_update_super_and_backups(main_bm_inode, new_clusters); out_commit: ocfs2_commit_trans(osb, handle); out_unlock: brelse(group_bh); brelse(main_bm_bh); ocfs2_inode_unlock(main_bm_inode, 1); out_mutex: mutex_unlock(&main_bm_inode->i_mutex); iput(main_bm_inode); out: mlog_exit_void(); return ret; }
static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, handle_t *handle, u32 bits_wanted, u32 min_bits, u16 *bit_off, unsigned int *num_bits, u64 *bg_blkno, u16 *bits_left) { int status; u16 chain, tmp_bits; u32 tmp_used; u64 next_group; struct inode *alloc_inode = ac->ac_inode; struct buffer_head *group_bh = NULL; struct buffer_head *prev_group_bh = NULL; struct ocfs2_dinode *fe = (struct ocfs2_dinode *) ac->ac_bh->b_data; struct ocfs2_chain_list *cl = (struct ocfs2_chain_list *) &fe->id2.i_chain; struct ocfs2_group_desc *bg; chain = ac->ac_chain; mlog(0, "trying to alloc %u bits from chain %u, inode %llu\n", bits_wanted, chain, (unsigned long long)OCFS2_I(alloc_inode)->ip_blkno); status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), le64_to_cpu(cl->cl_recs[chain].c_blkno), &group_bh, OCFS2_BH_CACHED, alloc_inode); if (status < 0) { mlog_errno(status); goto bail; } bg = (struct ocfs2_group_desc *) group_bh->b_data; status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, bg); if (status) { mlog_errno(status); goto bail; } status = -ENOSPC; /* for now, the chain search is a bit simplistic. We just use * the 1st group with any empty bits. */ while ((status = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, min_bits, bit_off, &tmp_bits)) == -ENOSPC) { if (!bg->bg_next_group) break; if (prev_group_bh) { brelse(prev_group_bh); prev_group_bh = NULL; } next_group = le64_to_cpu(bg->bg_next_group); prev_group_bh = group_bh; group_bh = NULL; status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), next_group, &group_bh, OCFS2_BH_CACHED, alloc_inode); if (status < 0) { mlog_errno(status); goto bail; } bg = (struct ocfs2_group_desc *) group_bh->b_data; status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, bg); if (status) { mlog_errno(status); goto bail; } } if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto bail; } mlog(0, "alloc succeeds: we give %u bits from block group %llu\n", tmp_bits, (unsigned long long)le64_to_cpu(bg->bg_blkno)); *num_bits = tmp_bits; BUG_ON(*num_bits == 0); /* * Keep track of previous block descriptor read. When * we find a target, if we have read more than X * number of descriptors, and the target is reasonably * empty, relink him to top of his chain. * * We've read 0 extra blocks and only send one more to * the transaction, yet the next guy to search has a * much easier time. * * Do this *after* figuring out how many bits we're taking out * of our target group. */ if (ac->ac_allow_chain_relink && (prev_group_bh) && (ocfs2_block_group_reasonably_empty(bg, *num_bits))) { status = ocfs2_relink_block_group(handle, alloc_inode, ac->ac_bh, group_bh, prev_group_bh, chain); if (status < 0) { mlog_errno(status); goto bail; } } /* Ok, claim our bits now: set the info on dinode, chainlist * and then the group */ status = ocfs2_journal_access(handle, alloc_inode, ac->ac_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } tmp_used = le32_to_cpu(fe->id1.bitmap1.i_used); fe->id1.bitmap1.i_used = cpu_to_le32(*num_bits + tmp_used); le32_add_cpu(&cl->cl_recs[chain].c_free, -(*num_bits)); status = ocfs2_journal_dirty(handle, ac->ac_bh); if (status < 0) { mlog_errno(status); goto bail; } status = ocfs2_block_group_set_bits(handle, alloc_inode, bg, group_bh, *bit_off, *num_bits); if (status < 0) { mlog_errno(status); goto bail; } mlog(0, "Allocated %u bits from suballocator %llu\n", *num_bits, (unsigned long long)le64_to_cpu(fe->i_blkno)); *bg_blkno = le64_to_cpu(bg->bg_blkno); *bits_left = le16_to_cpu(bg->bg_free_bits_count); bail: if (group_bh) brelse(group_bh); if (prev_group_bh) brelse(prev_group_bh); mlog_exit(status); return status; }