mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 11:33:28 +02:00
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:
commit
07b2bbcf77
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user