> Subject: xfs: extent transaction reservations for parent attributeso s/extent/extend/? On Sat, Jun 11, 2022 at 02:41:52AM -0700, Allison Henderson wrote: > We need to add, remove or modify parent pointer attributes during > create/link/unlink/rename operations atomically with the dirents in the > parent directories being modified. This means they need to be modified > in the same transaction as the parent directories, and so we need to add > the required space for the attribute modifications to the transaction > reservations. > > [achender: rebased, added xfs_sb_version_hasparent stub] > > Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> > Signed-off-by: Allison Henderson <allison.henderson@xxxxxxxxxx> > --- > fs/xfs/libxfs/xfs_format.h | 5 ++ > fs/xfs/libxfs/xfs_trans_resv.c | 103 +++++++++++++++++++++++++++------ > fs/xfs/libxfs/xfs_trans_resv.h | 1 + > 3 files changed, 90 insertions(+), 19 deletions(-) > > diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h > index afdfc8108c5f..96976497306c 100644 > --- a/fs/xfs/libxfs/xfs_format.h > +++ b/fs/xfs/libxfs/xfs_format.h > @@ -390,6 +390,11 @@ xfs_sb_has_incompat_feature( > return (sbp->sb_features_incompat & feature) != 0; > } > > +static inline bool xfs_sb_version_hasparent(struct xfs_sb *sbp) > +{ > + return false; /* We'll enable this at the end of the set */ > +} > + > #define XFS_SB_FEAT_INCOMPAT_LOG_XATTRS (1 << 0) /* Delayed Attributes */ > #define XFS_SB_FEAT_INCOMPAT_LOG_ALL \ > (XFS_SB_FEAT_INCOMPAT_LOG_XATTRS) > diff --git a/fs/xfs/libxfs/xfs_trans_resv.c b/fs/xfs/libxfs/xfs_trans_resv.c > index e9913c2c5a24..fbe46fd3b722 100644 > --- a/fs/xfs/libxfs/xfs_trans_resv.c > +++ b/fs/xfs/libxfs/xfs_trans_resv.c > @@ -909,24 +909,30 @@ xfs_calc_sb_reservation( > return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); > } > > -void > -xfs_trans_resv_calc( > +/* > + * Namespace reservations. > + * > + * These get tricky when parent pointers are enabled as we have attribute > + * modifications occurring from within these transactions. Rather than confuse > + * each of these reservation calculations with the conditional attribute > + * reservations, add them here in a clear and concise manner. This assumes that > + * the attribute reservations have already been calculated. > + * > + * Note that we only include the static attribute reservation here; the runtime > + * reservation will have to be modified by the size of the attributes being > + * added/removed/modified. See the comments on the attribute reservation > + * calculations for more details. > + * > + * Note for rename: rename will vastly overestimate requirements. This will be > + * addressed later when modifications are made to ensure parent attribute > + * modifications can be done atomically with the rename operation. > + */ > +STATIC void > +xfs_calc_namespace_reservations( > struct xfs_mount *mp, > struct xfs_trans_resv *resp) > { > - int logcount_adj = 0; > - > - /* > - * The following transactions are logged in physical format and > - * require a permanent reservation on space. > - */ > - resp->tr_write.tr_logres = xfs_calc_write_reservation(mp, false); > - resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT; > - resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > - > - resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp, false); > - resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT; > - resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > + ASSERT(resp->tr_attrsetm.tr_logres > 0); > > resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp); > resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT; > @@ -948,15 +954,72 @@ xfs_trans_resv_calc( > resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; > resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > > + resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); > + resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; > + resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > + > + xfs_calc_parent_ptr_reservations(mp); > +} > + > +void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp) Indenting, etc. Also vaguely wondering if this should be static inline? Or does something else call this? --D > +{ > + struct xfs_trans_resv *resp = M_RES(mp); > + > + /* Calculate extra space needed for parent pointer attributes */ > + if (!xfs_sb_version_hasparent(&mp->m_sb)) > + return; > + > + /* rename can add/remove/modify 4 parent attributes */ > + resp->tr_rename.tr_logres += 4 * max(resp->tr_attrsetm.tr_logres, > + resp->tr_attrrm.tr_logres); > + resp->tr_rename.tr_logcount += 4 * max(resp->tr_attrsetm.tr_logcount, > + resp->tr_attrrm.tr_logcount); > + > + /* create will add 1 parent attribute */ > + resp->tr_create.tr_logres += resp->tr_attrsetm.tr_logres; > + resp->tr_create.tr_logcount += resp->tr_attrsetm.tr_logcount; > + > + /* mkdir will add 1 parent attribute */ > + resp->tr_mkdir.tr_logres += resp->tr_attrsetm.tr_logres; > + resp->tr_mkdir.tr_logcount += resp->tr_attrsetm.tr_logcount; > + > + /* link will add 1 parent attribute */ > + resp->tr_link.tr_logres += resp->tr_attrsetm.tr_logres; > + resp->tr_link.tr_logcount += resp->tr_attrsetm.tr_logcount; > + > + /* symlink will add 1 parent attribute */ > + resp->tr_symlink.tr_logres += resp->tr_attrsetm.tr_logres; > + resp->tr_symlink.tr_logcount += resp->tr_attrsetm.tr_logcount; > + > + /* remove will remove 1 parent attribute */ > + resp->tr_remove.tr_logres += resp->tr_attrrm.tr_logres; > + resp->tr_remove.tr_logcount += resp->tr_attrrm.tr_logcount; > +} > + > +void > +xfs_trans_resv_calc( > + struct xfs_mount *mp, > + struct xfs_trans_resv *resp) > +{ > + int logcount_adj = 0; > + > + /* > + * The following transactions are logged in physical format and > + * require a permanent reservation on space. > + */ > + resp->tr_write.tr_logres = xfs_calc_write_reservation(mp, false); > + resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT; > + resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > + > + resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp, false); > + resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT; > + resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > + > resp->tr_create_tmpfile.tr_logres = > xfs_calc_create_tmpfile_reservation(mp); > resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT; > resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > > - resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); > - resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; > - resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > - > resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp); > resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT; > resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > @@ -986,6 +1049,8 @@ xfs_trans_resv_calc( > resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT; > resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; > > + xfs_calc_namespace_reservations(mp, resp); > + > /* > * The following transactions are logged in logical format with > * a default log count. > diff --git a/fs/xfs/libxfs/xfs_trans_resv.h b/fs/xfs/libxfs/xfs_trans_resv.h > index 0554b9d775d2..cab8084a84d6 100644 > --- a/fs/xfs/libxfs/xfs_trans_resv.h > +++ b/fs/xfs/libxfs/xfs_trans_resv.h > @@ -101,5 +101,6 @@ uint xfs_allocfree_block_count(struct xfs_mount *mp, uint num_ops); > unsigned int xfs_calc_itruncate_reservation_minlogsize(struct xfs_mount *mp); > unsigned int xfs_calc_write_reservation_minlogsize(struct xfs_mount *mp); > unsigned int xfs_calc_qm_dqalloc_reservation_minlogsize(struct xfs_mount *mp); > +void xfs_calc_parent_ptr_reservations(struct xfs_mount *mp); > > #endif /* __XFS_TRANS_RESV_H__ */ > -- > 2.25.1 >