summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-07-14 11:15:50 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-10-14 14:17:19 -0700
commit1027f6f3a8eecc3805caa6c3221df51f407bdc72 (patch)
treef8e164308be994b9f3d5b53eae56da91e0b55c50
parentfccb294353ac025974c728a9b949c358126fda50 (diff)
xfs: enable userspace to hide an AG from allocation
Add an administrative interface so that userspace can hide an allocation group from block allocation. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/libxfs/xfs_ag.c54
-rw-r--r--fs/xfs/libxfs/xfs_fs.h5
-rw-r--r--fs/xfs/xfs_ioctl.c4
3 files changed, 62 insertions, 1 deletions
diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
index d6c89841ba18..cc63e89e07ab 100644
--- a/fs/xfs/libxfs/xfs_ag.c
+++ b/fs/xfs/libxfs/xfs_ag.c
@@ -1005,6 +1005,54 @@ xfs_ag_extend_space(
return 0;
}
+/* Compute the AG geometry flags. */
+static inline uint32_t
+xfs_ag_calc_geoflags(
+ struct xfs_perag *pag)
+{
+ uint32_t ret = 0;
+
+ if (pag->pagf_noalloc)
+ ret |= XFS_AG_FLAG_NOALLOC;
+
+ return ret;
+}
+
+/*
+ * Compare the current AG geometry flags against the flags in the AG geometry
+ * structure and update the AG state to reflect any changes, then update the
+ * struct to reflect the current status.
+ */
+static inline int
+xfs_ag_update_geoflags(
+ struct xfs_perag *pag,
+ struct xfs_ag_geometry *ageo,
+ uint32_t new_flags)
+{
+ uint32_t old_flags = xfs_ag_calc_geoflags(pag);
+ int error;
+
+ if (!(new_flags & XFS_AG_FLAG_UPDATE)) {
+ ageo->ag_flags = old_flags;
+ return 0;
+ }
+
+ if ((old_flags & XFS_AG_FLAG_NOALLOC) &&
+ !(new_flags & XFS_AG_FLAG_NOALLOC)) {
+ xfs_ag_clear_noalloc(pag);
+ }
+
+ if (!(old_flags & XFS_AG_FLAG_NOALLOC) &&
+ (new_flags & XFS_AG_FLAG_NOALLOC)) {
+ error = xfs_ag_set_noalloc(pag);
+ if (error)
+ return error;
+ }
+
+ ageo->ag_flags = xfs_ag_calc_geoflags(pag);
+ return 0;
+}
+
/* Retrieve AG geometry. */
int
xfs_ag_get_geometry(
@@ -1016,6 +1064,7 @@ xfs_ag_get_geometry(
struct xfs_agi *agi;
struct xfs_agf *agf;
unsigned int freeblks;
+ uint32_t inflags = ageo->ag_flags;
int error;
/* Lock the AG headers. */
@@ -1026,6 +1075,10 @@ xfs_ag_get_geometry(
if (error)
goto out_agi;
+ error = xfs_ag_update_geoflags(pag, ageo, inflags);
+ if (error)
+ goto out;
+
/* Fill out form. */
memset(ageo, 0, sizeof(*ageo));
ageo->ag_number = pag->pag_agno;
@@ -1043,6 +1096,7 @@ xfs_ag_get_geometry(
ageo->ag_freeblks = freeblks;
xfs_ag_geom_health(pag, ageo);
+out:
/* Release resources. */
xfs_buf_relse(agf_bp);
out_agi:
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 0c6f013f40ca..dba34b311e05 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -299,6 +299,11 @@ struct xfs_ag_geometry {
#define XFS_AG_GEOM_SICK_REFCNTBT (1 << 9) /* reference counts */
#define XFS_AG_GEOM_SICK_INODES (1 << 10) /* bad inodes were seen */
+#define XFS_AG_FLAG_UPDATE (1 << 0) /* update flags */
+#define XFS_AG_FLAG_NOALLOC (1 << 1) /* do not allocate from this AG */
+#define XFS_AG_FLAG_ALL (XFS_AG_FLAG_UPDATE | \
+ XFS_AG_FLAG_NOALLOC)
+
/*
* Output for XFS_IOC_RTGROUP_GEOMETRY
*/
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 06a8df79d92a..3cd9e6d9eea5 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -972,10 +972,12 @@ xfs_ioc_ag_geometry(
if (copy_from_user(&ageo, arg, sizeof(ageo)))
return -EFAULT;
- if (ageo.ag_flags)
+ if (ageo.ag_flags & ~XFS_AG_FLAG_ALL)
return -EINVAL;
if (memchr_inv(&ageo.ag_reserved, 0, sizeof(ageo.ag_reserved)))
return -EINVAL;
+ if ((ageo.ag_flags & XFS_AG_FLAG_UPDATE) && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
pag = xfs_perag_get(mp, ageo.ag_number);
if (!pag)