|
@@ -1385,7 +1385,7 @@ xfs_free_file_space(
|
|
|
}
|
|
|
|
|
|
|
|
|
-STATIC int
|
|
|
+int
|
|
|
xfs_zero_file_space(
|
|
|
struct xfs_inode *ip,
|
|
|
xfs_off_t offset,
|
|
@@ -1445,182 +1445,6 @@ out:
|
|
|
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * xfs_change_file_space()
|
|
|
- * This routine allocates or frees disk space for the given file.
|
|
|
- * The user specified parameters are checked for alignment and size
|
|
|
- * limitations.
|
|
|
- *
|
|
|
- * RETURNS:
|
|
|
- * 0 on success
|
|
|
- * errno on error
|
|
|
- *
|
|
|
- */
|
|
|
-int
|
|
|
-xfs_change_file_space(
|
|
|
- xfs_inode_t *ip,
|
|
|
- int cmd,
|
|
|
- xfs_flock64_t *bf,
|
|
|
- xfs_off_t offset,
|
|
|
- int attr_flags)
|
|
|
-{
|
|
|
- xfs_mount_t *mp = ip->i_mount;
|
|
|
- int clrprealloc;
|
|
|
- int error;
|
|
|
- xfs_fsize_t fsize;
|
|
|
- int setprealloc;
|
|
|
- xfs_off_t startoffset;
|
|
|
- xfs_trans_t *tp;
|
|
|
- struct iattr iattr;
|
|
|
-
|
|
|
- if (!S_ISREG(ip->i_d.di_mode))
|
|
|
- return XFS_ERROR(EINVAL);
|
|
|
-
|
|
|
- switch (bf->l_whence) {
|
|
|
- case 0: /*SEEK_SET*/
|
|
|
- break;
|
|
|
- case 1: /*SEEK_CUR*/
|
|
|
- bf->l_start += offset;
|
|
|
- break;
|
|
|
- case 2: /*SEEK_END*/
|
|
|
- bf->l_start += XFS_ISIZE(ip);
|
|
|
- break;
|
|
|
- default:
|
|
|
- return XFS_ERROR(EINVAL);
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * length of <= 0 for resv/unresv/zero is invalid. length for
|
|
|
- * alloc/free is ignored completely and we have no idea what userspace
|
|
|
- * might have set it to, so set it to zero to allow range
|
|
|
- * checks to pass.
|
|
|
- */
|
|
|
- switch (cmd) {
|
|
|
- case XFS_IOC_ZERO_RANGE:
|
|
|
- case XFS_IOC_RESVSP:
|
|
|
- case XFS_IOC_RESVSP64:
|
|
|
- case XFS_IOC_UNRESVSP:
|
|
|
- case XFS_IOC_UNRESVSP64:
|
|
|
- if (bf->l_len <= 0)
|
|
|
- return XFS_ERROR(EINVAL);
|
|
|
- break;
|
|
|
- default:
|
|
|
- bf->l_len = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (bf->l_start < 0 ||
|
|
|
- bf->l_start > mp->m_super->s_maxbytes ||
|
|
|
- bf->l_start + bf->l_len < 0 ||
|
|
|
- bf->l_start + bf->l_len >= mp->m_super->s_maxbytes)
|
|
|
- return XFS_ERROR(EINVAL);
|
|
|
-
|
|
|
- bf->l_whence = 0;
|
|
|
-
|
|
|
- startoffset = bf->l_start;
|
|
|
- fsize = XFS_ISIZE(ip);
|
|
|
-
|
|
|
- setprealloc = clrprealloc = 0;
|
|
|
- switch (cmd) {
|
|
|
- case XFS_IOC_ZERO_RANGE:
|
|
|
- error = xfs_zero_file_space(ip, startoffset, bf->l_len);
|
|
|
- if (error)
|
|
|
- return error;
|
|
|
- setprealloc = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case XFS_IOC_RESVSP:
|
|
|
- case XFS_IOC_RESVSP64:
|
|
|
- error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
|
|
|
- XFS_BMAPI_PREALLOC);
|
|
|
- if (error)
|
|
|
- return error;
|
|
|
- setprealloc = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case XFS_IOC_UNRESVSP:
|
|
|
- case XFS_IOC_UNRESVSP64:
|
|
|
- error = xfs_free_file_space(ip, startoffset, bf->l_len);
|
|
|
- if (error)
|
|
|
- return error;
|
|
|
- break;
|
|
|
-
|
|
|
- case XFS_IOC_ALLOCSP:
|
|
|
- case XFS_IOC_ALLOCSP64:
|
|
|
- case XFS_IOC_FREESP:
|
|
|
- case XFS_IOC_FREESP64:
|
|
|
- /*
|
|
|
- * These operations actually do IO when extending the file, but
|
|
|
- * the allocation is done seperately to the zeroing that is
|
|
|
- * done. This set of operations need to be serialised against
|
|
|
- * other IO operations, such as truncate and buffered IO. We
|
|
|
- * need to take the IOLOCK here to serialise the allocation and
|
|
|
- * zeroing IO to prevent other IOLOCK holders (e.g. getbmap,
|
|
|
- * truncate, direct IO) from racing against the transient
|
|
|
- * allocated but not written state we can have here.
|
|
|
- */
|
|
|
- if (startoffset > fsize) {
|
|
|
- error = xfs_alloc_file_space(ip, fsize,
|
|
|
- startoffset - fsize, 0);
|
|
|
- if (error)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- iattr.ia_valid = ATTR_SIZE;
|
|
|
- iattr.ia_size = startoffset;
|
|
|
-
|
|
|
- error = xfs_setattr_size(ip, &iattr);
|
|
|
-
|
|
|
- if (error)
|
|
|
- return error;
|
|
|
-
|
|
|
- clrprealloc = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- ASSERT(0);
|
|
|
- return XFS_ERROR(EINVAL);
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * update the inode timestamp, mode, and prealloc flag bits
|
|
|
- */
|
|
|
- tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID);
|
|
|
- error = xfs_trans_reserve(tp, &M_RES(mp)->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 ((attr_flags & XFS_ATTR_DMI) == 0) {
|
|
|
- ip->i_d.di_mode &= ~S_ISUID;
|
|
|
-
|
|
|
- /*
|
|
|
- * Note that we don't have to worry about mandatory
|
|
|
- * file locking being disabled here because we only
|
|
|
- * clear the S_ISGID bit if the Group execute bit is
|
|
|
- * on, but if it was on then mandatory locking wouldn't
|
|
|
- * have been enabled.
|
|
|
- */
|
|
|
- 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 (setprealloc)
|
|
|
- ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
|
|
|
- else if (clrprealloc)
|
|
|
- ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;
|
|
|
-
|
|
|
- xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
|
|
- if (attr_flags & XFS_ATTR_SYNC)
|
|
|
- xfs_trans_set_sync(tp);
|
|
|
- return xfs_trans_commit(tp, 0);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* We need to check that the format of the data fork in the temporary inode is
|
|
|
* valid for the target inode before doing the swap. This is not a problem with
|