|
@@ -1179,85 +1179,85 @@ xfs_ioc_fsgetxattr(
|
|
|
}
|
|
|
|
|
|
STATIC int
|
|
|
-xfs_ioc_xattr(
|
|
|
+xfs_ioc_fssetxattr(
|
|
|
xfs_inode_t *ip,
|
|
|
struct file *filp,
|
|
|
- unsigned int cmd,
|
|
|
void __user *arg)
|
|
|
{
|
|
|
struct fsxattr fa;
|
|
|
struct bhv_vattr *vattr;
|
|
|
- int error = 0;
|
|
|
+ int error;
|
|
|
int attr_flags;
|
|
|
- unsigned int flags;
|
|
|
+
|
|
|
+ if (copy_from_user(&fa, arg, sizeof(fa)))
|
|
|
+ return -EFAULT;
|
|
|
|
|
|
vattr = kmalloc(sizeof(*vattr), GFP_KERNEL);
|
|
|
if (unlikely(!vattr))
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- switch (cmd) {
|
|
|
- case XFS_IOC_FSSETXATTR: {
|
|
|
- if (copy_from_user(&fa, arg, sizeof(fa))) {
|
|
|
- error = -EFAULT;
|
|
|
- break;
|
|
|
- }
|
|
|
+ attr_flags = 0;
|
|
|
+ if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
|
|
|
+ attr_flags |= ATTR_NONBLOCK;
|
|
|
|
|
|
- attr_flags = 0;
|
|
|
- if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
|
|
|
- attr_flags |= ATTR_NONBLOCK;
|
|
|
+ vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID;
|
|
|
+ vattr->va_xflags = fa.fsx_xflags;
|
|
|
+ vattr->va_extsize = fa.fsx_extsize;
|
|
|
+ vattr->va_projid = fa.fsx_projid;
|
|
|
|
|
|
- vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID;
|
|
|
- vattr->va_xflags = fa.fsx_xflags;
|
|
|
- vattr->va_extsize = fa.fsx_extsize;
|
|
|
- vattr->va_projid = fa.fsx_projid;
|
|
|
+ error = -xfs_setattr(ip, vattr, attr_flags, NULL);
|
|
|
+ if (!error)
|
|
|
+ vn_revalidate(XFS_ITOV(ip)); /* update flags */
|
|
|
+ kfree(vattr);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- error = xfs_setattr(ip, vattr, attr_flags, NULL);
|
|
|
- if (likely(!error))
|
|
|
- vn_revalidate(XFS_ITOV(ip)); /* update flags */
|
|
|
- error = -error;
|
|
|
- break;
|
|
|
- }
|
|
|
+STATIC int
|
|
|
+xfs_ioc_getxflags(
|
|
|
+ xfs_inode_t *ip,
|
|
|
+ void __user *arg)
|
|
|
+{
|
|
|
+ unsigned int flags;
|
|
|
|
|
|
- case XFS_IOC_GETXFLAGS: {
|
|
|
- flags = xfs_di2lxflags(ip->i_d.di_flags);
|
|
|
- if (copy_to_user(arg, &flags, sizeof(flags)))
|
|
|
- error = -EFAULT;
|
|
|
- break;
|
|
|
- }
|
|
|
+ flags = xfs_di2lxflags(ip->i_d.di_flags);
|
|
|
+ if (copy_to_user(arg, &flags, sizeof(flags)))
|
|
|
+ return -EFAULT;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- case XFS_IOC_SETXFLAGS: {
|
|
|
- if (copy_from_user(&flags, arg, sizeof(flags))) {
|
|
|
- error = -EFAULT;
|
|
|
- break;
|
|
|
- }
|
|
|
+STATIC int
|
|
|
+xfs_ioc_setxflags(
|
|
|
+ xfs_inode_t *ip,
|
|
|
+ struct file *filp,
|
|
|
+ void __user *arg)
|
|
|
+{
|
|
|
+ struct bhv_vattr *vattr;
|
|
|
+ unsigned int flags;
|
|
|
+ int attr_flags;
|
|
|
+ int error;
|
|
|
|
|
|
- if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
|
|
|
- FS_NOATIME_FL | FS_NODUMP_FL | \
|
|
|
- FS_SYNC_FL)) {
|
|
|
- error = -EOPNOTSUPP;
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (copy_from_user(&flags, arg, sizeof(flags)))
|
|
|
+ return -EFAULT;
|
|
|
|
|
|
- attr_flags = 0;
|
|
|
- if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
|
|
|
- attr_flags |= ATTR_NONBLOCK;
|
|
|
+ if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
|
|
|
+ FS_NOATIME_FL | FS_NODUMP_FL | \
|
|
|
+ FS_SYNC_FL))
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
|
|
- vattr->va_mask = XFS_AT_XFLAGS;
|
|
|
- vattr->va_xflags = xfs_merge_ioc_xflags(flags,
|
|
|
- xfs_ip2xflags(ip));
|
|
|
+ vattr = kmalloc(sizeof(*vattr), GFP_KERNEL);
|
|
|
+ if (unlikely(!vattr))
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- error = xfs_setattr(ip, vattr, attr_flags, NULL);
|
|
|
- if (likely(!error))
|
|
|
- vn_revalidate(XFS_ITOV(ip)); /* update flags */
|
|
|
- error = -error;
|
|
|
- break;
|
|
|
- }
|
|
|
+ attr_flags = 0;
|
|
|
+ if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
|
|
|
+ attr_flags |= ATTR_NONBLOCK;
|
|
|
|
|
|
- default:
|
|
|
- error = -ENOTTY;
|
|
|
- break;
|
|
|
- }
|
|
|
+ vattr->va_mask = XFS_AT_XFLAGS;
|
|
|
+ vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
|
|
|
|
|
|
+ error = -xfs_setattr(ip, vattr, attr_flags, NULL);
|
|
|
+ if (likely(!error))
|
|
|
+ vn_revalidate(XFS_ITOV(ip)); /* update flags */
|
|
|
kfree(vattr);
|
|
|
return error;
|
|
|
}
|
|
@@ -1332,3 +1332,259 @@ xfs_ioc_getbmapx(
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+int
|
|
|
+xfs_ioctl(
|
|
|
+ xfs_inode_t *ip,
|
|
|
+ struct file *filp,
|
|
|
+ int ioflags,
|
|
|
+ unsigned int cmd,
|
|
|
+ void __user *arg)
|
|
|
+{
|
|
|
+ struct inode *inode = filp->f_path.dentry->d_inode;
|
|
|
+ xfs_mount_t *mp = ip->i_mount;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ xfs_itrace_entry(XFS_I(inode));
|
|
|
+ switch (cmd) {
|
|
|
+
|
|
|
+ case XFS_IOC_ALLOCSP:
|
|
|
+ case XFS_IOC_FREESP:
|
|
|
+ case XFS_IOC_RESVSP:
|
|
|
+ case XFS_IOC_UNRESVSP:
|
|
|
+ case XFS_IOC_ALLOCSP64:
|
|
|
+ case XFS_IOC_FREESP64:
|
|
|
+ case XFS_IOC_RESVSP64:
|
|
|
+ case XFS_IOC_UNRESVSP64:
|
|
|
+ /*
|
|
|
+ * Only allow the sys admin to reserve space unless
|
|
|
+ * unwritten extents are enabled.
|
|
|
+ */
|
|
|
+ if (!xfs_sb_version_hasextflgbit(&mp->m_sb) &&
|
|
|
+ !capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ return xfs_ioc_space(ip, inode, filp, ioflags, cmd, arg);
|
|
|
+
|
|
|
+ case XFS_IOC_DIOINFO: {
|
|
|
+ struct dioattr da;
|
|
|
+ xfs_buftarg_t *target =
|
|
|
+ XFS_IS_REALTIME_INODE(ip) ?
|
|
|
+ mp->m_rtdev_targp : mp->m_ddev_targp;
|
|
|
+
|
|
|
+ da.d_mem = da.d_miniosz = 1 << target->bt_sshift;
|
|
|
+ da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1);
|
|
|
+
|
|
|
+ if (copy_to_user(arg, &da, sizeof(da)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_FSBULKSTAT_SINGLE:
|
|
|
+ case XFS_IOC_FSBULKSTAT:
|
|
|
+ case XFS_IOC_FSINUMBERS:
|
|
|
+ return xfs_ioc_bulkstat(mp, cmd, arg);
|
|
|
+
|
|
|
+ case XFS_IOC_FSGEOMETRY_V1:
|
|
|
+ return xfs_ioc_fsgeometry_v1(mp, arg);
|
|
|
+
|
|
|
+ case XFS_IOC_FSGEOMETRY:
|
|
|
+ return xfs_ioc_fsgeometry(mp, arg);
|
|
|
+
|
|
|
+ case XFS_IOC_GETVERSION:
|
|
|
+ return put_user(inode->i_generation, (int __user *)arg);
|
|
|
+
|
|
|
+ case XFS_IOC_FSGETXATTR:
|
|
|
+ return xfs_ioc_fsgetxattr(ip, 0, arg);
|
|
|
+ case XFS_IOC_FSGETXATTRA:
|
|
|
+ return xfs_ioc_fsgetxattr(ip, 1, arg);
|
|
|
+ case XFS_IOC_FSSETXATTR:
|
|
|
+ return xfs_ioc_fssetxattr(ip, filp, arg);
|
|
|
+ case XFS_IOC_GETXFLAGS:
|
|
|
+ return xfs_ioc_getxflags(ip, arg);
|
|
|
+ case XFS_IOC_SETXFLAGS:
|
|
|
+ return xfs_ioc_setxflags(ip, filp, arg);
|
|
|
+
|
|
|
+ case XFS_IOC_FSSETDM: {
|
|
|
+ struct fsdmidata dmi;
|
|
|
+
|
|
|
+ if (copy_from_user(&dmi, arg, sizeof(dmi)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+
|
|
|
+ error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask,
|
|
|
+ dmi.fsd_dmstate);
|
|
|
+ return -error;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_GETBMAP:
|
|
|
+ case XFS_IOC_GETBMAPA:
|
|
|
+ return xfs_ioc_getbmap(ip, ioflags, cmd, arg);
|
|
|
+
|
|
|
+ case XFS_IOC_GETBMAPX:
|
|
|
+ return xfs_ioc_getbmapx(ip, arg);
|
|
|
+
|
|
|
+ case XFS_IOC_FD_TO_HANDLE:
|
|
|
+ case XFS_IOC_PATH_TO_HANDLE:
|
|
|
+ case XFS_IOC_PATH_TO_FSHANDLE:
|
|
|
+ return xfs_find_handle(cmd, arg);
|
|
|
+
|
|
|
+ case XFS_IOC_OPEN_BY_HANDLE:
|
|
|
+ return xfs_open_by_handle(mp, arg, filp, inode);
|
|
|
+
|
|
|
+ case XFS_IOC_FSSETDM_BY_HANDLE:
|
|
|
+ return xfs_fssetdm_by_handle(mp, arg, inode);
|
|
|
+
|
|
|
+ case XFS_IOC_READLINK_BY_HANDLE:
|
|
|
+ return xfs_readlink_by_handle(mp, arg, inode);
|
|
|
+
|
|
|
+ case XFS_IOC_ATTRLIST_BY_HANDLE:
|
|
|
+ return xfs_attrlist_by_handle(mp, arg, inode);
|
|
|
+
|
|
|
+ case XFS_IOC_ATTRMULTI_BY_HANDLE:
|
|
|
+ return xfs_attrmulti_by_handle(mp, arg, inode);
|
|
|
+
|
|
|
+ case XFS_IOC_SWAPEXT: {
|
|
|
+ error = xfs_swapext((struct xfs_swapext __user *)arg);
|
|
|
+ return -error;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_FSCOUNTS: {
|
|
|
+ xfs_fsop_counts_t out;
|
|
|
+
|
|
|
+ error = xfs_fs_counts(mp, &out);
|
|
|
+ if (error)
|
|
|
+ return -error;
|
|
|
+
|
|
|
+ if (copy_to_user(arg, &out, sizeof(out)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_SET_RESBLKS: {
|
|
|
+ xfs_fsop_resblks_t inout;
|
|
|
+ __uint64_t in;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ if (copy_from_user(&inout, arg, sizeof(inout)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+
|
|
|
+ /* input parameter is passed in resblks field of structure */
|
|
|
+ in = inout.resblks;
|
|
|
+ error = xfs_reserve_blocks(mp, &in, &inout);
|
|
|
+ if (error)
|
|
|
+ return -error;
|
|
|
+
|
|
|
+ if (copy_to_user(arg, &inout, sizeof(inout)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_GET_RESBLKS: {
|
|
|
+ xfs_fsop_resblks_t out;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ error = xfs_reserve_blocks(mp, NULL, &out);
|
|
|
+ if (error)
|
|
|
+ return -error;
|
|
|
+
|
|
|
+ if (copy_to_user(arg, &out, sizeof(out)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_FSGROWFSDATA: {
|
|
|
+ xfs_growfs_data_t in;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ if (copy_from_user(&in, arg, sizeof(in)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+
|
|
|
+ error = xfs_growfs_data(mp, &in);
|
|
|
+ return -error;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_FSGROWFSLOG: {
|
|
|
+ xfs_growfs_log_t in;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ if (copy_from_user(&in, arg, sizeof(in)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+
|
|
|
+ error = xfs_growfs_log(mp, &in);
|
|
|
+ return -error;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_FSGROWFSRT: {
|
|
|
+ xfs_growfs_rt_t in;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ if (copy_from_user(&in, arg, sizeof(in)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+
|
|
|
+ error = xfs_growfs_rt(mp, &in);
|
|
|
+ return -error;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_FREEZE:
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ if (inode->i_sb->s_frozen == SB_UNFROZEN)
|
|
|
+ freeze_bdev(inode->i_sb->s_bdev);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ case XFS_IOC_THAW:
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+ if (inode->i_sb->s_frozen != SB_UNFROZEN)
|
|
|
+ thaw_bdev(inode->i_sb->s_bdev, inode->i_sb);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ case XFS_IOC_GOINGDOWN: {
|
|
|
+ __uint32_t in;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ if (get_user(in, (__uint32_t __user *)arg))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+
|
|
|
+ error = xfs_fs_goingdown(mp, in);
|
|
|
+ return -error;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_ERROR_INJECTION: {
|
|
|
+ xfs_error_injection_t in;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ if (copy_from_user(&in, arg, sizeof(in)))
|
|
|
+ return -XFS_ERROR(EFAULT);
|
|
|
+
|
|
|
+ error = xfs_errortag_add(in.errtag, mp);
|
|
|
+ return -error;
|
|
|
+ }
|
|
|
+
|
|
|
+ case XFS_IOC_ERROR_CLEARALL:
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ error = xfs_errortag_clearall(mp, 1);
|
|
|
+ return -error;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -ENOTTY;
|
|
|
+ }
|
|
|
+}
|