diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
| -rw-r--r-- | fs/xfs/xfs_file.c | 92 | 
1 files changed, 57 insertions, 35 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 4c749ab543d0..52c91e143725 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -17,25 +17,27 @@   */  #include "xfs.h"  #include "xfs_fs.h" -#include "xfs_log.h" +#include "xfs_shared.h" +#include "xfs_format.h" +#include "xfs_log_format.h" +#include "xfs_trans_resv.h"  #include "xfs_sb.h"  #include "xfs_ag.h" -#include "xfs_trans.h"  #include "xfs_mount.h" -#include "xfs_bmap_btree.h" -#include "xfs_alloc.h" -#include "xfs_dinode.h" +#include "xfs_da_format.h" +#include "xfs_da_btree.h"  #include "xfs_inode.h" +#include "xfs_trans.h"  #include "xfs_inode_item.h"  #include "xfs_bmap.h"  #include "xfs_bmap_util.h"  #include "xfs_error.h" -#include "xfs_da_btree.h" -#include "xfs_dir2_format.h"  #include "xfs_dir2.h"  #include "xfs_dir2_priv.h"  #include "xfs_ioctl.h"  #include "xfs_trace.h" +#include "xfs_log.h" +#include "xfs_dinode.h"  #include <linux/aio.h>  #include <linux/dcache.h> @@ -805,44 +807,64 @@ out:  STATIC long  xfs_file_fallocate( -	struct file	*file, -	int		mode, -	loff_t		offset, -	loff_t		len) +	struct file		*file, +	int			mode, +	loff_t			offset, +	loff_t			len)  { -	struct inode	*inode = file_inode(file); -	long		error; -	loff_t		new_size = 0; -	xfs_flock64_t	bf; -	xfs_inode_t	*ip = XFS_I(inode); -	int		cmd = XFS_IOC_RESVSP; -	int		attr_flags = XFS_ATTR_NOLOCK; +	struct inode		*inode = file_inode(file); +	struct xfs_inode	*ip = XFS_I(inode); +	struct xfs_trans	*tp; +	long			error; +	loff_t			new_size = 0; +	if (!S_ISREG(inode->i_mode)) +		return -EINVAL;  	if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))  		return -EOPNOTSUPP; -	bf.l_whence = 0; -	bf.l_start = offset; -	bf.l_len = len; -  	xfs_ilock(ip, XFS_IOLOCK_EXCL); +	if (mode & FALLOC_FL_PUNCH_HOLE) { +		error = xfs_free_file_space(ip, offset, len); +		if (error) +			goto out_unlock; +	} else { +		if (!(mode & FALLOC_FL_KEEP_SIZE) && +		    offset + len > i_size_read(inode)) { +			new_size = offset + len; +			error = -inode_newsize_ok(inode, new_size); +			if (error) +				goto out_unlock; +		} -	if (mode & FALLOC_FL_PUNCH_HOLE) -		cmd = XFS_IOC_UNRESVSP; - -	/* check the new inode size is valid before allocating */ -	if (!(mode & FALLOC_FL_KEEP_SIZE) && -	    offset + len > i_size_read(inode)) { -		new_size = offset + len; -		error = inode_newsize_ok(inode, new_size); +		error = xfs_alloc_file_space(ip, offset, len, +					     XFS_BMAPI_PREALLOC);  		if (error)  			goto out_unlock;  	} -	if (file->f_flags & O_DSYNC) -		attr_flags |= XFS_ATTR_SYNC; +	tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID); +	error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0); +	if (error) { +		xfs_trans_cancel(tp, 0); +		goto out_unlock; +	} + +	xfs_ilock(ip, XFS_ILOCK_EXCL); +	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); +	ip->i_d.di_mode &= ~S_ISUID; +	if (ip->i_d.di_mode & S_IXGRP) +		ip->i_d.di_mode &= ~S_ISGID; + +	if (!(mode & FALLOC_FL_PUNCH_HOLE)) +		ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; -	error = -xfs_change_file_space(ip, cmd, &bf, 0, attr_flags); +	xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); +	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + +	if (file->f_flags & O_DSYNC) +		xfs_trans_set_sync(tp); +	error = xfs_trans_commit(tp, 0);  	if (error)  		goto out_unlock; @@ -852,12 +874,12 @@ xfs_file_fallocate(  		iattr.ia_valid = ATTR_SIZE;  		iattr.ia_size = new_size; -		error = -xfs_setattr_size(ip, &iattr, XFS_ATTR_NOLOCK); +		error = xfs_setattr_size(ip, &iattr);  	}  out_unlock:  	xfs_iunlock(ip, XFS_IOLOCK_EXCL); -	return error; +	return -error;  }  |