xfs: cleanups for the realtime allocator [v4.2 5/8]

This third series cleans up the realtime allocator code so that it'll be
 somewhat less difficult to figure out what on earth it's doing.  We also
 rearrange the fsmap code a bit.
 
 With a bit of luck, this should all go splendidly.
 
 Signed-off-by: Darrick J. Wong <djwong@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQ2qTKExjcn+O1o2YRKO3ySh0YRpgUCZtX/YwAKCRBKO3ySh0YR
 pnxRAQDXsK7oTlu4G4jmDAPfDvbYqQlI9S3IPVA1T/V8LTAqCQEA22zjHGmUfSZT
 08aP+fAQ6FmQIP92vYqwEzew02jIzAo=
 =/a70
 -----END PGP SIGNATURE-----

Merge tag 'rtalloc-cleanups-6.12_2024-09-02' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.12-mergeA

xfs: cleanups for the realtime allocator [v4.2 5/8]

This third series cleans up the realtime allocator code so that it'll be
somewhat less difficult to figure out what on earth it's doing.  We also
rearrange the fsmap code a bit.

With a bit of luck, this should all go splendidly.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>

* tag 'rtalloc-cleanups-6.12_2024-09-02' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: move xfs_ioc_getfsmap out of xfs_ioctl.c
  xfs: rearrange xfs_fsmap.c a little bit
  xfs: replace m_rsumsize with m_rsumblocks
  xfs: remove xfs_{rtbitmap,rtsummary}_wordcount
  xfs: add xchk_setup_nothing and xchk_nothing helpers
  xfs: make the rtalloc start hint a xfs_rtblock_t
  xfs: factor out a xfs_rtallocate_align helper
  xfs: rework the rtalloc fallback handling
  xfs: factor out a xfs_rtallocate helper
  xfs: clean up the ISVALID macro in xfs_bmap_adjacent
This commit is contained in:
Chandan Babu R 2024-09-03 09:14:28 +05:30
commit 07b2bbcf77
14 changed files with 477 additions and 489 deletions

View File

@ -3112,6 +3112,23 @@ xfs_bmap_extsize_align(
return 0;
}
static inline bool
xfs_bmap_adjacent_valid(
struct xfs_bmalloca *ap,
xfs_fsblock_t x,
xfs_fsblock_t y)
{
struct xfs_mount *mp = ap->ip->i_mount;
if (XFS_IS_REALTIME_INODE(ap->ip) &&
(ap->datatype & XFS_ALLOC_USERDATA))
return x < mp->m_sb.sb_rblocks;
return XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) &&
XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount &&
XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks;
}
#define XFS_ALLOC_GAP_UNITS 4
/* returns true if ap->blkno was modified */
@ -3119,36 +3136,25 @@ bool
xfs_bmap_adjacent(
struct xfs_bmalloca *ap) /* bmap alloc argument struct */
{
xfs_fsblock_t adjust; /* adjustment to block numbers */
xfs_mount_t *mp; /* mount point structure */
int rt; /* true if inode is realtime */
xfs_fsblock_t adjust; /* adjustment to block numbers */
#define ISVALID(x,y) \
(rt ? \
(x) < mp->m_sb.sb_rblocks : \
XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \
XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \
XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks)
mp = ap->ip->i_mount;
rt = XFS_IS_REALTIME_INODE(ap->ip) &&
(ap->datatype & XFS_ALLOC_USERDATA);
/*
* If allocating at eof, and there's a previous real block,
* try to use its last block as our starting point.
*/
if (ap->eof && ap->prev.br_startoff != NULLFILEOFF &&
!isnullstartblock(ap->prev.br_startblock) &&
ISVALID(ap->prev.br_startblock + ap->prev.br_blockcount,
ap->prev.br_startblock)) {
xfs_bmap_adjacent_valid(ap,
ap->prev.br_startblock + ap->prev.br_blockcount,
ap->prev.br_startblock)) {
ap->blkno = ap->prev.br_startblock + ap->prev.br_blockcount;
/*
* Adjust for the gap between prevp and us.
*/
adjust = ap->offset -
(ap->prev.br_startoff + ap->prev.br_blockcount);
if (adjust &&
ISVALID(ap->blkno + adjust, ap->prev.br_startblock))
if (adjust && xfs_bmap_adjacent_valid(ap, ap->blkno + adjust,
ap->prev.br_startblock))
ap->blkno += adjust;
return true;
}
@ -3171,7 +3177,8 @@ xfs_bmap_adjacent(
!isnullstartblock(ap->prev.br_startblock) &&
(prevbno = ap->prev.br_startblock +
ap->prev.br_blockcount) &&
ISVALID(prevbno, ap->prev.br_startblock)) {
xfs_bmap_adjacent_valid(ap, prevbno,
ap->prev.br_startblock)) {
/*
* Calculate gap to end of previous block.
*/
@ -3187,8 +3194,8 @@ xfs_bmap_adjacent(
* number, then just use the end of the previous block.
*/
if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->length &&
ISVALID(prevbno + prevdiff,
ap->prev.br_startblock))
xfs_bmap_adjacent_valid(ap, prevbno + prevdiff,
ap->prev.br_startblock))
prevbno += adjust;
else
prevdiff += adjust;
@ -3220,9 +3227,11 @@ xfs_bmap_adjacent(
* offset by our length.
*/
if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->length &&
ISVALID(gotbno - gotdiff, gotbno))
xfs_bmap_adjacent_valid(ap, gotbno - gotdiff,
gotbno))
gotbno -= adjust;
else if (ISVALID(gotbno - ap->length, gotbno)) {
else if (xfs_bmap_adjacent_valid(ap, gotbno - ap->length,
gotbno)) {
gotbno -= ap->length;
gotdiff += adjust - ap->length;
} else
@ -3250,7 +3259,7 @@ xfs_bmap_adjacent(
return true;
}
}
#undef ISVALID
return false;
}

View File

