|
@@ -127,6 +127,42 @@ xfs_iozero(
|
|
|
return (-status);
|
|
|
}
|
|
|
|
|
|
+int
|
|
|
+xfs_update_prealloc_flags(
|
|
|
+ struct xfs_inode *ip,
|
|
|
+ enum xfs_prealloc_flags flags)
|
|
|
+{
|
|
|
+ struct xfs_trans *tp;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
|
|
|
+ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
|
|
|
+
|
|
|
+ if (!(flags & XFS_PREALLOC_INVISIBLE)) {
|
|
|
+ ip->i_d.di_mode &= ~S_ISUID;
|
|
|
+ if (ip->i_d.di_mode & S_IXGRP)
|
|
|
+ ip->i_d.di_mode &= ~S_ISGID;
|
|
|
+ xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (flags & XFS_PREALLOC_SET)
|
|
|
+ ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
|
|
|
+ if (flags & XFS_PREALLOC_CLEAR)
|
|
|
+ ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;
|
|
|
+
|
|
|
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
|
|
+ if (flags & XFS_PREALLOC_SYNC)
|
|
|
+ xfs_trans_set_sync(tp);
|
|
|
+ return xfs_trans_commit(tp, 0);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Fsync operations on directories are much simpler than on regular files,
|
|
|
* as there is no file data to flush, and thus also no need for explicit
|
|
@@ -784,8 +820,8 @@ xfs_file_fallocate(
|
|
|
{
|
|
|
struct inode *inode = file_inode(file);
|
|
|
struct xfs_inode *ip = XFS_I(inode);
|
|
|
- struct xfs_trans *tp;
|
|
|
long error;
|
|
|
+ enum xfs_prealloc_flags flags = 0;
|
|
|
loff_t new_size = 0;
|
|
|
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
@@ -822,6 +858,8 @@ xfs_file_fallocate(
|
|
|
if (error)
|
|
|
goto out_unlock;
|
|
|
} else {
|
|
|
+ flags |= XFS_PREALLOC_SET;
|
|
|
+
|
|
|
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
|
|
offset + len > i_size_read(inode)) {
|
|
|
new_size = offset + len;
|
|
@@ -839,28 +877,10 @@ xfs_file_fallocate(
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
|
|
|
- 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 | FALLOC_FL_COLLAPSE_RANGE)))
|
|
|
- ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
|
|
|
-
|
|
|
- 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);
|
|
|
+ flags |= XFS_PREALLOC_SYNC;
|
|
|
+
|
|
|
+ error = xfs_update_prealloc_flags(ip, flags);
|
|
|
if (error)
|
|
|
goto out_unlock;
|
|
|
|