xfs: export the geometry of realtime groups to userspace
authorDarrick J. Wong <djwong@kernel.org>
Mon, 4 Nov 2024 04:19:22 +0000 (20:19 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 5 Nov 2024 21:38:40 +0000 (13:38 -0800)
Create an ioctl so that the kernel can report the status of realtime
groups to userspace.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_fs.h
fs/xfs/libxfs/xfs_health.h
fs/xfs/libxfs/xfs_rtgroup.c
fs/xfs/libxfs/xfs_rtgroup.h
fs/xfs/xfs_health.c
fs/xfs/xfs_ioctl.c

index 5c224d0..4c06821 100644 (file)
@@ -971,6 +971,21 @@ struct xfs_getparents_by_handle {
        struct xfs_getparents           gph_request;
 };
 
+/*
+ * Output for XFS_IOC_RTGROUP_GEOMETRY
+ */
+struct xfs_rtgroup_geometry {
+       __u32 rg_number;        /* i/o: rtgroup number */
+       __u32 rg_length;        /* o: length in blocks */
+       __u32 rg_sick;          /* o: sick things in ag */
+       __u32 rg_checked;       /* o: checked metadata in ag */
+       __u32 rg_flags;         /* i/o: flags for this ag */
+       __u32 rg_reserved[27];  /* o: zero */
+};
+#define XFS_RTGROUP_GEOM_SICK_SUPER    (1U << 0)  /* superblock */
+#define XFS_RTGROUP_GEOM_SICK_BITMAP   (1U << 1)  /* rtbitmap */
+#define XFS_RTGROUP_GEOM_SICK_SUMMARY  (1U << 2)  /* rtsummary */
+
 /*
  * ioctl commands that are used by Linux filesystems
  */
@@ -1009,6 +1024,7 @@ struct xfs_getparents_by_handle {
 #define XFS_IOC_GETPARENTS     _IOWR('X', 62, struct xfs_getparents)
 #define XFS_IOC_GETPARENTS_BY_HANDLE _IOWR('X', 63, struct xfs_getparents_by_handle)
 #define XFS_IOC_SCRUBV_METADATA        _IOWR('X', 64, struct xfs_scrub_vec_head)
+#define XFS_IOC_RTGROUP_GEOMETRY _IOWR('X', 65, struct xfs_rtgroup_geometry)
 
 /*
  * ioctl commands that replace IRIX syssgi()'s
index 3d93b57..d34986a 100644 (file)
@@ -278,6 +278,8 @@ xfs_inode_is_healthy(struct xfs_inode *ip)
 
 void xfs_fsop_geom_health(struct xfs_mount *mp, struct xfs_fsop_geom *geo);
 void xfs_ag_geom_health(struct xfs_perag *pag, struct xfs_ag_geometry *ageo);
+void xfs_rtgroup_geom_health(struct xfs_rtgroup *rtg,
+               struct xfs_rtgroup_geometry *rgeo);
 void xfs_bulkstat_health(struct xfs_inode *ip, struct xfs_bulkstat *bs);
 
 #define xfs_metadata_is_sick(error) \
index 790a0b8..624d8b2 100644 (file)
@@ -214,6 +214,20 @@ xfs_rtgroup_trans_join(
        }
 }
 
+/* Retrieve rt group geometry. */
+int
+xfs_rtgroup_get_geometry(
+       struct xfs_rtgroup      *rtg,
+       struct xfs_rtgroup_geometry *rgeo)
+{
+       /* Fill out form. */
+       memset(rgeo, 0, sizeof(*rgeo));
+       rgeo->rg_number = rtg_rgno(rtg);
+       rgeo->rg_length = rtg->rtg_extents * rtg_mount(rtg)->m_sb.sb_rextsize;
+       xfs_rtgroup_geom_health(rtg, rgeo);
+       return 0;
+}
+
 #ifdef CONFIG_PROVE_LOCKING
 static struct lock_class_key xfs_rtginode_lock_class;
 
index fba62b2..026f34f 100644 (file)
@@ -234,6 +234,9 @@ void xfs_rtgroup_unlock(struct xfs_rtgroup *rtg, unsigned int rtglock_flags);
 void xfs_rtgroup_trans_join(struct xfs_trans *tp, struct xfs_rtgroup *rtg,
                unsigned int rtglock_flags);
 
+int xfs_rtgroup_get_geometry(struct xfs_rtgroup *rtg,
+               struct xfs_rtgroup_geometry *rgeo);
+
 int xfs_rtginode_mkdir_parent(struct xfs_mount *mp);
 int xfs_rtginode_load_parent(struct xfs_trans *tp);
 
@@ -277,6 +280,7 @@ static inline int xfs_initialize_rtgroups(struct xfs_mount *mp,
 # define xfs_rtgroup_trans_join(tp, rtg, gf)   ((void)0)
 # define xfs_update_rtsb(bp, sb_bp)    ((void)0)
 # define xfs_log_rtsb(tp, sb_bp)       (NULL)
+# define xfs_rtgroup_get_geometry(rtg, rgeo)   (-EOPNOTSUPP)
 #endif /* CONFIG_XFS_RT */
 
 #endif /* __LIBXFS_RTGROUP_H */
index 9d8ee01..c7c2e65 100644 (file)
@@ -443,6 +443,34 @@ xfs_ag_geom_health(
        }
 }
 
+static const struct ioctl_sick_map rtgroup_map[] = {
+       { XFS_SICK_RG_SUPER,    XFS_RTGROUP_GEOM_SICK_SUPER },
+       { XFS_SICK_RG_BITMAP,   XFS_RTGROUP_GEOM_SICK_BITMAP },
+       { XFS_SICK_RG_SUMMARY,  XFS_RTGROUP_GEOM_SICK_SUMMARY },
+};
+
+/* Fill out rtgroup geometry health info. */
+void
+xfs_rtgroup_geom_health(
+       struct xfs_rtgroup      *rtg,
+       struct xfs_rtgroup_geometry *rgeo)
+{
+       const struct ioctl_sick_map     *m;
+       unsigned int                    sick;
+       unsigned int                    checked;
+
+       rgeo->rg_sick = 0;
+       rgeo->rg_checked = 0;
+
+       xfs_group_measure_sickness(rtg_group(rtg), &sick, &checked);
+       for_each_sick_map(rtgroup_map, m) {
+               if (checked & m->sick_mask)
+                       rgeo->rg_checked |= m->ioctl_mask;
+               if (sick & m->sick_mask)
+                       rgeo->rg_sick |= m->ioctl_mask;
+       }
+}
+
 static const struct ioctl_sick_map ino_map[] = {
        { XFS_SICK_INO_CORE,    XFS_BS_SICK_INODE },
        { XFS_SICK_INO_BMBTD,   XFS_BS_SICK_BMBTD },
index 1e233ab..64cf51c 100644 (file)
@@ -40,6 +40,7 @@
 #include "xfs_file.h"
 #include "xfs_exchrange.h"
 #include "xfs_handle.h"
+#include "xfs_rtgroup.h"
 
 #include <linux/mount.h>
 #include <linux/fileattr.h>
@@ -403,6 +404,38 @@ xfs_ioc_ag_geometry(
        return 0;
 }
 
+STATIC int
+xfs_ioc_rtgroup_geometry(
+       struct xfs_mount        *mp,
+       void                    __user *arg)
+{
+       struct xfs_rtgroup      *rtg;
+       struct xfs_rtgroup_geometry rgeo;
+       int                     error;
+
+       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;
+}
+
 /*
  * Linux extended inode flags interface.
  */
@@ -1225,6 +1258,8 @@ xfs_file_ioctl(
 
        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);