From: Darrick J. Wong <djwong@xxxxxxxxxx> Convert the quota file creation code to use xfs_imeta_create instead of open-coding a bunch of logic. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/xfs_qm.c | 91 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 3e7e0f9cecc0e..2352eed966022 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -27,6 +27,8 @@ #include "xfs_ialloc.h" #include "xfs_log_priv.h" #include "xfs_health.h" +#include "xfs_imeta.h" +#include "xfs_imeta_utils.h" /* * The global quota manager. There is only one of these for the entire @@ -732,6 +734,18 @@ xfs_qm_destroy_quotainfo( mp->m_quotainfo = NULL; } +static inline const struct xfs_imeta_path * +xfs_qflags_to_imeta_path( + unsigned int qflags) +{ + if (qflags & XFS_QMOPT_UQUOTA) + return &XFS_IMETA_USRQUOTA; + else if (qflags & XFS_QMOPT_GQUOTA) + return &XFS_IMETA_GRPQUOTA; + else + return &XFS_IMETA_PRJQUOTA; +} + /* * Switch the group and project quota in-core inode pointers if needed. * @@ -739,6 +753,12 @@ xfs_qm_destroy_quotainfo( * between gquota and pquota. If the on-disk superblock has GQUOTA and the * filesystem is now mounted with PQUOTA, just use sb_gquotino for sb_pquotino * and vice-versa. + * + * We tolerate the direct manipulation of the in-core sb quota inode pointers + * here because calling xfs_imeta_ functions is only really required for + * filesystems with the metadata directory feature. That feature requires a v5 + * superblock, which always supports simultaneous group and project quotas, so + * we'll never get here. */ STATIC int xfs_qm_qino_switch( @@ -777,8 +797,13 @@ xfs_qm_qino_switch( if (error) return error; - mp->m_sb.sb_gquotino = NULLFSINO; - mp->m_sb.sb_pquotino = NULLFSINO; + if (flags & XFS_QMOPT_PQUOTA) { + mp->m_sb.sb_gquotino = NULLFSINO; + mp->m_sb.sb_pquotino = ino; + } else if (flags & XFS_QMOPT_GQUOTA) { + mp->m_sb.sb_gquotino = ino; + mp->m_sb.sb_pquotino = NULLFSINO; + } *need_alloc = false; return 0; } @@ -793,7 +818,8 @@ xfs_qm_qino_alloc( struct xfs_inode **ipp, unsigned int flags) { - struct xfs_trans *tp; + struct xfs_imeta_update upd = { }; + const struct xfs_imeta_path *path = xfs_qflags_to_imeta_path(flags); int error; bool need_alloc = true; @@ -803,29 +829,14 @@ xfs_qm_qino_alloc( if (error) return error; - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_create, - need_alloc ? XFS_QM_QINOCREATE_SPACE_RES(mp) : 0, - 0, 0, &tp); - if (error) - return error; - if (need_alloc) { - struct xfs_icreate_args args = { - .nlink = 1, - }; - xfs_ino_t ino; - - xfs_icreate_args_rootfile(&args, mp, S_IFREG, - xfs_has_parent(mp)); - - error = xfs_dialloc(&tp, 0, S_IFREG, &ino); - if (!error) - error = xfs_icreate(tp, ino, &args, ipp); - if (error) { - xfs_trans_cancel(tp); - return error; - } + error = xfs_imeta_start_create(mp, path, &upd); + } else { + error = xfs_trans_alloc(mp, &M_RES(mp)->tr_create, 0, 0, 0, + &upd.tp); } + if (error) + goto out_end; /* * Make the changes in the superblock, and log those too. @@ -844,23 +855,35 @@ xfs_qm_qino_alloc( /* qflags will get updated fully _after_ quotacheck */ mp->m_sb.sb_qflags = mp->m_qflags & XFS_ALL_QUOTA_ACCT; } - if (flags & XFS_QMOPT_UQUOTA) - mp->m_sb.sb_uquotino = (*ipp)->i_ino; - else if (flags & XFS_QMOPT_GQUOTA) - mp->m_sb.sb_gquotino = (*ipp)->i_ino; - else - mp->m_sb.sb_pquotino = (*ipp)->i_ino; spin_unlock(&mp->m_sb_lock); - xfs_log_sb(tp); + xfs_log_sb(upd.tp); - error = xfs_trans_commit(tp); + if (need_alloc) { + error = xfs_imeta_create(&upd, S_IFREG, ipp); + if (error) + goto out_cancel; + } + + error = xfs_imeta_commit_update(&upd); if (error) { ASSERT(xfs_is_shutdown(mp)); xfs_alert(mp, "%s failed (error %d)!", __func__, error); + goto out_end; } - if (need_alloc) { - xfs_iunlock(*ipp, XFS_ILOCK_EXCL); + + if (need_alloc) xfs_finish_inode_setup(*ipp); + + return 0; + +out_cancel: + xfs_imeta_cancel_update(&upd, error); +out_end: + /* Have to finish setting up the inode to ensure it's deleted. */ + if (*ipp) { + xfs_finish_inode_setup(*ipp); + xfs_irele(*ipp); + *ipp = NULL; } return error; }