/* * FSBULKSTAT_SINGLE expects that *lastip contains the inode number * that we want to stat. However, FSINUMBERS and FSBULKSTAT expect * that *lastip contains either zero or the number of the last inode to * be examined by the previous call and return results starting with * the next inode after that. The new bulk request back end functions * take the inode to start with, so we have to compute the startino * parameter from lastino to maintain correct function. lastino == 0 * is a special case because it has traditionally meant "first inode * in filesystem".
*/ if (cmd == XFS_IOC_FSINUMBERS) {
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_inumbers(&breq, xfs_fsinumbers_fmt);
lastino = breq.startino - 1;
} elseif (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
breq.startino = lastino;
breq.icount = 1;
error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_one_fmt);
} else { /* XFS_IOC_FSBULKSTAT */
breq.startino = lastino ? lastino + 1 : 0;
error = xfs_bulkstat(&breq, xfs_fsbulkstat_one_fmt);
lastino = breq.startino - 1;
}
if (error) return error;
if (bulkreq.lastip != NULL &&
copy_to_user(bulkreq.lastip, &lastino, sizeof(xfs_ino_t))) return -EFAULT;
if (bulkreq.ocount != NULL &&
copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32))) return -EFAULT;
return 0;
}
/* Return 0 on success or positive error */ staticint
xfs_bulkstat_fmt( struct xfs_ibulk *breq, conststruct xfs_bulkstat *bstat)
{ if (copy_to_user(breq->ubuffer, bstat, sizeof(struct xfs_bulkstat))) return -EFAULT; return xfs_ibulk_advance(breq, sizeof(struct xfs_bulkstat));
}
/* * Check the incoming bulk request @hdr from userspace and initialize the * internal @breq bulk request appropriately. Returns 0 if the bulk request * should proceed; -ECANCELED if there's nothing to do; or the usual * negative error code.
*/ staticint
xfs_bulk_ireq_setup( struct xfs_mount *mp, conststruct xfs_bulk_ireq *hdr, struct xfs_ibulk *breq, void __user *ubuffer)
{ if (hdr->icount == 0 ||
(hdr->flags & ~XFS_BULK_IREQ_FLAGS_ALL) ||
memchr_inv(hdr->reserved, 0, sizeof(hdr->reserved))) return -EINVAL;
/* * The @ino parameter is a special value, so we must look it up here. * We're not allowed to have IREQ_AGNO, and we only return one inode * worth of data.
*/ if (hdr->flags & XFS_BULK_IREQ_SPECIAL) { if (hdr->flags & XFS_BULK_IREQ_AGNO) return -EINVAL;
/* * The IREQ_AGNO flag means that we only want results from a given AG. * If @hdr->ino is zero, we start iterating in that AG. If @hdr->ino is * beyond the specified AG then we return no results.
*/ if (hdr->flags & XFS_BULK_IREQ_AGNO) { if (hdr->agno >= mp->m_sb.sb_agcount) return -EINVAL;
/* Asking for an inode past the end of the AG? We're done! */ if (XFS_INO_TO_AGNO(mp, breq->startino) > hdr->agno) return -ECANCELED;
} elseif (hdr->agno) return -EINVAL;
/* Asking for an inode past the end of the FS? We're done! */ if (XFS_INO_TO_AGNO(mp, breq->startino) >= mp->m_sb.sb_agcount) return -ECANCELED;
if (hdr->flags & XFS_BULK_IREQ_NREXT64)
breq->flags |= XFS_IBULK_NREXT64;
/* Caller wants to see metadata directories in bulkstat output. */ if (hdr->flags & XFS_BULK_IREQ_METADIR)
breq->flags |= XFS_IBULK_METADIR;
return 0;
}
/* * Update the userspace bulk request @hdr to reflect the end state of the * internal bulk request @breq.
*/ staticvoid
xfs_bulk_ireq_teardown( struct xfs_bulk_ireq *hdr, struct xfs_ibulk *breq)
{
hdr->ino = breq->startino;
hdr->ocount = breq->ocount;
}
if (copy_from_user(&rgeo, arg, sizeof(rgeo))) return -EFAULT; if (rgeo.rg_flags) return -EINVAL; if (memchr_inv(&rgeo.rg_reserved, 0, sizeof(rgeo.rg_reserved))) return -EINVAL; if (!xfs_has_rtgroups(mp)) return -EINVAL;
rtg = xfs_rtgroup_get(mp, rgeo.rg_number); if (!rtg) return -EINVAL;
error = xfs_rtgroup_get_geometry(rtg, &rgeo);
xfs_rtgroup_put(rtg); if (error) return error;
if (copy_to_user(arg, &rgeo, sizeof(rgeo))) return -EFAULT; return 0;
}
if (rtflag != XFS_IS_REALTIME_INODE(ip)) { /* Can't change realtime flag if any extents are allocated. */ if (xfs_inode_has_filedata(ip)) return -EINVAL;
/* * If S_DAX is enabled on this file, we can only switch the * device if both support fsdax. We can't update S_DAX because * there might be other threads walking down the access paths.
*/ if (IS_DAX(VFS_I(ip)) &&
(mp->m_ddev_targp->bt_daxdev == NULL ||
(mp->m_rtdev_targp &&
mp->m_rtdev_targp->bt_daxdev == NULL))) return -EINVAL;
}
if (rtflag) { /* If realtime flag is set then must have realtime device */ if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 ||
xfs_extlen_to_rtxmod(mp, ip->i_extsize)) return -EINVAL;
}
/* diflags2 only valid for v3 inodes. */
i_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags); if (i_flags2 && !xfs_has_v3inodes(mp)) return -EINVAL;
/* * Make the stable writes flag match that of the device the inode * resides on when flipping the RT flag.
*/ if (rtflag != XFS_IS_REALTIME_INODE(ip) && S_ISREG(VFS_I(ip)->i_mode))
xfs_update_stable_writes(ip);
/* * Set up the transaction structure for the setattr operation, checking that we * have permission to do so. On success, return a clean transaction and the * inode locked exclusively ready for further operation specific checks. On * failure, return an error without modifying or locking the inode.
*/ staticstruct xfs_trans *
xfs_ioctl_setattr_get_trans( struct xfs_inode *ip, struct xfs_dquot *pdqp)
{ struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error = -EROFS;
if (xfs_is_readonly(mp)) goto out_error;
error = -EIO; if (xfs_is_shutdown(mp)) goto out_error;
/* * Validate a proposed extent size hint. For regular files, the hint can only * be changed if no extents are allocated.
*/ staticint
xfs_ioctl_setattr_check_extsize( struct xfs_inode *ip, struct file_kattr *fa)
{ struct xfs_mount *mp = ip->i_mount;
xfs_failaddr_t failaddr;
uint16_t new_diflags;
/* * Inode verifiers do not check that the extent size hint is an integer * multiple of the rt extent size on a directory with both rtinherit * and extszinherit flags set. Don't let sysadmins misconfigure * directories.
*/ if ((new_diflags & XFS_DIFLAG_RTINHERIT) &&
(new_diflags & XFS_DIFLAG_EXTSZINHERIT)) { unsignedint rtextsize_bytes;
error = xfs_ioctl_setattr_check_projid(ip, fa); if (error) return error;
/* * If disk quotas is on, we make sure that the dquots do exist on disk, * before we start any other transactions. Trying to do this later * is messy. We don't care to take a readlock to look at the ids * in inode here, because we can't hold it across the trans_reserve. * If the IDs do change before we take the ilock, we're covered * because the i_*dquot fields will get updated anyway.
*/ if (fa->fsx_valid && XFS_IS_QUOTA_ON(mp)) {
error = xfs_qm_vop_dqalloc(ip, VFS_I(ip)->i_uid,
VFS_I(ip)->i_gid, fa->fsx_projid,
XFS_QMOPT_PQUOTA, NULL, NULL, &pdqp); if (error) return error;
}
error = xfs_ioctl_setattr_check_extsize(ip, fa); if (error) goto error_trans_cancel;
error = xfs_ioctl_setattr_check_cowextsize(ip, fa); if (error) goto error_trans_cancel;
error = xfs_ioctl_setattr_xflags(tp, ip, fa); if (error) goto error_trans_cancel;
if (!fa->fsx_valid) goto skip_xattr; /* * Change file ownership. Must be the owner or privileged. CAP_FSETID * overrides the following restrictions: * * The set-user-ID and set-group-ID bits of a file will be cleared upon * successful return from chown()
*/
/* Change the ownerships and register project quota modifications */ if (ip->i_projid != fa->fsx_projid) { if (XFS_IS_PQUOTA_ON(mp)) {
olddquot = xfs_qm_vop_chown(tp, ip,
&ip->i_pdquot, pdqp);
}
ip->i_projid = fa->fsx_projid;
}
/* * Only set the extent size hint if we've already determined that the * extent size hint should be set on the inode. If no extent size flags * are set on the inode then unconditionally clear the extent size hint.
*/ if (ip->i_diflags & (XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT))
ip->i_extsize = XFS_B_TO_FSB(mp, fa->fsx_extsize); else
ip->i_extsize = 0;
if (xfs_has_v3inodes(mp)) { if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE)
ip->i_cowextsize = XFS_B_TO_FSB(mp, fa->fsx_cowextsize); else
ip->i_cowextsize = 0;
}
skip_xattr:
error = xfs_trans_commit(tp);
/* * Release any dquot(s) the inode had kept before chown.
*/
xfs_qm_dqrele(olddquot);
xfs_qm_dqrele(pdqp);
if (IS_SWAPFILE(file_inode(fd_file(f))) ||
IS_SWAPFILE(file_inode(fd_file(tmp)))) return -EINVAL;
/* * We need to ensure that the fds passed in point to XFS inodes * before we cast and access them as XFS structures as we have no * control over what the user passes us here.
*/ if (fd_file(f)->f_op != &xfs_file_operations ||
fd_file(tmp)->f_op != &xfs_file_operations) return -EINVAL;
ip = XFS_I(file_inode(fd_file(f)));
tip = XFS_I(file_inode(fd_file(tmp)));
/* 1 larger than sb_fname, so this ensures a trailing NUL char */
spin_lock(&mp->m_sb_lock);
memtostr_pad(label, sbp->sb_fname);
spin_unlock(&mp->m_sb_lock);
if (copy_to_user(user_label, label, sizeof(label))) return -EFAULT; return 0;
}
if (!capable(CAP_SYS_ADMIN)) return -EPERM; /* * The generic ioctl allows up to FSLABEL_MAX chars, but XFS is much * smaller, at 12 bytes. We copy one more to be sure we find the * (required) NULL character to test the incoming label length. * NB: The on disk label doesn't need to be null terminated.
*/ if (copy_from_user(label, newlabel, XFSLABEL_MAX + 1)) return -EFAULT;
len = strnlen(label, XFSLABEL_MAX + 1); if (len > sizeof(sbp->sb_fname)) return -EINVAL;
error = mnt_want_write_file(filp); if (error) return error;
/* * Now we do several things to satisfy userspace. * In addition to normal logging of the primary superblock, we also * immediately write these changes to sector zero for the primary, then * update all backup supers (as xfs_db does for a label change), then * invalidate the block device page cache. This is so that any prior * buffered reads from userspace (i.e. from blkid) are invalidated, * and userspace will see the newly-written label.
*/
error = xfs_sync_sb_buf(mp, true); if (error) goto out; /* * growfs also updates backup supers so lock against that.
*/
mutex_lock(&mp->m_growlock);
error = xfs_update_secondary_sbs(mp);
mutex_unlock(&mp->m_growlock);
invalidate_bdev(mp->m_ddev_targp->bt_bdev); if (xfs_has_rtsb(mp) && mp->m_rtdev_targp)
invalidate_bdev(mp->m_rtdev_targp->bt_bdev);
if (copy_to_user(uarg, &out, sizeof(out))) return -EFAULT; return 0;
}
/* * These long-unused ioctls were removed from the official ioctl API in 5.17, * but retain these definitions so that we can log warnings about them.
*/ #define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) #define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) #define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) #define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64)
/* * Note: some of the ioctl's return positive numbers as a * byte count indicating success, such as readlink_by_handle. * So we don't "sign flip" like most other routines. This means * true errors need to be returned as a negative value.
*/ long
xfs_file_ioctl( struct file *filp, unsignedint cmd, unsignedlong p)
{ struct inode *inode = file_inode(filp); struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; void __user *arg = (void __user *)p; int error;
trace_xfs_file_ioctl(ip);
switch (cmd) { case FITRIM: return xfs_ioc_trim(mp, arg); case FS_IOC_GETFSLABEL: return xfs_ioc_getlabel(mp, arg); case FS_IOC_SETFSLABEL: return xfs_ioc_setlabel(filp, mp, arg); case XFS_IOC_ALLOCSP: case XFS_IOC_FREESP: case XFS_IOC_ALLOCSP64: case XFS_IOC_FREESP64:
xfs_warn_once(mp, "%s should use fallocate; XFS_IOC_{ALLOC,FREE}SP ioctl unsupported",
current->comm); return -ENOTTY; case XFS_IOC_DIOINFO: { struct xfs_buftarg *target = xfs_inode_buftarg(ip); struct dioattr da;
da.d_mem = target->bt_logical_sectorsize;
/* * See xfs_report_dioalign() for an explanation about why this * reports a value larger than the sector size for COW inodes.
*/ if (xfs_is_cow_inode(ip))
da.d_miniosz = xfs_inode_alloc_unitsize(ip); else
da.d_miniosz = target->bt_logical_sectorsize;
da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1);
if (copy_to_user(arg, &da, sizeof(da))) return -EFAULT; return 0;
}
case XFS_IOC_FSBULKSTAT_SINGLE: case XFS_IOC_FSBULKSTAT: case XFS_IOC_FSINUMBERS: return xfs_ioc_fsbulkstat(filp, cmd, arg);
case XFS_IOC_BULKSTAT: return xfs_ioc_bulkstat(filp, cmd, arg); case XFS_IOC_INUMBERS: return xfs_ioc_inumbers(mp, cmd, arg);
case XFS_IOC_FSGEOMETRY_V1: return xfs_ioc_fsgeometry(mp, arg, 3); case XFS_IOC_FSGEOMETRY_V4: return xfs_ioc_fsgeometry(mp, arg, 4); case XFS_IOC_FSGEOMETRY: return xfs_ioc_fsgeometry(mp, arg, 5);
case XFS_IOC_AG_GEOMETRY: return xfs_ioc_ag_geometry(mp, arg); case XFS_IOC_RTGROUP_GEOMETRY: return xfs_ioc_rtgroup_geometry(mp, arg);
case XFS_IOC_GETVERSION: return put_user(inode->i_generation, (int __user *)arg);
case XFS_IOC_FSGETXATTRA: return xfs_ioc_fsgetxattra(ip, arg); case XFS_IOC_GETPARENTS: return xfs_ioc_getparents(filp, arg); case XFS_IOC_GETPARENTS_BY_HANDLE: return xfs_ioc_getparents_by_handle(filp, arg); case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: case XFS_IOC_GETBMAPX: return xfs_ioc_getbmap(filp, cmd, arg);
case FS_IOC_GETFSMAP: return xfs_ioc_getfsmap(ip, arg);
case XFS_IOC_SCRUBV_METADATA: return xfs_ioc_scrubv_metadata(filp, arg); case XFS_IOC_SCRUB_METADATA: return xfs_ioc_scrub_metadata(filp, arg);
case XFS_IOC_FD_TO_HANDLE: case XFS_IOC_PATH_TO_HANDLE: case XFS_IOC_PATH_TO_FSHANDLE: {
xfs_fsop_handlereq_t hreq;
if (copy_from_user(&hreq, arg, sizeof(hreq))) return -EFAULT; return xfs_find_handle(cmd, &hreq);
} case XFS_IOC_OPEN_BY_HANDLE: {
xfs_fsop_handlereq_t hreq;
if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) return -EFAULT; return xfs_open_by_handle(filp, &hreq);
}
case XFS_IOC_READLINK_BY_HANDLE: {
xfs_fsop_handlereq_t hreq;
if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) return -EFAULT; return xfs_readlink_by_handle(filp, &hreq);
} case XFS_IOC_ATTRLIST_BY_HANDLE: return xfs_attrlist_by_handle(filp, arg);
case XFS_IOC_ATTRMULTI_BY_HANDLE: return xfs_attrmulti_by_handle(filp, arg);
case XFS_IOC_SWAPEXT: { struct xfs_swapext sxp;
if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t))) return -EFAULT;
error = mnt_want_write_file(filp); if (error) return error;
error = xfs_ioc_swapext(&sxp);
mnt_drop_write_file(filp); return error;
}
case XFS_IOC_FSCOUNTS: return xfs_ioctl_fs_counts(mp, arg);
case XFS_IOC_SET_RESBLKS: case XFS_IOC_GET_RESBLKS: return xfs_ioctl_getset_resblocks(filp, cmd, arg);
case XFS_IOC_FSGROWFSDATA: { struct xfs_growfs_data in;
if (copy_from_user(&in, arg, sizeof(in))) return -EFAULT;
case XFS_IOC_EXCHANGE_RANGE: return xfs_ioc_exchange_range(filp, arg); case XFS_IOC_START_COMMIT: return xfs_ioc_start_commit(filp, arg); case XFS_IOC_COMMIT_RANGE: return xfs_ioc_commit_range(filp, arg);
default: return -ENOTTY;
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.