/* * pass it the bitmap lock in lock_bh if you have it. */ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, struct ocfs2_journal_handle *handle, struct ocfs2_alloc_context *ac) { int status = 0; u32 cluster_off, cluster_count; struct ocfs2_dinode *alloc = NULL; struct ocfs2_local_alloc *la; mlog_entry_void(); alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data; la = OCFS2_LOCAL_ALLOC(alloc); if (alloc->id1.bitmap1.i_total) mlog(0, "asking me to alloc a new window over a non-empty " "one\n"); mlog(0, "Allocating %u clusters for a new window.\n", ocfs2_local_alloc_window_bits(osb)); /* we used the generic suballoc reserve function, but we set * everything up nicely, so there's no reason why we can't use * the more specific cluster api to claim bits. */ status = ocfs2_claim_clusters(osb, handle, ac, ocfs2_local_alloc_window_bits(osb), &cluster_off, &cluster_count); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto bail; } la->la_bm_off = cpu_to_le32(cluster_off); alloc->id1.bitmap1.i_total = cpu_to_le32(cluster_count); /* just in case... In the future when we find space ourselves, * we don't have to get all contiguous -- but we'll have to * set all previously used bits in bitmap and update * la_bits_set before setting the bits in the main bitmap. */ alloc->id1.bitmap1.i_used = 0; memset(OCFS2_LOCAL_ALLOC(alloc)->la_bitmap, 0, le16_to_cpu(la->la_size)); mlog(0, "New window allocated:\n"); mlog(0, "window la_bm_off = %u\n", OCFS2_LOCAL_ALLOC(alloc)->la_bm_off); mlog(0, "window bits = %u\n", le32_to_cpu(alloc->id1.bitmap1.i_total)); bail: mlog_exit(status); return status; }
static struct buffer_head * ocfs2_block_group_alloc_contig(struct ocfs2_super *osb, handle_t *handle, struct inode *alloc_inode, struct ocfs2_alloc_context *ac, struct ocfs2_chain_list *cl) { int status; u32 bit_off, num_bits; u64 bg_blkno; struct buffer_head *bg_bh; unsigned int alloc_rec = ocfs2_find_smallest_chain(cl); status = ocfs2_claim_clusters(handle, ac, le16_to_cpu(cl->cl_cpg), &bit_off, &num_bits); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto bail; } /* setup the group */ bg_blkno = ocfs2_clusters_to_blocks(osb->sb, bit_off); trace_ocfs2_block_group_alloc_contig( (unsigned long long)bg_blkno, alloc_rec); bg_bh = sb_getblk(osb->sb, bg_blkno); if (!bg_bh) { status = -EIO; mlog_errno(status); goto bail; } ocfs2_set_new_buffer_uptodate(INODE_CACHE(alloc_inode), bg_bh); status = ocfs2_block_group_fill(handle, alloc_inode, bg_bh, bg_blkno, num_bits, alloc_rec, cl); if (status < 0) { brelse(bg_bh); mlog_errno(status); } bail: return status ? ERR_PTR(status) : bg_bh; }
static int ocfs2_block_group_claim_bits(struct ocfs2_super *osb, handle_t *handle, struct ocfs2_alloc_context *ac, unsigned int min_bits, u32 *bit_off, u32 *num_bits) { int status = 0; while (min_bits) { status = ocfs2_claim_clusters(handle, ac, min_bits, bit_off, num_bits); if (status != -ENOSPC) break; min_bits >>= 1; } return status; }
/* * extend allocation only here. * we'll update all the disk stuff, and oip->alloc_size * * expect stuff to be locked, a transaction started and enough data / * metadata reservations in the contexts. * * Will return -EAGAIN, and a reason if a restart is needed. * If passed in, *reason will always be set, even in error. */ int ocfs2_do_extend_allocation(struct ocfs2_super *osb, struct inode *inode, u32 *logical_offset, u32 clusters_to_add, struct buffer_head *fe_bh, handle_t *handle, struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret) { int status = 0; int free_extents; struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data; enum ocfs2_alloc_restarted reason = RESTART_NONE; u32 bit_off, num_bits; u64 block; BUG_ON(!clusters_to_add); free_extents = ocfs2_num_free_extents(osb, inode, fe); if (free_extents < 0) { status = free_extents; mlog_errno(status); goto leave; } /* there are two cases which could cause us to EAGAIN in the * we-need-more-metadata case: * 1) we haven't reserved *any* * 2) we are so fragmented, we've needed to add metadata too * many times. */ if (!free_extents && !meta_ac) { mlog(0, "we haven't reserved any metadata!\n"); status = -EAGAIN; reason = RESTART_META; goto leave; } else if ((!free_extents) && (ocfs2_alloc_context_bits_left(meta_ac) < ocfs2_extend_meta_needed(fe))) { mlog(0, "filesystem is really fragmented...\n"); status = -EAGAIN; reason = RESTART_META; goto leave; } status = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &num_bits); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto leave; } BUG_ON(num_bits > clusters_to_add); /* reserve our write early -- insert_extent may update the inode */ status = ocfs2_journal_access(handle, inode, fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto leave; } block = ocfs2_clusters_to_blocks(osb->sb, bit_off); mlog(0, "Allocating %u clusters at block %u for inode %llu\n", num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); status = ocfs2_insert_extent(osb, handle, inode, fe_bh, *logical_offset, block, num_bits, meta_ac); if (status < 0) { mlog_errno(status); goto leave; } status = ocfs2_journal_dirty(handle, fe_bh); if (status < 0) { mlog_errno(status); goto leave; } clusters_to_add -= num_bits; *logical_offset += num_bits; if (clusters_to_add) { mlog(0, "need to alloc once more, clusters = %u, wanted = " "%u\n", fe->i_clusters, clusters_to_add); status = -EAGAIN; reason = RESTART_TRANS; } leave: mlog_exit(status); if (reason_ret) *reason_ret = reason; return status; }
/* * We expect the block group allocator to already be locked. */ static int ocfs2_block_group_alloc(struct ocfs2_super *osb, struct inode *alloc_inode, struct buffer_head *bh) { int status, credits; struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data; struct ocfs2_chain_list *cl; struct ocfs2_alloc_context *ac = NULL; handle_t *handle = NULL; u32 bit_off, num_bits; u16 alloc_rec; u64 bg_blkno; struct buffer_head *bg_bh = NULL; struct ocfs2_group_desc *bg; BUG_ON(ocfs2_is_cluster_bitmap(alloc_inode)); mlog_entry_void(); cl = &fe->id2.i_chain; status = ocfs2_reserve_clusters(osb, le16_to_cpu(cl->cl_cpg), &ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto bail; } credits = ocfs2_calc_group_alloc_credits(osb->sb, le16_to_cpu(cl->cl_cpg)); handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; mlog_errno(status); goto bail; } status = ocfs2_claim_clusters(osb, handle, ac, le16_to_cpu(cl->cl_cpg), &bit_off, &num_bits); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); goto bail; } alloc_rec = ocfs2_find_smallest_chain(cl); /* setup the group */ bg_blkno = ocfs2_clusters_to_blocks(osb->sb, bit_off); mlog(0, "new descriptor, record %u, at block %llu\n", alloc_rec, (unsigned long long)bg_blkno); bg_bh = sb_getblk(osb->sb, bg_blkno); if (!bg_bh) { status = -EIO; mlog_errno(status); goto bail; } ocfs2_set_new_buffer_uptodate(alloc_inode, bg_bh); status = ocfs2_block_group_fill(handle, alloc_inode, bg_bh, bg_blkno, alloc_rec, cl); if (status < 0) { mlog_errno(status); goto bail; } bg = (struct ocfs2_group_desc *) bg_bh->b_data; status = ocfs2_journal_access(handle, alloc_inode, bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } le32_add_cpu(&cl->cl_recs[alloc_rec].c_free, le16_to_cpu(bg->bg_free_bits_count)); le32_add_cpu(&cl->cl_recs[alloc_rec].c_total, le16_to_cpu(bg->bg_bits)); cl->cl_recs[alloc_rec].c_blkno = cpu_to_le64(bg_blkno); if (le16_to_cpu(cl->cl_next_free_rec) < le16_to_cpu(cl->cl_count)) le16_add_cpu(&cl->cl_next_free_rec, 1); le32_add_cpu(&fe->id1.bitmap1.i_used, le16_to_cpu(bg->bg_bits) - le16_to_cpu(bg->bg_free_bits_count)); le32_add_cpu(&fe->id1.bitmap1.i_total, le16_to_cpu(bg->bg_bits)); le32_add_cpu(&fe->i_clusters, le16_to_cpu(cl->cl_cpg)); status = ocfs2_journal_dirty(handle, bh); if (status < 0) { mlog_errno(status); goto bail; } spin_lock(&OCFS2_I(alloc_inode)->ip_lock); OCFS2_I(alloc_inode)->ip_clusters = le32_to_cpu(fe->i_clusters); fe->i_size = cpu_to_le64(ocfs2_clusters_to_bytes(alloc_inode->i_sb, le32_to_cpu(fe->i_clusters))); spin_unlock(&OCFS2_I(alloc_inode)->ip_lock); i_size_write(alloc_inode, le64_to_cpu(fe->i_size)); alloc_inode->i_blocks = ocfs2_inode_sector_count(alloc_inode); status = 0; bail: if (handle) ocfs2_commit_trans(osb, handle); if (ac) ocfs2_free_alloc_context(ac); if (bg_bh) brelse(bg_bh); mlog_exit(status); return status; }