Introduce a new ioctl(2) for setting a.g. state. - Add a new structure xfs_ioc_agstate. - Add a macro to indicate an a.g. is offline. - Add XFS_IOC_SET_AGSTATE for ioctl(2). - Teach xfs_alloc_log_agf() aware of agf_state. Signed-off-by: Jie Liu <jeff.liu@xxxxxxxxxx> --- fs/xfs/xfs_ag.h | 17 ++++++++++++ fs/xfs/xfs_alloc.c | 1 + fs/xfs/xfs_fs.h | 1 + fs/xfs/xfs_fsops.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++- fs/xfs/xfs_ioctl.c | 13 +++++++++ fs/xfs/xfs_trans.h | 2 +- 6 files changed, 104 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h index fd578e6..e2588d9 100644 --- a/fs/xfs/xfs_ag.h +++ b/fs/xfs/xfs_ag.h @@ -235,6 +235,23 @@ typedef struct xfs_perag { } xfs_perag_t; /* + * Structure for ioctl per a.g. state get/set. + */ +typedef struct xfs_ioc_agstate { + xfs_agnumber_t agno; + __uint32_t state; +} xfs_ioc_agstate_t; + +/* + * Skip an AG with below state for inodes/blocks allocation. + */ +#define XFS_AG_STATE_ALLOC_DENY (1 << 0) +#define XFS_AG_ALL_STATE (XFS_AG_STATE_ALLOC_DENY) + +extern int xfs_set_agstate(struct xfs_mount *mp, + struct xfs_ioc_agstate *agstate); + +/* * tags for inode radix tree */ #define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 4f33c32..bd9cc41 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2005,6 +2005,7 @@ xfs_alloc_log_agf( offsetof(xfs_agf_t, agf_freeblks), offsetof(xfs_agf_t, agf_longest), offsetof(xfs_agf_t, agf_btreeblks), + offsetof(xfs_agf_t, agf_state), sizeof(xfs_agf_t) }; diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index c13fed8..991c09e 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -486,6 +486,7 @@ typedef struct xfs_handle { #define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) #define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) #define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t) +#define XFS_IOC_SET_AGSTATE _IOW('X', 126, struct xfs_ioc_agstate) /* XFS_IOC_GETFSUUID ---------- deprecated 140 */ diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index c25b094..3742511 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -112,10 +112,79 @@ xfs_fs_geometry( return 0; } +/* + * Setting a.g. persistent state as well as perag incore state. + */ +static void +xfs_set_agstate_private( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer for a.g. freelist header */ + xfs_perag_t *pag, /* incore perag structure */ + __uint32_t state) /* a.g. state to be set */ +{ + xfs_agf_t *agf; /* a.g. free space */ + + agf = XFS_BUF_TO_AGF(agbp); + agf->agf_state |= cpu_to_be32(state); + pag->pag_state |= state; + + xfs_alloc_log_agf(tp, agbp, XFS_AGF_STATE); +} + +/* + * Setting the state of the given AG. + * + * For now, we can set a given AG to be offline or online, and + * allocaters will skip an AG being offline to allocate inodes + * or free space. + */ +int +xfs_set_agstate( + xfs_mount_t *mp, + xfs_ioc_agstate_t *agstate) +{ + xfs_agnumber_t agno; + xfs_perag_t *pag; + xfs_trans_t *tp; + xfs_buf_t *bp; + int error; + + agno = agstate->agno; + if (agno >= mp->m_sb.sb_agcount) + return XFS_ERROR(EINVAL); + + if ((agstate->state & XFS_AG_ALL_STATE) != agstate->state) + return XFS_ERROR(EINVAL); + + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_AGSTATE); + error = xfs_trans_reserve(tp, 0, XFS_SETAGSTATE_LOG_RES(mp), 0, 0, + XFS_DEFAULT_LOG_COUNT); + if (error) { + xfs_trans_cancel(tp, 0); + return error; + } + + error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp); + if (error) + goto error0; + + pag = xfs_perag_get(mp, agno); + xfs_set_agstate_private(tp, bp, pag, agstate->state); + xfs_perag_put(pag); + + xfs_trans_set_sync(tp); + xfs_trans_commit(tp, 0); + return error; + +error0: + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + return error; +} + static int xfs_growfs_data_private( - xfs_mount_t *mp, /* mount point for filesystem */ - xfs_growfs_data_t *in) /* growfs data input struct */ + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_growfs_data_t *in) /* growfs data input struct */ { xfs_agf_t *agf; xfs_agi_t *agi; diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 8305f2a..efe39ef 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1602,6 +1602,19 @@ xfs_file_ioctl( error = xfs_errortag_clearall(mp, 1); return -error; + case XFS_IOC_SET_AGSTATE: { + xfs_ioc_agstate_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&in, arg, sizeof(in))) + return -XFS_ERROR(EFAULT); + + error = xfs_set_agstate(mp, &in); + return -error; + } + default: return -ENOTTY; } diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index a4f4092..14f897d 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -264,7 +264,7 @@ struct xfs_log_item_desc { (128 * (ext + (ext * XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))))) #define XFS_ATTRRM_LOG_RES(mp) ((mp)->m_reservations.tr_attrrm) #define XFS_CLEAR_AGI_BUCKET_LOG_RES(mp) ((mp)->m_reservations.tr_clearagi) -#define XFS_SETAGSTATE_LOG_RES ((mp)->m_reservations.tr_setagstate) +#define XFS_SETAGSTATE_LOG_RES(mp) ((mp)->m_reservations.tr_setagstate) /* * Various log count values. -- 1.7.4.1 _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs