On Thu, May 09, 2024 at 05:14:59PM +0200, Andrey Albershteyn wrote: > As XFS didn't have ioctls for special files setting an inode > extended attributes was rejected for them in xfs_fileattr_set(). > Same applies for reading. > > With XFS's project quota directories this is necessary. When project > is setup, xfs_quota opens and calls FS_IOC_SETFSXATTR on every inode > in the directory. However, special files are skipped due to open() > returning a special inode for them. So, they don't even get to this > check. > > The further patch introduces XFS_IOC_SETFSXATTRAT which will call > xfs_fileattr_set/get() on a special file. This patch add handling of > setting xflags and project ID for special files. > > Signed-off-by: Andrey Albershteyn <aalbersh@xxxxxxxxxx> > --- > fs/xfs/xfs_ioctl.c | 96 ++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 92 insertions(+), 4 deletions(-) > > diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c > index f0117188f302..515c9b4b862d 100644 > --- a/fs/xfs/xfs_ioctl.c > +++ b/fs/xfs/xfs_ioctl.c > @@ -459,9 +459,6 @@ xfs_fileattr_get( > { > struct xfs_inode *ip = XFS_I(d_inode(dentry)); > > - if (d_is_special(dentry)) > - return -ENOTTY; > - > xfs_ilock(ip, XFS_ILOCK_SHARED); > xfs_fill_fsxattr(ip, XFS_DATA_FORK, fa); > xfs_iunlock(ip, XFS_ILOCK_SHARED); > @@ -721,6 +718,97 @@ xfs_ioctl_setattr_check_projid( > return 0; > } > > +static int > +xfs_fileattr_spec_set( > + struct mnt_idmap *idmap, > + struct dentry *dentry, > + struct fileattr *fa) > +{ > + struct xfs_inode *ip = XFS_I(d_inode(dentry)); > + struct xfs_mount *mp = ip->i_mount; > + struct xfs_trans *tp; > + struct xfs_dquot *pdqp = NULL; > + struct xfs_dquot *olddquot = NULL; > + int error; > + > + if (!fa->fsx_valid) > + return -EOPNOTSUPP; > + > + if (fa->fsx_extsize || > + fa->fsx_nextents || > + fa->fsx_cowextsize) > + return -EOPNOTSUPP; > + > + 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)) { Didn't we already check fsx_valid? Also, what's different about the behavior of setxattr on special files (vs. directories and regular files) such that we need a separate function? Is it to disable the ability to set the extent size hints or the xflags? --D > + 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; > + } > + > + tp = xfs_ioctl_setattr_get_trans(ip, pdqp); > + if (IS_ERR(tp)) { > + error = PTR_ERR(tp); > + goto error_free_dquots; > + } > + > + error = xfs_ioctl_setattr_xflags(tp, ip, fa); > + if (error) > + goto error_trans_cancel; > + > + /* > + * 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() > + */ > + > + if ((VFS_I(ip)->i_mode & (S_ISUID | S_ISGID)) && > + !capable_wrt_inode_uidgid(idmap, VFS_I(ip), CAP_FSETID)) > + VFS_I(ip)->i_mode &= ~(S_ISUID | S_ISGID); > + > + /* 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; > + } > + > + error = xfs_trans_commit(tp); > + > + /* > + * Release any dquot(s) the inode had kept before chown. > + */ > + xfs_qm_dqrele(olddquot); > + xfs_qm_dqrele(pdqp); > + > + return error; > + > +error_trans_cancel: > + xfs_trans_cancel(tp); > +error_free_dquots: > + xfs_qm_dqrele(pdqp); > + return error; > + > + return 0; > +} > + > int > xfs_fileattr_set( > struct mnt_idmap *idmap, > @@ -737,7 +825,7 @@ xfs_fileattr_set( > trace_xfs_ioctl_setattr(ip); > > if (d_is_special(dentry)) > - return -ENOTTY; > + return xfs_fileattr_spec_set(idmap, dentry, fa); > > if (!fa->fsx_valid) { > if (fa->flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | > -- > 2.42.0 > >