Commit 34f76326 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'xfs-6.7-merge-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs updates from Chandan Babu:

 - Realtime device subsystem:
    - Cleanup usage of xfs_rtblock_t and xfs_fsblock_t data types
    - Replace open coded conversions between rt blocks and rt extents
      with calls to static inline helpers
    - Replace open coded realtime geometry compuation and macros with
      helper functions
    - CPU usage optimizations for realtime allocator
    - Misc bug fixes associated with Realtime device

 - Allow read operations to execute while an FICLONE ioctl is being
   serviced

 - Misc bug fixes:
    - Alert user when xfs_droplink() encounters an inode with a link
      count of zero
    - Handle the case where the allocator could return zero extents when
      servicing an fallocate request

* tag 'xfs-6.7-merge-2' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (40 commits)
  xfs: allow read IO and FICLONE to run concurrently
  xfs: handle nimaps=0 from xfs_bmapi_write in xfs_alloc_file_space
  xfs: introduce protection for drop nlink
  xfs: don't look for end of extent further than necessary in xfs_rtallocate_extent_near()
  xfs: don't try redundant allocations in xfs_rtallocate_extent_near()
  xfs: limit maxlen based on available space in xfs_rtallocate_extent_near()
  xfs: return maximum free size from xfs_rtany_summary()
  xfs: invert the realtime summary cache
  xfs: simplify rt bitmap/summary block accessor functions
  xfs: simplify xfs_rtbuf_get calling conventions
  xfs: cache last bitmap block in realtime allocator
  xfs: use accessor functions for summary info words
  xfs: consolidate realtime allocation arguments
  xfs: create helpers for rtsummary block/wordcount computations
  xfs: use accessor functions for bitmap words
  xfs: create helpers for rtbitmap block/wordcount computations
  xfs: create a helper to handle logging parts of rt bitmap/summary blocks
  xfs: convert rt summary macros to helpers
  xfs: convert open-coded xfs_rtword_t pointer accesses to helper
  xfs: remove XFS_BLOCKWSIZE and XFS_BLOCKWMASK macros
  ...