@ -162,7 +162,7 @@ xfs_rtsummary_read_buf(
{
struct xfs_mount *mp = args->mp;
if (XFS_IS_CORRUPT(mp, block >= XFS_B_TO_FSB(mp, mp->m_rsumsize))) {
if (XFS_IS_CORRUPT(mp, block >= mp->m_rsumblocks)) {
xfs_rt_mark_sick(args->mp, XFS_SICK_RT_SUMMARY);
return -EFSCORRUPTED;
}
@ -1148,21 +1148,6 @@ xfs_rtbitmap_blockcount(
return howmany_64(rtextents, NBBY * mp->m_sb.sb_blocksize);
}
/*
* Compute the number of rtbitmap words needed to populate every block of a
* bitmap that is large enough to track the given number of rt extents.
*/
unsigned long long
xfs_rtbitmap_wordcount(
struct xfs_mount *mp,
xfs_rtbxlen_t rtextents)
{
xfs_filblks_t blocks;
blocks = xfs_rtbitmap_blockcount(mp, rtextents);
return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
}
/* Compute the number of rtsummary blocks needed to track the given rt space. */
xfs_filblks_t
xfs_rtsummary_blockcount(
@ -1176,22 +1161,6 @@ xfs_rtsummary_blockcount(
return XFS_B_TO_FSB(mp, rsumwords << XFS_WORDLOG);
}
/*
* Compute the number of rtsummary info words needed to populate every block of
* a summary file that is large enough to track the given rt space.
*/
unsigned long long
xfs_rtsummary_wordcount(
struct xfs_mount *mp,
unsigned int rsumlevels,
xfs_extlen_t rbmblocks)
{
xfs_filblks_t blocks;
blocks = xfs_rtsummary_blockcount(mp, rsumlevels, rbmblocks);
return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
}
/* Lock both realtime free space metadata inodes for a freespace update. */
void
xfs_rtbitmap_lock(

View File

@ -316,13 +316,8 @@ int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno,
xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t
rtextents);
unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp,
xfs_rtbxlen_t rtextents);
xfs_filblks_t xfs_rtsummary_blockcount(struct xfs_mount *mp,
unsigned int rsumlevels, xfs_extlen_t rbmblocks);
unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp,
unsigned int rsumlevels, xfs_extlen_t rbmblocks);
int xfs_rtfile_initialize_blocks(struct xfs_inode *ip,
xfs_fileoff_t offset_fsb, xfs_fileoff_t end_fsb, void *data);
@ -355,9 +350,7 @@ xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents)
/* shut up gcc */
return 0;
}
# define xfs_rtbitmap_wordcount(mp, r) (0)
# define xfs_rtsummary_blockcount(mp, l, b) (0)
# define xfs_rtsummary_wordcount(mp, l, b) (0)
# define xfs_rtbitmap_lock(mp) do { } while (0)
# define xfs_rtbitmap_trans_join(tp) do { } while (0)
# define xfs_rtbitmap_unlock(mp) do { } while (0)

View File

@ -918,7 +918,7 @@ xfs_calc_growrtfree_reservation(
return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
xfs_calc_inode_res(mp, 2) +
xfs_calc_buf_res(1, mp->m_sb.sb_blocksize) +
xfs_calc_buf_res(1, mp->m_rsumsize);
xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, mp->m_rsumblocks));
}
/*

View File

@ -53,6 +53,11 @@ int xchk_checkpoint_log(struct xfs_mount *mp);
bool xchk_should_check_xref(struct xfs_scrub *sc, int *error,
struct xfs_btree_cur **curpp);
static inline int xchk_setup_nothing(struct xfs_scrub *sc)
{
return -ENOENT;
}
/* Setup functions */
int xchk_setup_agheader(struct xfs_scrub *sc);
int xchk_setup_fs(struct xfs_scrub *sc);
@ -72,16 +77,8 @@ int xchk_setup_dirtree(struct xfs_scrub *sc);
int xchk_setup_rtbitmap(struct xfs_scrub *sc);
int xchk_setup_rtsummary(struct xfs_scrub *sc);
#else
static inline int
xchk_setup_rtbitmap(struct xfs_scrub *sc)
{
return -ENOENT;
}
static inline int
xchk_setup_rtsummary(struct xfs_scrub *sc)
{
return -ENOENT;
}
# define xchk_setup_rtbitmap xchk_setup_nothing
# define xchk_setup_rtsummary xchk_setup_nothing
#endif
#ifdef CONFIG_XFS_QUOTA
int xchk_ino_dqattach(struct xfs_scrub *sc);
@ -93,16 +90,8 @@ xchk_ino_dqattach(struct xfs_scrub *sc)
{
return 0;
}
static inline int
xchk_setup_quota(struct xfs_scrub *sc)
{
return -ENOENT;
}
static inline int
xchk_setup_quotacheck(struct xfs_scrub *sc)
{
return -ENOENT;
}
# define xchk_setup_quota xchk_setup_nothing
# define xchk_setup_quotacheck xchk_setup_nothing
#endif
int xchk_setup_fscounters(struct xfs_scrub *sc);
int xchk_setup_nlinks(struct xfs_scrub *sc);

View File

