Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6f0a6d6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw: (22 commits)
  GFS2: fixed typo
  GFS2: Fix type mapping for demote_rq interface
  GFS2 fatal: filesystem consistency error on rename
  GFS2: Improve journal allocation via sysfs
  GFS2: Add "norecovery" mount option as a synonym for "spectator"
  GFS2: Fix spectator umount issue
  GFS2: Fix compiler warning from previous patch
  GFS2: reserve more blocks for transactions
  GFS2: Fix journal check for spectator mounts
  GFS2: Remove upgrade mount option
  GFS2: Remove localcaching mount option
  GFS2: Remove ignore_local_fs mount argument
  GFS2: Make . and .. qstrs constant
  GFS2: Use new workqueue scheme
  GFS2: Update handling of DLM return codes to match reality
  GFS2: Don't enforce min hold time when two demotes occur in rapid succession
  GFS2: Fix whitespace in previous patch
  GFS2: fallocate support
  GFS2: Add a bug trap in allocation code
  GFS2: No longer experimental
  ...
parents 2017bd19 33027af6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
config GFS2_FS
	tristate "GFS2 file system support"
	depends on EXPERIMENTAL && (64BIT || LBDAF)
	depends on (64BIT || LBDAF)
	select DLM if GFS2_FS_LOCKING_DLM
	select CONFIGFS_FS if GFS2_FS_LOCKING_DLM
	select SYSFS if GFS2_FS_LOCKING_DLM
+10 −14
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@
#include "glops.h"


static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
			    unsigned int from, unsigned int to)
{
	struct buffer_head *head = page_buffers(page);
@@ -615,7 +615,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
	unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
	int alloc_required;
	int error = 0;
	struct gfs2_alloc *al;
	struct gfs2_alloc *al = NULL;
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
	unsigned to = from + len;
@@ -663,6 +663,8 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
		rblocks += RES_STATFS + RES_QUOTA;
	if (&ip->i_inode == sdp->sd_rindex)
		rblocks += 2 * RES_STATFS;
	if (alloc_required)
		rblocks += gfs2_rg_blocks(al);

	error = gfs2_trans_begin(sdp, rblocks,
				 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
@@ -696,13 +698,11 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,

	page_cache_release(page);

	/*
	 * XXX(truncate): the call below should probably be replaced with
	 * a call to the gfs2-specific truncate blocks helper to actually
	 * release disk blocks..
	 */
	gfs2_trans_end(sdp);
	if (pos + len > ip->i_inode.i_size)
		truncate_setsize(&ip->i_inode, ip->i_inode.i_size);
		gfs2_trim_blocks(&ip->i_inode);
	goto out_trans_fail;

out_endtrans:
	gfs2_trans_end(sdp);
out_trans_fail:
@@ -802,10 +802,8 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
	page_cache_release(page);

	if (copied) {
		if (inode->i_size < to) {
		if (inode->i_size < to)
			i_size_write(inode, to);
			ip->i_disksize = inode->i_size;
		}
		gfs2_dinode_out(ip, di);
		mark_inode_dirty(inode);
	}
@@ -876,8 +874,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,

	ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
	if (ret > 0) {
		if (inode->i_size > ip->i_disksize)
			ip->i_disksize = inode->i_size;
		gfs2_dinode_out(ip, dibh->b_data);
		mark_inode_dirty(inode);
	}
+122 −133
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ struct strip_mine {
 * @ip: the inode
 * @dibh: the dinode buffer
 * @block: the block number that was allocated
 * @private: any locked page held by the caller process
 * @page: The (optional) page. This is looked up if @page is NULL
 *
 * Returns: errno
 */
@@ -109,8 +109,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
/**
 * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big
 * @ip: The GFS2 inode to unstuff
 * @unstuffer: the routine that handles unstuffing a non-zero length file
 * @private: private data for the unstuffer
 * @page: The (optional) page. This is looked up if the @page is NULL
 *
 * This routine unstuffs a dinode and returns it to a "normal" state such
 * that the height can be grown in the traditional way.
@@ -132,7 +131,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
	if (error)
		goto out;

	if (ip->i_disksize) {
	if (i_size_read(&ip->i_inode)) {
		/* Get a free block, fill it with the stuffed data,
		   and write it out to disk */

@@ -161,7 +160,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
	di = (struct gfs2_dinode *)dibh->b_data;
	gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));

	if (ip->i_disksize) {
	if (i_size_read(&ip->i_inode)) {
		*(__be64 *)(di + 1) = cpu_to_be64(block);
		gfs2_add_inode_blocks(&ip->i_inode, 1);
		di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode));
@@ -884,84 +883,15 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
	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;
	int error;

	al = gfs2_alloc_get(ip);
	if (!al)
		return -ENOMEM;

	error = gfs2_quota_lock_check(ip);
	if (error)
		goto out;

	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;

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (error)
		goto out_end_trans;

	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_brelse;
		}
	}

	ip->i_disksize = 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);

