diff options
Diffstat (limited to 'fs/gfs2/file.c')
| -rw-r--r-- | fs/gfs2/file.c | 104 | 
1 files changed, 69 insertions, 35 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index b2682e073ee..a9f5cbe45cd 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -545,18 +545,10 @@ static int gfs2_close(struct inode *inode, struct file *file)  /**   * gfs2_fsync - sync the dirty data for a file (across the cluster)   * @file: the file that points to the dentry (we ignore this) - * @dentry: the dentry that points to the inode to sync + * @datasync: set if we can ignore timestamp changes   * - * The VFS will flush "normal" data for us. We only need to worry - * about metadata here. For journaled data, we just do a log flush - * as we can't avoid it. Otherwise we can just bale out if datasync - * is set. For stuffed inodes we must flush the log in order to - * ensure that all data is on disk. - * - * The call to write_inode_now() is there to write back metadata and - * the inode itself. It does also try and write the data, but thats - * (hopefully) a no-op due to the VFS having already called filemap_fdatawrite() - * for us. + * The VFS will flush data for us. We only need to worry + * about metadata here.   *   * Returns: errno   */ @@ -565,22 +557,20 @@ static int gfs2_fsync(struct file *file, int datasync)  {  	struct inode *inode = file->f_mapping->host;  	int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); -	int ret = 0; - -	if (gfs2_is_jdata(GFS2_I(inode))) { -		gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl); -		return 0; -	} +	struct gfs2_inode *ip = GFS2_I(inode); +	int ret; -	if (sync_state != 0) { -		if (!datasync) -			ret = write_inode_now(inode, 0); +	if (datasync) +		sync_state &= ~I_DIRTY_SYNC; -		if (gfs2_is_stuffed(GFS2_I(inode))) -			gfs2_log_flush(GFS2_SB(inode), GFS2_I(inode)->i_gl); +	if (sync_state) { +		ret = sync_inode_metadata(inode, 1); +		if (ret) +			return ret; +		gfs2_ail_flush(ip->i_gl);  	} -	return ret; +	return 0;  }  /** @@ -617,18 +607,51 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,  	return generic_file_aio_write(iocb, iov, nr_segs, pos);  } -static void empty_write_end(struct page *page, unsigned from, -			   unsigned to) +static int empty_write_end(struct page *page, unsigned from, +			   unsigned to, int mode)  { -	struct gfs2_inode *ip = GFS2_I(page->mapping->host); +	struct inode *inode = page->mapping->host; +	struct gfs2_inode *ip = GFS2_I(inode); +	struct buffer_head *bh; +	unsigned offset, blksize = 1 << inode->i_blkbits; +	pgoff_t end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;  	zero_user(page, from, to-from);  	mark_page_accessed(page); -	if (!gfs2_is_writeback(ip)) -		gfs2_page_add_databufs(ip, page, from, to); +	if (page->index < end_index || !(mode & FALLOC_FL_KEEP_SIZE)) { +		if (!gfs2_is_writeback(ip)) +			gfs2_page_add_databufs(ip, page, from, to); -	block_commit_write(page, from, to); +		block_commit_write(page, from, to); +		return 0; +	} + +	offset = 0; +	bh = page_buffers(page); +	while (offset < to) { +		if (offset >= from) { +			set_buffer_uptodate(bh); +			mark_buffer_dirty(bh); +			clear_buffer_new(bh); +			write_dirty_buffer(bh, WRITE); +		} +		offset += blksize; +		bh = bh->b_this_page; +	} + +	offset = 0; +	bh = page_buffers(page); +	while (offset < to) { +		if (offset >= from) { +			wait_on_buffer(bh); +			if (!buffer_uptodate(bh)) +				return -EIO; +		} +		offset += blksize; +		bh = bh->b_this_page; +	} +	return 0;  }  static int needs_empty_write(sector_t block, struct inode *inode) @@ -643,7 +666,8 @@ static int needs_empty_write(sector_t block, struct inode *inode)  	return !buffer_mapped(&bh_map);  } -static int write_empty_blocks(struct page *page, unsigned from, unsigned to) +static int write_empty_blocks(struct page *page, unsigned from, unsigned to, +			      int mode)  {  	struct inode *inode = page->mapping->host;  	unsigned start, end, next, blksize; @@ -668,7 +692,9 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)  							  gfs2_block_map);  				if (unlikely(ret))  					return ret; -				empty_write_end(page, start, end); +				ret = empty_write_end(page, start, end, mode); +				if (unlikely(ret)) +					return ret;  				end = 0;  			}  			start = next; @@ -682,7 +708,9 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to)  		ret = __block_write_begin(page, start, end - start, gfs2_block_map);  		if (unlikely(ret))  			return ret; -		empty_write_end(page, start, end); +		ret = empty_write_end(page, start, end, mode); +		if (unlikely(ret)) +			return ret;  	}  	return 0; @@ -731,7 +759,7 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,  		if (curr == end)  			to = end_offset; -		error = write_empty_blocks(page, from, to); +		error = write_empty_blocks(page, from, to, mode);  		if (!error && offset + to > inode->i_size &&  		    !(mode & FALLOC_FL_KEEP_SIZE)) {  			i_size_write(inode, offset + to); @@ -788,6 +816,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,  	loff_t bytes, max_bytes;  	struct gfs2_alloc *al;  	int error; +	loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1);  	loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;  	next = (next + 1) << sdp->sd_sb.sb_bsize_shift; @@ -795,13 +824,15 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,  	if (mode & ~FALLOC_FL_KEEP_SIZE)  		return -EOPNOTSUPP; -	offset = (offset >> sdp->sd_sb.sb_bsize_shift) << -		 sdp->sd_sb.sb_bsize_shift; +	offset &= bsize_mask;  	len = next - offset;  	bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2;  	if (!bytes)  		bytes = UINT_MAX; +	bytes &= bsize_mask; +	if (bytes == 0) +		bytes = sdp->sd_sb.sb_bsize;  	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);  	error = gfs2_glock_nq(&ip->i_gh); @@ -832,6 +863,9 @@ retry:  		if (error) {  			if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {  				bytes >>= 1; +				bytes &= bsize_mask; +				if (bytes == 0) +					bytes = sdp->sd_sb.sb_bsize;  				goto retry;  			}  			goto out_qunlock;  |