int xfs_ioc_space( struct xfs_inode *ip, struct inode *inode, struct file *filp, int ioflags, unsigned int cmd, xfs_flock64_t *bf) { int attr_flags = 0; int error; /* * Only allow the sys admin to reserve space unless * unwritten extents are enabled. */ if (!xfs_sb_version_hasextflgbit(&ip->i_mount->m_sb) && !capable(CAP_SYS_ADMIN)) return -XFS_ERROR(EPERM); if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) return -XFS_ERROR(EPERM); if (!(filp->f_mode & FMODE_WRITE)) return -XFS_ERROR(EBADF); if (!S_ISREG(inode->i_mode)) return -XFS_ERROR(EINVAL); if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= XFS_ATTR_NONBLOCK; if (ioflags & IO_INVIS) attr_flags |= XFS_ATTR_DMI; error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags); return -error; }
STATIC long xfs_vn_fallocate( struct inode *inode, int mode, loff_t offset, loff_t len) { 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; if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) return -EOPNOTSUPP; /* preallocation on directories not yet supported */ error = -ENODEV; if (S_ISDIR(inode->i_mode)) goto out_error; bf.l_whence = 0; bf.l_start = offset; bf.l_len = len; xfs_ilock(ip, XFS_IOLOCK_EXCL); 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); if (error) goto out_unlock; } /* * RHEL6 porting note: mainline only does sync preallocations here on * O_SYNC files as it is passed a filp and can check this. For RHEL6, * just default to the old "always sync" behaviour as we cannot work * out if we are operating in a sync context or not. */ attr_flags |= XFS_ATTR_SYNC; error = -xfs_change_file_space(ip, cmd, &bf, 0, attr_flags); if (error) goto out_unlock; /* Change file size if needed */ if (new_size) { struct iattr iattr; iattr.ia_valid = ATTR_SIZE; iattr.ia_size = new_size; error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK); } out_unlock: xfs_iunlock(ip, XFS_IOLOCK_EXCL); out_error: return error; }