out_brelse:
	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)
static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
{
	struct inode *inode = mapping->host;
	struct gfs2_inode *ip = GFS2_I(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;
@@ -1023,9 +953,11 @@ static int gfs2_block_truncate_page(struct address_space *mapping)
	return err;
}

static int trunc_start(struct gfs2_inode *ip, u64 size)
static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
{
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct address_space *mapping = inode->i_mapping;
	struct buffer_head *dibh;
	int journaled = gfs2_is_jdata(ip);
	int error;
@@ -1039,31 +971,26 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
	if (error)
		goto out;

	if (gfs2_is_stuffed(ip)) {
		u64 dsize = size + sizeof(struct gfs2_dinode);
		ip->i_disksize = 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);
		if (dsize > dibh->b_size)
			dsize = dibh->b_size;
		gfs2_buffer_clear_tail(dibh, dsize);
		error = 1;

	if (gfs2_is_stuffed(ip)) {
		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize);
	} else {
		if (size & (u64)(sdp->sd_sb.sb_bsize - 1))
			error = gfs2_block_truncate_page(ip->i_inode.i_mapping);
		if (newsize & (u64)(sdp->sd_sb.sb_bsize - 1)) {
			error = gfs2_block_truncate_page(mapping, newsize);
			if (error)
				goto out_brelse;
		}
		ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
	}

		if (!error) {
			ip->i_disksize = size;
	i_size_write(inode, newsize);
	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
			ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
			gfs2_trans_add_bh(ip->i_gl, dibh, 1);
	gfs2_dinode_out(ip, dibh->b_data);
		}
	}

	truncate_pagecache(inode, oldsize, newsize);
out_brelse:
	brelse(dibh);

out:
	gfs2_trans_end(sdp);
	return error;