@ -63,7 +63,8 @@ xchk_setup_rtsummary(
* us to avoid pinning kernel memory for this purpose.
*/
descr = xchk_xfile_descr(sc, "realtime summary file");
error = xfile_create(descr, mp->m_rsumsize, &sc->xfile);
error = xfile_create(descr, XFS_FSB_TO_B(mp, mp->m_rsumblocks),
&sc->xfile);
kfree(descr);
if (error)
return error;
@ -95,16 +96,14 @@ xchk_setup_rtsummary(
* volume. Hence it is safe to compute and check the geometry values.
*/
if (mp->m_sb.sb_rblocks) {
xfs_filblks_t rsumblocks;
int rextslog;
rts->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
rextslog = xfs_compute_rextslog(rts->rextents);
rts->rsumlevels = rextslog + 1;
rts->rbmblocks = xfs_rtbitmap_blockcount(mp, rts->rextents);
rsumblocks = xfs_rtsummary_blockcount(mp, rts->rsumlevels,
rts->rsumblocks = xfs_rtsummary_blockcount(mp, rts->rsumlevels,
rts->rbmblocks);
rts->rsumsize = XFS_FSB_TO_B(mp, rsumblocks);
}
return 0;
}
@ -316,7 +315,7 @@ xchk_rtsummary(
}
/* Is m_rsumsize correct? */
if (mp->m_rsumsize != rts->rsumsize) {
if (mp->m_rsumblocks != rts->rsumblocks) {
xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
goto out_rbm;
}
@ -332,7 +331,7 @@ xchk_rtsummary(
* growfsrt expands the summary file before updating sb_rextents, so
* the file can be larger than rsumsize.
*/
if (mp->m_rsumip->i_disk_size < rts->rsumsize) {
if (mp->m_rsumip->i_disk_size < XFS_FSB_TO_B(mp, rts->rsumblocks)) {
xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino);
goto out_rbm;
}

View File

@ -14,7 +14,7 @@ struct xchk_rtsummary {
uint64_t rextents;
uint64_t rbmblocks;
uint64_t rsumsize;
xfs_filblks_t rsumblocks;
unsigned int rsumlevels;
unsigned int resblks;

View File

@ -56,7 +56,7 @@ xrep_setup_rtsummary(
* transaction (which we cannot drop because we cannot drop the
* rtsummary ILOCK) and cannot ask for more reservation.
*/
blocks = XFS_B_TO_FSB(mp, mp->m_rsumsize);
blocks = mp->m_rsumblocks;
blocks += xfs_bmbt_calc_size(mp, blocks) * 2;
if (blocks > UINT_MAX)
return -EOPNOTSUPP;
@ -100,7 +100,6 @@ xrep_rtsummary(
{
struct xchk_rtsummary *rts = sc->buf;
struct xfs_mount *mp = sc->mp;
xfs_filblks_t rsumblocks;
int error;
/* We require the rmapbt to rebuild anything. */
@ -131,10 +130,9 @@ xrep_rtsummary(
}
/* Make sure we have space allocated for the entire summary file. */
rsumblocks = XFS_B_TO_FSB(mp, rts->rsumsize);
xfs_trans_ijoin(sc->tp, sc->ip, 0);
xfs_trans_ijoin(sc->tp, sc->tempip, 0);
error = xrep_tempfile_prealloc(sc, 0, rsumblocks);
error = xrep_tempfile_prealloc(sc, 0, rts->rsumblocks);
if (error)
return error;
@ -143,11 +141,11 @@ xrep_rtsummary(
return error;
/* Copy the rtsummary file that we generated. */
error = xrep_tempfile_copyin(sc, 0, rsumblocks,
error = xrep_tempfile_copyin(sc, 0, rts->rsumblocks,
xrep_rtsummary_prep_buf, rts);
if (error)
return error;
error = xrep_tempfile_set_isize(sc, rts->rsumsize);
error = xrep_tempfile_set_isize(sc, XFS_FSB_TO_B(mp, rts->rsumblocks));
if (error)
return error;
@ -168,7 +166,7 @@ xrep_rtsummary(
memset(mp->m_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks);
mp->m_rsumlevels = rts->rsumlevels;
mp->m_rsumsize = rts->rsumsize;
mp->m_rsumblocks = rts->rsumblocks;
/* Free the old rtsummary blocks if they're not in use. */
return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);

View File

@ -231,6 +231,11 @@ xchk_should_terminate(
return false;
}
static inline int xchk_nothing(struct xfs_scrub *sc)
{
return -ENOENT;
}
/* Metadata scrubbers */
int xchk_tester(struct xfs_scrub *sc);
int xchk_superblock(struct xfs_scrub *sc);
@ -254,31 +259,15 @@ int xchk_dirtree(struct xfs_scrub *sc);
int xchk_rtbitmap(struct xfs_scrub *sc);
int xchk_rtsummary(struct xfs_scrub *sc);
#else
static inline int
xchk_rtbitmap(struct xfs_scrub *sc)
{
return -ENOENT;
}
static inline int
xchk_rtsummary(struct xfs_scrub *sc)
{
return -ENOENT;
}
# define xchk_rtbitmap xchk_nothing
# define xchk_rtsummary xchk_nothing
#endif
#ifdef CONFIG_XFS_QUOTA
int xchk_quota(struct xfs_scrub *sc);
int xchk_quotacheck(struct xfs_scrub *sc);
#else
static inline int
xchk_quota(struct xfs_scrub *sc)
{
return -ENOENT;
}
static inline int
xchk_quotacheck(struct xfs_scrub *sc)
{
return -ENOENT;
}
# define xchk_quota xchk_nothing
# define xchk_quotacheck xchk_nothing
#endif
int xchk_fscounters(struct xfs_scrub *sc);
int xchk_nlinks(struct xfs_scrub *sc);

View File

@ -44,7 +44,7 @@ xfs_fsmap_from_internal(
}
/* Convert an fsmap to an xfs_fsmap. */
void
static void
xfs_fsmap_to_internal(
struct xfs_fsmap *dest,
struct fsmap *src)
@ -441,140 +441,6 @@ xfs_getfsmap_set_irec_flags(
irec->rm_flags |= XFS_RMAP_UNWRITTEN;
}
/* Execute a getfsmap query against the log device. */
STATIC int
xfs_getfsmap_logdev(
struct xfs_trans *tp,
const struct xfs_fsmap *keys,
struct xfs_getfsmap_info *info)
{
struct xfs_mount *mp = tp->t_mountp;
struct xfs_rmap_irec rmap;
xfs_daddr_t rec_daddr, len_daddr;
xfs_fsblock_t start_fsb, end_fsb;
uint64_t eofs;
eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
if (keys[0].fmr_physical >= eofs)
return 0;
start_fsb = XFS_BB_TO_FSBT(mp,
keys[0].fmr_physical + keys[0].fmr_length);
end_fsb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fmr_physical));
/* Adjust the low key if we are continuing from where we left off. */
if (keys[0].fmr_length > 0)
info->low_daddr = XFS_FSB_TO_BB(mp, start_fsb);
trace_xfs_fsmap_low_key_linear(mp, info->dev, start_fsb);
trace_xfs_fsmap_high_key_linear(mp, info->dev, end_fsb);
if (start_fsb > 0)
return 0;
/* Fabricate an rmap entry for the external log device. */
rmap.rm_startblock = 0;
rmap.rm_blockcount = mp->m_sb.sb_logblocks;
rmap.rm_owner = XFS_RMAP_OWN_LOG;
rmap.rm_offset = 0;
rmap.rm_flags = 0;
rec_daddr = XFS_FSB_TO_BB(mp, rmap.rm_startblock);
len_daddr = XFS_FSB_TO_BB(mp, rmap.rm_blockcount);
return xfs_getfsmap_helper(tp, info, &rmap, rec_daddr, len_daddr);
}
#ifdef CONFIG_XFS_RT
/* Transform a rtbitmap "record" into a fsmap */
STATIC int
xfs_getfsmap_rtdev_rtbitmap_helper(
struct xfs_mount *mp,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv)
{
struct xfs_getfsmap_info *info = priv;
struct xfs_rmap_irec irec;
xfs_rtblock_t rtbno;
xfs_daddr_t rec_daddr, len_daddr;
rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
rec_daddr = XFS_FSB_TO_BB(mp, rtbno);
irec.rm_startblock = rtbno;
rtbno = xfs_rtx_to_rtb(mp, rec->ar_extcount);
len_daddr = XFS_FSB_TO_BB(mp, rtbno);
irec.rm_blockcount = rtbno;
irec.rm_owner = XFS_RMAP_OWN_NULL; /* "free" */
irec.rm_offset = 0;
irec.rm_flags = 0;
return xfs_getfsmap_helper(tp, info, &irec, rec_daddr, len_daddr);
}
/* Execute a getfsmap query against the realtime device rtbitmap. */
STATIC int
xfs_getfsmap_rtdev_rtbitmap(
struct xfs_trans *tp,
const struct xfs_fsmap *keys,
struct xfs_getfsmap_info *info)
{
struct xfs_rtalloc_rec ahigh = { 0 };
struct xfs_mount *mp = tp->t_mountp;
xfs_rtblock_t start_rtb;
xfs_rtblock_t end_rtb;
xfs_rtxnum_t high;
uint64_t eofs;
int error;
eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
if (keys[0].fmr_physical >= eofs)
return 0;
start_rtb = XFS_BB_TO_FSBT(mp,
keys[0].fmr_physical + keys[0].fmr_length);
end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fmr_physical));
info->missing_owner = XFS_FMR_OWN_UNKNOWN;
/* Adjust the low key if we are continuing from where we left off. */
if (keys[0].fmr_length > 0) {
info->low_daddr = XFS_FSB_TO_BB(mp, start_rtb);
if (info->low_daddr >= eofs)
return 0;
}
trace_xfs_fsmap_low_key_linear(mp, info->dev, start_rtb);
trace_xfs_fsmap_high_key_linear(mp, info->dev, end_rtb);
xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
/*
* Set up query parameters to return free rtextents covering the range
* we want.
*/
high = xfs_rtb_to_rtxup(mp, end_rtb);
error = xfs_rtalloc_query_range(mp, tp, xfs_rtb_to_rtx(mp, start_rtb),
high, xfs_getfsmap_rtdev_rtbitmap_helper, info);
if (error)
goto err;
/*
* Report any gaps at the end of the rtbitmap by simulating a null
* rmap starting at the block after the end of the query range.
*/
info->last = true;
ahigh.ar_startext = min(mp->m_sb.sb_rextents, high);
error = xfs_getfsmap_rtdev_rtbitmap_helper(mp, tp, &ahigh, info);
if (error)
goto err;
err:
xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
return error;
}
#endif /* CONFIG_XFS_RT */
static inline bool
rmap_not_shareable(struct xfs_mount *mp, const struct xfs_rmap_irec *r)
{
@ -799,6 +665,140 @@ xfs_getfsmap_datadev_bnobt(
xfs_getfsmap_datadev_bnobt_query, &akeys[0]);
}
/* Execute a getfsmap query against the log device. */
STATIC int
xfs_getfsmap_logdev(
struct xfs_trans *tp,
const struct xfs_fsmap *keys,
struct xfs_getfsmap_info *info)
{
struct xfs_mount *mp = tp->t_mountp;
struct xfs_rmap_irec rmap;
xfs_daddr_t rec_daddr, len_daddr;
xfs_fsblock_t start_fsb, end_fsb;
uint64_t eofs;
eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
if (keys[0].fmr_physical >= eofs)
return 0;
start_fsb = XFS_BB_TO_FSBT(mp,
keys[0].fmr_physical + keys[0].fmr_length);
end_fsb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fmr_physical));
/* Adjust the low key if we are continuing from where we left off. */
if (keys[0].fmr_length > 0)
info->low_daddr = XFS_FSB_TO_BB(mp, start_fsb);
trace_xfs_fsmap_low_key_linear(mp, info->dev, start_fsb);
trace_xfs_fsmap_high_key_linear(mp, info->dev, end_fsb);
if (start_fsb > 0)
return 0;
/* Fabricate an rmap entry for the external log device. */
rmap.rm_startblock = 0;
rmap.rm_blockcount = mp->m_sb.sb_logblocks;
rmap.rm_owner = XFS_RMAP_OWN_LOG;
rmap.rm_offset = 0;
rmap.rm_flags = 0;
rec_daddr = XFS_FSB_TO_BB(mp, rmap.rm_startblock);
len_daddr = XFS_FSB_TO_BB(mp, rmap.rm_blockcount);
return xfs_getfsmap_helper(tp, info, &rmap, rec_daddr, len_daddr);
}
#ifdef CONFIG_XFS_RT
/* Transform a rtbitmap "record" into a fsmap */
STATIC int
xfs_getfsmap_rtdev_rtbitmap_helper(
struct xfs_mount *mp,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv)
{
struct xfs_getfsmap_info *info = priv;
struct xfs_rmap_irec irec;
xfs_rtblock_t rtbno;
xfs_daddr_t rec_daddr, len_daddr;
rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
rec_daddr = XFS_FSB_TO_BB(mp, rtbno);
irec.rm_startblock = rtbno;
rtbno = xfs_rtx_to_rtb(mp, rec->ar_extcount);
len_daddr = XFS_FSB_TO_BB(mp, rtbno);
irec.rm_blockcount = rtbno;
irec.rm_owner = XFS_RMAP_OWN_NULL; /* "free" */
irec.rm_offset = 0;
irec.rm_flags = 0;
return xfs_getfsmap_helper(tp, info, &irec, rec_daddr, len_daddr);
}
/* Execute a getfsmap query against the realtime device rtbitmap. */
STATIC int
xfs_getfsmap_rtdev_rtbitmap(
struct xfs_trans *tp,
const struct xfs_fsmap *keys,
struct xfs_getfsmap_info *info)
{
struct xfs_rtalloc_rec ahigh = { 0 };
struct xfs_mount *mp = tp->t_mountp;
xfs_rtblock_t start_rtb;
xfs_rtblock_t end_rtb;
xfs_rtxnum_t high;
uint64_t eofs;
int error;
eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
if (keys[0].fmr_physical >= eofs)
return 0;
start_rtb = XFS_BB_TO_FSBT(mp,
keys[0].fmr_physical + keys[0].fmr_length);
end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fmr_physical));
info->missing_owner = XFS_FMR_OWN_UNKNOWN;
/* Adjust the low key if we are continuing from where we left off. */
if (keys[0].fmr_length > 0) {
info->low_daddr = XFS_FSB_TO_BB(mp, start_rtb);
if (info->low_daddr >= eofs)
return 0;
}
trace_xfs_fsmap_low_key_linear(mp, info->dev, start_rtb);
trace_xfs_fsmap_high_key_linear(mp, info->dev, end_rtb);
xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
/*
* Set up query parameters to return free rtextents covering the range
* we want.
*/
high = xfs_rtb_to_rtxup(mp, end_rtb);
error = xfs_rtalloc_query_range(mp, tp, xfs_rtb_to_rtx(mp, start_rtb),
high, xfs_getfsmap_rtdev_rtbitmap_helper, info);
if (error)
goto err;
/*
* Report any gaps at the end of the rtbitmap by simulating a null
* rmap starting at the block after the end of the query range.
*/
info->last = true;
ahigh.ar_startext = min(mp->m_sb.sb_rextents, high);
error = xfs_getfsmap_rtdev_rtbitmap_helper(mp, tp, &ahigh, info);
if (error)
goto err;
err:
xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
return error;
}
#endif /* CONFIG_XFS_RT */
/* Do we recognize the device? */
STATIC bool
xfs_getfsmap_is_valid_device(
@ -889,7 +889,7 @@ xfs_getfsmap_check_keys(
* xfs_getfsmap_info.low/high -- per-AG low/high keys computed from
* dkeys; used to query the metadata.
*/
int
STATIC int
xfs_getfsmap(
struct xfs_mount *mp,
struct xfs_fsmap_head *head,
@ -1019,3 +1019,133 @@ xfs_getfsmap(
head->fmh_oflags = FMH_OF_DEV_T;
return error;
}
int
xfs_ioc_getfsmap(
struct xfs_inode *ip,
struct fsmap_head __user *arg)
{
struct xfs_fsmap_head xhead = {0};
struct fsmap_head head;
struct fsmap *recs;
unsigned int count;
__u32 last_flags = 0;
bool done = false;
int error;
if (copy_from_user(&head, arg, sizeof(struct fsmap_head)))
return -EFAULT;
if (memchr_inv(head.fmh_reserved, 0, sizeof(head.fmh_reserved)) ||
memchr_inv(head.fmh_keys[0].fmr_reserved, 0,
sizeof(head.fmh_keys[0].fmr_reserved)) ||
memchr_inv(head.fmh_keys[1].fmr_reserved, 0,
sizeof(head.fmh_keys[1].fmr_reserved)))
return -EINVAL;
/*
* Use an internal memory buffer so that we don't have to copy fsmap
* data to userspace while holding locks. Start by trying to allocate
* up to 128k for the buffer, but fall back to a single page if needed.
*/
count = min_t(unsigned int, head.fmh_count,
131072 / sizeof(struct fsmap));
recs = kvcalloc(count, sizeof(struct fsmap), GFP_KERNEL);
if (!recs) {
count = min_t(unsigned int, head.fmh_count,
PAGE_SIZE / sizeof(struct fsmap));
recs = kvcalloc(count, sizeof(struct fsmap), GFP_KERNEL);
if (!recs)
return -ENOMEM;
}
xhead.fmh_iflags = head.fmh_iflags;
xfs_fsmap_to_internal(&xhead.fmh_keys[0], &head.fmh_keys[0]);
xfs_fsmap_to_internal(&xhead.fmh_keys[1], &head.fmh_keys[1]);
trace_xfs_getfsmap_low_key(ip->i_mount, &xhead.fmh_keys[0]);
trace_xfs_getfsmap_high_key(ip->i_mount, &xhead.fmh_keys[1]);
head.fmh_entries = 0;
do {
struct fsmap __user *user_recs;
struct fsmap *last_rec;
user_recs = &arg->fmh_recs[head.fmh_entries];
xhead.fmh_entries = 0;
xhead.fmh_count = min_t(unsigned int, count,
head.fmh_count - head.fmh_entries);
/* Run query, record how many entries we got. */
error = xfs_getfsmap(ip->i_mount, &xhead, recs);
switch (error) {
case 0:
/*
* There are no more records in the result set. Copy
* whatever we got to userspace and break out.
*/
done = true;
break;
case -ECANCELED:
/*
* The internal memory buffer is full. Copy whatever
* records we got to userspace and go again if we have
* not yet filled the userspace buffer.
*/
error = 0;
break;
default:
goto out_free;
}
head.fmh_entries += xhead.fmh_entries;
head.fmh_oflags = xhead.fmh_oflags;
/*
* If the caller wanted a record count or there aren't any
* new records to return, we're done.
*/
if (head.fmh_count == 0 || xhead.fmh_entries == 0)
break;
/* Copy all the records we got out to userspace. */
if (copy_to_user(user_recs, recs,
xhead.fmh_entries * sizeof(struct fsmap))) {
error = -EFAULT;
goto out_free;
}
/* Remember the last record flags we copied to userspace. */
last_rec = &recs[xhead.fmh_entries - 1];
last_flags = last_rec->fmr_flags;
/* Set up the low key for the next iteration. */
xfs_fsmap_to_internal(&xhead.fmh_keys[0], last_rec);
trace_xfs_getfsmap_low_key(ip->i_mount, &xhead.fmh_keys[0]);
} while (!done && head.fmh_entries < head.fmh_count);
/*
* If there are no more records in the query result set and we're not
* in counting mode, mark the last record returned with the LAST flag.
*/
if (done && head.fmh_count > 0 && head.fmh_entries > 0) {
struct fsmap __user *user_rec;
last_flags |= FMR_OF_LAST;
user_rec = &arg->fmh_recs[head.fmh_entries - 1];
if (copy_to_user(&user_rec->fmr_flags, &last_flags,
sizeof(last_flags))) {
error = -EFAULT;
goto out_free;
}
}
/* copy back header */
if (copy_to_user(arg, &head, sizeof(struct fsmap_head))) {
error = -EFAULT;
goto out_free;
}
out_free:
kvfree(recs);
return error;
}

View File

@ -7,6 +7,7 @@
#define __XFS_FSMAP_H__
struct fsmap;
struct fsmap_head;
/* internal fsmap representation */
struct xfs_fsmap {
@ -27,9 +28,6 @@ struct xfs_fsmap_head {
struct xfs_fsmap fmh_keys[2]; /* low and high keys */
};
void xfs_fsmap_to_internal(struct xfs_fsmap *dest, struct fsmap *src);
int xfs_getfsmap(struct xfs_mount *mp, struct xfs_fsmap_head *head,
struct fsmap *out_recs);
int xfs_ioc_getfsmap(struct xfs_inode *ip, struct fsmap_head __user *arg);
#endif /* __XFS_FSMAP_H__ */

View File

@ -876,136 +876,6 @@ xfs_ioc_getbmap(
return error;
}
STATIC int
xfs_ioc_getfsmap(
struct xfs_inode *ip,
struct fsmap_head __user *arg)
{
struct xfs_fsmap_head xhead = {0};
struct fsmap_head head;
struct fsmap *recs;
unsigned int count;
__u32 last_flags = 0;
bool done = false;
int error;
if (copy_from_user(&head, arg, sizeof(struct fsmap_head)))
return -EFAULT;
if (memchr_inv(head.fmh_reserved, 0, sizeof(head.fmh_reserved)) ||
memchr_inv(head.fmh_keys[0].fmr_reserved, 0,
sizeof(head.fmh_keys[0].fmr_reserved)) ||
memchr_inv(head.fmh_keys[1].fmr_reserved, 0,
sizeof(head.fmh_keys[1].fmr_reserved)))
return -EINVAL;
/*
* Use an internal memory buffer so that we don't have to copy fsmap
* data to userspace while holding locks. Start by trying to allocate
* up to 128k for the buffer, but fall back to a single page if needed.
*/
count = min_t(unsigned int, head.fmh_count,
131072 / sizeof(struct fsmap));
recs = kvcalloc(count, sizeof(struct fsmap), GFP_KERNEL);
if (!recs) {
count = min_t(unsigned int, head.fmh_count,
PAGE_SIZE / sizeof(struct fsmap));
recs = kvcalloc(count, sizeof(struct fsmap), GFP_KERNEL);
if (!recs)
return -ENOMEM;
}
xhead.fmh_iflags = head.fmh_iflags;
xfs_fsmap_to_internal(&xhead.fmh_keys[0], &head.fmh_keys[0]);
xfs_fsmap_to_internal(&xhead.fmh_keys[1], &head.fmh_keys[1]);
trace_xfs_getfsmap_low_key(ip->i_mount, &xhead.fmh_keys[0]);
trace_xfs_getfsmap_high_key(ip->i_mount, &xhead.fmh_keys[1]);
head.fmh_entries = 0;
do {
struct fsmap __user *user_recs;
struct fsmap *last_rec;
user_recs = &arg->fmh_recs[head.fmh_entries];
xhead.fmh_entries = 0;
xhead.fmh_count = min_t(unsigned int, count,
head.fmh_count - head.fmh_entries);
/* Run query, record how many entries we got. */
error = xfs_getfsmap(ip->i_mount, &xhead, recs);
switch (error) {
case 0:
/*
* There are no more records in the result set. Copy
* whatever we got to userspace and break out.
*/
done = true;
break;
case -ECANCELED:
/*
* The internal memory buffer is full. Copy whatever
* records we got to userspace and go again if we have
* not yet filled the userspace buffer.
*/
error = 0;
break;
default:
goto out_free;
}
head.fmh_entries += xhead.fmh_entries;
head.fmh_oflags = xhead.fmh_oflags;
/*
* If the caller wanted a record count or there aren't any
* new records to return, we're done.
*/
if (head.fmh_count == 0 || xhead.fmh_entries == 0)
break;
/* Copy all the records we got out to userspace. */
if (copy_to_user(user_recs, recs,
xhead.fmh_entries * sizeof(struct fsmap))) {
error = -EFAULT;
goto out_free;
}
/* Remember the last record flags we copied to userspace. */
last_rec = &recs[xhead.fmh_entries - 1];
last_flags = last_rec->fmr_flags;
/* Set up the low key for the next iteration. */
xfs_fsmap_to_internal(&xhead.fmh_keys[0], last_rec);
trace_xfs_getfsmap_low_key(ip->i_mount, &xhead.fmh_keys[0]);
} while (!done && head.fmh_entries < head.fmh_count);
/*
* If there are no more records in the query result set and we're not
* in counting mode, mark the last record returned with the LAST flag.
*/
if (done && head.fmh_count > 0 && head.fmh_entries > 0) {
struct fsmap __user *user_rec;
last_flags |= FMR_OF_LAST;
user_rec = &arg->fmh_recs[head.fmh_entries - 1];
if (copy_to_user(&user_rec->fmr_flags, &last_flags,
sizeof(last_flags))) {
error = -EFAULT;
goto out_free;
}
}
/* copy back header */
if (copy_to_user(arg, &head, sizeof(struct fsmap_head))) {
error = -EFAULT;
goto out_free;
}
out_free:
kvfree(recs);
return error;
}
int
xfs_ioc_swapext(
xfs_swapext_t *sxp)

View File

@ -147,7 +147,7 @@ typedef struct xfs_mount {
int m_logbufs; /* number of log buffers */
int m_logbsize; /* size of each log buffer */
uint m_rsumlevels; /* rt summary levels */
uint m_rsumsize; /* size of rt summary, bytes */
xfs_filblks_t m_rsumblocks; /* size of rt summary, FSBs */
int m_fixedfsid[2]; /* unchanged for life of FS */
uint m_qflags; /* quota status flags */
uint64_t m_features; /* active filesystem features */

View File

@ -734,9 +734,8 @@ xfs_growfs_rt_bmblock(
nmp->m_sb.sb_rextents = xfs_rtb_to_rtx(nmp, nmp->m_sb.sb_rblocks);
nmp->m_sb.sb_rextslog = xfs_compute_rextslog(nmp->m_sb.sb_rextents);
nmp->m_rsumlevels = nmp->m_sb.sb_rextslog + 1;
nmp->m_rsumsize = XFS_FSB_TO_B(mp,
xfs_rtsummary_blockcount(mp, nmp->m_rsumlevels,
nmp->m_sb.sb_rbmblocks));
nmp->m_rsumblocks = xfs_rtsummary_blockcount(mp, nmp->m_rsumlevels,
nmp->m_sb.sb_rbmblocks);
/*
* Recompute the growfsrt reservation from the new rsumsize, so that the
@ -766,7 +765,7 @@ xfs_growfs_rt_bmblock(
* so that inode inactivation won't punch what it thinks are "posteof"
* blocks.
*/
rsumip->i_disk_size = nmp->m_rsumsize;
rsumip->i_disk_size = nmp->m_rsumblocks * nmp->m_sb.sb_blocksize;
i_size_write(VFS_I(rsumip), rsumip->i_disk_size);
xfs_trans_log_inode(args.tp, rsumip, XFS_ILOG_CORE);
@ -818,7 +817,7 @@ xfs_growfs_rt_bmblock(
* Update the calculated values in the real mount structure.
*/
mp->m_rsumlevels = nmp->m_rsumlevels;
mp->m_rsumsize = nmp->m_rsumsize;
mp->m_rsumblocks = nmp->m_rsumblocks;
xfs_mount_sb_set_rextsize(mp, &mp->m_sb);
/*
@ -1022,7 +1021,6 @@ xfs_rtmount_init(
struct xfs_buf *bp; /* buffer for last block of subvolume */
struct xfs_sb *sbp; /* filesystem superblock copy in mount */
xfs_daddr_t d; /* address of last block of subvolume */
unsigned int rsumblocks;
int error;
sbp = &mp->m_sb;
@ -1034,9 +1032,8 @@ xfs_rtmount_init(
return -ENODEV;
}
mp->m_rsumlevels = sbp->sb_rextslog + 1;
rsumblocks = xfs_rtsummary_blockcount(mp, mp->m_rsumlevels,
mp->m_rsumblocks = xfs_rtsummary_blockcount(mp, mp->m_rsumlevels,
mp->m_sb.sb_rbmblocks);
mp->m_rsumsize = XFS_FSB_TO_B(mp, rsumblocks);
mp->m_rbmip = mp->m_rsumip = NULL;
/*
* Check that the realtime section is an ok size.
@ -1263,36 +1260,109 @@ xfs_rtalloc_align_minmax(
*raminlen = newminlen;
}
int
xfs_bmap_rtalloc(
struct xfs_bmalloca *ap)
static int
xfs_rtallocate(
struct xfs_trans *tp,
xfs_rtblock_t bno_hint,
xfs_rtxlen_t minlen,
xfs_rtxlen_t maxlen,
xfs_rtxlen_t prod,
bool wasdel,
bool initial_user_data,
bool *rtlocked,
xfs_rtblock_t *bno,
xfs_extlen_t *blen)
{
struct xfs_rtalloc_args args = {
.mp = tp->t_mountp,
.tp = tp,
};
xfs_rtxnum_t start = 0;
xfs_rtxnum_t rtx;
xfs_rtxlen_t len = 0;
int error = 0;
/*
* Lock out modifications to both the RT bitmap and summary inodes.
*/
if (!*rtlocked) {
xfs_rtbitmap_lock(args.mp);
xfs_rtbitmap_trans_join(tp);
*rtlocked = true;
}
/*
* For an allocation to an empty file at offset 0, pick an extent that
* will space things out in the rt area.
*/
if (bno_hint)
start = xfs_rtb_to_rtx(args.mp, bno_hint);
else if (initial_user_data)
start = xfs_rtpick_extent(args.mp, tp, maxlen);
if (start) {
error = xfs_rtallocate_extent_near(&args, start, minlen, maxlen,
&len, prod, &rtx);
/*
* If we can't allocate near a specific rt extent, try again
* without locality criteria.
*/
if (error == -ENOSPC) {
xfs_rtbuf_cache_relse(&args);
error = 0;
}
}
if (!error) {
error = xfs_rtallocate_extent_size(&args, minlen, maxlen, &len,
prod, &rtx);
}
if (error)
goto out_release;
error = xfs_rtallocate_range(&args, rtx, len);
if (error)
goto out_release;
xfs_trans_mod_sb(tp, wasdel ?
XFS_TRANS_SB_RES_FREXTENTS : XFS_TRANS_SB_FREXTENTS,
-(long)len);
*bno = xfs_rtx_to_rtb(args.mp, rtx);
*blen = xfs_rtxlen_to_extlen(args.mp, len);
out_release:
xfs_rtbuf_cache_relse(&args);
return error;
}
static int
xfs_rtallocate_align(
struct xfs_bmalloca *ap,
xfs_rtxlen_t *ralen,
xfs_rtxlen_t *raminlen,
xfs_rtxlen_t *prod,
bool *noalign)
{
struct xfs_mount *mp = ap->ip->i_mount;
xfs_fileoff_t orig_offset = ap->offset;
xfs_rtxnum_t start; /* allocation hint rtextent no */
xfs_rtxnum_t rtx; /* actually allocated rtextent no */
xfs_rtxlen_t prod = 0; /* product factor for allocators */
xfs_extlen_t mod = 0; /* product factor for allocators */
xfs_rtxlen_t ralen = 0; /* realtime allocation length */
xfs_extlen_t align; /* minimum allocation alignment */
xfs_extlen_t orig_length = ap->length;
xfs_extlen_t minlen = mp->m_sb.sb_rextsize;
xfs_rtxlen_t raminlen;
bool rtlocked = false;
bool ignore_locality = false;
struct xfs_rtalloc_args args = {
.mp = mp,
.tp = ap->tp,
};
xfs_extlen_t align; /* minimum allocation alignment */
xfs_extlen_t mod; /* product factor for allocators */
int error;
align = xfs_get_extsz_hint(ap->ip);
if (!align)
align = 1;
retry:
error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
align, 1, ap->eof, 0,
ap->conv, &ap->offset, &ap->length);
if (*noalign) {
align = mp->m_sb.sb_rextsize;
} else {
align = xfs_get_extsz_hint(ap->ip);
if (!align)
align = 1;
if (align == mp->m_sb.sb_rextsize)
*noalign = true;
}
error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev, align, 1,
ap->eof, 0, ap->conv, &ap->offset, &ap->length);
if (error)
return error;
ASSERT(ap->length);
@ -1316,61 +1386,55 @@ xfs_bmap_rtalloc(
* XFS_BMBT_MAX_EXTLEN), we don't hear about that number, and can't
* adjust the starting point to match it.
*/
ralen = xfs_extlen_to_rtxlen(mp, min(ap->length, XFS_MAX_BMBT_EXTLEN));
raminlen = max_t(xfs_rtxlen_t, 1, xfs_extlen_to_rtxlen(mp, minlen));
ASSERT(raminlen > 0);
ASSERT(raminlen <= ralen);
/*
* Lock out modifications to both the RT bitmap and summary inodes
*/
if (!rtlocked) {
xfs_rtbitmap_lock(mp);
xfs_rtbitmap_trans_join(ap->tp);
rtlocked = true;
}
if (ignore_locality) {
start = 0;
} else if (xfs_bmap_adjacent(ap)) {
start = xfs_rtb_to_rtx(mp, ap->blkno);
} else if (ap->datatype & XFS_ALLOC_INITIAL_USER_DATA) {
/*
* If it's an allocation to an empty file at offset 0, pick an
* extent that will space things out in the rt area.
*/
start = xfs_rtpick_extent(mp, ap->tp, ralen);
} else {
start = 0;
}
*ralen = xfs_extlen_to_rtxlen(mp, min(ap->length, XFS_MAX_BMBT_EXTLEN));
*raminlen = max_t(xfs_rtxlen_t, 1, xfs_extlen_to_rtxlen(mp, minlen));
ASSERT(*raminlen > 0);
ASSERT(*raminlen <= *ralen);
/*
* Only bother calculating a real prod factor if offset & length are
* perfectly aligned, otherwise it will just get us in trouble.
*/
div_u64_rem(ap->offset, align, &mod);
if (mod || ap->length % align) {
prod = 1;
} else {
prod = xfs_extlen_to_rtxlen(mp, align);
if (prod > 1)
xfs_rtalloc_align_minmax(&raminlen, &ralen, &prod);
}
if (mod || ap->length % align)
*prod = 1;
else
*prod = xfs_extlen_to_rtxlen(mp, align);
if (start) {
error = xfs_rtallocate_extent_near(&args, start, raminlen,
ralen, &ralen, prod, &rtx);
} else {
error = xfs_rtallocate_extent_size(&args, raminlen,
ralen, &ralen, prod, &rtx);
}
if (*prod > 1)
xfs_rtalloc_align_minmax(raminlen, ralen, prod);
return 0;
}
if (error) {
xfs_rtbuf_cache_relse(&args);
if (error != -ENOSPC)
return error;
int
xfs_bmap_rtalloc(
struct xfs_bmalloca *ap)
{
xfs_fileoff_t orig_offset = ap->offset;
xfs_rtxlen_t prod = 0; /* product factor for allocators */
xfs_rtxlen_t ralen = 0; /* realtime allocation length */
xfs_rtblock_t bno_hint = NULLRTBLOCK;
xfs_extlen_t orig_length = ap->length;
xfs_rtxlen_t raminlen;
bool rtlocked = false;
bool noalign = false;
bool initial_user_data =
ap->datatype & XFS_ALLOC_INITIAL_USER_DATA;
int error;
if (align > mp->m_sb.sb_rextsize) {
retry:
error = xfs_rtallocate_align(ap, &ralen, &raminlen, &prod, &noalign);
if (error)
return error;
if (xfs_bmap_adjacent(ap))
bno_hint = ap->blkno;
error = xfs_rtallocate(ap->tp, bno_hint, raminlen, ralen, prod,
ap->wasdel, initial_user_data, &rtlocked,
&ap->blkno, &ap->length);
if (error == -ENOSPC) {
if (!noalign) {
/*
* We previously enlarged the request length to try to
* satisfy an extent size hint. The allocator didn't
@ -1380,16 +1444,7 @@ xfs_bmap_rtalloc(
*/
ap->offset = orig_offset;
ap->length = orig_length;
minlen = align = mp->m_sb.sb_rextsize;
goto retry;
}
if (!ignore_locality && start != 0) {
/*
* If we can't allocate near a specific rt extent, try
* again without locality criteria.
*/
ignore_locality = true;
noalign = true;
goto retry;
}
@ -1397,20 +1452,9 @@ xfs_bmap_rtalloc(
ap->length = 0;
return 0;
}
error = xfs_rtallocate_range(&args, rtx, ralen);
if (error)
goto out_release;
return error;
xfs_trans_mod_sb(ap->tp, ap->wasdel ?
XFS_TRANS_SB_RES_FREXTENTS : XFS_TRANS_SB_FREXTENTS,
-(long)ralen);
ap->blkno = xfs_rtx_to_rtb(mp, rtx);
ap->length = xfs_rtxlen_to_extlen(mp, ralen);
xfs_bmap_alloc_account(ap);
out_release:
xfs_rtbuf_cache_relse(&args);
return error;
return 0;
}