📄 xfs_ioctl.c
字号:
struct inode *inode, struct file *filp, int flags, unsigned int cmd, void __user *arg);STATIC intxfs_ioc_bulkstat( xfs_mount_t *mp, unsigned int cmd, void __user *arg);STATIC intxfs_ioc_fsgeometry_v1( xfs_mount_t *mp, void __user *arg);STATIC intxfs_ioc_fsgeometry( xfs_mount_t *mp, void __user *arg);STATIC intxfs_ioc_xattr( bhv_vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, void __user *arg);STATIC intxfs_ioc_fsgetxattr( xfs_inode_t *ip, int attr, void __user *arg);STATIC intxfs_ioc_getbmap( struct xfs_inode *ip, int flags, unsigned int cmd, void __user *arg);STATIC intxfs_ioc_getbmapx( struct xfs_inode *ip, void __user *arg);intxfs_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; bhv_vnode_t *vp = vn_from_inode(inode); xfs_mount_t *mp = ip->i_mount; int error; vn_trace_entry(XFS_I(inode), "xfs_ioctl", (inst_t *)__return_address); 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 = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? 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_GETXFLAGS: case XFS_IOC_SETXFLAGS: case XFS_IOC_FSSETXATTR: return xfs_ioc_xattr(vp, ip, filp, cmd, 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; }}STATIC intxfs_ioc_space( struct xfs_inode *ip, struct inode *inode, struct file *filp, int ioflags, unsigned int cmd, void __user *arg){ xfs_flock64_t bf; int attr_flags = 0; int error; 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 (copy_from_user(&bf, arg, sizeof(bf))) return -XFS_ERROR(EFAULT); if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; if (ioflags & IO_INVIS) attr_flags |= ATTR_DMI; error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos, NULL, attr_flags); return -error;}STATIC intxfs_ioc_bulkstat( xfs_mount_t *mp, unsigned int cmd, void __user *arg){ xfs_fsop_bulkreq_t bulkreq; int count; /* # of records returned */ xfs_ino_t inlast; /* last inode number */ int done; int error; /* done = 1 if there are more stats to get and if bulkstat */ /* should be called again (unused here, but used in dmapi) */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (XFS_FORCED_SHUTDOWN(mp)) return -XFS_ERROR(EIO); if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) return -XFS_ERROR(EFAULT); if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) return -XFS_ERROR(EFAULT); if ((count = bulkreq.icount) <= 0) return -XFS_ERROR(EINVAL); if (bulkreq.ubuffer == NULL) return -XFS_ERROR(EINVAL); if (cmd == XFS_IOC_FSINUMBERS) error = xfs_inumbers(mp, &inlast, &count, bulkreq.ubuffer, xfs_inumbers_fmt); else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) error = xfs_bulkstat_single(mp, &inlast, bulkreq.ubuffer, &done); else /* XFS_IOC_FSBULKSTAT */ error = xfs_bulkstat(mp, &inlast, &count, (bulkstat_one_pf)xfs_bulkstat_one, NULL, sizeof(xfs_bstat_t), bulkreq.ubuffer, BULKSTAT_FG_QUICK, &done); if (error) return -error; if (bulkreq.ocount != NULL) { if (copy_to_user(bulkreq.lastip, &inlast, sizeof(xfs_ino_t))) return -XFS_ERROR(EFAULT); if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) return -XFS_ERROR(EFAULT); } return 0;}STATIC intxfs_ioc_fsgeometry_v1( xfs_mount_t *mp, void __user *arg){ xfs_fsop_geom_v1_t fsgeo; int error; error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3); if (error) return -error; if (copy_to_user(arg, &fsgeo, sizeof(fsgeo))) return -XFS_ERROR(EFAULT); return 0;}STATIC intxfs_ioc_fsgeometry( xfs_mount_t *mp, void __user *arg){ xfs_fsop_geom_t fsgeo; int error; error = xfs_fs_geometry(mp, &fsgeo, 4); if (error) return -error; if (copy_to_user(arg, &fsgeo, sizeof(fsgeo))) return -XFS_ERROR(EFAULT); return 0;}/* * Linux extended inode flags interface. */STATIC unsigned intxfs_merge_ioc_xflags( unsigned int flags, unsigned int start){ unsigned int xflags = start; if (flags & FS_IMMUTABLE_FL) xflags |= XFS_XFLAG_IMMUTABLE; else xflags &= ~XFS_XFLAG_IMMUTABLE; if (flags & FS_APPEND_FL) xflags |= XFS_XFLAG_APPEND; else xflags &= ~XFS_XFLAG_APPEND; if (flags & FS_SYNC_FL) xflags |= XFS_XFLAG_SYNC; else xflags &= ~XFS_XFLAG_SYNC; if (flags & FS_NOATIME_FL) xflags |= XFS_XFLAG_NOATIME; else xflags &= ~XFS_XFLAG_NOATIME; if (flags & FS_NODUMP_FL) xflags |= XFS_XFLAG_NODUMP; else xflags &= ~XFS_XFLAG_NODUMP; return xflags;}STATIC unsigned intxfs_di2lxflags( __uint16_t di_flags){ unsigned int flags = 0; if (di_flags & XFS_DIFLAG_IMMUTABLE) flags |= FS_IMMUTABLE_FL; if (di_flags & XFS_DIFLAG_APPEND) flags |= FS_APPEND_FL; if (di_flags & XFS_DIFLAG_SYNC) flags |= FS_SYNC_FL; if (di_flags & XFS_DIFLAG_NOATIME) flags |= FS_NOATIME_FL; if (di_flags & XFS_DIFLAG_NODUMP) flags |= FS_NODUMP_FL; return flags;}STATIC intxfs_ioc_fsgetxattr( xfs_inode_t *ip, int attr, void __user *arg){ struct fsxattr fa; xfs_ilock(ip, XFS_ILOCK_SHARED); fa.fsx_xflags = xfs_ip2xflags(ip); fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; fa.fsx_projid = ip->i_d.di_projid; if (attr) { if (ip->i_afp) { if (ip->i_afp->if_flags & XFS_IFEXTENTS) fa.fsx_nextents = ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t); else fa.fsx_nextents = ip->i_d.di_anextents; } else fa.fsx_nextents = 0; } else { if (ip->i_df.if_flags & XFS_IFEXTENTS) fa.fsx_nextents = ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t); else fa.fsx_nextents = ip->i_d.di_nextents; } xfs_iunlock(ip, XFS_ILOCK_SHARED); if (copy_to_user(arg, &fa, sizeof(fa))) return -EFAULT; return 0;}STATIC intxfs_ioc_xattr( bhv_vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, void __user *arg){ struct fsxattr fa; struct bhv_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_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; error = xfs_setattr(ip, vattr, attr_flags, NULL); if (likely(!error)) __vn_revalidate(vp, vattr); /* update flags */ error = -error; 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 & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ FS_NOATIME_FL | FS_NODUMP_FL | \ FS_SYNC_FL)) { 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)); error = xfs_setattr(ip, vattr, attr_flags, NULL); if (likely(!error)) __vn_revalidate(vp, vattr); /* update flags */ error = -error; break; } default: error = -ENOTTY; break; } kfree(vattr); return error;}STATIC intxfs_ioc_getbmap( struct xfs_inode *ip, int ioflags, unsigned int cmd, void __user *arg){ struct getbmap bm; int iflags; int error; if (copy_from_user(&bm, arg, sizeof(bm))) return -XFS_ERROR(EFAULT); if (bm.bmv_count < 2) return -XFS_ERROR(EINVAL); iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); if (ioflags & IO_INVIS) iflags |= BMV_IF_NO_DMAPI_READ; error = xfs_getbmap(ip, &bm, (struct getbmap __user *)arg+1, iflags); if (error) return -error; if (copy_to_user(arg, &bm, sizeof(bm))) return -XFS_ERROR(EFAULT); return 0;}STATIC intxfs_ioc_getbmapx( struct xfs_inode *ip, void __user *arg){ struct getbmapx bmx; struct getbmap bm; int iflags; int error; if (copy_from_user(&bmx, arg, sizeof(bmx))) return -XFS_ERROR(EFAULT); if (bmx.bmv_count < 2) return -XFS_ERROR(EINVAL); /* * Map input getbmapx structure to a getbmap * structure for xfs_getbmap. */ GETBMAP_CONVERT(bmx, bm); iflags = bmx.bmv_iflags; if (iflags & (~BMV_IF_VALID)) return -XFS_ERROR(EINVAL); iflags |= BMV_IF_EXTENDED; error = xfs_getbmap(ip, &bm, (struct getbmapx __user *)arg+1, iflags); if (error) return -error; GETBMAP_CONVERT(bm, bmx); if (copy_to_user(arg, &bmx, sizeof(bmx))) return -XFS_ERROR(EFAULT); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -