⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rgrp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	sdp->sd_rindex_vn = ip->i_gl->gl_vn;	return 0;}/** * gfs2_ri_update_special - Pull in a new resource index from the disk * * This is a special version that's safe to call from gfs2_inplace_reserve_i. * In this case we know that we don't have any resource groups in memory yet. * * @ip: pointer to the rindex inode * * Returns: 0 on successful update, error code otherwise */static int gfs2_ri_update_special(struct gfs2_inode *ip){	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	struct inode *inode = &ip->i_inode;	struct file_ra_state ra_state;	int error;	file_ra_state_init(&ra_state, inode->i_mapping);	for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) {		/* Ignore partials */		if ((sdp->sd_rgrps + 1) * sizeof(struct gfs2_rindex) >		    ip->i_di.di_size)			break;		error = read_rindex_entry(ip, &ra_state);		if (error) {			clear_rgrpdi(sdp);			return error;		}	}	sdp->sd_rindex_vn = ip->i_gl->gl_vn;	return 0;}/** * gfs2_rindex_hold - Grab a lock on the rindex * @sdp: The GFS2 superblock * @ri_gh: the glock holder * * We grab a lock on the rindex inode to make sure that it doesn't * change whilst we are performing an operation. We keep this lock * for quite long periods of time compared to other locks. This * doesn't matter, since it is shared and it is very, very rarely * accessed in the exclusive mode (i.e. only when expanding the filesystem). * * This makes sure that we're using the latest copy of the resource index * special file, which might have been updated if someone expanded the * filesystem (via gfs2_grow utility), which adds new resource groups. * * Returns: 0 on success, error code otherwise */int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh){	struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);	struct gfs2_glock *gl = ip->i_gl;	int error;	error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh);	if (error)		return error;	/* Read new copy from disk if we don't have the latest */	if (sdp->sd_rindex_vn != gl->gl_vn) {		mutex_lock(&sdp->sd_rindex_mutex);		if (sdp->sd_rindex_vn != gl->gl_vn) {			error = gfs2_ri_update(ip);			if (error)				gfs2_glock_dq_uninit(ri_gh);		}		mutex_unlock(&sdp->sd_rindex_mutex);	}	return error;}static void gfs2_rgrp_in(struct gfs2_rgrp_host *rg, const void *buf){	const struct gfs2_rgrp *str = buf;	rg->rg_flags = be32_to_cpu(str->rg_flags);	rg->rg_free = be32_to_cpu(str->rg_free);	rg->rg_dinodes = be32_to_cpu(str->rg_dinodes);	rg->rg_igeneration = be64_to_cpu(str->rg_igeneration);}static void gfs2_rgrp_out(const struct gfs2_rgrp_host *rg, void *buf){	struct gfs2_rgrp *str = buf;	str->rg_flags = cpu_to_be32(rg->rg_flags);	str->rg_free = cpu_to_be32(rg->rg_free);	str->rg_dinodes = cpu_to_be32(rg->rg_dinodes);	str->__pad = cpu_to_be32(0);	str->rg_igeneration = cpu_to_be64(rg->rg_igeneration);	memset(&str->rg_reserved, 0, sizeof(str->rg_reserved));}/** * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps * @rgd: the struct gfs2_rgrpd describing the RG to read in * * Read in all of a Resource Group's header and bitmap blocks. * Caller must eventually call gfs2_rgrp_relse() to free the bitmaps. * * Returns: errno */int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd){	struct gfs2_sbd *sdp = rgd->rd_sbd;	struct gfs2_glock *gl = rgd->rd_gl;	unsigned int length = rgd->rd_length;	struct gfs2_bitmap *bi;	unsigned int x, y;	int error;	mutex_lock(&rgd->rd_mutex);	spin_lock(&sdp->sd_rindex_spin);	if (rgd->rd_bh_count) {		rgd->rd_bh_count++;		spin_unlock(&sdp->sd_rindex_spin);		mutex_unlock(&rgd->rd_mutex);		return 0;	}	spin_unlock(&sdp->sd_rindex_spin);	for (x = 0; x < length; x++) {		bi = rgd->rd_bits + x;		error = gfs2_meta_read(gl, rgd->rd_addr + x, 0, &bi->bi_bh);		if (error)			goto fail;	}	for (y = length; y--;) {		bi = rgd->rd_bits + y;		error = gfs2_meta_wait(sdp, bi->bi_bh);		if (error)			goto fail;		if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB :					      GFS2_METATYPE_RG)) {			error = -EIO;			goto fail;		}	}	if (rgd->rd_rg_vn != gl->gl_vn) {		gfs2_rgrp_in(&rgd->rd_rg, (rgd->rd_bits[0].bi_bh)->b_data);		rgd->rd_rg_vn = gl->gl_vn;	}	spin_lock(&sdp->sd_rindex_spin);	rgd->rd_free_clone = rgd->rd_rg.rg_free;	rgd->rd_bh_count++;	spin_unlock(&sdp->sd_rindex_spin);	mutex_unlock(&rgd->rd_mutex);	return 0;fail:	while (x--) {		bi = rgd->rd_bits + x;		brelse(bi->bi_bh);		bi->bi_bh = NULL;		gfs2_assert_warn(sdp, !bi->bi_clone);	}	mutex_unlock(&rgd->rd_mutex);	return error;}void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd){	struct gfs2_sbd *sdp = rgd->rd_sbd;	spin_lock(&sdp->sd_rindex_spin);	gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);	rgd->rd_bh_count++;	spin_unlock(&sdp->sd_rindex_spin);}/** * gfs2_rgrp_bh_put - Release RG bitmaps read in with gfs2_rgrp_bh_get() * @rgd: the struct gfs2_rgrpd describing the RG to read in * */void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd){	struct gfs2_sbd *sdp = rgd->rd_sbd;	int x, length = rgd->rd_length;	spin_lock(&sdp->sd_rindex_spin);	gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);	if (--rgd->rd_bh_count) {		spin_unlock(&sdp->sd_rindex_spin);		return;	}	for (x = 0; x < length; x++) {		struct gfs2_bitmap *bi = rgd->rd_bits + x;		kfree(bi->bi_clone);		bi->bi_clone = NULL;		brelse(bi->bi_bh);		bi->bi_bh = NULL;	}	spin_unlock(&sdp->sd_rindex_spin);}void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd){	struct gfs2_sbd *sdp = rgd->rd_sbd;	unsigned int length = rgd->rd_length;	unsigned int x;	for (x = 0; x < length; x++) {		struct gfs2_bitmap *bi = rgd->rd_bits + x;		if (!bi->bi_clone)			continue;		memcpy(bi->bi_clone + bi->bi_offset,		       bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);	}	spin_lock(&sdp->sd_rindex_spin);	rgd->rd_free_clone = rgd->rd_rg.rg_free;	spin_unlock(&sdp->sd_rindex_spin);}/** * gfs2_alloc_get - get the struct gfs2_alloc structure for an inode * @ip: the incore GFS2 inode structure * * Returns: the struct gfs2_alloc */struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip){	struct gfs2_alloc *al = &ip->i_alloc;	/* FIXME: Should assert that the correct locks are held here... */	memset(al, 0, sizeof(*al));	return al;}/** * try_rgrp_fit - See if a given reservation will fit in a given RG * @rgd: the RG data * @al: the struct gfs2_alloc structure describing the reservation * * If there's room for the requested blocks to be allocated from the RG: *   Sets the $al_rgd field in @al. * * Returns: 1 on success (it fits), 0 on failure (it doesn't fit) */static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al){	struct gfs2_sbd *sdp = rgd->rd_sbd;	int ret = 0;	if (rgd->rd_rg.rg_flags & GFS2_RGF_NOALLOC)		return 0;	spin_lock(&sdp->sd_rindex_spin);	if (rgd->rd_free_clone >= al->al_requested) {		al->al_rgd = rgd;		ret = 1;	}	spin_unlock(&sdp->sd_rindex_spin);	return ret;}/** * try_rgrp_unlink - Look for any unlinked, allocated, but unused inodes * @rgd: The rgrp * * Returns: The inode, if one has been found */static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked){	struct inode *inode;	u32 goal = 0, block;	u64 no_addr;	struct gfs2_sbd *sdp = rgd->rd_sbd;	for(;;) {		if (goal >= rgd->rd_data)			break;		down_write(&sdp->sd_log_flush_lock);		block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,				     GFS2_BLKST_UNLINKED);		up_write(&sdp->sd_log_flush_lock);		if (block == BFITNOENT)			break;		/* rgblk_search can return a block < goal, so we need to		   keep it marching forward. */		no_addr = block + rgd->rd_data0;		goal++;		if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked)			continue;		*last_unlinked = no_addr;		inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN,					  no_addr, -1, 1);		if (!IS_ERR(inode))			return inode;	}	rgd->rd_flags &= ~GFS2_RDF_CHECK;	return NULL;}/** * recent_rgrp_first - get first RG from "recent" list * @sdp: The GFS2 superblock * @rglast: address of the rgrp used last * * Returns: The first rgrp in the recent list */static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp,					    u64 rglast){	struct gfs2_rgrpd *rgd = NULL;	spin_lock(&sdp->sd_rindex_spin);	if (list_empty(&sdp->sd_rindex_recent_list))		goto out;	if (!rglast)		goto first;	list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {		if (rgd->rd_addr == rglast)			goto out;	}first:	rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd,			 rd_recent);out:	spin_unlock(&sdp->sd_rindex_spin);	return rgd;}/** * recent_rgrp_next - get next RG from "recent" list * @cur_rgd: current rgrp * @remove: * * Returns: The next rgrp in the recent list */static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd,					   int remove){	struct gfs2_sbd *sdp = cur_rgd->rd_sbd;	struct list_head *head;	struct gfs2_rgrpd *rgd;	spin_lock(&sdp->sd_rindex_spin);	head = &sdp->sd_rindex_recent_list;	list_for_each_entry(rgd, head, rd_recent) {		if (rgd == cur_rgd) {			if (cur_rgd->rd_recent.next != head)				rgd = list_entry(cur_rgd->rd_recent.next,						 struct gfs2_rgrpd, rd_recent);			else				rgd = NULL;			if (remove)				list_del(&cur_rgd->rd_recent);			goto out;		}	}	rgd = NULL;	if (!list_empty(head))		rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent);out:	spin_unlock(&sdp->sd_rindex_spin);	return rgd;}/** * recent_rgrp_add - add an RG to tail of "recent" list * @new_rgd: The rgrp to add * */static void recent_rgrp_add(struct gfs2_rgrpd *new_rgd){	struct gfs2_sbd *sdp = new_rgd->rd_sbd;	struct gfs2_rgrpd *rgd;	unsigned int count = 0;	unsigned int max = sdp->sd_rgrps / gfs2_jindex_size(sdp);	spin_lock(&sdp->sd_rindex_spin);	list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {		if (rgd == new_rgd)			goto out;		if (++count >= max)			goto out;	}	list_add_tail(&new_rgd->rd_recent, &sdp->sd_rindex_recent_list);out:	spin_unlock(&sdp->sd_rindex_spin);}/** * forward_rgrp_get - get an rgrp to try next from full list * @sdp: The GFS2 superblock * * Returns: The rgrp to try next */static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp){	struct gfs2_rgrpd *rgd;	unsigned int journals = gfs2_jindex_size(sdp);	unsigned int rg = 0, x;	spin_lock(&sdp->sd_rindex_spin);	rgd = sdp->sd_rindex_forward;	if (!rgd) {		if (sdp->sd_rgrps >= journals)			rg = sdp->sd_rgrps * sdp->sd_jdesc->jd_jid / journals;		for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); x < rg;		     x++, rgd = gfs2_rgrpd_get_next(rgd))			/* Do Nothing */;		sdp->sd_rindex_forward = rgd;	}	spin_unlock(&sdp->sd_rindex_spin);	return rgd;}/** * forward_rgrp_set - set the forward rgrp pointer * @sdp: the filesystem * @rgd: The new forward rgrp * */static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd){	spin_lock(&sdp->sd_rindex_spin);	sdp->sd_rindex_forward = rgd;	spin_unlock(&sdp->sd_rindex_spin);}/** * get_local_rgrp - Choose and lock a rgrp for allocation * @ip: the inode to reserve space for * @rgp: the chosen and locked rgrp * * Try to acquire rgrp in way which avoids contending with others. * * Returns: errno */static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked){	struct inode *inode = NULL;	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	struct gfs2_rgrpd *rgd, *begin = NULL;	struct gfs2_alloc *al = &ip->i_alloc;	int flags = LM_FLAG_TRY;	int skipped = 0;	int loops = 0;	int error;	/* Try recently successful rgrps */	rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);	while (rgd) {		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,					   LM_FLAG_TRY, &al->al_rgd_gh);		switch (error) {		case 0:			if (try_rgrp_fit(rgd, al))				goto out;			if (rgd->rd_flags & GFS2_RDF_CHECK)				inode = try_rgrp_unlink(rgd, last_unlinked);			gfs2_glock_dq_uninit(&al->al_rgd_gh);			if (inode)				return inode;			rgd = recent_rgrp_next(rgd, 1);			break;		case GLR_TRYFAILED:			rgd = recent_rgrp_next(rgd, 0);			break;		default:			return ERR_PTR(error);		}	}	/* Go through full list of rgrps */	begin = rgd = forward_rgrp_get(sdp);	for (;;) {		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,					  &al->al_rgd_gh);		switch (error) {		case 0:			if (try_rgrp_fit(rgd, al))				goto out;			if (rgd->rd_flags & GFS2_RDF_CHECK)				inode = try_rgrp_unlink(rgd, last_unlinked);			gfs2_glock_dq_uninit(&al->al_rgd_gh);			if (inode)				return inode;			break;		case GLR_TRYFAILED:			skipped++;			break;		default:			return ERR_PTR(error);		}		rgd = gfs2_rgrpd_get_next(rgd);		if (!rgd)			rgd = gfs2_rgrpd_get_first(sdp);		if (rgd == begin) {			if (++loops >= 3)				return ERR_PTR(-ENOSPC);			if (!skipped)				loops++;			flags = 0;			if (loops == 2)				gfs2_log_flush(sdp, NULL);		}	}out:	ip->i_last_rg_alloc = rgd->rd_addr;	if (begin) {		recent_rgrp_add(rgd);		rgd = gfs2_rgrpd_get_next(rgd);		if (!rgd)			rgd = gfs2_rgrpd_get_first(sdp);		forward_rgrp_set(sdp, rgd);	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -