/* * If we have a cached buffer, and the block number matches, use that.
*/ if (*cbpp && *coffp == block) return 0;
/* * Otherwise we have to have to get the buffer. If there was an old * one, get rid of it first.
*/ if (*cbpp) {
xfs_trans_brelse(args->tp, *cbpp);
*cbpp = NULL;
}
/* * Searching backward from start find the first block whose allocated/free state * is different from start's.
*/ int
xfs_rtfind_back( struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext to look at */
xfs_rtxnum_t *rtx) /* out: start rtext found */
{ struct xfs_mount *mp = args->mp; int bit; /* bit number in the word */
xfs_fileoff_t block; /* bitmap block number */ int error; /* error value */
xfs_rtxnum_t firstbit; /* first useful bit in the word */
xfs_rtxnum_t i; /* current bit number rel. to start */
xfs_rtxnum_t len; /* length of inspected area */
xfs_rtword_t mask; /* mask of relevant bits for value */
xfs_rtword_t want; /* mask for "good" values */
xfs_rtword_t wdiff; /* difference from wanted value */
xfs_rtword_t incore; unsignedint word; /* word number in the buffer */
/* * Compute and read in starting bitmap block for starting block.
*/
block = xfs_rtx_to_rbmblock(mp, start);
error = xfs_rtbitmap_read_buf(args, block); if (error) return error;
/* * Get the first word's index & point to it.
*/
word = xfs_rtx_to_rbmword(mp, start);
bit = (int)(start & (XFS_NBWORD - 1));
len = start + 1; /* * Compute match value, based on the bit at start: if 1 (free) * then all-ones, else all-zeroes.
*/
incore = xfs_rtbitmap_getword(args, word);
want = (incore & ((xfs_rtword_t)1 << bit)) ? -1 : 0; /* * If the starting position is not word-aligned, deal with the * partial word.
*/ if (bit < XFS_NBWORD - 1) { /* * Calculate first (leftmost) bit number to look at, * and mask for all the relevant bits in this word.
*/
firstbit = max_t(xfs_srtblock_t, bit - len + 1, 0);
mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) <<
firstbit; /* * Calculate the difference between the value there * and what we're looking for.
*/ if ((wdiff = (incore ^ want) & mask)) { /* * Different. Mark where we are and return.
*/
i = bit - xfs_highbit32(wdiff);
*rtx = start - i + 1; return 0;
}
i = bit - firstbit + 1; /* * Go on to previous block if that's where the previous word is * and we need the previous word.
*/ if (--word == -1 && i < len) { /* * If done with this block, get the previous one.
*/
error = xfs_rtbitmap_read_buf(args, --block); if (error) return error;
word = mp->m_blockwsize - 1;
}
} else { /* * Starting on a word boundary, no partial word.
*/
i = 0;
} /* * Loop over whole words in buffers. When we use up one buffer * we move on to the previous one.
*/ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value.
*/
incore = xfs_rtbitmap_getword(args, word); if ((wdiff = incore ^ want)) { /* * Different, mark where we are and return.
*/
i += XFS_NBWORD - 1 - xfs_highbit32(wdiff);
*rtx = start - i + 1; return 0;
}
i += XFS_NBWORD; /* * Go on to previous block if that's where the previous word is * and we need the previous word.
*/ if (--word == -1 && i < len) { /* * If done with this block, get the previous one.
*/
error = xfs_rtbitmap_read_buf(args, --block); if (error) return error;
word = mp->m_blockwsize - 1;
}
} /* * If not ending on a word boundary, deal with the last * (partial) word.
*/ if (len - i) { /* * Calculate first (leftmost) bit number to look at, * and mask for all the relevant bits in this word.
*/
firstbit = XFS_NBWORD - (len - i);
mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; /* * Compute difference between actual and desired value.
*/
incore = xfs_rtbitmap_getword(args, word); if ((wdiff = (incore ^ want) & mask)) { /* * Different, mark where we are and return.
*/
i += XFS_NBWORD - 1 - xfs_highbit32(wdiff);
*rtx = start - i + 1; return 0;
} else
i = len;
} /* * No match, return that we scanned the whole area.
*/
*rtx = start - i + 1; return 0;
}
/* * Searching forward from start to limit, find the first block whose * allocated/free state is different from start's.
*/ int
xfs_rtfind_forw( struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext to look at */
xfs_rtxnum_t limit, /* last rtext to look at */
xfs_rtxnum_t *rtx) /* out: start rtext found */
{ struct xfs_mount *mp = args->mp; int bit; /* bit number in the word */
xfs_fileoff_t block; /* bitmap block number */ int error;
xfs_rtxnum_t i; /* current bit number rel. to start */
xfs_rtxnum_t lastbit;/* last useful bit in the word */
xfs_rtxnum_t len; /* length of inspected area */
xfs_rtword_t mask; /* mask of relevant bits for value */
xfs_rtword_t want; /* mask for "good" values */
xfs_rtword_t wdiff; /* difference from wanted value */
xfs_rtword_t incore; unsignedint word; /* word number in the buffer */
ASSERT(start <= limit);
/* * Compute and read in starting bitmap block for starting block.
*/
block = xfs_rtx_to_rbmblock(mp, start);
error = xfs_rtbitmap_read_buf(args, block); if (error) return error;
/* * Get the first word's index & point to it.
*/
word = xfs_rtx_to_rbmword(mp, start);
bit = (int)(start & (XFS_NBWORD - 1));
len = limit - start + 1; /* * Compute match value, based on the bit at start: if 1 (free) * then all-ones, else all-zeroes.
*/
incore = xfs_rtbitmap_getword(args, word);
want = (incore & ((xfs_rtword_t)1 << bit)) ? -1 : 0; /* * If the starting position is not word-aligned, deal with the * partial word.
*/ if (bit) { /* * Calculate last (rightmost) bit number to look at, * and mask for all the relevant bits in this word.
*/
lastbit = min(bit + len, XFS_NBWORD);
mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Calculate the difference between the value there * and what we're looking for.
*/ if ((wdiff = (incore ^ want) & mask)) { /* * Different. Mark where we are and return.
*/
i = xfs_lowbit32(wdiff) - bit;
*rtx = start + i - 1; return 0;
}
i = lastbit - bit; /* * Go on to next block if that's where the next word is * and we need the next word.
*/ if (++word == mp->m_blockwsize && i < len) { /* * If done with this block, get the previous one.
*/
error = xfs_rtbitmap_read_buf(args, ++block); if (error) return error;
word = 0;
}
} else { /* * Starting on a word boundary, no partial word.
*/
i = 0;
} /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one.
*/ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value.
*/
incore = xfs_rtbitmap_getword(args, word); if ((wdiff = incore ^ want)) { /* * Different, mark where we are and return.
*/
i += xfs_lowbit32(wdiff);
*rtx = start + i - 1; return 0;
}
i += XFS_NBWORD; /* * Go on to next block if that's where the next word is * and we need the next word.
*/ if (++word == mp->m_blockwsize && i < len) { /* * If done with this block, get the next one.
*/
error = xfs_rtbitmap_read_buf(args, ++block); if (error) return error;
word = 0;
}
} /* * If not ending on a word boundary, deal with the last * (partial) word.
*/ if ((lastbit = len - i)) { /* * Calculate mask for all the relevant bits in this word.
*/
mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Compute difference between actual and desired value.
*/
incore = xfs_rtbitmap_getword(args, word); if ((wdiff = (incore ^ want) & mask)) { /* * Different, mark where we are and return.
*/
i += xfs_lowbit32(wdiff);
*rtx = start + i - 1; return 0;
} else
i = len;
} /* * No match, return that we scanned the whole area.
*/
*rtx = start + i - 1; return 0;
}
/* * Read and return the summary information for a given extent size, bitmap block * combination.
*/ int
xfs_rtget_summary( struct xfs_rtalloc_args *args, int log, /* log2 of extent size */
xfs_fileoff_t bbno, /* bitmap block number */
xfs_suminfo_t *sum) /* out: summary info for this block */
{ struct xfs_mount *mp = args->mp;
xfs_rtsumoff_t so = xfs_rtsumoffs(mp, log, bbno); int error;
/* Log rtbitmap block from the word @from to the byte before @next. */ staticinlinevoid
xfs_trans_log_rtbitmap( struct xfs_rtalloc_args *args, unsignedint from, unsignedint next)
{ struct xfs_buf *bp = args->rbmbp;
size_t first, last;
first = (void *)xfs_rbmblock_wordptr(args, from) - bp->b_addr;
last = ((void *)xfs_rbmblock_wordptr(args, next) - 1) - bp->b_addr;
xfs_trans_log_buf(args->tp, bp, first, last);
}
/* * Set the given range of bitmap bits to the given value. * Do whatever I/O and logging is required.
*/ int
xfs_rtmodify_range( struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext to modify */
xfs_rtxlen_t len, /* length of extent to modify */ int val) /* 1 for free, 0 for allocated */
{ struct xfs_mount *mp = args->mp; int bit; /* bit number in the word */
xfs_fileoff_t block; /* bitmap block number */ int error; int i; /* current bit number rel. to start */ int lastbit; /* last useful bit in word */
xfs_rtword_t mask; /* mask of relevant bits for value */
xfs_rtword_t incore; unsignedint firstword; /* first word used in the buffer */ unsignedint word; /* word number in the buffer */
/* * Compute starting bitmap block number.
*/
block = xfs_rtx_to_rbmblock(mp, start); /* * Read the bitmap block, and point to its data.
*/
error = xfs_rtbitmap_read_buf(args, block); if (error) return error;
/* * Compute the starting word's address, and starting bit.
*/
firstword = word = xfs_rtx_to_rbmword(mp, start);
bit = (int)(start & (XFS_NBWORD - 1)); /* * 0 (allocated) => all zeroes; 1 (free) => all ones.
*/
val = -val; /* * If not starting on a word boundary, deal with the first * (partial) word.
*/ if (bit) { /* * Compute first bit not changed and mask of relevant bits.
*/
lastbit = min(bit + len, XFS_NBWORD);
mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Set/clear the active bits.
*/
incore = xfs_rtbitmap_getword(args, word); if (val)
incore |= mask; else
incore &= ~mask;
xfs_rtbitmap_setword(args, word, incore);
i = lastbit - bit; /* * Go on to the next block if that's where the next word is * and we need the next word.
*/ if (++word == mp->m_blockwsize && i < len) { /* * Log the changed part of this block. * Get the next one.
*/
xfs_trans_log_rtbitmap(args, firstword, word);
error = xfs_rtbitmap_read_buf(args, ++block); if (error) return error;
firstword = word = 0;
}
} else { /* * Starting on a word boundary, no partial word.
*/
i = 0;
} /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one.
*/ while (len - i >= XFS_NBWORD) { /* * Set the word value correctly.
*/
xfs_rtbitmap_setword(args, word, val);
i += XFS_NBWORD; /* * Go on to the next block if that's where the next word is * and we need the next word.
*/ if (++word == mp->m_blockwsize && i < len) { /* * Log the changed part of this block. * Get the next one.
*/
xfs_trans_log_rtbitmap(args, firstword, word);
error = xfs_rtbitmap_read_buf(args, ++block); if (error) return error;
firstword = word = 0;
}
} /* * If not ending on a word boundary, deal with the last * (partial) word.
*/ if ((lastbit = len - i)) { /* * Compute a mask of relevant bits.
*/
mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Set/clear the active bits.
*/
incore = xfs_rtbitmap_getword(args, word); if (val)
incore |= mask; else
incore &= ~mask;
xfs_rtbitmap_setword(args, word, incore);
word++;
} /* * Log any remaining changed bytes.
*/ if (word > firstword)
xfs_trans_log_rtbitmap(args, firstword, word); return 0;
}
/* * Mark an extent specified by start and len freed. * Updates all the summary information as well as the bitmap.
*/ int
xfs_rtfree_range( struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext to free */
xfs_rtxlen_t len) /* in/out: summary block number */
{ struct xfs_mount *mp = args->mp;
xfs_rtxnum_t end; /* end of the freed extent */ int error; /* error value */
xfs_rtxnum_t postblock; /* first rtext freed > end */
xfs_rtxnum_t preblock; /* first rtext freed < start */
end = start + len - 1; /* * Modify the bitmap to mark this extent freed.
*/
error = xfs_rtmodify_range(args, start, len, 1); if (error) { return error;
} /* * Assume we're freeing out of the middle of an allocated extent. * We need to find the beginning and end of the extent so we can * properly update the summary.
*/
error = xfs_rtfind_back(args, start, &preblock); if (error) { return error;
} /* * Find the next allocated block (end of allocated extent).
*/
error = xfs_rtfind_forw(args, end, args->rtg->rtg_extents - 1,
&postblock); if (error) return error; /* * If there are blocks not being freed at the front of the * old extent, add summary data for them to be allocated.
*/ if (preblock < start) {
error = xfs_rtmodify_summary(args,
xfs_highbit64(start - preblock),
xfs_rtx_to_rbmblock(mp, preblock), -1); if (error) { return error;
}
} /* * If there are blocks not being freed at the end of the * old extent, add summary data for them to be allocated.
*/ if (postblock > end) {
error = xfs_rtmodify_summary(args,
xfs_highbit64(postblock - end),
xfs_rtx_to_rbmblock(mp, end + 1), -1); if (error) { return error;
}
} /* * Increment the summary information corresponding to the entire * (new) free extent.
*/ return xfs_rtmodify_summary(args,
xfs_highbit64(postblock + 1 - preblock),
xfs_rtx_to_rbmblock(mp, preblock), 1);
}
/* * Check that the given range is either all allocated (val = 0) or * all free (val = 1).
*/ int
xfs_rtcheck_range( struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext number of extent */
xfs_rtxlen_t len, /* length of extent */ int val, /* 1 for free, 0 for allocated */
xfs_rtxnum_t *new, /* out: first rtext not matching */ int *stat) /* out: 1 for matches, 0 for not */
{ struct xfs_mount *mp = args->mp; int bit; /* bit number in the word */
xfs_fileoff_t block; /* bitmap block number */ int error;
xfs_rtxnum_t i; /* current bit number rel. to start */
xfs_rtxnum_t lastbit; /* last useful bit in word */
xfs_rtword_t mask; /* mask of relevant bits for value */
xfs_rtword_t wdiff; /* difference from wanted value */
xfs_rtword_t incore; unsignedint word; /* word number in the buffer */
/* * Compute starting bitmap block number
*/
block = xfs_rtx_to_rbmblock(mp, start); /* * Read the bitmap block.
*/
error = xfs_rtbitmap_read_buf(args, block); if (error) return error;
/* * Compute the starting word's address, and starting bit.
*/
word = xfs_rtx_to_rbmword(mp, start);
bit = (int)(start & (XFS_NBWORD - 1)); /* * 0 (allocated) => all zero's; 1 (free) => all one's.
*/
val = -val; /* * If not starting on a word boundary, deal with the first * (partial) word.
*/ if (bit) { /* * Compute first bit not examined.
*/
lastbit = min(bit + len, XFS_NBWORD); /* * Mask of relevant bits.
*/
mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Compute difference between actual and desired value.
*/
incore = xfs_rtbitmap_getword(args, word); if ((wdiff = (incore ^ val) & mask)) { /* * Different, compute first wrong bit and return.
*/
i = xfs_lowbit32(wdiff) - bit;
*new = start + i;
*stat = 0; return 0;
}
i = lastbit - bit; /* * Go on to next block if that's where the next word is * and we need the next word.
*/ if (++word == mp->m_blockwsize && i < len) { /* * If done with this block, get the next one.
*/
error = xfs_rtbitmap_read_buf(args, ++block); if (error) return error;
word = 0;
}
} else { /* * Starting on a word boundary, no partial word.
*/
i = 0;
} /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one.
*/ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value.
*/
incore = xfs_rtbitmap_getword(args, word); if ((wdiff = incore ^ val)) { /* * Different, compute first wrong bit and return.
*/
i += xfs_lowbit32(wdiff);
*new = start + i;
*stat = 0; return 0;
}
i += XFS_NBWORD; /* * Go on to next block if that's where the next word is * and we need the next word.
*/ if (++word == mp->m_blockwsize && i < len) { /* * If done with this block, get the next one.
*/
error = xfs_rtbitmap_read_buf(args, ++block); if (error) return error;
word = 0;
}
} /* * If not ending on a word boundary, deal with the last * (partial) word.
*/ if ((lastbit = len - i)) { /* * Mask of relevant bits.
*/
mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Compute difference between actual and desired value.
*/
incore = xfs_rtbitmap_getword(args, word); if ((wdiff = (incore ^ val) & mask)) { /* * Different, compute first wrong bit and return.
*/
i += xfs_lowbit32(wdiff);
*new = start + i;
*stat = 0; return 0;
} else
i = len;
} /* * Successful, return.
*/
*new = start + i;
*stat = 1; return 0;
}
#ifdef DEBUG /* * Check that the given extent (block range) is allocated already.
*/ STATICint
xfs_rtcheck_alloc_range( struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext number of extent */
xfs_rtxlen_t len) /* length of extent */
{
xfs_rtxnum_t new; /* dummy for xfs_rtcheck_range */ int stat; int error;
error = xfs_rtcheck_range(args, start, len, 0, &new, &stat); if (error) return error;
ASSERT(stat); return 0;
} #else #define xfs_rtcheck_alloc_range(a,b,l) (0) #endif /* * Free an extent in the realtime subvolume. Length is expressed in * realtime extents, as is the block number.
*/ int
xfs_rtfree_extent( struct xfs_trans *tp, /* transaction pointer */ struct xfs_rtgroup *rtg,
xfs_rtxnum_t start, /* starting rtext number to free */
xfs_rtxlen_t len) /* length of extent freed */
{ struct xfs_mount *mp = tp->t_mountp; struct xfs_inode *rbmip = rtg_bitmap(rtg); struct xfs_rtalloc_args args = {
.mp = mp,
.tp = tp,
.rtg = rtg,
}; int error; struct timespec64 atime;
if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FREE_EXTENT)) return -EIO;
error = xfs_rtcheck_alloc_range(&args, start, len); if (error) return error;
/* * Free the range of realtime blocks.
*/
error = xfs_rtfree_range(&args, start, len); if (error) goto out;
/* * Mark more blocks free in the superblock.
*/
xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len);
/* * If we've now freed all the blocks, reset the file sequence * number to 0 for pre-RTG file systems.
*/ if (!xfs_has_rtgroups(mp) &&
tp->t_frextents_delta + mp->m_sb.sb_frextents ==
mp->m_sb.sb_rextents) { if (!(rbmip->i_diflags & XFS_DIFLAG_NEWRTBM))
rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
/* * Free some blocks in the realtime subvolume. rtbno and rtlen are in units of * rt blocks, not rt extents; must be aligned to the rt extent size; and rtlen * cannot exceed XFS_MAX_BMBT_EXTLEN.
*/ int
xfs_rtfree_blocks( struct xfs_trans *tp, struct xfs_rtgroup *rtg,
xfs_fsblock_t rtbno,
xfs_filblks_t rtlen)
{ struct xfs_mount *mp = tp->t_mountp;
xfs_extlen_t mod; int error;
/* Compute the number of rt extents tracked by a single bitmap block. */
xfs_rtxnum_t
xfs_rtbitmap_rtx_per_rbmblock( struct xfs_mount *mp)
{ unsignedint rbmblock_bytes = mp->m_sb.sb_blocksize;
if (xfs_has_rtgroups(mp))
rbmblock_bytes -= sizeof(struct xfs_rtbuf_blkinfo);
return rbmblock_bytes * NBBY;
}
/* * Compute the number of rtbitmap blocks needed to track the given number of rt * extents.
*/
xfs_filblks_t
xfs_rtbitmap_blockcount_len( struct xfs_mount *mp,
xfs_rtbxlen_t rtextents)
{ if (xfs_has_zoned(mp)) return 0; return howmany_64(rtextents, xfs_rtbitmap_rtx_per_rbmblock(mp));
}
/* How many rt extents does each rtbitmap file track? */ staticinline xfs_rtbxlen_t
xfs_rtbitmap_bitcount( struct xfs_mount *mp)
{ if (!mp->m_sb.sb_rextents) return 0;
/* rtgroup size can be nonzero even if rextents is zero */ if (xfs_has_rtgroups(mp)) return mp->m_sb.sb_rgextents;
return mp->m_sb.sb_rextents;
}
/* * Compute the number of rtbitmap blocks used for a given file system.
*/
xfs_filblks_t
xfs_rtbitmap_blockcount( struct xfs_mount *mp)
{ return xfs_rtbitmap_blockcount_len(mp, xfs_rtbitmap_bitcount(mp));
}
/* * Compute the geometry of the rtsummary file needed to track the given rt * space.
*/
xfs_filblks_t
xfs_rtsummary_blockcount( struct xfs_mount *mp, unsignedint *rsumlevels)
{
xfs_rtbxlen_t rextents = xfs_rtbitmap_bitcount(mp); unsignedlonglong rsumwords;
if (xfs_has_zoned(mp)) {
*rsumlevels = 0; return 0;
}
/* * Allocate space to the bitmap or summary file, and zero it, for growfs. * @data must be a contiguous buffer large enough to fill all blocks in the * file; or NULL to initialize the contents to zeroes.
*/ int
xfs_rtfile_initialize_blocks( struct xfs_rtgroup *rtg, enum xfs_rtg_inodes type,
xfs_fileoff_t offset_fsb, /* offset to start from */
xfs_fileoff_t end_fsb, /* offset to allocate to */ void *data) /* data to fill the blocks */
{ struct xfs_mount *mp = rtg_mount(rtg); const size_t copylen = mp->m_blockwsize << XFS_WORDLOG;
while (offset_fsb < end_fsb) { struct xfs_bmbt_irec map;
xfs_filblks_t i; int error;
/* * Now we need to clear the allocated blocks. * * Do this one block per transaction, to keep it simple.
*/ for (i = 0; i < map.br_blockcount; i++) {
error = xfs_rtfile_initialize_block(rtg, type,
map.br_startblock + i, data); if (error) return error; if (data)
data += copylen;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.