STATIC int xfs_ioc_setxflags( xfs_inode_t *ip, struct file *filp, void __user *arg) { struct fsxattr fa; unsigned int flags; unsigned int mask; int error; if (copy_from_user(&flags, arg, sizeof(flags))) return -EFAULT; if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ FS_NOATIME_FL | FS_NODUMP_FL | \ FS_SYNC_FL)) return -EOPNOTSUPP; mask = FSX_XFLAGS; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) mask |= FSX_NONBLOCK; fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); error = mnt_want_write_file(filp); if (error) return error; error = xfs_ioctl_setattr(ip, &fa, mask); mnt_drop_write_file(filp); return -error; }
STATIC int xfs_ioc_xattr( vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, unsigned long arg) { struct fsxattr fa; vattr_t va; int error; int attr_flags; unsigned int flags; switch (cmd) { case XFS_IOC_FSGETXATTR: { va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS; VOP_GETATTR(vp, &va, 0, NULL, error); if (error) return -error; fa.fsx_xflags = va.va_xflags; fa.fsx_extsize = va.va_extsize; fa.fsx_nextents = va.va_nextents; if (copy_to_user((struct fsxattr *)arg, &fa, sizeof(fa))) return -XFS_ERROR(EFAULT); return 0; } case XFS_IOC_FSSETXATTR: { if (copy_from_user(&fa, (struct fsxattr *)arg, sizeof(fa))) return -XFS_ERROR(EFAULT); attr_flags = 0; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE; va.va_xflags = fa.fsx_xflags; va.va_extsize = fa.fsx_extsize; VOP_SETATTR(vp, &va, attr_flags, NULL, error); if (!error) vn_revalidate(vp); /* update Linux inode flags */ return -error; } case XFS_IOC_FSGETXATTRA: { va.va_mask = XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_ANEXTENTS; VOP_GETATTR(vp, &va, 0, NULL, error); if (error) return -error; fa.fsx_xflags = va.va_xflags; fa.fsx_extsize = va.va_extsize; fa.fsx_nextents = va.va_anextents; if (copy_to_user((struct fsxattr *)arg, &fa, sizeof(fa))) return -XFS_ERROR(EFAULT); return 0; } case XFS_IOC_GETXFLAGS: { flags = xfs_di2lxflags(ip->i_d.di_flags); if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags))) return -XFS_ERROR(EFAULT); return 0; } case XFS_IOC_SETXFLAGS: { if (copy_from_user(&flags, (unsigned int *)arg, sizeof(flags))) return -XFS_ERROR(EFAULT); if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \ LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \ LINUX_XFLAG_SYNC)) return -XFS_ERROR(EOPNOTSUPP); attr_flags = 0; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; va.va_mask = XFS_AT_XFLAGS; va.va_xflags = xfs_merge_ioc_xflags(flags, xfs_dic2xflags(&ip->i_d, ARCH_NOCONVERT)); VOP_SETATTR(vp, &va, attr_flags, NULL, error); if (!error) vn_revalidate(vp); /* update Linux inode flags */ return -error; } case XFS_IOC_GETVERSION: { flags = LINVFS_GET_IP(vp)->i_generation; if (copy_to_user((unsigned int *)arg, &flags, sizeof(flags))) return -XFS_ERROR(EFAULT); return 0; } default: return -ENOTTY; } }
STATIC int xfs_ioc_xattr( vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, void __user *arg) { struct fsxattr fa; struct vattr *vattr; int error = 0; int attr_flags; unsigned int flags; vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); if (unlikely(!vattr)) return -ENOMEM; switch (cmd) { case XFS_IOC_FSGETXATTR: { vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ XFS_AT_NEXTENTS | XFS_AT_PROJID; VOP_GETATTR(vp, vattr, 0, NULL, error); if (unlikely(error)) { error = -error; break; } fa.fsx_xflags = vattr->va_xflags; fa.fsx_extsize = vattr->va_extsize; fa.fsx_nextents = vattr->va_nextents; fa.fsx_projid = vattr->va_projid; if (copy_to_user(arg, &fa, sizeof(fa))) { error = -EFAULT; break; } break; } 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; 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; VOP_SETATTR(vp, vattr, attr_flags, NULL, error); if (likely(!error)) __vn_revalidate(vp, vattr); /* update flags */ error = -error; break; } case XFS_IOC_FSGETXATTRA: { vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ XFS_AT_ANEXTENTS | XFS_AT_PROJID; VOP_GETATTR(vp, vattr, 0, NULL, error); if (unlikely(error)) { error = -error; break; } fa.fsx_xflags = vattr->va_xflags; fa.fsx_extsize = vattr->va_extsize; fa.fsx_nextents = vattr->va_anextents; fa.fsx_projid = vattr->va_projid; if (copy_to_user(arg, &fa, sizeof(fa))) { error = -EFAULT; break; } break; } case XFS_IOC_GETXFLAGS: { flags = xfs_di2lxflags(ip->i_d.di_flags); if (copy_to_user(arg, &flags, sizeof(flags))) error = -EFAULT; break; } case XFS_IOC_SETXFLAGS: { if (copy_from_user(&flags, arg, sizeof(flags))) { error = -EFAULT; break; } if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \ LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \ LINUX_XFLAG_SYNC)) { error = -EOPNOTSUPP; break; } attr_flags = 0; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; vattr->va_mask = XFS_AT_XFLAGS; vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); VOP_SETATTR(vp, vattr, attr_flags, NULL, error); if (likely(!error)) __vn_revalidate(vp, vattr); /* update flags */ error = -error; break; } case XFS_IOC_GETVERSION: { flags = vn_to_inode(vp)->i_generation; if (copy_to_user(arg, &flags, sizeof(flags))) error = -EFAULT; break; } default: error = -ENOTTY; break; } kfree(vattr); return error; }