diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
| -rw-r--r-- | fs/gfs2/bmap.c | 128 | 
1 files changed, 123 insertions, 5 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 62a65fc448d..e6ee5b6e8d9 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -707,7 +707,7 @@ int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsi   * @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 + * @sm: a pointer to a struct strip_mine   *   * Returns: errno   */ @@ -992,6 +992,8 @@ unlock:  	return err;  } +#define GFS2_JTRUNC_REVOKES 8192 +  /**   * gfs2_journaled_truncate - Wrapper for truncate_pagecache for jdata files   * @inode: The inode being truncated @@ -1003,8 +1005,6 @@ unlock:   * if the number of pages being truncated gets too large.   */ -#define GFS2_JTRUNC_REVOKES 8192 -  static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize)  {  	struct gfs2_sbd *sdp = GFS2_SB(inode); @@ -1216,6 +1216,7 @@ static int do_grow(struct inode *inode, u64 size)  {  	struct gfs2_inode *ip = GFS2_I(inode);  	struct gfs2_sbd *sdp = GFS2_SB(inode); +	struct gfs2_alloc_parms ap = { .target = 1, };  	struct buffer_head *dibh;  	int error;  	int unstuff = 0; @@ -1226,7 +1227,7 @@ static int do_grow(struct inode *inode, u64 size)  		if (error)  			return error; -		error = gfs2_inplace_reserve(ip, 1, 0); +		error = gfs2_inplace_reserve(ip, &ap);  		if (error)  			goto do_grow_qunlock;  		unstuff = 1; @@ -1279,6 +1280,7 @@ do_grow_qunlock:  int gfs2_setattr_size(struct inode *inode, u64 newsize)  { +	struct gfs2_inode *ip = GFS2_I(inode);  	int ret;  	u64 oldsize; @@ -1294,7 +1296,7 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)  	inode_dio_wait(inode); -	ret = gfs2_rs_alloc(GFS2_I(inode)); +	ret = gfs2_rs_alloc(ip);  	if (ret)  		goto out; @@ -1304,6 +1306,7 @@ int gfs2_setattr_size(struct inode *inode, u64 newsize)  		goto out;  	} +	gfs2_rs_deltree(ip->i_res);  	ret = do_shrink(inode, oldsize, newsize);  out:  	put_write_access(inode); @@ -1325,6 +1328,121 @@ int gfs2_file_dealloc(struct gfs2_inode *ip)  }  /** + * gfs2_free_journal_extents - Free cached journal bmap info + * @jd: The journal + * + */ + +void gfs2_free_journal_extents(struct gfs2_jdesc *jd) +{ +	struct gfs2_journal_extent *jext; + +	while(!list_empty(&jd->extent_list)) { +		jext = list_entry(jd->extent_list.next, struct gfs2_journal_extent, list); +		list_del(&jext->list); +		kfree(jext); +	} +} + +/** + * gfs2_add_jextent - Add or merge a new extent to extent cache + * @jd: The journal descriptor + * @lblock: The logical block at start of new extent + * @dblock: The physical block at start of new extent + * @blocks: Size of extent in fs blocks + * + * Returns: 0 on success or -ENOMEM + */ + +static int gfs2_add_jextent(struct gfs2_jdesc *jd, u64 lblock, u64 dblock, u64 blocks) +{ +	struct gfs2_journal_extent *jext; + +	if (!list_empty(&jd->extent_list)) { +		jext = list_entry(jd->extent_list.prev, struct gfs2_journal_extent, list); +		if ((jext->dblock + jext->blocks) == dblock) { +			jext->blocks += blocks; +			return 0; +		} +	} + +	jext = kzalloc(sizeof(struct gfs2_journal_extent), GFP_NOFS); +	if (jext == NULL) +		return -ENOMEM; +	jext->dblock = dblock; +	jext->lblock = lblock; +	jext->blocks = blocks; +	list_add_tail(&jext->list, &jd->extent_list); +	jd->nr_extents++; +	return 0; +} + +/** + * gfs2_map_journal_extents - Cache journal bmap info + * @sdp: The super block + * @jd: The journal to map + * + * Create a reusable "extent" mapping from all logical + * blocks to all physical blocks for the given journal.  This will save + * us time when writing journal blocks.  Most journals will have only one + * extent that maps all their logical blocks.  That's because gfs2.mkfs + * arranges the journal blocks sequentially to maximize performance. + * So the extent would map the first block for the entire file length. + * However, gfs2_jadd can happen while file activity is happening, so + * those journals may not be sequential.  Less likely is the case where + * the users created their own journals by mounting the metafs and + * laying it out.  But it's still possible.  These journals might have + * several extents. + * + * Returns: 0 on success, or error on failure + */ + +int gfs2_map_journal_extents(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd) +{ +	u64 lblock = 0; +	u64 lblock_stop; +	struct gfs2_inode *ip = GFS2_I(jd->jd_inode); +	struct buffer_head bh; +	unsigned int shift = sdp->sd_sb.sb_bsize_shift; +	u64 size; +	int rc; + +	lblock_stop = i_size_read(jd->jd_inode) >> shift; +	size = (lblock_stop - lblock) << shift; +	jd->nr_extents = 0; +	WARN_ON(!list_empty(&jd->extent_list)); + +	do { +		bh.b_state = 0; +		bh.b_blocknr = 0; +		bh.b_size = size; +		rc = gfs2_block_map(jd->jd_inode, lblock, &bh, 0); +		if (rc || !buffer_mapped(&bh)) +			goto fail; +		rc = gfs2_add_jextent(jd, lblock, bh.b_blocknr, bh.b_size >> shift); +		if (rc) +			goto fail; +		size -= bh.b_size; +		lblock += (bh.b_size >> ip->i_inode.i_blkbits); +	} while(size > 0); + +	fs_info(sdp, "journal %d mapped with %u extents\n", jd->jd_jid, +		jd->nr_extents); +	return 0; + +fail: +	fs_warn(sdp, "error %d mapping journal %u at offset %llu (extent %u)\n", +		rc, jd->jd_jid, +		(unsigned long long)(i_size_read(jd->jd_inode) - size), +		jd->nr_extents); +	fs_warn(sdp, "bmap=%d lblock=%llu block=%llu, state=0x%08lx, size=%llu\n", +		rc, (unsigned long long)lblock, (unsigned long long)bh.b_blocknr, +		bh.b_state, (unsigned long long)bh.b_size); +	gfs2_free_journal_extents(jd); +	return rc; +} + +/**   * 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  | 
