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

📄 bmap.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (height < ip->i_di.di_height - 1)		for (; top < bottom; top++, first = 0) {			if (!*top)				continue;			bn = be64_to_cpu(*top);			error = recursive_scan(ip, dibh, mp, height + 1, bn,					       first, bc, data);			if (error)				break;		}out:	brelse(bh);	return error;}/** * do_strip - Look for a layer a particular layer of the file and strip it off * @ip: the inode * @dibh: the dinode buffer * @bh: A buffer of pointers * @top: The first pointer in the buffer * @bottom: One more than the last pointer * @height: the height this buffer is at * @data: a pointer to a struct strip_mine * * Returns: errno */static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,		    struct buffer_head *bh, __be64 *top, __be64 *bottom,		    unsigned int height, void *data){	struct strip_mine *sm = data;	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	struct gfs2_rgrp_list rlist;	u64 bn, bstart;	u32 blen;	__be64 *p;	unsigned int rg_blocks = 0;	int metadata;	unsigned int revokes = 0;	int x;	int error;	if (!*top)		sm->sm_first = 0;	if (height != sm->sm_height)		return 0;	if (sm->sm_first) {		top++;		sm->sm_first = 0;	}	metadata = (height != ip->i_di.di_height - 1);	if (metadata)		revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;	error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh);	if (error)		return error;	memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));	bstart = 0;	blen = 0;	for (p = top; p < bottom; p++) {		if (!*p)			continue;		bn = be64_to_cpu(*p);		if (bstart + blen == bn)			blen++;		else {			if (bstart)				gfs2_rlist_add(sdp, &rlist, bstart);			bstart = bn;			blen = 1;		}	}	if (bstart)		gfs2_rlist_add(sdp, &rlist, bstart);	else		goto out; /* Nothing to do */	gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);	for (x = 0; x < rlist.rl_rgrps; x++) {		struct gfs2_rgrpd *rgd;		rgd = rlist.rl_ghs[x].gh_gl->gl_object;		rg_blocks += rgd->rd_length;	}	error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);	if (error)		goto out_rlist;	error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +				 RES_INDIRECT + RES_STATFS + RES_QUOTA,				 revokes);	if (error)		goto out_rg_gunlock;	down_write(&ip->i_rw_mutex);	gfs2_trans_add_bh(ip->i_gl, dibh, 1);	gfs2_trans_add_bh(ip->i_gl, bh, 1);	bstart = 0;	blen = 0;	for (p = top; p < bottom; p++) {		if (!*p)			continue;		bn = be64_to_cpu(*p);		if (bstart + blen == bn)			blen++;		else {			if (bstart) {				if (metadata)					gfs2_free_meta(ip, bstart, blen);				else					gfs2_free_data(ip, bstart, blen);			}			bstart = bn;			blen = 1;		}		*p = 0;		if (!ip->i_di.di_blocks)			gfs2_consist_inode(ip);		ip->i_di.di_blocks--;		gfs2_set_inode_blocks(&ip->i_inode);	}	if (bstart) {		if (metadata)			gfs2_free_meta(ip, bstart, blen);		else			gfs2_free_data(ip, bstart, blen);	}	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;	gfs2_dinode_out(ip, dibh->b_data);	up_write(&ip->i_rw_mutex);	gfs2_trans_end(sdp);out_rg_gunlock:	gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);out_rlist:	gfs2_rlist_free(&rlist);out:	gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh);	return error;}/** * do_grow - Make a file look bigger than it is * @ip: the inode * @size: the size to set the file to * * Called with an exclusive lock on @ip. * * Returns: errno */static int do_grow(struct gfs2_inode *ip, u64 size){	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	struct gfs2_alloc *al;	struct buffer_head *dibh;	unsigned int h;	int error;	al = gfs2_alloc_get(ip);	error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);	if (error)		goto out;	error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid);	if (error)		goto out_gunlock_q;	al->al_requested = sdp->sd_max_height + RES_DATA;	error = gfs2_inplace_reserve(ip);	if (error)		goto out_gunlock_q;	error = gfs2_trans_begin(sdp,			sdp->sd_max_height + al->al_rgd->rd_length +			RES_JDATA + RES_DINODE + RES_STATFS + RES_QUOTA, 0);	if (error)		goto out_ipres;	if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {		if (gfs2_is_stuffed(ip)) {			error = gfs2_unstuff_dinode(ip, NULL);			if (error)				goto out_end_trans;		}		h = calc_tree_height(ip, size);		if (ip->i_di.di_height < h) {			down_write(&ip->i_rw_mutex);			error = build_height(&ip->i_inode, h);			up_write(&ip->i_rw_mutex);			if (error)				goto out_end_trans;		}	}	ip->i_di.di_size = size;	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;	error = gfs2_meta_inode_buffer(ip, &dibh);	if (error)		goto out_end_trans;	gfs2_trans_add_bh(ip->i_gl, dibh, 1);	gfs2_dinode_out(ip, dibh->b_data);	brelse(dibh);out_end_trans:	gfs2_trans_end(sdp);out_ipres:	gfs2_inplace_release(ip);out_gunlock_q:	gfs2_quota_unlock(ip);out:	gfs2_alloc_put(ip);	return error;}/** * gfs2_block_truncate_page - Deal with zeroing out data for truncate * * This is partly borrowed from ext3. */static int gfs2_block_truncate_page(struct address_space *mapping){	struct inode *inode = mapping->host;	struct gfs2_inode *ip = GFS2_I(inode);	struct gfs2_sbd *sdp = GFS2_SB(inode);	loff_t from = inode->i_size;	unsigned long index = from >> PAGE_CACHE_SHIFT;	unsigned offset = from & (PAGE_CACHE_SIZE-1);	unsigned blocksize, iblock, length, pos;	struct buffer_head *bh;	struct page *page;	int err;	page = grab_cache_page(mapping, index);	if (!page)		return 0;	blocksize = inode->i_sb->s_blocksize;	length = blocksize - (offset & (blocksize - 1));	iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);	if (!page_has_buffers(page))		create_empty_buffers(page, blocksize, 0);	/* Find the buffer that contains "offset" */	bh = page_buffers(page);	pos = blocksize;	while (offset >= pos) {		bh = bh->b_this_page;		iblock++;		pos += blocksize;	}	err = 0;	if (!buffer_mapped(bh)) {		gfs2_get_block(inode, iblock, bh, 0);		/* unmapped? It's a hole - nothing to do */		if (!buffer_mapped(bh))			goto unlock;	}	/* Ok, it's mapped. Make sure it's up-to-date */	if (PageUptodate(page))		set_buffer_uptodate(bh);	if (!buffer_uptodate(bh)) {		err = -EIO;		ll_rw_block(READ, 1, &bh);		wait_on_buffer(bh);		/* Uhhuh. Read error. Complain and punt. */		if (!buffer_uptodate(bh))			goto unlock;		err = 0;	}	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))		gfs2_trans_add_bh(ip->i_gl, bh, 0);	zero_user_page(page, offset, length, KM_USER0);unlock:	unlock_page(page);	page_cache_release(page);	return err;}static int trunc_start(struct gfs2_inode *ip, u64 size){	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	struct buffer_head *dibh;	int journaled = gfs2_is_jdata(ip);	int error;	error = gfs2_trans_begin(sdp,				 RES_DINODE + (journaled ? RES_JDATA : 0), 0);	if (error)		return error;	error = gfs2_meta_inode_buffer(ip, &dibh);	if (error)		goto out;	if (gfs2_is_stuffed(ip)) {		ip->i_di.di_size = size;		ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;		gfs2_trans_add_bh(ip->i_gl, dibh, 1);		gfs2_dinode_out(ip, dibh->b_data);		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size);		error = 1;	} else {		if (size & (u64)(sdp->sd_sb.sb_bsize - 1))			error = gfs2_block_truncate_page(ip->i_inode.i_mapping);		if (!error) {			ip->i_di.di_size = size;			ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;			ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG;			gfs2_trans_add_bh(ip->i_gl, dibh, 1);			gfs2_dinode_out(ip, dibh->b_data);		}	}	brelse(dibh);out:	gfs2_trans_end(sdp);	return error;}static int trunc_dealloc(struct gfs2_inode *ip, u64 size){	unsigned int height = ip->i_di.di_height;	u64 lblock;	struct metapath mp;	int error;	if (!size)		lblock = 0;	else		lblock = (size - 1) >> GFS2_SB(&ip->i_inode)->sd_sb.sb_bsize_shift;	find_metapath(ip, lblock, &mp);	gfs2_alloc_get(ip);	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);	if (error)		goto out;	while (height--) {		struct strip_mine sm;		sm.sm_first = !!size;		sm.sm_height = height;		error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm);		if (error)			break;	}	gfs2_quota_unhold(ip);out:	gfs2_alloc_put(ip);	return error;}static int trunc_end(struct gfs2_inode *ip){	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	struct buffer_head *dibh;	int error;	error = gfs2_trans_begin(sdp, RES_DINODE, 0);	if (error)		return error;	down_write(&ip->i_rw_mutex);	error = gfs2_meta_inode_buffer(ip, &dibh);	if (error)		goto out;	if (!ip->i_di.di_size) {		ip->i_di.di_height = 0;		ip->i_di.di_goal_meta =			ip->i_di.di_goal_data =			ip->i_no_addr;		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));	}	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;	ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG;	gfs2_trans_add_bh(ip->i_gl, dibh, 1);	gfs2_dinode_out(ip, dibh->b_data);	brelse(dibh);out:	up_write(&ip->i_rw_mutex);	gfs2_trans_end(sdp);	return error;}/** * do_shrink - make a file smaller * @ip: the inode * @size: the size to make the file * @truncator: function to truncate the last partial block * * Called with an exclusive lock on @ip. * * Returns: errno */static int do_shrink(struct gfs2_inode *ip, u64 size){	int error;	error = trunc_start(ip, size);	if (error < 0)		return error;	if (error > 0)		return 0;	error = trunc_dealloc(ip, size);	if (!error)		error = trunc_end(ip);	return error;}static int do_touch(struct gfs2_inode *ip, u64 size){	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	struct buffer_head *dibh;	int error;	error = gfs2_trans_begin(sdp, RES_DINODE, 0);	if (error)		return error;	down_write(&ip->i_rw_mutex);	error = gfs2_meta_inode_buffer(ip, &dibh);	if (error)		goto do_touch_out;	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;	gfs2_trans_add_bh(ip->i_gl, dibh, 1);	gfs2_dinode_out(ip, dibh->b_data);	brelse(dibh);do_touch_out:	up_write(&ip->i_rw_mutex);	gfs2_trans_end(sdp);	return error;}/** * gfs2_truncatei - make a file a given size * @ip: the inode * @size: the size to make the file * @truncator: function to truncate the last partial block * * The file size can grow, shrink, or stay the same size. * * Returns: errno */int gfs2_truncatei(struct gfs2_inode *ip, u64 size){	int error;	if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_inode.i_mode)))		return -EINVAL;	if (size > ip->i_di.di_size)		error = do_grow(ip, size);	else if (size < ip->i_di.di_size)		error = do_shrink(ip, size);	else		/* update time stamps */		error = do_touch(ip, size);	return error;}int gfs2_truncatei_resume(struct gfs2_inode *ip){	int error;	error = trunc_dealloc(ip, ip->i_di.di_size);	if (!error)		error = trunc_end(ip);	return error;}int gfs2_file_dealloc(struct gfs2_inode *ip){	return trunc_dealloc(ip, 0);}/** * gfs2_write_calc_reserv - calculate number of blocks needed to write to a file * @ip: the file * @len: the number of bytes to be written to the file * @data_blocks: returns the number of data blocks required * @ind_blocks: returns the number of indirect blocks required * */void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,			    unsigned int *data_blocks, unsigned int *ind_blocks){	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	unsigned int tmp;	if (gfs2_is_dir(ip)) {		*data_blocks = DIV_ROUND_UP(len, sdp->sd_jbsize) + 2;		*ind_blocks = 3 * (sdp->sd_max_jheight - 1);	} else {		*data_blocks = (len >> sdp->sd_sb.sb_bsize_shift) + 3;		*ind_blocks = 3 * (sdp->sd_max_height - 1);	}	for (tmp = *data_blocks; tmp > sdp->sd_diptrs;) {		tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);		*ind_blocks += tmp;	}}/** * gfs2_write_alloc_required - figure out if a write will require an allocation * @ip: the file being written to * @offset: the offset to write to * @len: the number of bytes being written * @alloc_required: set to 1 if an alloc is required, 0 otherwise * * Returns: errno */int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,			      unsigned int len, int *alloc_required){	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);	u64 lblock, lblock_stop, dblock;	u32 extlen;	int new = 0;	int error = 0;	*alloc_required = 0;	if (!len)		return 0;	if (gfs2_is_stuffed(ip)) {		if (offset + len >		    sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))			*alloc_required = 1;		return 0;	}	if (gfs2_is_dir(ip)) {		unsigned int bsize = sdp->sd_jbsize;		lblock = offset;		do_div(lblock, bsize);		lblock_stop = offset + len + bsize - 1;		do_div(lblock_stop, bsize);	} else {		unsigned int shift = sdp->sd_sb.sb_bsize_shift;		lblock = offset >> shift;		lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;	}	for (; lblock < lblock_stop; lblock += extlen) {		error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);		if (error)			return error;		if (!dblock) {			*alloc_required = 1;			return 0;		}	}	return 0;}

⌨️ 快捷键说明

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