@@ -1123,7 +1050,7 @@ static int trunc_end(struct gfs2_inode *ip)
	if (error)
		goto out;

	if (!ip->i_disksize) {
	if (!i_size_read(&ip->i_inode)) {
		ip->i_height = 0;
		ip->i_goal = ip->i_no_addr;
		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
@@ -1143,92 +1070,154 @@ static int trunc_end(struct gfs2_inode *ip)

/**
 * do_shrink - make a file smaller
 * @ip: the inode
 * @size: the size to make the file
 * @truncator: function to truncate the last partial block
 * @inode: the inode
 * @oldsize: the current inode size
 * @newsize: the size to make the file
 *
 * Called with an exclusive lock on @ip.
 * Called with an exclusive lock on @inode. The @size must
 * be equal to or smaller than the current inode size.
 *
 * Returns: errno
 */

static int do_shrink(struct gfs2_inode *ip, u64 size)
static int do_shrink(struct inode *inode, u64 oldsize, u64 newsize)
{
	struct gfs2_inode *ip = GFS2_I(inode);
	int error;

	error = trunc_start(ip, size);
	error = trunc_start(inode, oldsize, newsize);
	if (error < 0)
		return error;
	if (error > 0)
	if (gfs2_is_stuffed(ip))
		return 0;

	error = trunc_dealloc(ip, size);
	if (!error)
	error = trunc_dealloc(ip, newsize);
	if (error == 0)
		error = trunc_end(ip);

	return error;
}

static int do_touch(struct gfs2_inode *ip, u64 size)
void gfs2_trim_blocks(struct inode *inode)
{
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
	u64 size = inode->i_size;
	int ret;

	ret = do_shrink(inode, size, size);
	WARN_ON(ret != 0);
}

/**
 * do_grow - Touch and update inode size
 * @inode: The inode
 * @size: The new size
 *
 * This function updates the timestamps on the inode and
 * may also increase the size of the inode. This function
 * must not be called with @size any smaller than the current
 * inode size.
 *
 * Although it is not strictly required to unstuff files here,
 * earlier versions of GFS2 have a bug in the stuffed file reading
 * code which will result in a buffer overrun if the size is larger
 * than the max stuffed file size. In order to prevent this from
 * occuring, such files are unstuffed, but in other cases we can
 * just update the inode size directly.
 *
 * Returns: 0 on success, or -ve on error
 */

static int do_grow(struct inode *inode, u64 size)
{
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct buffer_head *dibh;
	struct gfs2_alloc *al = NULL;
	int error;

	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
	if (gfs2_is_stuffed(ip) &&
	    (size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) {
		al = gfs2_alloc_get(ip);
		if (al == NULL)
			return -ENOMEM;

		error = gfs2_quota_lock_check(ip);
		if (error)
		return error;
			goto do_grow_alloc_put;

	down_write(&ip->i_rw_mutex);
		al->al_requested = 1;
		error = gfs2_inplace_reserve(ip);
		if (error)
			goto do_grow_qunlock;
	}

	error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT, 0);
	if (error)
		goto do_grow_release;

	if (al) {
		error = gfs2_unstuff_dinode(ip, NULL);
		if (error)
			goto do_end_trans;
	}

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (error)
		goto do_touch_out;
		goto do_end_trans;

	i_size_write(inode, 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);
	brelse(dibh);

do_touch_out:
	up_write(&ip->i_rw_mutex);
do_end_trans:
	gfs2_trans_end(sdp);
do_grow_release:
	if (al) {
		gfs2_inplace_release(ip);
do_grow_qunlock:
		gfs2_quota_unlock(ip);
do_grow_alloc_put:
		gfs2_alloc_put(ip);
	}
	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
 * gfs2_setattr_size - make a file a given size
 * @inode: the inode
 * @newsize: the size to make the file
 *
 * The file size can grow, shrink, or stay the same size.
 * The file size can grow, shrink, or stay the same size. This
 * is called holding i_mutex and an exclusive glock on the inode
 * in question.
 *
 * Returns: errno
 */

int gfs2_truncatei(struct gfs2_inode *ip, u64 size)
int gfs2_setattr_size(struct inode *inode, u64 newsize)
{
	int error;
	int ret;
	u64 oldsize;

	if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_inode.i_mode)))
		return -EINVAL;
	BUG_ON(!S_ISREG(inode->i_mode));

	if (size > ip->i_disksize)
		error = do_grow(ip, size);
	else if (size < ip->i_disksize)
		error = do_shrink(ip, size);
	else
		/* update time stamps */
		error = do_touch(ip, size);
	ret = inode_newsize_ok(inode, newsize);
	if (ret)
		return ret;

	return error;
	oldsize = inode->i_size;
	if (newsize >= oldsize)
		return do_grow(inode, newsize);

	return do_shrink(inode, oldsize, newsize);
}

int gfs2_truncatei_resume(struct gfs2_inode *ip)
{
	int error;
	error = trunc_dealloc(ip, ip->i_disksize);
	error = trunc_dealloc(ip, i_size_read(&ip->i_inode));
	if (!error)
		error = trunc_end(ip);
	return error;
@@ -1269,7 +1258,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,

	shift = sdp->sd_sb.sb_bsize_shift;
	BUG_ON(gfs2_is_dir(ip));
	end_of_file = (ip->i_disksize + sdp->sd_sb.sb_bsize - 1) >> shift;
	end_of_file = (i_size_read(&ip->i_inode) + sdp->sd_sb.sb_bsize - 1) >> shift;
	lblock = offset >> shift;
	lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
	if (lblock_stop > end_of_file)
+11 −9
Original line number Diff line number Diff line
@@ -44,14 +44,16 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip,
	}
}

int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
int gfs2_block_map(struct inode *inode, sector_t lblock, struct buffer_head *bh, int create);
int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);

int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
int gfs2_truncatei_resume(struct gfs2_inode *ip);
int gfs2_file_dealloc(struct gfs2_inode *ip);
int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
extern int gfs2_block_map(struct inode *inode, sector_t lblock,
			  struct buffer_head *bh, int create);
extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new,
			   u64 *dblock, unsigned *extlen);
extern int gfs2_setattr_size(struct inode *inode, u64 size);
extern void gfs2_trim_blocks(struct inode *inode);
extern int gfs2_truncatei_resume(struct gfs2_inode *ip);
extern int gfs2_file_dealloc(struct gfs2_inode *ip);
extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
				     unsigned int len);

#endif /* __BMAP_DOT_H__ */
+1 −1
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
		ip = GFS2_I(inode);
	}

	if (sdp->sd_args.ar_localcaching)
	if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
		goto valid;

	had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL);
Loading