parents 6d795e2a 14a53798
......@@ -21,7 +21,7 @@
#include "xfs_bmap.h"
#include "xfs_bmap_util.h"
#include "xfs_bmap_btree.h"
#include "xfs_rtalloc.h"
#include "xfs_rtbitmap.h"
#include "xfs_errortag.h"
#include "xfs_error.h"
#include "xfs_quota.h"
......@@ -2989,7 +2989,7 @@ xfs_bmap_extsize_align(
* If realtime, and the result isn't a multiple of the realtime
* extent size we need to remove blocks until it is.
*/
if (rt && (temp = (align_alen % mp->m_sb.sb_rextsize))) {
if (rt && (temp = xfs_extlen_to_rtxmod(mp, align_alen))) {
/*
* We're not covering the original request, or
* we won't be able to once we fix the length.
......@@ -3016,7 +3016,7 @@ xfs_bmap_extsize_align(
else {
align_alen -= orig_off - align_off;
align_off = orig_off;
align_alen -= align_alen % mp->m_sb.sb_rextsize;
align_alen -= xfs_extlen_to_rtxmod(mp, align_alen);
}
/*
* Result doesn't cover the request, fail it.
......@@ -4826,12 +4826,8 @@ xfs_bmap_del_extent_delay(
ASSERT(got->br_startoff <= del->br_startoff);
ASSERT(got_endoff >= del_endoff);
if (isrt) {
uint64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount);
do_div(rtexts, mp->m_sb.sb_rextsize);
xfs_mod_frextents(mp, rtexts);
}
if (isrt)
xfs_mod_frextents(mp, xfs_rtb_to_rtx(mp, del->br_blockcount));
/*
* Update the inode delalloc counter now and wait to update the
......@@ -5057,33 +5053,20 @@ xfs_bmap_del_extent_real(
flags = XFS_ILOG_CORE;
if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) {
xfs_filblks_t len;
xfs_extlen_t mod;
len = div_u64_rem(del->br_blockcount, mp->m_sb.sb_rextsize,
&mod);
ASSERT(mod == 0);
if (!(bflags & XFS_BMAPI_REMAP)) {
xfs_fsblock_t bno;
bno = div_u64_rem(del->br_startblock,
mp->m_sb.sb_rextsize, &mod);
ASSERT(mod == 0);
error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len);
error = xfs_rtfree_blocks(tp, del->br_startblock,
del->br_blockcount);
if (error)
goto done;
}
do_fx = 0;
nblks = len * mp->m_sb.sb_rextsize;
qfield = XFS_TRANS_DQ_RTBCOUNT;
} else {
do_fx = 1;
nblks = del->br_blockcount;
qfield = XFS_TRANS_DQ_BCOUNT;
}
nblks = del->br_blockcount;
del_endblock = del->br_startblock + del->br_blockcount;
if (cur) {
......@@ -5289,7 +5272,6 @@ __xfs_bunmapi(
int tmp_logflags; /* partial logging flags */
int wasdel; /* was a delayed alloc extent */
int whichfork; /* data or attribute fork */
xfs_fsblock_t sum;
xfs_filblks_t len = *rlen; /* length to unmap in file */
xfs_fileoff_t end;
struct xfs_iext_cursor icur;
......@@ -5384,8 +5366,8 @@ __xfs_bunmapi(
if (!isrt)
goto delete;
sum = del.br_startblock + del.br_blockcount;
div_u64_rem(sum, mp->m_sb.sb_rextsize, &mod);
mod = xfs_rtb_to_rtxoff(mp,
del.br_startblock + del.br_blockcount);
if (mod) {
/*
* Realtime extent not lined up at the end.
......@@ -5432,7 +5414,8 @@ __xfs_bunmapi(
goto error0;
goto nodelete;
}
div_u64_rem(del.br_startblock, mp->m_sb.sb_rextsize, &mod);
mod = xfs_rtb_to_rtxoff(mp, del.br_startblock);
if (mod) {
xfs_extlen_t off = mp->m_sb.sb_rextsize - mod;
......@@ -6209,7 +6192,7 @@ xfs_bmap_validate_extent(
return __this_address;
if (XFS_IS_REALTIME_INODE(ip) && whichfork == XFS_DATA_FORK) {
if (!xfs_verify_rtext(mp, irec->br_startblock,
if (!xfs_verify_rtbext(mp, irec->br_startblock,
irec->br_blockcount))
return __this_address;
} else {
......
......@@ -98,7 +98,7 @@ typedef struct xfs_sb {
uint32_t sb_blocksize; /* logical block size, bytes */
xfs_rfsblock_t sb_dblocks; /* number of data blocks */
xfs_rfsblock_t sb_rblocks; /* number of realtime blocks */
xfs_rtblock_t sb_rextents; /* number of realtime extents */
xfs_rtbxlen_t sb_rextents; /* number of realtime extents */
uuid_t sb_uuid; /* user-visible file system unique id */
xfs_fsblock_t sb_logstart; /* starting block of log if internal */
xfs_ino_t sb_rootino; /* root inode number */
......@@ -690,6 +690,22 @@ struct xfs_agfl {
ASSERT(xfs_daddr_to_agno(mp, d) == \
xfs_daddr_to_agno(mp, (d) + (len) - 1)))
/*
* Realtime bitmap information is accessed by the word, which is currently
* stored in host-endian format.
*/
union xfs_rtword_raw {
__u32 old;
};
/*
* Realtime summary counts are accessed by the word, which is currently
* stored in host-endian format.
*/
union xfs_suminfo_raw {
__u32 old;
};
/*
* XFS Timestamps
* ==============
......@@ -1142,24 +1158,10 @@ static inline bool xfs_dinode_has_large_extent_counts(
#define XFS_BLOCKSIZE(mp) ((mp)->m_sb.sb_blocksize)
#define XFS_BLOCKMASK(mp) ((mp)->m_blockmask)
#define XFS_BLOCKWSIZE(mp) ((mp)->m_blockwsize)
#define XFS_BLOCKWMASK(mp) ((mp)->m_blockwmask)
/*
* RT Summary and bit manipulation macros.
* RT bit manipulation macros.
*/
#define XFS_SUMOFFS(mp,ls,bb) ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb)))
#define XFS_SUMOFFSTOBLOCK(mp,s) \
(((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog)
#define XFS_SUMPTR(mp,bp,so) \
((xfs_suminfo_t *)((bp)->b_addr + \
(((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp))))
#define XFS_BITTOBLOCK(mp,bi) ((bi) >> (mp)->m_blkbit_log)
#define XFS_BLOCKTOBIT(mp,bb) ((bb) << (mp)->m_blkbit_log)
#define XFS_BITTOWORD(mp,bi) \
((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp)))
#define XFS_RTMIN(a,b) ((a) < (b) ? (a) : (b))
#define XFS_RTMAX(a,b) ((a) > (b) ? (a) : (b))
......
......@@ -16,6 +16,7 @@
#include "xfs_trans.h"
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_rtbitmap.h"
/*
* Realtime allocator bitmap functions shared with userspace.
......@@ -46,25 +47,69 @@ const struct xfs_buf_ops xfs_rtbuf_ops = {
.verify_write = xfs_rtbuf_verify_write,
};
/* Release cached rt bitmap and summary buffers. */
void
xfs_rtbuf_cache_relse(
struct xfs_rtalloc_args *args)
{
if (args->rbmbp) {
xfs_trans_brelse(args->tp, args->rbmbp);
args->rbmbp = NULL;
args->rbmoff = NULLFILEOFF;
}
if (args->sumbp) {
xfs_trans_brelse(args->tp, args->sumbp);
args->sumbp = NULL;
args->sumoff = NULLFILEOFF;
}
}
/*
* Get a buffer for the bitmap or summary file block specified.
* The buffer is returned read and locked.
*/
int
xfs_rtbuf_get(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t block, /* block number in bitmap or summary */
int issum, /* is summary not bitmap */
struct xfs_buf **bpp) /* output: buffer for the block */
struct xfs_rtalloc_args *args,
xfs_fileoff_t block, /* block number in bitmap or summary */
int issum) /* is summary not bitmap */
{
struct xfs_mount *mp = args->mp;
struct xfs_buf **cbpp; /* cached block buffer */
xfs_fileoff_t *coffp; /* cached block number */
struct xfs_buf *bp; /* block buffer, result */
xfs_inode_t *ip; /* bitmap or summary inode */
xfs_bmbt_irec_t map;
struct xfs_inode *ip; /* bitmap or summary inode */
struct xfs_bmbt_irec map;
enum xfs_blft type;
int nmap = 1;
int error; /* error value */
int error;
ip = issum ? mp->m_rsumip : mp->m_rbmip;
if (issum) {
cbpp = &args->sumbp;
coffp = &args->sumoff;
ip = mp->m_rsumip;
type = XFS_BLFT_RTSUMMARY_BUF;
} else {
cbpp = &args->rbmbp;
coffp = &args->rbmoff;
ip = mp->m_rbmip;
type = XFS_BLFT_RTBITMAP_BUF;
}
/*
* 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;
}
error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0);
if (error)
......@@ -74,15 +119,15 @@ xfs_rtbuf_get(
return -EFSCORRUPTED;
ASSERT(map.br_startblock != NULLFSBLOCK);
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
error = xfs_trans_read_buf(mp, args->tp, mp->m_ddev_targp,
XFS_FSB_TO_DADDR(mp, map.br_startblock),
mp->m_bsize, 0, &bp, &xfs_rtbuf_ops);
if (error)
return error;
xfs_trans_buf_set_type(tp, bp, issum ? XFS_BLFT_RTSUMMARY_BUF
: XFS_BLFT_RTBITMAP_BUF);
*bpp = bp;
xfs_trans_buf_set_type(args->tp, bp, type);
*cbpp = bp;
*coffp = block;
return 0;
}
......@@ -92,47 +137,44 @@ xfs_rtbuf_get(
*/
int
xfs_rtfind_back(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t start, /* starting block to look at */
xfs_rtblock_t limit, /* last block to look at */
xfs_rtblock_t *rtblock) /* out: start block found */
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 */
{
xfs_rtword_t *b; /* current word in buffer */
struct xfs_mount *mp = args->mp;
int bit; /* bit number in the word */
xfs_rtblock_t block; /* bitmap block number */
struct xfs_buf *bp; /* buf for the block */
xfs_rtword_t *bufp; /* starting word in buffer */
xfs_fileoff_t block; /* bitmap block number */
int error; /* error value */
xfs_rtblock_t firstbit; /* first useful bit in the word */
xfs_rtblock_t i; /* current bit number rel. to start */
xfs_rtblock_t len; /* length of inspected area */
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 */
int word; /* word number in the buffer */
xfs_rtword_t incore;
unsigned int word; /* word number in the buffer */
/*
* Compute and read in starting bitmap block for starting block.
*/
block = XFS_BITTOBLOCK(mp, start);
error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
if (error) {
block = xfs_rtx_to_rbmblock(mp, start);
error = xfs_rtbitmap_read_buf(args, block);
if (error)
return error;
}
bufp = bp->b_addr;
/*
* Get the first word's index & point to it.
*/
word = XFS_BITTOWORD(mp, start);
b = &bufp[word];
word = xfs_rtx_to_rbmword(mp, start);
bit = (int)(start & (XFS_NBWORD - 1));
len = start - limit + 1;
/*
* Compute match value, based on the bit at start: if 1 (free)
* then all-ones, else all-zeroes.
*/
want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
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.
......@@ -149,13 +191,12 @@ xfs_rtfind_back(
* Calculate the difference between the value there
* and what we're looking for.
*/
if ((wdiff = (*b ^ want) & mask)) {
if ((wdiff = (incore ^ want) & mask)) {
/*
* Different. Mark where we are and return.
*/
xfs_trans_brelse(tp, bp);
i = bit - XFS_RTHIBIT(wdiff);
*rtblock = start - i + 1;
*rtx = start - i + 1;
return 0;
}
i = bit - firstbit + 1;
......@@ -167,19 +208,11 @@ xfs_rtfind_back(
/*
* If done with this block, get the previous one.
*/
xfs_trans_brelse(tp, bp);
error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
if (error) {
error = xfs_rtbitmap_read_buf(args, --block);
if (error)
return error;
}
bufp = bp->b_addr;
word = XFS_BLOCKWMASK(mp);
b = &bufp[word];
} else {
/*
* Go on to the previous word in the buffer.
*/
b--;
word = mp->m_blockwsize - 1;
}
} else {
/*
......@@ -195,13 +228,13 @@ xfs_rtfind_back(
/*
* Compute difference between actual and desired value.
*/
if ((wdiff = *b ^ want)) {
incore = xfs_rtbitmap_getword(args, word);
if ((wdiff = incore ^ want)) {
/*
* Different, mark where we are and return.
*/
xfs_trans_brelse(tp, bp);
i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
*rtblock = start - i + 1;
*rtx = start - i + 1;
return 0;
}
i += XFS_NBWORD;
......@@ -213,19 +246,11 @@ xfs_rtfind_back(
/*
* If done with this block, get the previous one.
*/
xfs_trans_brelse(tp, bp);
error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
if (error) {
error = xfs_rtbitmap_read_buf(args, --block);
if (error)
return error;
}
bufp = bp->b_addr;
word = XFS_BLOCKWMASK(mp);
b = &bufp[word];
} else {
/*
* Go on to the previous word in the buffer.
*/
b--;
word = mp->m_blockwsize - 1;
}
}
/*
......@@ -242,13 +267,13 @@ xfs_rtfind_back(
/*
* Compute difference between actual and desired value.
*/
if ((wdiff = (*b ^ want) & mask)) {
incore = xfs_rtbitmap_getword(args, word);
if ((wdiff = (incore ^ want) & mask)) {
/*
* Different, mark where we are and return.
*/
xfs_trans_brelse(tp, bp);
i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
*rtblock = start - i + 1;
*rtx = start - i + 1;
return 0;
} else
i = len;
......@@ -256,8 +281,7 @@ xfs_rtfind_back(
/*
* No match, return that we scanned the whole area.
*/
xfs_trans_brelse(tp, bp);
*rtblock = start - i + 1;
*rtx = start - i + 1;
return 0;
}
......@@ -267,47 +291,44 @@ xfs_rtfind_back(
*/
int
xfs_rtfind_forw(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t start, /* starting block to look at */
xfs_rtblock_t limit, /* last block to look at */
xfs_rtblock_t *rtblock) /* out: start block found */
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 */
{
xfs_rtword_t *b; /* current word in buffer */
struct xfs_mount *mp = args->mp;
int bit; /* bit number in the word */
xfs_rtblock_t block; /* bitmap block number */
struct xfs_buf *bp; /* buf for the block */
xfs_rtword_t *bufp; /* starting word in buffer */
int error; /* error value */
xfs_rtblock_t i; /* current bit number rel. to start */
xfs_rtblock_t lastbit; /* last useful bit in the word */
xfs_rtblock_t len; /* length of inspected area */
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 */
int word; /* word number in the buffer */
xfs_rtword_t incore;
unsigned int word; /* word number in the buffer */
/*
* Compute and read in starting bitmap block for starting block.
*/
block = XFS_BITTOBLOCK(mp, start);
error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
if (error) {
block = xfs_rtx_to_rbmblock(mp, start);
error = xfs_rtbitmap_read_buf(args, block);
if (error)
return error;
}
bufp = bp->b_addr;
/*
* Get the first word's index & point to it.
*/
word = XFS_BITTOWORD(mp, start);
b = &bufp[word];
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.
*/
want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
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.
......@@ -323,13 +344,12 @@ xfs_rtfind_forw(
* Calculate the difference between the value there
* and what we're looking for.
*/
if ((wdiff = (*b ^ want) & mask)) {
if ((wdiff = (incore ^ want) & mask)) {
/*
* Different. Mark where we are and return.
*/
xfs_trans_brelse(tp, bp);
i = XFS_RTLOBIT(wdiff) - bit;
*rtblock = start + i - 1;
*rtx = start + i - 1;
return 0;
}
i = lastbit - bit;
......@@ -337,22 +357,15 @@ xfs_rtfind_forw(
* Go on to next block if that's where the next word is
* and we need the next word.
*/
if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
if (++word == mp->m_blockwsize && i < len) {
/*
* If done with this block, get the previous one.
*/
xfs_trans_brelse(tp, bp);
error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
if (error) {
error = xfs_rtbitmap_read_buf(args, ++block);
if (error)
return error;
}
b = bufp = bp->b_addr;
word = 0;
} else {
/*
* Go on to the previous word in the buffer.
*/
b++;
}
} else {
/*
......@@ -368,13 +381,13 @@ xfs_rtfind_forw(
/*
* Compute difference between actual and desired value.
*/
if ((wdiff = *b ^ want)) {
incore = xfs_rtbitmap_getword(args, word);
if ((wdiff = incore ^ want)) {
/*
* Different, mark where we are and return.
*/
xfs_trans_brelse(tp, bp);
i += XFS_RTLOBIT(wdiff);
*rtblock = start + i - 1;
*rtx = start + i - 1;
return 0;
}
i += XFS_NBWORD;
......@@ -382,22 +395,15 @@ xfs_rtfind_forw(
* Go on to next block if that's where the next word is
* and we need the next word.
*/
if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
if (++word == mp->m_blockwsize && i < len) {
/*
* If done with this block, get the next one.
*/
xfs_trans_brelse(tp, bp);
error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
if (error) {
error = xfs_rtbitmap_read_buf(args, ++block);
if (error)
return error;
}
b = bufp = bp->b_addr;
word = 0;
} else {
/*
* Go on to the next word in the buffer.
*/
b++;
}
}
/*
......@@ -412,13 +418,13 @@ xfs_rtfind_forw(
/*
* Compute difference between actual and desired value.
*/
if ((wdiff = (*b ^ want) & mask)) {
incore = xfs_rtbitmap_getword(args, word);
if ((wdiff = (incore ^ want) & mask)) {
/*
* Different, mark where we are and return.
*/
xfs_trans_brelse(tp, bp);
i += XFS_RTLOBIT(wdiff);
*rtblock = start + i - 1;
*rtx = start + i - 1;
return 0;
} else
i = len;
......@@ -426,11 +432,25 @@ xfs_rtfind_forw(
/*
* No match, return that we scanned the whole area.
*/
xfs_trans_brelse(tp, bp);
*rtblock = start + i - 1;
*rtx = start + i - 1;
return 0;
}
/* Log rtsummary counter at @infoword. */
static inline void
xfs_trans_log_rtsummary(
struct xfs_rtalloc_args *args,
unsigned int infoword)
{
struct xfs_buf *bp = args->sumbp;
size_t first, last;
first = (void *)xfs_rsumblock_infoptr(args, infoword) - bp->b_addr;
last = first + sizeof(xfs_suminfo_t) - 1;
xfs_trans_log_buf(args->tp, bp, first, last);
}
/*
* Read and/or modify the summary information for a given extent size,
* bitmap block combination.
......@@ -442,86 +462,77 @@ xfs_rtfind_forw(
*/
int
xfs_rtmodify_summary_int(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
struct xfs_rtalloc_args *args,
int log, /* log2 of extent size */
xfs_rtblock_t bbno, /* bitmap block number */
xfs_fileoff_t bbno, /* bitmap block number */
int delta, /* change to make to summary info */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb, /* in/out: summary block number */
xfs_suminfo_t *sum) /* out: summary info for this block */
{
struct xfs_buf *bp; /* buffer for the summary block */
int error; /* error value */
xfs_fsblock_t sb; /* summary fsblock */
int so; /* index into the summary file */
xfs_suminfo_t *sp; /* pointer to returned data */
struct xfs_mount *mp = args->mp;
int error;
xfs_fileoff_t sb; /* summary fsblock */
xfs_rtsumoff_t so; /* index into the summary file */
unsigned int infoword;
/*
* Compute entry number in the summary file.
*/
so = XFS_SUMOFFS(mp, log, bbno);
so = xfs_rtsumoffs(mp, log, bbno);
/*
* Compute the block number in the summary file.
*/
sb = XFS_SUMOFFSTOBLOCK(mp, so);
/*
* If we have an old buffer, and the block number matches, use that.
*/
if (*rbpp && *rsb == sb)
bp = *rbpp;
/*
* Otherwise we have to get the buffer.
*/
else {
/*
* If there was an old one, get rid of it first.
*/
if (*rbpp)
xfs_trans_brelse(tp, *rbpp);
error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
if (error) {
sb = xfs_rtsumoffs_to_block(mp, so);
error = xfs_rtsummary_read_buf(args, sb);
if (error)
return error;
}
/*
* Remember this buffer and block for the next call.
*/
*rbpp = bp;
*rsb = sb;
}
/*
* Point to the summary information, modify/log it, and/or copy it out.
*/
sp = XFS_SUMPTR(mp, bp, so);
infoword = xfs_rtsumoffs_to_infoword(mp, so);
if (delta) {
uint first = (uint)((char *)sp - (char *)bp->b_addr);
xfs_suminfo_t val = xfs_suminfo_add(args, infoword, delta);
*sp += delta;
if (mp->m_rsum_cache) {
if (*sp == 0 && log == mp->m_rsum_cache[bbno])
mp->m_rsum_cache[bbno]++;
if (*sp != 0 && log < mp->m_rsum_cache[bbno])
if (val == 0 && log + 1 == mp->m_rsum_cache[bbno])
mp->m_rsum_cache[bbno] = log;
if (val != 0 && log >= mp->m_rsum_cache[bbno])
mp->m_rsum_cache[bbno] = log + 1;
}
xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
}
xfs_trans_log_rtsummary(args, infoword);
if (sum)
*sum = *sp;
*sum = val;
} else if (sum) {
*sum = xfs_suminfo_get(args, infoword);
}
return 0;
}
int
xfs_rtmodify_summary(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
struct xfs_rtalloc_args *args,
int log, /* log2 of extent size */
xfs_rtblock_t bbno, /* bitmap block number */
int delta, /* change to make to summary info */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb) /* in/out: summary block number */
xfs_fileoff_t bbno, /* bitmap block number */
int delta) /* in/out: summary block number */
{
return xfs_rtmodify_summary_int(args, log, bbno, delta, NULL);
}
/* Log rtbitmap block from the word @from to the byte before @next. */
static inline void
xfs_trans_log_rtbitmap(
struct xfs_rtalloc_args *args,
unsigned int from,
unsigned int next)
{
return xfs_rtmodify_summary_int(mp, tp, log, bbno,
delta, rbpp, rsb, NULL);
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);
}
/*
......@@ -530,41 +541,37 @@ xfs_rtmodify_summary(
*/
int
xfs_rtmodify_range(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t start, /* starting block to modify */
xfs_extlen_t len, /* length of extent to modify */
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 */
{
xfs_rtword_t *b; /* current word in buffer */
struct xfs_mount *mp = args->mp;
int bit; /* bit number in the word */
xfs_rtblock_t block; /* bitmap block number */
struct xfs_buf *bp; /* buf for the block */
xfs_rtword_t *bufp; /* starting word in buffer */
int error; /* error value */
xfs_rtword_t *first; /* first used word in the buffer */
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 o frelevant bits for value */
int word; /* word number in the buffer */
xfs_rtword_t mask; /* mask of relevant bits for value */
xfs_rtword_t incore;
unsigned int firstword; /* first word used in the buffer */
unsigned int word; /* word number in the buffer */
/*
* Compute starting bitmap block number.
*/
block = XFS_BITTOBLOCK(mp, start);
block = xfs_rtx_to_rbmblock(mp, start);
/*
* Read the bitmap block, and point to its data.
*/
error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
if (error) {
error = xfs_rtbitmap_read_buf(args, block);
if (error)
return error;
}
bufp = bp->b_addr;
/*
* Compute the starting word's address, and starting bit.
*/
word = XFS_BITTOWORD(mp, start);
first = b = &bufp[word];
firstword = word = xfs_rtx_to_rbmword(mp, start);
bit = (int)(start & (XFS_NBWORD - 1));
/*
* 0 (allocated) => all zeroes; 1 (free) => all ones.
......@@ -583,34 +590,28 @@ xfs_rtmodify_range(
/*
* Set/clear the active bits.
*/
incore = xfs_rtbitmap_getword(args, word);
if (val)
*b |= mask;
incore |= mask;
else
*b &= ~mask;
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 == XFS_BLOCKWSIZE(mp) && i < len) {
if (++word == mp->m_blockwsize && i < len) {
/*
* Log the changed part of this block.
* Get the next one.
*/
xfs_trans_log_buf(tp, bp,
(uint)((char *)first - (char *)bufp),
(uint)((char *)b - (char *)bufp));
error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
if (error) {
xfs_trans_log_rtbitmap(args, firstword, word);
error = xfs_rtbitmap_read_buf(args, ++block);
if (error)
return error;
}
first = b = bufp = bp->b_addr;
word = 0;
} else {
/*
* Go on to the next word in the buffer
*/
b++;
firstword = word = 0;
}
} else {
/*
......@@ -626,31 +627,23 @@ xfs_rtmodify_range(
/*
* Set the word value correctly.
*/
*b = val;
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 == XFS_BLOCKWSIZE(mp) && i < len) {
if (++word == mp->m_blockwsize && i < len) {
/*
* Log the changed part of this block.
* Get the next one.
*/
xfs_trans_log_buf(tp, bp,
(uint)((char *)first - (char *)bufp),
(uint)((char *)b - (char *)bufp));
error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
if (error) {
xfs_trans_log_rtbitmap(args, firstword, word);
error = xfs_rtbitmap_read_buf(args, ++block);
if (error)
return error;
}
first = b = bufp = bp->b_addr;
word = 0;
} else {
/*
* Go on to the next word in the buffer
*/
b++;
firstword = word = 0;
}
}
/*
......@@ -665,18 +658,19 @@ xfs_rtmodify_range(
/*
* Set/clear the active bits.
*/
incore = xfs_rtbitmap_getword(args, word);
if (val)
*b |= mask;
incore |= mask;
else
*b &= ~mask;
b++;
incore &= ~mask;
xfs_rtbitmap_setword(args, word, incore);
word++;
}
/*
* Log any remaining changed bytes.
*/
if (b > first)
xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp),
(uint)((char *)b - (char *)bufp - 1));
if (word > firstword)
xfs_trans_log_rtbitmap(args, firstword, word);
return 0;
}
......@@ -686,23 +680,21 @@ xfs_rtmodify_range(
*/
int
xfs_rtfree_range(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t start, /* starting block to free */
xfs_extlen_t len, /* length to free */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb) /* in/out: summary block number */
struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext to free */
xfs_rtxlen_t len) /* in/out: summary block number */
{
xfs_rtblock_t end; /* end of the freed extent */
struct xfs_mount *mp = args->mp;
xfs_rtxnum_t end; /* end of the freed extent */
int error; /* error value */
xfs_rtblock_t postblock; /* first block freed > end */
xfs_rtblock_t preblock; /* first block freed < start */
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(mp, tp, start, len, 1);
error = xfs_rtmodify_range(args, start, len, 1);
if (error) {
return error;
}
......@@ -711,14 +703,14 @@ xfs_rtfree_range(
* We need to find the beginning and end of the extent so we can
* properly update the summary.
*/
error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
error = xfs_rtfind_back(args, start, 0, &preblock);
if (error) {
return error;
}
/*
* Find the next allocated block (end of allocated extent).
*/
error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
&postblock);
if (error)
return error;
......@@ -727,9 +719,9 @@ xfs_rtfree_range(
* old extent, add summary data for them to be allocated.
*/
if (preblock < start) {
error = xfs_rtmodify_summary(mp, tp,
error = xfs_rtmodify_summary(args,
XFS_RTBLOCKLOG(start - preblock),
XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
xfs_rtx_to_rbmblock(mp, preblock), -1);
if (error) {
return error;
}
......@@ -739,9 +731,9 @@ xfs_rtfree_range(
* old extent, add summary data for them to be allocated.
*/
if (postblock > end) {
error = xfs_rtmodify_summary(mp, tp,
error = xfs_rtmodify_summary(args,
XFS_RTBLOCKLOG(postblock - end),
XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb);
xfs_rtx_to_rbmblock(mp, end + 1), -1);
if (error) {
return error;
}
......@@ -750,10 +742,9 @@ xfs_rtfree_range(
* Increment the summary information corresponding to the entire
* (new) free extent.
*/
error = xfs_rtmodify_summary(mp, tp,
return xfs_rtmodify_summary(args,
XFS_RTBLOCKLOG(postblock + 1 - preblock),
XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
return error;
xfs_rtx_to_rbmblock(mp, preblock), 1);
}
/*
......@@ -762,43 +753,39 @@ xfs_rtfree_range(
*/
int
xfs_rtcheck_range(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t start, /* starting block number of extent */
xfs_extlen_t len, /* length of extent */
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_rtblock_t *new, /* out: first block not matching */
xfs_rtxnum_t *new, /* out: first rtext not matching */
int *stat) /* out: 1 for matches, 0 for not */
{
xfs_rtword_t *b; /* current word in buffer */
struct xfs_mount *mp = args->mp;
int bit; /* bit number in the word */
xfs_rtblock_t block; /* bitmap block number */
struct xfs_buf *bp; /* buf for the block */
xfs_rtword_t *bufp; /* starting word in buffer */
int error; /* error value */
xfs_rtblock_t i; /* current bit number rel. to start */
xfs_rtblock_t lastbit; /* last useful bit in 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 */
int word; /* word number in the buffer */
xfs_rtword_t incore;
unsigned int word; /* word number in the buffer */
/*
* Compute starting bitmap block number
*/
block = XFS_BITTOBLOCK(mp, start);
block = xfs_rtx_to_rbmblock(mp, start);
/*
* Read the bitmap block.
*/
error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
if (error) {
error = xfs_rtbitmap_read_buf(args, block);
if (error)
return error;
}
bufp = bp->b_addr;
/*
* Compute the starting word's address, and starting bit.
*/
word = XFS_BITTOWORD(mp, start);
b = &bufp[word];
word = xfs_rtx_to_rbmword(mp, start);
bit = (int)(start & (XFS_NBWORD - 1));
/*
* 0 (allocated) => all zero's; 1 (free) => all one's.
......@@ -820,11 +807,11 @@ xfs_rtcheck_range(
/*
* Compute difference between actual and desired value.
*/
if ((wdiff = (*b ^ val) & mask)) {
incore = xfs_rtbitmap_getword(args, word);
if ((wdiff = (incore ^ val) & mask)) {
/*
* Different, compute first wrong bit and return.
*/
xfs_trans_brelse(tp, bp);
i = XFS_RTLOBIT(wdiff) - bit;
*new = start + i;
*stat = 0;
......@@ -835,22 +822,15 @@ xfs_rtcheck_range(
* Go on to next block if that's where the next word is
* and we need the next word.
*/
if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
if (++word == mp->m_blockwsize && i < len) {
/*
* If done with this block, get the next one.
*/
xfs_trans_brelse(tp, bp);
error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
if (error) {
error = xfs_rtbitmap_read_buf(args, ++block);
if (error)
return error;
}
b = bufp = bp->b_addr;
word = 0;
} else {
/*
* Go on to the next word in the buffer.
*/
b++;
}
} else {
/*
......@@ -866,11 +846,11 @@ xfs_rtcheck_range(
/*
* Compute difference between actual and desired value.
*/
if ((wdiff = *b ^ val)) {
incore = xfs_rtbitmap_getword(args, word);
if ((wdiff = incore ^ val)) {
/*
* Different, compute first wrong bit and return.
*/
xfs_trans_brelse(tp, bp);
i += XFS_RTLOBIT(wdiff);
*new = start + i;
*stat = 0;
......@@ -881,22 +861,15 @@ xfs_rtcheck_range(
* Go on to next block if that's where the next word is
* and we need the next word.
*/
if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
if (++word == mp->m_blockwsize && i < len) {
/*
* If done with this block, get the next one.
*/
xfs_trans_brelse(tp, bp);
error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
if (error) {
error = xfs_rtbitmap_read_buf(args, ++block);
if (error)
return error;
}
b = bufp = bp->b_addr;
word = 0;
} else {
/*
* Go on to the next word in the buffer.
*/
b++;
}
}
/*
......@@ -911,11 +884,11 @@ xfs_rtcheck_range(
/*
* Compute difference between actual and desired value.
*/
if ((wdiff = (*b ^ val) & mask)) {
incore = xfs_rtbitmap_getword(args, word);
if ((wdiff = (incore ^ val) & mask)) {
/*
* Different, compute first wrong bit and return.
*/
xfs_trans_brelse(tp, bp);
i += XFS_RTLOBIT(wdiff);
*new = start + i;
*stat = 0;
......@@ -926,7 +899,6 @@ xfs_rtcheck_range(
/*
* Successful, return.
*/
xfs_trans_brelse(tp, bp);
*new = start + i;
*stat = 1;
return 0;
......@@ -936,58 +908,57 @@ xfs_rtcheck_range(
/*
* Check that the given extent (block range) is allocated already.
*/
STATIC int /* error */
STATIC int
xfs_rtcheck_alloc_range(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t bno, /* starting block number of extent */
xfs_extlen_t len) /* length of extent */
struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext number of extent */
xfs_rtxlen_t len) /* length of extent */
{
xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */
xfs_rtxnum_t new; /* dummy for xfs_rtcheck_range */
int stat;
int error;
error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat);
error = xfs_rtcheck_range(args, start, len, 0, &new, &stat);
if (error)
return error;
ASSERT(stat);
return 0;
}
#else
#define xfs_rtcheck_alloc_range(m,t,b,l) (0)
#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 /* error */
int
xfs_rtfree_extent(
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t bno, /* starting block number to free */
xfs_extlen_t len) /* length of extent freed */
struct xfs_trans *tp, /* transaction pointer */
xfs_rtxnum_t start, /* starting rtext number to free */
xfs_rtxlen_t len) /* length of extent freed */
{
int error; /* error value */
xfs_mount_t *mp; /* file system mount structure */
xfs_fsblock_t sb; /* summary file block number */
struct xfs_buf *sumbp = NULL; /* summary file block buffer */
struct xfs_mount *mp = tp->t_mountp;
struct xfs_rtalloc_args args = {
.mp = mp,
.tp = tp,
};
int error;
struct timespec64 atime;
mp = tp->t_mountp;
ASSERT(mp->m_rbmip->i_itemp != NULL);
ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
error = xfs_rtcheck_alloc_range(mp, tp, bno, len);
error = xfs_rtcheck_alloc_range(&args, start, len);
if (error)
return error;
/*
* Free the range of realtime blocks.
*/
error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb);
if (error) {
return error;
}
error = xfs_rtfree_range(&args, start, len);
if (error)
goto out;
/*
* Mark more blocks free in the superblock.
*/
......@@ -1002,11 +973,47 @@ xfs_rtfree_extent(
mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
atime = inode_get_atime(VFS_I(mp->m_rbmip));
*((uint64_t *)&atime) = 0;
atime.tv_sec = 0;
inode_set_atime_to_ts(VFS_I(mp->m_rbmip), atime);
xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
}
return 0;
error = 0;
out:
xfs_rtbuf_cache_relse(&args);
return error;
}
/*
* 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,
xfs_fsblock_t rtbno,
xfs_filblks_t rtlen)
{
struct xfs_mount *mp = tp->t_mountp;
xfs_rtxnum_t start;
xfs_filblks_t len;
xfs_extlen_t mod;
ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN);
len = xfs_rtb_to_rtxrem(mp, rtlen, &mod);
if (mod) {
ASSERT(mod == 0);
return -EIO;
}
start = xfs_rtb_to_rtxrem(mp, rtbno, &mod);
if (mod) {
ASSERT(mod == 0);
return -EIO;
}
return xfs_rtfree_extent(tp, start, len);
}
/* Find all the free records within a given range. */
......@@ -1019,10 +1026,14 @@ xfs_rtalloc_query_range(
xfs_rtalloc_query_range_fn fn,
void *priv)
{
struct xfs_rtalloc_args args = {
.mp = mp,
.tp = tp,
};
struct xfs_rtalloc_rec rec;
xfs_rtblock_t rtstart;
xfs_rtblock_t rtend;
xfs_rtblock_t high_key;
xfs_rtxnum_t rtstart;
xfs_rtxnum_t rtend;
xfs_rtxnum_t high_key;
int is_free;
int error = 0;
......@@ -1038,13 +1049,13 @@ xfs_rtalloc_query_range(
rtstart = low_rec->ar_startext;
while (rtstart <= high_key) {
/* Is the first block free? */
error = xfs_rtcheck_range(mp, tp, rtstart, 1, 1, &rtend,
error = xfs_rtcheck_range(&args, rtstart, 1, 1, &rtend,
&is_free);
if (error)
break;
/* How long does the extent go for? */
error = xfs_rtfind_forw(mp, tp, rtstart, high_key, &rtend);
error = xfs_rtfind_forw(&args, rtstart, high_key, &rtend);
if (error)
break;
......@@ -1060,6 +1071,7 @@ xfs_rtalloc_query_range(
rtstart = rtend + 1;
}
xfs_rtbuf_cache_relse(&args);
return error;
}
......@@ -1085,18 +1097,79 @@ int
xfs_rtalloc_extent_is_free(
struct xfs_mount *mp,
struct xfs_trans *tp,
xfs_rtblock_t start,
xfs_extlen_t len,
xfs_rtxnum_t start,
xfs_rtxlen_t len,
bool *is_free)
{
xfs_rtblock_t end;
struct xfs_rtalloc_args args = {
.mp = mp,
.tp = tp,
};
xfs_rtxnum_t end;
int matches;
int error;
error = xfs_rtcheck_range(mp, tp, start, len, 1, &end, &matches);
error = xfs_rtcheck_range(&args, start, len, 1, &end, &matches);
xfs_rtbuf_cache_relse(&args);
if (error)
return error;
*is_free = matches;
return 0;
}
/*
* Compute the number of rtbitmap blocks needed to track the given number of rt
* extents.
*/
xfs_filblks_t
xfs_rtbitmap_blockcount(
struct xfs_mount *mp,
xfs_rtbxlen_t rtextents)
{
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(
struct xfs_mount *mp,
unsigned int rsumlevels,
xfs_extlen_t rbmblocks)
{
unsigned long long rsumwords;
rsumwords = (unsigned long long)rsumlevels * rbmblocks;
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;
}
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*/
#ifndef __XFS_RTBITMAP_H__
#define __XFS_RTBITMAP_H__
struct xfs_rtalloc_args {
struct xfs_mount *mp;
struct xfs_trans *tp;
struct xfs_buf *rbmbp; /* bitmap block buffer */
struct xfs_buf *sumbp; /* summary block buffer */
xfs_fileoff_t rbmoff; /* bitmap block number */
xfs_fileoff_t sumoff; /* summary block number */
};
static inline xfs_rtblock_t
xfs_rtx_to_rtb(
struct xfs_mount *mp,
xfs_rtxnum_t rtx)
{
if (mp->m_rtxblklog >= 0)
return rtx << mp->m_rtxblklog;
return rtx * mp->m_sb.sb_rextsize;
}
static inline xfs_extlen_t
xfs_rtxlen_to_extlen(
struct xfs_mount *mp,
xfs_rtxlen_t rtxlen)
{
if (mp->m_rtxblklog >= 0)
return rtxlen << mp->m_rtxblklog;
return rtxlen * mp->m_sb.sb_rextsize;
}
/* Compute the misalignment between an extent length and a realtime extent .*/
static inline unsigned int
xfs_extlen_to_rtxmod(
struct xfs_mount *mp,
xfs_extlen_t len)
{
if (mp->m_rtxblklog >= 0)
return len & mp->m_rtxblkmask;
return len % mp->m_sb.sb_rextsize;
}
static inline xfs_rtxlen_t
xfs_extlen_to_rtxlen(
struct xfs_mount *mp,
xfs_extlen_t len)
{
if (mp->m_rtxblklog >= 0)
return len >> mp->m_rtxblklog;
return len / mp->m_sb.sb_rextsize;
}
/* Convert an rt block number into an rt extent number. */
static inline xfs_rtxnum_t
xfs_rtb_to_rtx(
struct xfs_mount *mp,
xfs_rtblock_t rtbno)
{
if (likely(mp->m_rtxblklog >= 0))
return rtbno >> mp->m_rtxblklog;
return div_u64(rtbno, mp->m_sb.sb_rextsize);
}
/* Return the offset of an rt block number within an rt extent. */
static inline xfs_extlen_t
xfs_rtb_to_rtxoff(
struct xfs_mount *mp,
xfs_rtblock_t rtbno)
{
if (likely(mp->m_rtxblklog >= 0))
return rtbno & mp->m_rtxblkmask;
return do_div(rtbno, mp->m_sb.sb_rextsize);
}
/*
* Crack an rt block number into an rt extent number and an offset within that
* rt extent. Returns the rt extent number directly and the offset in @off.
*/
static inline xfs_rtxnum_t
xfs_rtb_to_rtxrem(
struct xfs_mount *mp,
xfs_rtblock_t rtbno,
xfs_extlen_t *off)
{
if (likely(mp->m_rtxblklog >= 0)) {
*off = rtbno & mp->m_rtxblkmask;
return rtbno >> mp->m_rtxblklog;
}
return div_u64_rem(rtbno, mp->m_sb.sb_rextsize, off);
}
/*
* Convert an rt block number into an rt extent number, rounding up to the next
* rt extent if the rt block is not aligned to an rt extent boundary.
*/
static inline xfs_rtxnum_t
xfs_rtb_to_rtxup(
struct xfs_mount *mp,
xfs_rtblock_t rtbno)
{
if (likely(mp->m_rtxblklog >= 0)) {
if (rtbno & mp->m_rtxblkmask)
return (rtbno >> mp->m_rtxblklog) + 1;
return rtbno >> mp->m_rtxblklog;
}
if (do_div(rtbno, mp->m_sb.sb_rextsize))
rtbno++;
return rtbno;
}
/* Round this rtblock up to the nearest rt extent size. */
static inline xfs_rtblock_t
xfs_rtb_roundup_rtx(
struct xfs_mount *mp,
xfs_rtblock_t rtbno)
{
return roundup_64(rtbno, mp->m_sb.sb_rextsize);
}
/* Round this rtblock down to the nearest rt extent size. */
static inline xfs_rtblock_t
xfs_rtb_rounddown_rtx(
struct xfs_mount *mp,
xfs_rtblock_t rtbno)
{
return rounddown_64(rtbno, mp->m_sb.sb_rextsize);
}
/* Convert an rt extent number to a file block offset in the rt bitmap file. */
static inline xfs_fileoff_t
xfs_rtx_to_rbmblock(
struct xfs_mount *mp,
xfs_rtxnum_t rtx)
{
return rtx >> mp->m_blkbit_log;
}
/* Convert an rt extent number to a word offset within an rt bitmap block. */
static inline unsigned int
xfs_rtx_to_rbmword(
struct xfs_mount *mp,
xfs_rtxnum_t rtx)
{
return (rtx >> XFS_NBWORDLOG) & (mp->m_blockwsize - 1);
}
/* Convert a file block offset in the rt bitmap file to an rt extent number. */
static inline xfs_rtxnum_t
xfs_rbmblock_to_rtx(
struct xfs_mount *mp,
xfs_fileoff_t rbmoff)
{
return rbmoff << mp->m_blkbit_log;
}
/* Return a pointer to a bitmap word within a rt bitmap block. */
static inline union xfs_rtword_raw *
xfs_rbmblock_wordptr(
struct xfs_rtalloc_args *args,
unsigned int index)
{
union xfs_rtword_raw *words = args->rbmbp->b_addr;
return words + index;
}
/* Convert an ondisk bitmap word to its incore representation. */
static inline xfs_rtword_t
xfs_rtbitmap_getword(
struct xfs_rtalloc_args *args,
unsigned int index)
{
union xfs_rtword_raw *word = xfs_rbmblock_wordptr(args, index);
return word->old;
}
/* Set an ondisk bitmap word from an incore representation. */
static inline void
xfs_rtbitmap_setword(
struct xfs_rtalloc_args *args,
unsigned int index,
xfs_rtword_t value)
{
union xfs_rtword_raw *word = xfs_rbmblock_wordptr(args, index);
word->old = value;
}
/*
* Convert a rt extent length and rt bitmap block number to a xfs_suminfo_t
* offset within the rt summary file.
*/
static inline xfs_rtsumoff_t
xfs_rtsumoffs(
struct xfs_mount *mp,
int log2_len,
xfs_fileoff_t rbmoff)
{
return log2_len * mp->m_sb.sb_rbmblocks + rbmoff;
}
/*
* Convert an xfs_suminfo_t offset to a file block offset within the rt summary
* file.
*/
static inline xfs_fileoff_t
xfs_rtsumoffs_to_block(
struct xfs_mount *mp,
xfs_rtsumoff_t rsumoff)
{
return XFS_B_TO_FSBT(mp, rsumoff * sizeof(xfs_suminfo_t));
}
/*
* Convert an xfs_suminfo_t offset to an info word offset within an rt summary
* block.
*/
static inline unsigned int
xfs_rtsumoffs_to_infoword(
struct xfs_mount *mp,
xfs_rtsumoff_t rsumoff)
{
unsigned int mask = mp->m_blockmask >> XFS_SUMINFOLOG;
return rsumoff & mask;
}
/* Return a pointer to a summary info word within a rt summary block. */
static inline union xfs_suminfo_raw *
xfs_rsumblock_infoptr(
struct xfs_rtalloc_args *args,
unsigned int index)
{
union xfs_suminfo_raw *info = args->sumbp->b_addr;
return info + index;
}
/* Get the current value of a summary counter. */
static inline xfs_suminfo_t
xfs_suminfo_get(
struct xfs_rtalloc_args *args,
unsigned int index)
{
union xfs_suminfo_raw *info = xfs_rsumblock_infoptr(args, index);
return info->old;
}
/* Add to the current value of a summary counter and return the new value. */
static inline xfs_suminfo_t
xfs_suminfo_add(
struct xfs_rtalloc_args *args,
unsigned int index,
int delta)
{
union xfs_suminfo_raw *info = xfs_rsumblock_infoptr(args, index);
info->old += delta;
return info->old;
}
/*
* Functions for walking free space rtextents in the realtime bitmap.
*/
struct xfs_rtalloc_rec {
xfs_rtxnum_t ar_startext;
xfs_rtbxlen_t ar_extcount;
};
typedef int (*xfs_rtalloc_query_range_fn)(
struct xfs_mount *mp,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv);
#ifdef CONFIG_XFS_RT
void xfs_rtbuf_cache_relse(struct xfs_rtalloc_args *args);
int xfs_rtbuf_get(struct xfs_rtalloc_args *args, xfs_fileoff_t block,
int issum);
static inline int
xfs_rtbitmap_read_buf(
struct xfs_rtalloc_args *args,
xfs_fileoff_t block)
{
return xfs_rtbuf_get(args, block, 0);
}
static inline int
xfs_rtsummary_read_buf(
struct xfs_rtalloc_args *args,
xfs_fileoff_t block)
{
return xfs_rtbuf_get(args, block, 1);
}
int xfs_rtcheck_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
xfs_rtxlen_t len, int val, xfs_rtxnum_t *new, int *stat);
int xfs_rtfind_back(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
xfs_rtxnum_t limit, xfs_rtxnum_t *rtblock);
int xfs_rtfind_forw(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
xfs_rtxnum_t limit, xfs_rtxnum_t *rtblock);
int xfs_rtmodify_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
xfs_rtxlen_t len, int val);
int xfs_rtmodify_summary_int(struct xfs_rtalloc_args *args, int log,
xfs_fileoff_t bbno, int delta, xfs_suminfo_t *sum);
int xfs_rtmodify_summary(struct xfs_rtalloc_args *args, int log,
xfs_fileoff_t bbno, int delta);
int xfs_rtfree_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
xfs_rtxlen_t len);
int xfs_rtalloc_query_range(struct xfs_mount *mp, struct xfs_trans *tp,
const struct xfs_rtalloc_rec *low_rec,
const struct xfs_rtalloc_rec *high_rec,
xfs_rtalloc_query_range_fn fn, void *priv);
int xfs_rtalloc_query_all(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtalloc_query_range_fn fn,
void *priv);
int xfs_rtalloc_extent_is_free(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtxnum_t start, xfs_rtxlen_t len,
bool *is_free);
/*
* Free an extent in the realtime subvolume. Length is expressed in
* realtime extents, as is the block number.
*/
int /* error */
xfs_rtfree_extent(
struct xfs_trans *tp, /* transaction pointer */
xfs_rtxnum_t start, /* starting rtext number to free */
xfs_rtxlen_t len); /* length of extent freed */
/* Same as above, but in units of rt blocks. */
int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno,
xfs_filblks_t rtlen);
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);
#else /* CONFIG_XFS_RT */
# define xfs_rtfree_extent(t,b,l) (-ENOSYS)
# define xfs_rtfree_blocks(t,rb,rl) (-ENOSYS)
# define xfs_rtalloc_query_range(m,t,l,h,f,p) (-ENOSYS)
# define xfs_rtalloc_query_all(m,t,f,p) (-ENOSYS)
# define xfs_rtbitmap_read_buf(a,b) (-ENOSYS)
# define xfs_rtsummary_read_buf(a,b) (-ENOSYS)
# define xfs_rtbuf_cache_relse(a) (0)
# define xfs_rtalloc_extent_is_free(m,t,s,l,i) (-ENOSYS)
static inline xfs_filblks_t
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)
#endif /* CONFIG_XFS_RT */
#endif /* __XFS_RTBITMAP_H__ */
......@@ -975,6 +975,8 @@ xfs_sb_mount_common(
mp->m_blockmask = sbp->sb_blocksize - 1;
mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
mp->m_blockwmask = mp->m_blockwsize - 1;
mp->m_rtxblklog = log2_if_power2(sbp->sb_rextsize);
mp->m_rtxblkmask = mask64_if_power2(sbp->sb_rextsize);
mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
......
......@@ -25,7 +25,7 @@ extern uint64_t xfs_sb_version_to_features(struct xfs_sb *sbp);
extern int xfs_update_secondary_sbs(struct xfs_mount *mp);
#define XFS_FS_GEOM_MAX_STRUCT_VER (4)
#define XFS_FS_GEOM_MAX_STRUCT_VER (5)
extern void xfs_fs_geometry(struct xfs_mount *mp, struct xfs_fsop_geom *geo,
int struct_version);
extern int xfs_sb_read_secondary(struct xfs_mount *mp,
......
......@@ -19,6 +19,7 @@
#include "xfs_trans.h"
#include "xfs_qm.h"
#include "xfs_trans_space.h"
#include "xfs_rtbitmap.h"
#define _ALLOC true
#define _FREE false
......@@ -217,11 +218,12 @@ xfs_rtalloc_block_count(
struct xfs_mount *mp,
unsigned int num_ops)
{
unsigned int blksz = XFS_FSB_TO_B(mp, 1);
unsigned int rtbmp_bytes;
unsigned int rtbmp_blocks;
xfs_rtxlen_t rtxlen;
rtbmp_bytes = (XFS_MAX_BMBT_EXTLEN / mp->m_sb.sb_rextsize) / NBBY;
return (howmany(rtbmp_bytes, blksz) + 1) * num_ops;
rtxlen = xfs_extlen_to_rtxlen(mp, XFS_MAX_BMBT_EXTLEN);
rtbmp_blocks = xfs_rtbitmap_blockcount(mp, rtxlen);
return (rtbmp_blocks + 1) * num_ops;
}
/*
......
......@@ -148,10 +148,10 @@ xfs_verify_rtbno(
/* Verify that a realtime device extent is fully contained inside the volume. */
bool
xfs_verify_rtext(
xfs_verify_rtbext(
struct xfs_mount *mp,
xfs_rtblock_t rtbno,
xfs_rtblock_t len)
xfs_filblks_t len)
{
if (rtbno + len <= rtbno)
return false;
......
......@@ -11,6 +11,7 @@ typedef uint32_t prid_t; /* project ID */
typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
typedef uint32_t xfs_agino_t; /* inode # within allocation grp */
typedef uint32_t xfs_extlen_t; /* extent length in blocks */
typedef uint32_t xfs_rtxlen_t; /* file extent length in rtextents */
typedef uint32_t xfs_agnumber_t; /* allocation group number */
typedef uint64_t xfs_extnum_t; /* # of extents in a file */
typedef uint32_t xfs_aextnum_t; /* # extents in an attribute fork */
......@@ -18,6 +19,7 @@ typedef int64_t xfs_fsize_t; /* bytes in a file */
typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */
typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */
typedef uint32_t xfs_rtsumoff_t; /* offset of an rtsummary info word */
typedef uint32_t xfs_rtword_t; /* word type for bitmap manipulations */
typedef int64_t xfs_lsn_t; /* log sequence number */
......@@ -31,6 +33,8 @@ typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */
typedef uint64_t xfs_fileoff_t; /* block number in a file */
typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
typedef uint64_t xfs_rtxnum_t; /* rtextent number */
typedef uint64_t xfs_rtbxlen_t; /* rtbitmap extent length in rtextents */
typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
......@@ -47,6 +51,7 @@ typedef void * xfs_failaddr_t;
#define NULLRFSBLOCK ((xfs_rfsblock_t)-1)
#define NULLRTBLOCK ((xfs_rtblock_t)-1)
#define NULLFILEOFF ((xfs_fileoff_t)-1)
#define NULLRTEXTNO ((xfs_rtxnum_t)-1)
#define NULLAGBLOCK ((xfs_agblock_t)-1)
#define NULLAGNUMBER ((xfs_agnumber_t)-1)
......@@ -145,6 +150,7 @@ typedef uint32_t xfs_dqid_t;
*/
#define XFS_NBBYLOG 3 /* log2(NBBY) */
#define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */
#define XFS_SUMINFOLOG 2 /* log2(sizeof(xfs_suminfo_t)) */
#define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG)
#define XFS_NBWORD (1 << XFS_NBWORDLOG)
#define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1)
......@@ -229,8 +235,8 @@ bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino);
bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino);
bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino);
bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno);
bool xfs_verify_rtext(struct xfs_mount *mp, xfs_rtblock_t rtbno,
xfs_rtblock_t len);
bool xfs_verify_rtbext(struct xfs_mount *mp, xfs_rtblock_t rtbno,
xfs_filblks_t len);
bool xfs_verify_icount(struct xfs_mount *mp, unsigned long long icount);
bool xfs_verify_dablk(struct xfs_mount *mp, xfs_fileoff_t off);
void xfs_icount_range(struct xfs_mount *mp, unsigned long long *min,
......
......@@ -410,7 +410,7 @@ xchk_bmap_iextent(
/* Make sure the extent points to a valid place. */
if (info->is_rt &&
!xfs_verify_rtext(mp, irec->br_startblock, irec->br_blockcount))
!xfs_verify_rtbext(mp, irec->br_startblock, irec->br_blockcount))
xchk_fblock_set_corrupt(info->sc, info->whichfork,
irec->br_startoff);
if (!info->is_rt &&
......
......@@ -16,7 +16,7 @@
#include "xfs_health.h"
#include "xfs_btree.h"
#include "xfs_ag.h"
#include "xfs_rtalloc.h"
#include "xfs_rtbitmap.h"
#include "xfs_inode.h"
#include "xfs_icache.h"
#include "scrub/scrub.h"
......
......@@ -20,6 +20,7 @@
#include "xfs_reflink.h"
#include "xfs_rmap.h"
#include "xfs_bmap_util.h"
#include "xfs_rtbitmap.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/btree.h"
......@@ -225,7 +226,7 @@ xchk_inode_extsize(
*/
if ((flags & XFS_DIFLAG_RTINHERIT) &&
(flags & XFS_DIFLAG_EXTSZINHERIT) &&
value % sc->mp->m_sb.sb_rextsize > 0)
xfs_extlen_to_rtxmod(sc->mp, value) > 0)
xchk_ino_set_warning(sc, ino);
}
......
......@@ -11,7 +11,7 @@
#include "xfs_mount.h"
#include "xfs_log_format.h"
#include "xfs_trans.h"
#include "xfs_rtalloc.h"
#include "xfs_rtbitmap.h"
#include "xfs_inode.h"
#include "xfs_bmap.h"
#include "scrub/scrub.h"
......@@ -48,12 +48,12 @@ xchk_rtbitmap_rec(
{
struct xfs_scrub *sc = priv;
xfs_rtblock_t startblock;
xfs_rtblock_t blockcount;
xfs_filblks_t blockcount;
startblock = rec->ar_startext * mp->m_sb.sb_rextsize;
blockcount = rec->ar_extcount * mp->m_sb.sb_rextsize;
startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
if (!xfs_verify_rtext(mp, startblock, blockcount))
if (!xfs_verify_rtbext(mp, startblock, blockcount))
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
return 0;
}
......@@ -128,26 +128,22 @@ xchk_rtbitmap(
void
xchk_xref_is_used_rt_space(
struct xfs_scrub *sc,
xfs_rtblock_t fsbno,
xfs_rtblock_t rtbno,
xfs_extlen_t len)
{
xfs_rtblock_t startext;
xfs_rtblock_t endext;
xfs_rtblock_t extcount;
xfs_rtxnum_t startext;
xfs_rtxnum_t endext;
bool is_free;
int error;
if (xchk_skip_xref(sc->sm))
return;
startext = fsbno;
endext = fsbno + len - 1;
do_div(startext, sc->mp->m_sb.sb_rextsize);
do_div(endext, sc->mp->m_sb.sb_rextsize);
extcount = endext - startext + 1;
startext = xfs_rtb_to_rtx(sc->mp, rtbno);
endext = xfs_rtb_to_rtx(sc->mp, rtbno + len - 1);
xfs_ilock(sc->mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext, extcount,
&is_free);
error = xfs_rtalloc_extent_is_free(sc->mp, sc->tp, startext,
endext - startext + 1, &is_free);
if (!xchk_should_check_xref(sc, &error, NULL))
goto out_unlock;
if (is_free)
......
......@@ -13,7 +13,7 @@
#include "xfs_inode.h"
#include "xfs_log_format.h"
#include "xfs_trans.h"
#include "xfs_rtalloc.h"
#include "xfs_rtbitmap.h"
#include "xfs_bit.h"
#include "xfs_bmap.h"
#include "scrub/scrub.h"
......@@ -81,34 +81,45 @@ typedef unsigned int xchk_rtsumoff_t;
static inline int
xfsum_load(
struct xfs_scrub *sc,
xchk_rtsumoff_t sumoff,
xfs_suminfo_t *info)
xfs_rtsumoff_t sumoff,
union xfs_suminfo_raw *rawinfo)
{
return xfile_obj_load(sc->xfile, info, sizeof(xfs_suminfo_t),
return xfile_obj_load(sc->xfile, rawinfo,
sizeof(union xfs_suminfo_raw),
sumoff << XFS_WORDLOG);
}
static inline int
xfsum_store(
struct xfs_scrub *sc,
xchk_rtsumoff_t sumoff,
const xfs_suminfo_t info)
xfs_rtsumoff_t sumoff,
const union xfs_suminfo_raw rawinfo)
{
return xfile_obj_store(sc->xfile, &info, sizeof(xfs_suminfo_t),
return xfile_obj_store(sc->xfile, &rawinfo,
sizeof(union xfs_suminfo_raw),
sumoff << XFS_WORDLOG);
}
static inline int
xfsum_copyout(
struct xfs_scrub *sc,
xchk_rtsumoff_t sumoff,
xfs_suminfo_t *info,
xfs_rtsumoff_t sumoff,
union xfs_suminfo_raw *rawinfo,
unsigned int nr_words)
{
return xfile_obj_load(sc->xfile, info, nr_words << XFS_WORDLOG,
return xfile_obj_load(sc->xfile, rawinfo, nr_words << XFS_WORDLOG,
sumoff << XFS_WORDLOG);
}
static inline xfs_suminfo_t
xchk_rtsum_inc(
struct xfs_mount *mp,
union xfs_suminfo_raw *v)
{
v->old += 1;
return v->old;
}
/* Update the summary file to reflect the free extent that we've accumulated. */
STATIC int
xchk_rtsum_record_free(
......@@ -121,23 +132,24 @@ xchk_rtsum_record_free(
xfs_fileoff_t rbmoff;
xfs_rtblock_t rtbno;
xfs_filblks_t rtlen;
xchk_rtsumoff_t offs;
xfs_rtsumoff_t offs;
unsigned int lenlog;
xfs_suminfo_t v = 0;
union xfs_suminfo_raw v;
xfs_suminfo_t value;
int error = 0;
if (xchk_should_terminate(sc, &error))
return error;
/* Compute the relevant location in the rtsum file. */
rbmoff = XFS_BITTOBLOCK(mp, rec->ar_startext);
rbmoff = xfs_rtx_to_rbmblock(mp, rec->ar_startext);
lenlog = XFS_RTBLOCKLOG(rec->ar_extcount);
offs = XFS_SUMOFFS(mp, lenlog, rbmoff);
offs = xfs_rtsumoffs(mp, lenlog, rbmoff);
rtbno = rec->ar_startext * mp->m_sb.sb_rextsize;
rtlen = rec->ar_extcount * mp->m_sb.sb_rextsize;
rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
if (!xfs_verify_rtext(mp, rtbno, rtlen)) {
if (!xfs_verify_rtbext(mp, rtbno, rtlen)) {
xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
return -EFSCORRUPTED;
}
......@@ -147,9 +159,9 @@ xchk_rtsum_record_free(
if (error)
return error;
v++;
value = xchk_rtsum_inc(sc->mp, &v);
trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount,
lenlog, offs, v);
lenlog, offs, value);
return xfsum_store(sc, offs, v);
}
......@@ -160,12 +172,11 @@ xchk_rtsum_compute(
struct xfs_scrub *sc)
{
struct xfs_mount *mp = sc->mp;
unsigned long long rtbmp_bytes;
unsigned long long rtbmp_blocks;
/* If the bitmap size doesn't match the computed size, bail. */
rtbmp_bytes = howmany_64(mp->m_sb.sb_rextents, NBBY);
if (roundup_64(rtbmp_bytes, mp->m_sb.sb_blocksize) !=
mp->m_rbmip->i_disk_size)
rtbmp_blocks = xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents);
if (XFS_FSB_TO_B(mp, rtbmp_blocks) != mp->m_rbmip->i_disk_size)
return -EFSCORRUPTED;
return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,
......@@ -177,14 +188,18 @@ STATIC int
xchk_rtsum_compare(
struct xfs_scrub *sc)
{
struct xfs_rtalloc_args args = {
.mp = sc->mp,
.tp = sc->tp,
};
struct xfs_mount *mp = sc->mp;
struct xfs_buf *bp;
struct xfs_bmbt_irec map;
xfs_fileoff_t off;
xchk_rtsumoff_t sumoff = 0;
int nmap;
for (off = 0; off < XFS_B_TO_FSB(mp, mp->m_rsumsize); off++) {
union xfs_suminfo_raw *ondisk_info;
int error = 0;
if (xchk_should_terminate(sc, &error))
......@@ -205,22 +220,23 @@ xchk_rtsum_compare(
}
/* Read a block's worth of ondisk rtsummary file. */
error = xfs_rtbuf_get(mp, sc->tp, off, 1, &bp);
error = xfs_rtsummary_read_buf(&args, off);
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
return error;
/* Read a block's worth of computed rtsummary file. */
error = xfsum_copyout(sc, sumoff, sc->buf, mp->m_blockwsize);
if (error) {
xfs_trans_brelse(sc->tp, bp);
xfs_rtbuf_cache_relse(&args);
return error;
}
if (memcmp(bp->b_addr, sc->buf,
ondisk_info = xfs_rsumblock_infoptr(&args, 0);
if (memcmp(ondisk_info, sc->buf,
mp->m_blockwsize << XFS_WORDLOG) != 0)
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
xfs_trans_brelse(sc->tp, bp);
xfs_rtbuf_cache_relse(&args);
sumoff += mp->m_blockwsize;
}
......
......@@ -13,6 +13,7 @@
#include "xfs_inode.h"
#include "xfs_btree.h"
#include "xfs_ag.h"
#include "xfs_rtbitmap.h"
#include "scrub/scrub.h"
#include "scrub/xfile.h"
#include "scrub/xfarray.h"
......
......@@ -1036,17 +1036,18 @@ TRACE_EVENT(xfarray_sort_stats,
#ifdef CONFIG_XFS_RT
TRACE_EVENT(xchk_rtsum_record_free,
TP_PROTO(struct xfs_mount *mp, xfs_rtblock_t start,
uint64_t len, unsigned int log, loff_t pos, xfs_suminfo_t v),
TP_ARGS(mp, start, len, log, pos, v),
TP_PROTO(struct xfs_mount *mp, xfs_rtxnum_t start,
xfs_rtbxlen_t len, unsigned int log, loff_t pos,
xfs_suminfo_t value),
TP_ARGS(mp, start, len, log, pos, value),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(dev_t, rtdev)
__field(xfs_rtblock_t, start)
__field(xfs_rtxnum_t, start)
__field(unsigned long long, len)
__field(unsigned int, log)
__field(loff_t, pos)
__field(xfs_suminfo_t, v)
__field(xfs_suminfo_t, value)
),
TP_fast_assign(
__entry->dev = mp->m_super->s_dev;
......@@ -1055,7 +1056,7 @@ TRACE_EVENT(xchk_rtsum_record_free,
__entry->len = len;
__entry->log = log;
__entry->pos = pos;
__entry->v = v;
__entry->value = value;
),
TP_printk("dev %d:%d rtdev %d:%d rtx 0x%llx rtxcount 0x%llx log %u rsumpos 0x%llx sumcount %u",
MAJOR(__entry->dev), MINOR(__entry->dev),
......@@ -1064,7 +1065,7 @@ TRACE_EVENT(xchk_rtsum_record_free,
__entry->len,
__entry->log,
__entry->pos,
__entry->v)
__entry->value)
);
#endif /* CONFIG_XFS_RT */
......
......@@ -28,6 +28,7 @@
#include "xfs_icache.h"
#include "xfs_iomap.h"
#include "xfs_reflink.h"
#include "xfs_rtbitmap.h"
/* Kernel only BMAP related definitions and functions */
......@@ -75,28 +76,28 @@ xfs_bmap_rtalloc(
{
struct xfs_mount *mp = ap->ip->i_mount;
xfs_fileoff_t orig_offset = ap->offset;
xfs_rtblock_t rtb;
xfs_extlen_t prod = 0; /* product factor for allocators */
xfs_rtxnum_t rtx;
xfs_rtxlen_t prod = 0; /* product factor for allocators */
xfs_extlen_t mod = 0; /* product factor for allocators */
xfs_extlen_t ralen = 0; /* realtime allocation length */
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_extlen_t raminlen;
xfs_rtxlen_t raminlen;
bool rtlocked = false;
bool ignore_locality = false;
int error;
align = xfs_get_extsz_hint(ap->ip);
retry:
prod = align / mp->m_sb.sb_rextsize;
prod = xfs_extlen_to_rtxlen(mp, align);
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);
ASSERT(ap->length % mp->m_sb.sb_rextsize == 0);
ASSERT(xfs_extlen_to_rtxmod(mp, ap->length) == 0);
/*
* If we shifted the file offset downward to satisfy an extent size
......@@ -116,17 +117,14 @@ xfs_bmap_rtalloc(
prod = 1;
/*
* Set ralen to be the actual requested length in rtextents.
*/
ralen = ap->length / mp->m_sb.sb_rextsize;
/*
*
* If the old value was close enough to XFS_BMBT_MAX_EXTLEN that
* we rounded up to it, cut it back so it's valid again.
* Note that if it's a really large request (bigger than
* XFS_BMBT_MAX_EXTLEN), we don't hear about that number, and can't
* adjust the starting point to match it.
*/
if (ralen * mp->m_sb.sb_rextsize >= XFS_MAX_BMBT_EXTLEN)
ralen = XFS_MAX_BMBT_EXTLEN / mp->m_sb.sb_rextsize;
ralen = xfs_extlen_to_rtxlen(mp, min(ap->length, XFS_MAX_BMBT_EXTLEN));
/*
* Lock out modifications to both the RT bitmap and summary inodes
......@@ -144,12 +142,10 @@ xfs_bmap_rtalloc(
* pick an extent that will space things out in the rt area.
*/
if (ap->eof && ap->offset == 0) {
xfs_rtblock_t rtx; /* realtime extent no */
error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx);
if (error)
return error;
ap->blkno = rtx * mp->m_sb.sb_rextsize;
ap->blkno = xfs_rtx_to_rtb(mp, rtx);
} else {
ap->blkno = 0;
}
......@@ -160,20 +156,18 @@ xfs_bmap_rtalloc(
* Realtime allocation, done through xfs_rtallocate_extent.
*/
if (ignore_locality)
ap->blkno = 0;
rtx = 0;
else
do_div(ap->blkno, mp->m_sb.sb_rextsize);
rtb = ap->blkno;
ap->length = ralen;
raminlen = max_t(xfs_extlen_t, 1, minlen / mp->m_sb.sb_rextsize);
error = xfs_rtallocate_extent(ap->tp, ap->blkno, raminlen, ap->length,
&ralen, ap->wasdel, prod, &rtb);
rtx = xfs_rtb_to_rtx(mp, ap->blkno);
raminlen = max_t(xfs_rtxlen_t, 1, xfs_extlen_to_rtxlen(mp, minlen));
error = xfs_rtallocate_extent(ap->tp, rtx, raminlen, ralen, &ralen,
ap->wasdel, prod, &rtx);
if (error)
return error;
if (rtb != NULLRTBLOCK) {
ap->blkno = rtb * mp->m_sb.sb_rextsize;
ap->length = ralen * mp->m_sb.sb_rextsize;
if (rtx != NULLRTEXTNO) {
ap->blkno = xfs_rtx_to_rtb(mp, rtx);
ap->length = xfs_rtxlen_to_extlen(mp, ralen);
ap->ip->i_nblocks += ap->length;
xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
if (ap->wasdel)
......@@ -690,7 +684,7 @@ xfs_can_free_eofblocks(
*/
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
if (XFS_IS_REALTIME_INODE(ip) && mp->m_sb.sb_rextsize > 1)
end_fsb = roundup_64(end_fsb, mp->m_sb.sb_rextsize);
end_fsb = xfs_rtb_roundup_rtx(mp, end_fsb);
last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
if (last_fsb <= end_fsb)
return false;
......@@ -780,12 +774,10 @@ xfs_alloc_file_space(
{
xfs_mount_t *mp = ip->i_mount;
xfs_off_t count;
xfs_filblks_t allocated_fsb;
xfs_filblks_t allocatesize_fsb;
xfs_extlen_t extsz, temp;
xfs_fileoff_t startoffset_fsb;
xfs_fileoff_t endoffset_fsb;
int nimaps;
int rt;
xfs_trans_t *tp;
xfs_bmbt_irec_t imaps[1], *imapp;
......@@ -808,7 +800,6 @@ xfs_alloc_file_space(
count = len;
imapp = &imaps[0];
nimaps = 1;
startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
endoffset_fsb = XFS_B_TO_FSB(mp, offset + count);
allocatesize_fsb = endoffset_fsb - startoffset_fsb;
......@@ -819,6 +810,7 @@ xfs_alloc_file_space(
while (allocatesize_fsb && !error) {
xfs_fileoff_t s, e;
unsigned int dblocks, rblocks, resblks;
int nimaps = 1;
/*
* Determine space reservations for data/realtime.
......@@ -884,15 +876,19 @@ xfs_alloc_file_space(
if (error)
break;
allocated_fsb = imapp->br_blockcount;
if (nimaps == 0) {
error = -ENOSPC;
break;
/*
* If the allocator cannot find a single free extent large
* enough to cover the start block of the requested range,
* xfs_bmapi_write will return 0 but leave *nimaps set to 0.
*
* In that case we simply need to keep looping with the same
* startoffset_fsb so that one of the following allocations
* will eventually reach the requested range.
*/
if (nimaps) {
startoffset_fsb += imapp->br_blockcount;
allocatesize_fsb -= imapp->br_blockcount;
}
startoffset_fsb += allocated_fsb;
allocatesize_fsb -= allocated_fsb;
}
return error;
......@@ -989,10 +985,8 @@ xfs_free_file_space(
/* We can only free complete realtime extents. */
if (XFS_IS_REALTIME_INODE(ip) && mp->m_sb.sb_rextsize > 1) {
startoffset_fsb = roundup_64(startoffset_fsb,
mp->m_sb.sb_rextsize);
endoffset_fsb = rounddown_64(endoffset_fsb,
mp->m_sb.sb_rextsize);
startoffset_fsb = xfs_rtb_roundup_rtx(mp, startoffset_fsb);
endoffset_fsb = xfs_rtb_rounddown_rtx(mp, endoffset_fsb);
}
/*
......
......@@ -214,6 +214,43 @@ xfs_ilock_iocb(
return 0;
}
static int
xfs_ilock_iocb_for_write(
struct kiocb *iocb,
unsigned int *lock_mode)
{
ssize_t ret;
struct xfs_inode *ip = XFS_I(file_inode(iocb->ki_filp));
ret = xfs_ilock_iocb(iocb, *lock_mode);
if (ret)
return ret;
if (*lock_mode == XFS_IOLOCK_EXCL)
return 0;
if (!xfs_iflags_test(ip, XFS_IREMAPPING))
return 0;
xfs_iunlock(ip, *lock_mode);
*lock_mode = XFS_IOLOCK_EXCL;
return xfs_ilock_iocb(iocb, *lock_mode);
}
static unsigned int
xfs_ilock_for_write_fault(
struct xfs_inode *ip)
{
/* get a shared lock if no remapping in progress */
xfs_ilock(ip, XFS_MMAPLOCK_SHARED);
if (!xfs_iflags_test(ip, XFS_IREMAPPING))
return XFS_MMAPLOCK_SHARED;
/* wait for remapping to complete */
xfs_iunlock(ip, XFS_MMAPLOCK_SHARED);
xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
return XFS_MMAPLOCK_EXCL;
}
STATIC ssize_t
xfs_file_dio_read(
struct kiocb *iocb,
......@@ -551,7 +588,7 @@ xfs_file_dio_write_aligned(
unsigned int iolock = XFS_IOLOCK_SHARED;
ssize_t ret;
ret = xfs_ilock_iocb(iocb, iolock);
ret = xfs_ilock_iocb_for_write(iocb, &iolock);
if (ret)
return ret;
ret = xfs_file_write_checks(iocb, from, &iolock);
......@@ -618,7 +655,7 @@ xfs_file_dio_write_unaligned(
flags = IOMAP_DIO_FORCE_WAIT;
}
ret = xfs_ilock_iocb(iocb, iolock);
ret = xfs_ilock_iocb_for_write(iocb, &iolock);
if (ret)
return ret;
......@@ -1180,7 +1217,7 @@ xfs_file_remap_range(
if (xfs_file_sync_writes(file_in) || xfs_file_sync_writes(file_out))
xfs_log_force_inode(dest);
out_unlock:
xfs_iunlock2_io_mmap(src, dest);
xfs_iunlock2_remapping(src, dest);
if (ret)
trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
return remapped > 0 ? remapped : ret;
......@@ -1328,6 +1365,7 @@ __xfs_filemap_fault(
struct inode *inode = file_inode(vmf->vma->vm_file);
struct xfs_inode *ip = XFS_I(inode);
vm_fault_t ret;
unsigned int lock_mode = 0;
trace_xfs_filemap_fault(ip, order, write_fault);
......@@ -1336,24 +1374,23 @@ __xfs_filemap_fault(
file_update_time(vmf->vma->vm_file);
}
if (IS_DAX(inode) || write_fault)
lock_mode = xfs_ilock_for_write_fault(XFS_I(inode));
if (IS_DAX(inode)) {
pfn_t pfn;
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
ret = xfs_dax_fault(vmf, order, write_fault, &pfn);
if (ret & VM_FAULT_NEEDDSYNC)
ret = dax_finish_sync_fault(vmf, order, pfn);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
} else {
if (write_fault) {
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
ret = iomap_page_mkwrite(vmf,
&xfs_page_mkwrite_iomap_ops);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
} else if (write_fault) {
ret = iomap_page_mkwrite(vmf, &xfs_page_mkwrite_iomap_ops);
} else {
ret = filemap_fault(vmf);
}
}
if (lock_mode)
xfs_iunlock(XFS_I(inode), lock_mode);
if (write_fault)
sb_end_pagefault(inode->i_sb);
......
......@@ -23,7 +23,7 @@
#include "xfs_refcount.h"
#include "xfs_refcount_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_rtalloc.h"
#include "xfs_rtbitmap.h"
#include "xfs_ag.h"
/* Convert an xfs_fsmap to an fsmap. */
......@@ -483,11 +483,11 @@ xfs_getfsmap_rtdev_rtbitmap_helper(
xfs_rtblock_t rtbno;
xfs_daddr_t rec_daddr, len_daddr;
rtbno = rec->ar_startext * mp->m_sb.sb_rextsize;
rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext);
rec_daddr = XFS_FSB_TO_BB(mp, rtbno);
irec.rm_startblock = rtbno;
rtbno = rec->ar_extcount * mp->m_sb.sb_rextsize;
rtbno = xfs_rtx_to_rtb(mp, rec->ar_extcount);
len_daddr = XFS_FSB_TO_BB(mp, rtbno);
irec.rm_blockcount = rtbno;
......@@ -514,7 +514,7 @@ xfs_getfsmap_rtdev_rtbitmap(
uint64_t eofs;
int error;
eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rextents * mp->m_sb.sb_rextsize);
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,
......@@ -539,11 +539,8 @@ xfs_getfsmap_rtdev_rtbitmap(
* Set up query parameters to return free rtextents covering the range
* we want.
*/
alow.ar_startext = start_rtb;
ahigh.ar_startext = end_rtb;
do_div(alow.ar_startext, mp->m_sb.sb_rextsize);
if (do_div(ahigh.ar_startext, mp->m_sb.sb_rextsize))
ahigh.ar_startext++;
alow.ar_startext = xfs_rtb_to_rtx(mp, start_rtb);
ahigh.ar_startext = xfs_rtb_to_rtxup(mp, end_rtb);
error = xfs_rtalloc_query_range(mp, tp, &alow, &ahigh,
xfs_getfsmap_rtdev_rtbitmap_helper, info);
if (error)
......
......@@ -918,6 +918,13 @@ xfs_droplink(
xfs_trans_t *tp,
xfs_inode_t *ip)
{
if (VFS_I(ip)->i_nlink == 0) {
xfs_alert(ip->i_mount,
"%s: Attempt to drop inode (%llu) with nlink zero.",
__func__, ip->i_ino);
return -EFSCORRUPTED;
}
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
drop_nlink(VFS_I(ip));
......@@ -3621,6 +3628,23 @@ xfs_iunlock2_io_mmap(
inode_unlock(VFS_I(ip1));
}
/* Drop the MMAPLOCK and the IOLOCK after a remap completes. */
void
xfs_iunlock2_remapping(
struct xfs_inode *ip1,
struct xfs_inode *ip2)
{
xfs_iflags_clear(ip1, XFS_IREMAPPING);
if (ip1 != ip2)
xfs_iunlock(ip1, XFS_MMAPLOCK_SHARED);
xfs_iunlock(ip2, XFS_MMAPLOCK_EXCL);
if (ip1 != ip2)
inode_unlock_shared(VFS_I(ip1));
inode_unlock(VFS_I(ip2));
}
/*
* Reload the incore inode list for this inode. Caller should ensure that
* the link count cannot change, either by taking ILOCK_SHARED or otherwise
......
......@@ -347,6 +347,14 @@ static inline bool xfs_inode_has_large_extent_counts(struct xfs_inode *ip)
/* Quotacheck is running but inode has not been added to quota counts. */
#define XFS_IQUOTAUNCHECKED (1 << 14)
/*
* Remap in progress. Callers that wish to update file data while
* holding a shared IOLOCK or MMAPLOCK must drop the lock and retake
* the lock in exclusive mode. Relocking the file will block until
* IREMAPPING is cleared.
*/
#define XFS_IREMAPPING (1U << 15)
/* All inode state flags related to inode reclaim. */
#define XFS_ALL_IRECLAIM_FLAGS (XFS_IRECLAIMABLE | \
XFS_IRECLAIM | \
......@@ -595,6 +603,7 @@ void xfs_end_io(struct work_struct *work);
int xfs_ilock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
void xfs_iunlock2_io_mmap(struct xfs_inode *ip1, struct xfs_inode *ip2);
void xfs_iunlock2_remapping(struct xfs_inode *ip1, struct xfs_inode *ip2);
static inline bool
xfs_inode_unlinked_incomplete(
......
......@@ -19,6 +19,7 @@
#include "xfs_log.h"
#include "xfs_log_priv.h"
#include "xfs_error.h"
#include "xfs_rtbitmap.h"
#include <linux/iversion.h>
......@@ -107,7 +108,7 @@ xfs_inode_item_precommit(
*/
if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
(ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) &&
(ip->i_extsize % ip->i_mount->m_sb.sb_rextsize) > 0) {
xfs_extlen_to_rtxmod(ip->i_mount, ip->i_extsize) > 0) {
ip->i_diflags &= ~(XFS_DIFLAG_EXTSIZE |
XFS_DIFLAG_EXTSZINHERIT);
ip->i_extsize = 0;
......
......@@ -38,6 +38,7 @@
#include "xfs_reflink.h"
#include "xfs_ioctl.h"
#include "xfs_xattr.h"
#include "xfs_rtbitmap.h"
#include <linux/mount.h>
#include <linux/namei.h>
......@@ -1004,7 +1005,7 @@ xfs_fill_fsxattr(
* later.
*/
if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
ip->i_extsize % mp->m_sb.sb_rextsize > 0) {
xfs_extlen_to_rtxmod(mp, ip->i_extsize) > 0) {
fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE |
FS_XFLAG_EXTSZINHERIT);
fa->fsx_extsize = 0;
......@@ -1130,7 +1131,7 @@ xfs_ioctl_setattr_xflags(
/* If realtime flag is set then must have realtime device */
if (fa->fsx_xflags & FS_XFLAG_REALTIME) {
if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 ||
(ip->i_extsize % mp->m_sb.sb_rextsize))
xfs_extlen_to_rtxmod(mp, ip->i_extsize))
return -EINVAL;
}
......
......@@ -198,6 +198,18 @@ static inline uint64_t howmany_64(uint64_t x, uint32_t y)
return x;
}
/* If @b is a power of 2, return log2(b). Else return -1. */
static inline int8_t log2_if_power2(unsigned long b)
{
return is_power_of_2(b) ? ilog2(b) : -1;
}
/* If @b is a power of 2, return a mask of the lower bits, else return zero. */
static inline unsigned long long mask64_if_power2(unsigned long b)
{
return is_power_of_2(b) ? b - 1 : 0;
}
int xfs_rw_bdev(struct block_device *bdev, sector_t sector, unsigned int count,
char *data, enum req_op op);
......
......@@ -101,9 +101,9 @@ typedef struct xfs_mount {
/*
* Optional cache of rt summary level per bitmap block with the
* invariant that m_rsum_cache[bbno] <= the minimum i for which
* rsum[i][bbno] != 0. Reads and writes are serialized by the rsumip
* inode lock.
* invariant that m_rsum_cache[bbno] > the maximum i for which
* rsum[i][bbno] != 0, or 0 if rsum[i][bbno] == 0 for all i.
* Reads and writes are serialized by the rsumip inode lock.
*/
uint8_t *m_rsum_cache;
struct xfs_mru_cache *m_filestream; /* per-mount filestream data */
......@@ -119,6 +119,7 @@ typedef struct xfs_mount {
uint8_t m_blkbb_log; /* blocklog - BBSHIFT */
uint8_t m_agno_log; /* log #ag's */
uint8_t m_sectbb_log; /* sectlog - BBSHIFT */
int8_t m_rtxblklog; /* log2 of rextsize, if possible */
uint m_blockmask; /* sb_blocksize-1 */
uint m_blockwsize; /* sb_blocksize in words */
uint m_blockwmask; /* blockwsize-1 */
......@@ -152,6 +153,7 @@ typedef struct xfs_mount {
uint64_t m_features; /* active filesystem features */
uint64_t m_low_space[XFS_LOWSP_MAX];
uint64_t m_low_rtexts[XFS_LOWSP_MAX];
uint64_t m_rtxblkmask; /* rt extent block mask */
struct xfs_ino_geometry m_ino_geo; /* inode geometry */
struct xfs_trans_resv m_resv; /* precomputed res values */
/* low free space thresholds */
......
......@@ -72,6 +72,10 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_map_t, 4);
XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_name_local_t, 4);
/* realtime structures */
XFS_CHECK_STRUCT_SIZE(union xfs_rtword_raw, 4);
XFS_CHECK_STRUCT_SIZE(union xfs_suminfo_raw, 4);
/*
* m68k has problems with xfs_attr_leaf_name_remote_t, but we pad it to
* 4 bytes anyway so it's not obviously a problem. Hence for the moment
......
......@@ -1540,6 +1540,10 @@ xfs_reflink_remap_prep(
if (ret)
goto out_unlock;
xfs_iflags_set(src, XFS_IREMAPPING);
if (inode_in != inode_out)
xfs_ilock_demote(src, XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL);
return 0;
out_unlock:
xfs_iunlock2_io_mmap(src, dest);
......
......@@ -19,6 +19,7 @@
#include "xfs_icache.h"
#include "xfs_rtalloc.h"
#include "xfs_sb.h"
#include "xfs_rtbitmap.h"
/*
* Read and return the summary information for a given extent size,
......@@ -28,48 +29,48 @@
*/
static int
xfs_rtget_summary(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
struct xfs_rtalloc_args *args,
int log, /* log2 of extent size */
xfs_rtblock_t bbno, /* bitmap block number */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb, /* in/out: summary block number */
xfs_fileoff_t bbno, /* bitmap block number */
xfs_suminfo_t *sum) /* out: summary info for this block */
{
return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rbpp, rsb, sum);
return xfs_rtmodify_summary_int(args, log, bbno, 0, sum);
}
/*
* Return whether there are any free extents in the size range given
* by low and high, for the bitmap block bbno.
*/
STATIC int /* error */
STATIC int
xfs_rtany_summary(
xfs_mount_t *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */
struct xfs_rtalloc_args *args,
int low, /* low log2 extent size */
int high, /* high log2 extent size */
xfs_rtblock_t bbno, /* bitmap block number */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb, /* in/out: summary block number */
int *stat) /* out: any good extents here? */
xfs_fileoff_t bbno, /* bitmap block number */
int *maxlog) /* out: max log2 extent size free */
{
int error; /* error value */
struct xfs_mount *mp = args->mp;
int error;
int log; /* loop counter, log2 of ext. size */
xfs_suminfo_t sum; /* summary data */
/* There are no extents at levels < m_rsum_cache[bbno]. */
if (mp->m_rsum_cache && low < mp->m_rsum_cache[bbno])
low = mp->m_rsum_cache[bbno];
/* There are no extents at levels >= m_rsum_cache[bbno]. */
if (mp->m_rsum_cache) {
high = min(high, mp->m_rsum_cache[bbno] - 1);
if (low > high) {
*maxlog = -1;
return 0;
}
}
/*
* Loop over logs of extent sizes.
*/
for (log = low; log <= high; log++) {
for (log = high; log >= low; log--) {
/*
* Get one summary datum.
*/
error = xfs_rtget_summary(mp, tp, log, bbno, rbpp, rsb, &sum);
error = xfs_rtget_summary(args, log, bbno, &sum);
if (error) {
return error;
}
......@@ -77,18 +78,18 @@ xfs_rtany_summary(
* If there are any, return success.
*/
if (sum) {
*stat = 1;
*maxlog = log;
goto out;
}
}
/*
* Found nothing, return failure.
*/
*stat = 0;
*maxlog = -1;
out:
/* There were no extents at levels < log. */
if (mp->m_rsum_cache && log > mp->m_rsum_cache[bbno])
mp->m_rsum_cache[bbno] = log;
/* There were no extents at levels > log. */
if (mp->m_rsum_cache && log + 1 < mp->m_rsum_cache[bbno])
mp->m_rsum_cache[bbno] = log + 1;
return 0;
}
......@@ -97,60 +98,54 @@ xfs_rtany_summary(
* Copy and transform the summary file, given the old and new
* parameters in the mount structures.
*/
STATIC int /* error */
STATIC int
xfs_rtcopy_summary(
xfs_mount_t *omp, /* old file system mount point */
xfs_mount_t *nmp, /* new file system mount point */
xfs_trans_t *tp) /* transaction pointer */
struct xfs_rtalloc_args *oargs,
struct xfs_rtalloc_args *nargs)
{
xfs_rtblock_t bbno; /* bitmap block number */
struct xfs_buf *bp; /* summary buffer */
int error; /* error return value */
xfs_fileoff_t bbno; /* bitmap block number */
int error;
int log; /* summary level number (log length) */
xfs_suminfo_t sum; /* summary data */
xfs_fsblock_t sumbno; /* summary block number */
bp = NULL;
for (log = omp->m_rsumlevels - 1; log >= 0; log--) {
for (bbno = omp->m_sb.sb_rbmblocks - 1;
for (log = oargs->mp->m_rsumlevels - 1; log >= 0; log--) {
for (bbno = oargs->mp->m_sb.sb_rbmblocks - 1;
(xfs_srtblock_t)bbno >= 0;
bbno--) {
error = xfs_rtget_summary(omp, tp, log, bbno, &bp,
&sumbno, &sum);
error = xfs_rtget_summary(oargs, log, bbno, &sum);
if (error)
return error;
goto out;
if (sum == 0)
continue;
error = xfs_rtmodify_summary(omp, tp, log, bbno, -sum,
&bp, &sumbno);
error = xfs_rtmodify_summary(oargs, log, bbno, -sum);
if (error)
return error;
error = xfs_rtmodify_summary(nmp, tp, log, bbno, sum,
&bp, &sumbno);
goto out;
error = xfs_rtmodify_summary(nargs, log, bbno, sum);
if (error)
return error;
goto out;
ASSERT(sum > 0);
}
}
error = 0;
out:
xfs_rtbuf_cache_relse(oargs);
return 0;
}
/*
* Mark an extent specified by start and len allocated.
* Updates all the summary information as well as the bitmap.
*/
STATIC int /* error */
STATIC int
xfs_rtallocate_range(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t start, /* start block to allocate */
xfs_extlen_t len, /* length to allocate */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb) /* in/out: summary block number */
struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* start rtext to allocate */
xfs_rtxlen_t len) /* in/out: summary block number */
{
xfs_rtblock_t end; /* end of the allocated extent */
int error; /* error value */
xfs_rtblock_t postblock = 0; /* first block allocated > end */
xfs_rtblock_t preblock = 0; /* first block allocated < start */
struct xfs_mount *mp = args->mp;
xfs_rtxnum_t end; /* end of the allocated rtext */
int error;
xfs_rtxnum_t postblock = 0; /* first rtext allocated > end */
xfs_rtxnum_t preblock = 0; /* first rtext allocated < start */
end = start + len - 1;
/*
......@@ -158,14 +153,14 @@ xfs_rtallocate_range(
* We need to find the beginning and end of the extent so we can
* properly update the summary.
*/
error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
error = xfs_rtfind_back(args, start, 0, &preblock);
if (error) {
return error;
}
/*
* Find the next allocated block (end of free extent).
*/
error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
&postblock);
if (error) {
return error;
......@@ -174,9 +169,9 @@ xfs_rtallocate_range(
* Decrement the summary information corresponding to the entire
* (old) free extent.
*/
error = xfs_rtmodify_summary(mp, tp,
error = xfs_rtmodify_summary(args,
XFS_RTBLOCKLOG(postblock + 1 - preblock),
XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
xfs_rtx_to_rbmblock(mp, preblock), -1);
if (error) {
return error;
}
......@@ -185,9 +180,9 @@ xfs_rtallocate_range(
* old extent, add summary data for them to be free.
*/
if (preblock < start) {
error = xfs_rtmodify_summary(mp, tp,
error = xfs_rtmodify_summary(args,
XFS_RTBLOCKLOG(start - preblock),
XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
xfs_rtx_to_rbmblock(mp, preblock), 1);
if (error) {
return error;
}
......@@ -197,9 +192,9 @@ xfs_rtallocate_range(
* old extent, add summary data for them to be free.
*/
if (postblock > end) {
error = xfs_rtmodify_summary(mp, tp,
error = xfs_rtmodify_summary(args,
XFS_RTBLOCKLOG(postblock - end),
XFS_BITTOBLOCK(mp, end + 1), 1, rbpp, rsb);
xfs_rtx_to_rbmblock(mp, end + 1), 1);
if (error) {
return error;
}
......@@ -207,54 +202,69 @@ xfs_rtallocate_range(
/*
* Modify the bitmap to mark this extent allocated.
*/
error = xfs_rtmodify_range(mp, tp, start, len, 0);
error = xfs_rtmodify_range(args, start, len, 0);
return error;
}
/*
* Make sure we don't run off the end of the rt volume. Be careful that
* adjusting maxlen downwards doesn't cause us to fail the alignment checks.
*/
static inline xfs_rtxlen_t
xfs_rtallocate_clamp_len(
struct xfs_mount *mp,
xfs_rtxnum_t startrtx,
xfs_rtxlen_t rtxlen,
xfs_rtxlen_t prod)
{
xfs_rtxlen_t ret;
ret = min(mp->m_sb.sb_rextents, startrtx + rtxlen) - startrtx;
return rounddown(ret, prod);
}
/*
* Attempt to allocate an extent minlen<=len<=maxlen starting from
* bitmap block bbno. If we don't get maxlen then use prod to trim
* the length, if given. Returns error; returns starting block in *rtblock.
* the length, if given. Returns error; returns starting block in *rtx.
* The lengths are all in rtextents.
*/
STATIC int /* error */
STATIC int
xfs_rtallocate_extent_block(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t bbno, /* bitmap block number */
xfs_extlen_t minlen, /* minimum length to allocate */
xfs_extlen_t maxlen, /* maximum length to allocate */
xfs_extlen_t *len, /* out: actual length allocated */
xfs_rtblock_t *nextp, /* out: next block to try */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb, /* in/out: summary block number */
xfs_extlen_t prod, /* extent product factor */
xfs_rtblock_t *rtblock) /* out: start block allocated */
struct xfs_rtalloc_args *args,
xfs_fileoff_t bbno, /* bitmap block number */
xfs_rtxlen_t minlen, /* minimum length to allocate */
xfs_rtxlen_t maxlen, /* maximum length to allocate */
xfs_rtxlen_t *len, /* out: actual length allocated */
xfs_rtxnum_t *nextp, /* out: next rtext to try */
xfs_rtxlen_t prod, /* extent product factor */
xfs_rtxnum_t *rtx) /* out: start rtext allocated */
{
xfs_rtblock_t besti; /* best rtblock found so far */
xfs_rtblock_t bestlen; /* best length found so far */
xfs_rtblock_t end; /* last rtblock in chunk */
int error; /* error value */
xfs_rtblock_t i; /* current rtblock trying */
xfs_rtblock_t next; /* next rtblock to try */
struct xfs_mount *mp = args->mp;
xfs_rtxnum_t besti; /* best rtext found so far */
xfs_rtxnum_t bestlen;/* best length found so far */
xfs_rtxnum_t end; /* last rtext in chunk */
int error;
xfs_rtxnum_t i; /* current rtext trying */
xfs_rtxnum_t next; /* next rtext to try */
int stat; /* status from internal calls */
/*
* Loop over all the extents starting in this bitmap block,
* looking for one that's long enough.
*/
for (i = XFS_BLOCKTOBIT(mp, bbno), besti = -1, bestlen = 0,
end = XFS_BLOCKTOBIT(mp, bbno + 1) - 1;
for (i = xfs_rbmblock_to_rtx(mp, bbno), besti = -1, bestlen = 0,
end = xfs_rbmblock_to_rtx(mp, bbno + 1) - 1;
i <= end;
i++) {
/* Make sure we don't scan off the end of the rt volume. */
maxlen = min(mp->m_sb.sb_rextents, i + maxlen) - i;
maxlen = xfs_rtallocate_clamp_len(mp, i, maxlen, prod);
/*
* See if there's a free extent of maxlen starting at i.
* If it's not so then next will contain the first non-free.
*/
error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat);
error = xfs_rtcheck_range(args, i, maxlen, 1, &next, &stat);
if (error) {
return error;
}
......@@ -262,13 +272,12 @@ xfs_rtallocate_extent_block(
/*
* i for maxlen is all free, allocate and return that.
*/
error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp,
rsb);
error = xfs_rtallocate_range(args, i, maxlen);
if (error) {
return error;
}
*len = maxlen;
*rtblock = i;
*rtx = i;
return 0;
}
/*
......@@ -278,7 +287,7 @@ xfs_rtallocate_extent_block(
* so far, remember it.
*/
if (minlen < maxlen) {
xfs_rtblock_t thislen; /* this extent size */
xfs_rtxnum_t thislen; /* this extent size */
thislen = next - i;
if (thislen >= minlen && thislen > bestlen) {
......@@ -290,7 +299,7 @@ xfs_rtallocate_extent_block(
* If not done yet, find the start of the next free space.
*/
if (next < end) {
error = xfs_rtfind_forw(mp, tp, next, end, &i);
error = xfs_rtfind_forw(args, next, end, &i);
if (error) {
return error;
}
......@@ -301,7 +310,7 @@ xfs_rtallocate_extent_block(
* Searched the whole thing & didn't find a maxlen free extent.
*/
if (minlen < maxlen && besti != -1) {
xfs_extlen_t p; /* amount to trim length by */
xfs_rtxlen_t p; /* amount to trim length by */
/*
* If size should be a multiple of prod, make that so.
......@@ -315,51 +324,49 @@ xfs_rtallocate_extent_block(
/*
* Allocate besti for bestlen & return that.
*/
error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb);
error = xfs_rtallocate_range(args, besti, bestlen);
if (error) {
return error;
}
*len = bestlen;
*rtblock = besti;
*rtx = besti;
return 0;
}
/*
* Allocation failed. Set *nextp to the next block to try.
*/
*nextp = next;
*rtblock = NULLRTBLOCK;
*rtx = NULLRTEXTNO;
return 0;
}
/*
* Allocate an extent of length minlen<=len<=maxlen, starting at block
* bno. If we don't get maxlen then use prod to trim the length, if given.
* Returns error; returns starting block in *rtblock.
* Returns error; returns starting block in *rtx.
* The lengths are all in rtextents.
*/
STATIC int /* error */
STATIC int
xfs_rtallocate_extent_exact(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t bno, /* starting block number to allocate */
xfs_extlen_t minlen, /* minimum length to allocate */
xfs_extlen_t maxlen, /* maximum length to allocate */
xfs_extlen_t *len, /* out: actual length allocated */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb, /* in/out: summary block number */
xfs_extlen_t prod, /* extent product factor */
xfs_rtblock_t *rtblock) /* out: start block allocated */
struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext number to allocate */
xfs_rtxlen_t minlen, /* minimum length to allocate */
xfs_rtxlen_t maxlen, /* maximum length to allocate */
xfs_rtxlen_t *len, /* out: actual length allocated */
xfs_rtxlen_t prod, /* extent product factor */
xfs_rtxnum_t *rtx) /* out: start rtext allocated */
{
int error; /* error value */
xfs_extlen_t i; /* extent length trimmed due to prod */
int error;
xfs_rtxlen_t i; /* extent length trimmed due to prod */
int isfree; /* extent is free */
xfs_rtblock_t next; /* next block to try (dummy) */
xfs_rtxnum_t next; /* next rtext to try (dummy) */
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
ASSERT(minlen % prod == 0);
ASSERT(maxlen % prod == 0);
/*
* Check if the range in question (for maxlen) is free.
*/
error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree);
error = xfs_rtcheck_range(args, start, maxlen, 1, &next, &isfree);
if (error) {
return error;
}
......@@ -367,23 +374,23 @@ xfs_rtallocate_extent_exact(
/*
* If it is, allocate it and return success.
*/
error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
error = xfs_rtallocate_range(args, start, maxlen);
if (error) {
return error;
}
*len = maxlen;
*rtblock = bno;
*rtx = start;
return 0;
}
/*
* If not, allocate what there is, if it's at least minlen.
*/
maxlen = next - bno;
maxlen = next - start;
if (maxlen < minlen) {
/*
* Failed, return failure status.
*/
*rtblock = NULLRTBLOCK;
*rtx = NULLRTEXTNO;
return 0;
}
/*
......@@ -395,81 +402,82 @@ xfs_rtallocate_extent_exact(
/*
* Now we can't do it, return failure status.
*/
*rtblock = NULLRTBLOCK;
*rtx = NULLRTEXTNO;
return 0;
}
}
/*
* Allocate what we can and return it.
*/
error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
error = xfs_rtallocate_range(args, start, maxlen);
if (error) {
return error;
}
*len = maxlen;
*rtblock = bno;
*rtx = start;
return 0;
}
/*
* Allocate an extent of length minlen<=len<=maxlen, starting as near
* to bno as possible. If we don't get maxlen then use prod to trim
* to start as possible. If we don't get maxlen then use prod to trim
* the length, if given. The lengths are all in rtextents.
*/
STATIC int /* error */
STATIC int
xfs_rtallocate_extent_near(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t bno, /* starting block number to allocate */
xfs_extlen_t minlen, /* minimum length to allocate */
xfs_extlen_t maxlen, /* maximum length to allocate */
xfs_extlen_t *len, /* out: actual length allocated */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb, /* in/out: summary block number */
xfs_extlen_t prod, /* extent product factor */
xfs_rtblock_t *rtblock) /* out: start block allocated */
struct xfs_rtalloc_args *args,
xfs_rtxnum_t start, /* starting rtext number to allocate */
xfs_rtxlen_t minlen, /* minimum length to allocate */
xfs_rtxlen_t maxlen, /* maximum length to allocate */
xfs_rtxlen_t *len, /* out: actual length allocated */
xfs_rtxlen_t prod, /* extent product factor */
xfs_rtxnum_t *rtx) /* out: start rtext allocated */
{
int any; /* any useful extents from summary */
xfs_rtblock_t bbno; /* bitmap block number */
int error; /* error value */
struct xfs_mount *mp = args->mp;
int maxlog; /* max useful extent from summary */
xfs_fileoff_t bbno; /* bitmap block number */
int error;
int i; /* bitmap block offset (loop control) */
int j; /* secondary loop control */
int log2len; /* log2 of minlen */
xfs_rtblock_t n; /* next block to try */
xfs_rtblock_t r; /* result block */
xfs_rtxnum_t n; /* next rtext to try */
xfs_rtxnum_t r; /* result rtext */
ASSERT(minlen % prod == 0);
ASSERT(maxlen % prod == 0);
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
/*
* If the block number given is off the end, silently set it to
* the last block.
*/
if (bno >= mp->m_sb.sb_rextents)
bno = mp->m_sb.sb_rextents - 1;
if (start >= mp->m_sb.sb_rextents)
start = mp->m_sb.sb_rextents - 1;
/* Make sure we don't run off the end of the rt volume. */
maxlen = min(mp->m_sb.sb_rextents, bno + maxlen) - bno;
maxlen = xfs_rtallocate_clamp_len(mp, start, maxlen, prod);
if (maxlen < minlen) {
*rtblock = NULLRTBLOCK;
*rtx = NULLRTEXTNO;
return 0;
}
/*
* Try the exact allocation first.
*/
error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len,
rbpp, rsb, prod, &r);
error = xfs_rtallocate_extent_exact(args, start, minlen, maxlen, len,
prod, &r);
if (error) {
return error;
}
/*
* If the exact allocation worked, return that.
*/
if (r != NULLRTBLOCK) {
*rtblock = r;
if (r != NULLRTEXTNO) {
*rtx = r;
return 0;
}
bbno = XFS_BITTOBLOCK(mp, bno);
bbno = xfs_rtx_to_rbmblock(mp, start);
i = 0;
j = -1;
ASSERT(minlen != 0);
log2len = xfs_highbit32(minlen);
/*
......@@ -480,8 +488,8 @@ xfs_rtallocate_extent_near(
* Get summary information of extents of all useful levels
* starting in this bitmap block.
*/
error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1,
bbno + i, rbpp, rsb, &any);
error = xfs_rtany_summary(args, log2len, mp->m_rsumlevels - 1,
bbno + i, &maxlog);
if (error) {
return error;
}
......@@ -489,7 +497,10 @@ xfs_rtallocate_extent_near(
* If there are any useful extents starting here, try
* allocating one.
*/
if (any) {
if (maxlog >= 0) {
xfs_extlen_t maxavail =
min_t(xfs_rtblock_t, maxlen,
(1ULL << (maxlog + 1)) - 1);
/*
* On the positive side of the starting location.
*/
......@@ -498,17 +509,17 @@ xfs_rtallocate_extent_near(
* Try to allocate an extent starting in
* this block.
*/
error = xfs_rtallocate_extent_block(mp, tp,
bbno + i, minlen, maxlen, len, &n, rbpp,
rsb, prod, &r);
error = xfs_rtallocate_extent_block(args,
bbno + i, minlen, maxavail, len,
&n, prod, &r);
if (error) {
return error;
}
/*
* If it worked, return it.
*/
if (r != NULLRTBLOCK) {
*rtblock = r;
if (r != NULLRTEXTNO) {
*rtx = r;
return 0;
}
}
......@@ -516,68 +527,46 @@ xfs_rtallocate_extent_near(
* On the negative side of the starting location.
*/
else { /* i < 0 */
int maxblocks;
/*
* Loop backwards through the bitmap blocks from
* the starting point-1 up to where we are now.
* There should be an extent which ends in this
* bitmap block and is long enough.
*/
for (j = -1; j > i; j--) {
/*
* Grab the summary information for
* this bitmap block.
* Loop backwards to find the end of the extent
* we found in the realtime summary.
*
* maxblocks is the maximum possible number of
* bitmap blocks from the start of the extent
* to the end of the extent.
*/
error = xfs_rtany_summary(mp, tp,
log2len, mp->m_rsumlevels - 1,
bbno + j, rbpp, rsb, &any);
if (error) {
return error;
}
if (maxlog == 0)
maxblocks = 0;
else if (maxlog < mp->m_blkbit_log)
maxblocks = 1;
else
maxblocks = 2 << (maxlog - mp->m_blkbit_log);
/*
* If there's no extent given in the
* summary that means the extent we
* found must carry over from an
* earlier block. If there is an
* extent given, we've already tried
* that allocation, don't do it again.
* We need to check bbno + i + maxblocks down to
* bbno + i. We already checked bbno down to
* bbno + j + 1, so we don't need to check those
* again.
*/
if (any)
continue;
error = xfs_rtallocate_extent_block(mp,
tp, bbno + j, minlen, maxlen,
len, &n, rbpp, rsb, prod, &r);
j = min(i + maxblocks, j);
for (; j >= i; j--) {
error = xfs_rtallocate_extent_block(args,
bbno + j, minlen,
maxavail, len, &n, prod,
&r);
if (error) {
return error;
}
/*
* If it works, return the extent.
*/
if (r != NULLRTBLOCK) {
*rtblock = r;
if (r != NULLRTEXTNO) {
*rtx = r;
return 0;
}
}
/*
* There weren't intervening bitmap blocks
* with a long enough extent, or the
* allocation didn't work for some reason
* (i.e. it's a little * too short).
* Try to allocate from the summary block
* that we found.
*/
error = xfs_rtallocate_extent_block(mp, tp,
bbno + i, minlen, maxlen, len, &n, rbpp,
rsb, prod, &r);
if (error) {
return error;
}
/*
* If it works, return the extent.
*/
if (r != NULLRTBLOCK) {
*rtblock = r;
return 0;
}
}
}
/*
......@@ -610,7 +599,7 @@ xfs_rtallocate_extent_near(
else
break;
}
*rtblock = NULLRTBLOCK;
*rtx = NULLRTEXTNO;
return 0;
}
......@@ -619,26 +608,25 @@ xfs_rtallocate_extent_near(
* specified. If we don't get maxlen then use prod to trim
* the length, if given. The lengths are all in rtextents.
*/
STATIC int /* error */
STATIC int
xfs_rtallocate_extent_size(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_extlen_t minlen, /* minimum length to allocate */
xfs_extlen_t maxlen, /* maximum length to allocate */
xfs_extlen_t *len, /* out: actual length allocated */
struct xfs_buf **rbpp, /* in/out: summary block buffer */
xfs_fsblock_t *rsb, /* in/out: summary block number */
xfs_extlen_t prod, /* extent product factor */
xfs_rtblock_t *rtblock) /* out: start block allocated */
struct xfs_rtalloc_args *args,
xfs_rtxlen_t minlen, /* minimum length to allocate */
xfs_rtxlen_t maxlen, /* maximum length to allocate */
xfs_rtxlen_t *len, /* out: actual length allocated */
xfs_rtxlen_t prod, /* extent product factor */
xfs_rtxnum_t *rtx) /* out: start rtext allocated */
{
int error; /* error value */
int i; /* bitmap block number */
struct xfs_mount *mp = args->mp;
int error;
xfs_fileoff_t i; /* bitmap block number */
int l; /* level number (loop control) */
xfs_rtblock_t n; /* next block to be tried */
xfs_rtblock_t r; /* result block number */
xfs_rtxnum_t n; /* next rtext to be tried */
xfs_rtxnum_t r; /* result rtext number */
xfs_suminfo_t sum; /* summary information for extents */
ASSERT(minlen % prod == 0 && maxlen % prod == 0);
ASSERT(minlen % prod == 0);
ASSERT(maxlen % prod == 0);
ASSERT(maxlen != 0);
/*
......@@ -656,8 +644,7 @@ xfs_rtallocate_extent_size(
/*
* Get the summary for this level/block.
*/
error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
&sum);
error = xfs_rtget_summary(args, l, i, &sum);
if (error) {
return error;
}
......@@ -669,16 +656,16 @@ xfs_rtallocate_extent_size(
/*
* Try allocating the extent.
*/
error = xfs_rtallocate_extent_block(mp, tp, i, maxlen,
maxlen, len, &n, rbpp, rsb, prod, &r);
error = xfs_rtallocate_extent_block(args, i, maxlen,
maxlen, len, &n, prod, &r);
if (error) {
return error;
}
/*
* If it worked, return that.
*/
if (r != NULLRTBLOCK) {
*rtblock = r;
if (r != NULLRTEXTNO) {
*rtx = r;
return 0;
}
/*
......@@ -686,8 +673,8 @@ xfs_rtallocate_extent_size(
* allocator is beyond the next bitmap block,
* skip to that bitmap block.
*/
if (XFS_BITTOBLOCK(mp, n) > i + 1)
i = XFS_BITTOBLOCK(mp, n) - 1;
if (xfs_rtx_to_rbmblock(mp, n) > i + 1)
i = xfs_rtx_to_rbmblock(mp, n) - 1;
}
}
/*
......@@ -695,7 +682,7 @@ xfs_rtallocate_extent_size(
* we're asking for a fixed size extent.
*/
if (minlen > --maxlen) {
*rtblock = NULLRTBLOCK;
*rtx = NULLRTEXTNO;
return 0;
}
ASSERT(minlen != 0);
......@@ -715,8 +702,7 @@ xfs_rtallocate_extent_size(
/*
* Get the summary information for this level/block.
*/
error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
&sum);
error = xfs_rtget_summary(args, l, i, &sum);
if (error) {
return error;
}
......@@ -730,18 +716,18 @@ xfs_rtallocate_extent_size(
* minlen/maxlen are in the possible range for
* this summary level.
*/
error = xfs_rtallocate_extent_block(mp, tp, i,
error = xfs_rtallocate_extent_block(args, i,
XFS_RTMAX(minlen, 1 << l),
XFS_RTMIN(maxlen, (1 << (l + 1)) - 1),
len, &n, rbpp, rsb, prod, &r);
len, &n, prod, &r);
if (error) {
return error;
}
/*
* If it worked, return that extent.
*/
if (r != NULLRTBLOCK) {
*rtblock = r;
if (r != NULLRTEXTNO) {
*rtx = r;
return 0;
}
/*
......@@ -749,14 +735,14 @@ xfs_rtallocate_extent_size(
* allocator is beyond the next bitmap block,
* skip to that bitmap block.
*/
if (XFS_BITTOBLOCK(mp, n) > i + 1)
i = XFS_BITTOBLOCK(mp, n) - 1;
if (xfs_rtx_to_rbmblock(mp, n) > i + 1)
i = xfs_rtx_to_rbmblock(mp, n) - 1;
}
}
/*
* Got nothing, return failure.
*/
*rtblock = NULLRTBLOCK;
*rtx = NULLRTEXTNO;
return 0;
}
......@@ -886,12 +872,14 @@ xfs_alloc_rsum_cache(
xfs_extlen_t rbmblocks) /* number of rt bitmap blocks */
{
/*
* The rsum cache is initialized to all zeroes, which is trivially a
* lower bound on the minimum level with any free extents. We can
* continue without the cache if it couldn't be allocated.
* The rsum cache is initialized to the maximum value, which is
* trivially an upper bound on the maximum level with any free extents.
* We can continue without the cache if it couldn't be allocated.
*/
mp->m_rsum_cache = kvzalloc(rbmblocks, GFP_KERNEL);
if (!mp->m_rsum_cache)
mp->m_rsum_cache = kvmalloc(rbmblocks, GFP_KERNEL);
if (mp->m_rsum_cache)
memset(mp->m_rsum_cache, -1, rbmblocks);
else
xfs_warn(mp, "could not allocate realtime summary cache");
}
......@@ -907,13 +895,13 @@ xfs_growfs_rt(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_growfs_rt_t *in) /* growfs rt input struct */
{
xfs_rtblock_t bmbno; /* bitmap block number */
xfs_fileoff_t bmbno; /* bitmap block number */
struct xfs_buf *bp; /* temporary buffer */
int error; /* error return value */
xfs_mount_t *nmp; /* new (fake) mount structure */
xfs_rfsblock_t nrblocks; /* new number of realtime blocks */
xfs_extlen_t nrbmblocks; /* new number of rt bitmap blocks */
xfs_rtblock_t nrextents; /* new number of realtime extents */
xfs_rtxnum_t nrextents; /* new number of realtime extents */
uint8_t nrextslog; /* new log2 of sb_rextents */
xfs_extlen_t nrsumblocks; /* new number of summary blocks */
uint nrsumlevels; /* new rt summary levels */
......@@ -922,7 +910,6 @@ xfs_growfs_rt(
xfs_extlen_t rbmblocks; /* current number of rt bitmap blocks */
xfs_extlen_t rsumblocks; /* current number of rt summary blks */
xfs_sb_t *sbp; /* old superblock */
xfs_fsblock_t sumbno; /* summary block number */
uint8_t *rsum_cache; /* old summary cache */
sbp = &mp->m_sb;
......@@ -954,7 +941,7 @@ xfs_growfs_rt(
return -EINVAL;
/* Unsupported realtime features. */
if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp))
if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp))
return -EOPNOTSUPP;
nrblocks = in->newblocks;
......@@ -976,11 +963,10 @@ xfs_growfs_rt(
*/
nrextents = nrblocks;
do_div(nrextents, in->extsize);
nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);
nrbmblocks = xfs_rtbitmap_blockcount(mp, nrextents);
nrextslog = xfs_highbit32(nrextents);
nrsumlevels = nrextslog + 1;
nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;
nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
nrsumblocks = xfs_rtsummary_blockcount(mp, nrsumlevels, nrbmblocks);
nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
/*
* New summary size can't be more than half the size of
......@@ -1023,6 +1009,12 @@ xfs_growfs_rt(
((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
bmbno < nrbmblocks;
bmbno++) {
struct xfs_rtalloc_args args = {
.mp = mp,
};
struct xfs_rtalloc_args nargs = {
.mp = nmp,
};
struct xfs_trans *tp;
xfs_rfsblock_t nrblocks_step;
......@@ -1032,19 +1024,17 @@ xfs_growfs_rt(
* Calculate new sb and mount fields for this round.
*/
nsbp->sb_rextsize = in->extsize;
nmp->m_rtxblklog = -1; /* don't use shift or masking */
nsbp->sb_rbmblocks = bmbno + 1;
nrblocks_step = (bmbno + 1) * NBBY * nsbp->sb_blocksize *
nsbp->sb_rextsize;
nsbp->sb_rblocks = min(nrblocks, nrblocks_step);
nsbp->sb_rextents = nsbp->sb_rblocks;
do_div(nsbp->sb_rextents, nsbp->sb_rextsize);
nsbp->sb_rextents = xfs_rtb_to_rtx(nmp, nsbp->sb_rblocks);
ASSERT(nsbp->sb_rextents != 0);
nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);
nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;
nrsumsize =
(uint)sizeof(xfs_suminfo_t) * nrsumlevels *
nsbp->sb_rbmblocks;
nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
nrsumblocks = xfs_rtsummary_blockcount(mp, nrsumlevels,
nsbp->sb_rbmblocks);
nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
/*
* Start a transaction, get the log reservation.
......@@ -1053,6 +1043,9 @@ xfs_growfs_rt(
&tp);
if (error)
break;
args.tp = tp;
nargs.tp = tp;
/*
* Lock out other callers by grabbing the bitmap inode lock.
*/
......@@ -1086,7 +1079,7 @@ xfs_growfs_rt(
*/
if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks ||
mp->m_rsumlevels != nmp->m_rsumlevels) {
error = xfs_rtcopy_summary(mp, nmp, tp);
error = xfs_rtcopy_summary(&args, &nargs);
if (error)
goto error_cancel;
}
......@@ -1111,9 +1104,9 @@ xfs_growfs_rt(
/*
* Free new extent.
*/
bp = NULL;
error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
error = xfs_rtfree_range(&nargs, sbp->sb_rextents,
nsbp->sb_rextents - sbp->sb_rextents);
xfs_rtbuf_cache_relse(&nargs);
if (error) {
error_cancel:
xfs_trans_cancel(tp);
......@@ -1171,59 +1164,60 @@ xfs_growfs_rt(
* parameters. The length units are all in realtime extents, as is the
* result block number.
*/
int /* error */
int
xfs_rtallocate_extent(
xfs_trans_t *tp, /* transaction pointer */
xfs_rtblock_t bno, /* starting block number to allocate */
xfs_extlen_t minlen, /* minimum length to allocate */
xfs_extlen_t maxlen, /* maximum length to allocate */
xfs_extlen_t *len, /* out: actual length allocated */
struct xfs_trans *tp,
xfs_rtxnum_t start, /* starting rtext number to allocate */
xfs_rtxlen_t minlen, /* minimum length to allocate */
xfs_rtxlen_t maxlen, /* maximum length to allocate */
xfs_rtxlen_t *len, /* out: actual length allocated */
int wasdel, /* was a delayed allocation extent */
xfs_extlen_t prod, /* extent product factor */
xfs_rtblock_t *rtblock) /* out: start block allocated */
xfs_rtxlen_t prod, /* extent product factor */
xfs_rtxnum_t *rtblock) /* out: start rtext allocated */
{
xfs_mount_t *mp = tp->t_mountp;
struct xfs_rtalloc_args args = {
.mp = tp->t_mountp,
.tp = tp,
};
int error; /* error value */
xfs_rtblock_t r; /* result allocated block */
xfs_fsblock_t sb; /* summary file block number */
struct xfs_buf *sumbp; /* summary file block buffer */
xfs_rtxnum_t r; /* result allocated rtext */
ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
ASSERT(xfs_isilocked(args.mp->m_rbmip, XFS_ILOCK_EXCL));
ASSERT(minlen > 0 && minlen <= maxlen);
/*
* If prod is set then figure out what to do to minlen and maxlen.
*/
if (prod > 1) {
xfs_extlen_t i;
xfs_rtxlen_t i;
if ((i = maxlen % prod))
maxlen -= i;
if ((i = minlen % prod))
minlen += prod - i;
if (maxlen < minlen) {
*rtblock = NULLRTBLOCK;
*rtblock = NULLRTEXTNO;
return 0;
}
}
retry:
sumbp = NULL;
if (bno == 0) {
error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len,
&sumbp, &sb, prod, &r);
if (start == 0) {
error = xfs_rtallocate_extent_size(&args, minlen,
maxlen, len, prod, &r);
} else {
error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen,
len, &sumbp, &sb, prod, &r);
error = xfs_rtallocate_extent_near(&args, start, minlen,
maxlen, len, prod, &r);
}
xfs_rtbuf_cache_relse(&args);
if (error)
return error;
/*
* If it worked, update the superblock.
*/
if (r != NULLRTBLOCK) {
if (r != NULLRTEXTNO) {
long slen = (long)*len;
ASSERT(*len >= minlen && *len <= maxlen);
......@@ -1250,6 +1244,7 @@ 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;
......@@ -1261,10 +1256,9 @@ xfs_rtmount_init(
return -ENODEV;
}
mp->m_rsumlevels = sbp->sb_rextslog + 1;
mp->m_rsumsize =
(uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels *
sbp->sb_rbmblocks;
mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize);
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.
......@@ -1422,23 +1416,23 @@ int /* error */
xfs_rtpick_extent(
xfs_mount_t *mp, /* file system mount point */
xfs_trans_t *tp, /* transaction pointer */
xfs_extlen_t len, /* allocation length (rtextents) */
xfs_rtblock_t *pick) /* result rt extent */
{
xfs_rtblock_t b; /* result block */
xfs_rtxlen_t len, /* allocation length (rtextents) */
xfs_rtxnum_t *pick) /* result rt extent */
{
xfs_rtxnum_t b; /* result rtext */
int log2; /* log of sequence number */
uint64_t resid; /* residual after log removed */
uint64_t seq; /* sequence number of file creation */
struct timespec64 ts; /* temporary timespec64 storage */
struct timespec64 ts; /* timespec in inode */
ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
ts = inode_get_atime(VFS_I(mp->m_rbmip));
if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) {
mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
seq = 0;
} else {
ts = inode_get_atime(VFS_I(mp->m_rbmip));
seq = (uint64_t)ts.tv_sec;
seq = ts.tv_sec;
}
if ((log2 = xfs_highbit64(seq)) == -1)
b = 0;
......@@ -1451,7 +1445,7 @@ xfs_rtpick_extent(
if (b + len > mp->m_sb.sb_rextents)
b = mp->m_sb.sb_rextents - len;
}
ts.tv_sec = (time64_t)seq + 1;
ts.tv_sec = seq + 1;
inode_set_atime_to_ts(VFS_I(mp->m_rbmip), ts);
xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
*pick = b;
......
......@@ -11,22 +11,6 @@
struct xfs_mount;
struct xfs_trans;
/*
* XXX: Most of the realtime allocation functions deal in units of realtime
* extents, not realtime blocks. This looks funny when paired with the type
* name and screams for a larger cleanup.
*/
struct xfs_rtalloc_rec {
xfs_rtblock_t ar_startext;
xfs_rtblock_t ar_extcount;
};
typedef int (*xfs_rtalloc_query_range_fn)(
struct xfs_mount *mp,
struct xfs_trans *tp,
const struct xfs_rtalloc_rec *rec,
void *priv);
#ifdef CONFIG_XFS_RT
/*
* Function prototypes for exported functions.
......@@ -40,23 +24,14 @@ typedef int (*xfs_rtalloc_query_range_fn)(
int /* error */
xfs_rtallocate_extent(
struct xfs_trans *tp, /* transaction pointer */
xfs_rtblock_t bno, /* starting block number to allocate */
xfs_extlen_t minlen, /* minimum length to allocate */
xfs_extlen_t maxlen, /* maximum length to allocate */
xfs_extlen_t *len, /* out: actual length allocated */
xfs_rtxnum_t start, /* starting rtext number to allocate */
xfs_rtxlen_t minlen, /* minimum length to allocate */
xfs_rtxlen_t maxlen, /* maximum length to allocate */
xfs_rtxlen_t *len, /* out: actual length allocated */
int wasdel, /* was a delayed allocation extent */
xfs_extlen_t prod, /* extent product factor */
xfs_rtblock_t *rtblock); /* out: start block allocated */
xfs_rtxlen_t prod, /* extent product factor */
xfs_rtxnum_t *rtblock); /* out: start rtext allocated */
/*
* Free an extent in the realtime subvolume. Length is expressed in
* realtime extents, as is the block number.
*/
int /* error */
xfs_rtfree_extent(
struct xfs_trans *tp, /* transaction pointer */
xfs_rtblock_t bno, /* starting block number to free */
xfs_extlen_t len); /* length of extent freed */
/*
* Initialize realtime fields in the mount structure.
......@@ -87,8 +62,8 @@ int /* error */
xfs_rtpick_extent(
struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */
xfs_extlen_t len, /* allocation length (rtextents) */
xfs_rtblock_t *pick); /* result rt extent */
xfs_rtxlen_t len, /* allocation length (rtextents) */
xfs_rtxnum_t *pick); /* result rt extent */
/*
* Grow the realtime area of the filesystem.
......@@ -98,54 +73,11 @@ xfs_growfs_rt(
struct xfs_mount *mp, /* file system mount structure */
xfs_growfs_rt_t *in); /* user supplied growfs struct */
/*
* From xfs_rtbitmap.c
*/
int xfs_rtbuf_get(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t block, int issum, struct xfs_buf **bpp);
int xfs_rtcheck_range(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t start, xfs_extlen_t len, int val,
xfs_rtblock_t *new, int *stat);
int xfs_rtfind_back(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t start, xfs_rtblock_t limit,
xfs_rtblock_t *rtblock);
int xfs_rtfind_forw(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t start, xfs_rtblock_t limit,
xfs_rtblock_t *rtblock);
int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t start, xfs_extlen_t len, int val);
int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp,
int log, xfs_rtblock_t bbno, int delta,
struct xfs_buf **rbpp, xfs_fsblock_t *rsb,
xfs_suminfo_t *sum);
int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log,
xfs_rtblock_t bbno, int delta, struct xfs_buf **rbpp,
xfs_fsblock_t *rsb);
int xfs_rtfree_range(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t start, xfs_extlen_t len,
struct xfs_buf **rbpp, xfs_fsblock_t *rsb);
int xfs_rtalloc_query_range(struct xfs_mount *mp, struct xfs_trans *tp,
const struct xfs_rtalloc_rec *low_rec,
const struct xfs_rtalloc_rec *high_rec,
xfs_rtalloc_query_range_fn fn, void *priv);
int xfs_rtalloc_query_all(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtalloc_query_range_fn fn,
void *priv);
bool xfs_verify_rtbno(struct xfs_mount *mp, xfs_rtblock_t rtbno);
int xfs_rtalloc_extent_is_free(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_rtblock_t start, xfs_extlen_t len,
bool *is_free);
int xfs_rtalloc_reinit_frextents(struct xfs_mount *mp);
#else
# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb) (ENOSYS)
# define xfs_rtfree_extent(t,b,l) (ENOSYS)
# define xfs_rtpick_extent(m,t,l,rb) (ENOSYS)
# define xfs_growfs_rt(mp,in) (ENOSYS)
# define xfs_rtalloc_query_range(t,l,h,f,p) (ENOSYS)
# define xfs_rtalloc_query_all(m,t,f,p) (ENOSYS)
# define xfs_rtbuf_get(m,t,b,i,p) (ENOSYS)
# define xfs_verify_rtbno(m, r) (false)
# define xfs_rtalloc_extent_is_free(m,t,s,l,i) (ENOSYS)
# define xfs_rtallocate_extent(t,b,min,max,l,f,p,rb) (-ENOSYS)
# define xfs_rtpick_extent(m,t,l,rb) (-ENOSYS)
# define xfs_growfs_rt(mp,in) (-ENOSYS)
# define xfs_rtalloc_reinit_frextents(m) (0)
static inline int /* error */
xfs_rtmount_init(
......@@ -157,7 +89,7 @@ xfs_rtmount_init(
xfs_warn(mp, "Not built with CONFIG_XFS_RT");
return -ENOSYS;
}
# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (-ENOSYS))
# define xfs_rtunmount_inodes(m)
#endif /* CONFIG_XFS_RT */
......
......@@ -42,6 +42,7 @@
#include "xfs_xattr.h"
#include "xfs_iunlink_item.h"
#include "xfs_dahash_test.h"
#include "xfs_rtbitmap.h"
#include "scrub/stats.h"
#include <linux/magic.h>
......@@ -896,7 +897,7 @@ xfs_fs_statfs(
statp->f_blocks = sbp->sb_rblocks;
freertx = percpu_counter_sum_positive(&mp->m_frextents);
statp->f_bavail = statp->f_bfree = freertx * sbp->sb_rextsize;
statp->f_bavail = statp->f_bfree = xfs_rtx_to_rtb(mp, freertx);
}
return 0;
......
......@@ -24,6 +24,7 @@
#include "xfs_dquot_item.h"
#include "xfs_dquot.h"
#include "xfs_icache.h"
#include "xfs_rtbitmap.h"
struct kmem_cache *xfs_trans_cache;
......@@ -655,6 +656,10 @@ xfs_trans_unreserve_and_mod_sb(
mp->m_sb.sb_agcount += tp->t_agcount_delta;
mp->m_sb.sb_imax_pct += tp->t_imaxpct_delta;
mp->m_sb.sb_rextsize += tp->t_rextsize_delta;
if (tp->t_rextsize_delta) {
mp->m_rtxblklog = log2_if_power2(mp->m_sb.sb_rextsize);
mp->m_rtxblkmask = mask64_if_power2(mp->m_sb.sb_rextsize);
}
mp->m_sb.sb_rbmblocks += tp->t_rbmblocks_delta;
mp->m_sb.sb_rblocks += tp->t_rblocks_delta;
mp->m_sb.sb_rextents += tp->t_rextents_delta;
......@@ -1196,7 +1201,7 @@ xfs_trans_alloc_inode(
retry:
error = xfs_trans_alloc(mp, resv, dblocks,
rblocks / mp->m_sb.sb_rextsize,
xfs_extlen_to_rtxlen(mp, rblocks),
force ? XFS_TRANS_RESERVE : 0, &tp);
if (error)
return error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment