Commit 0efdc097 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'xfs-6.11-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Chandan Babu:

 - Do not call out v1 inodes with non-zero di_nlink field as being
   corrupt

 - Change xfs_finobt_count_blocks() to count "free inode btree" blocks
   rather than "inode btree" blocks

 - Don't report the number of trimmed bytes via FITRIM because the
   underlying storage isn't required to do anything and failed discard
   IOs aren't reported to the caller anyway

 - Fix incorrect setting of rm_owner field in an rmap query

 - Report missing disk offset range in an fsmap query

 - Obtain m_growlock when extending realtime section of the filesystem

 - Reset rootdir extent size hint after extending realtime section of
   the filesystem

* tag 'xfs-6.11-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: reset rootdir extent size hint after growfsrt
  xfs: take m_growlock when running growfsrt
  xfs: Fix missing interval for missing_owner in xfs fsmap
  xfs: use XFS_BUF_DADDR_NULL for daddrs in getfsmap code
  xfs: Fix the owner setting issue for rmap query in xfs fsmap
  xfs: don't bother reporting blocks trimmed via FITRIM
  xfs: xfs_finobt_count_blocks() walks the wrong btree
  xfs: fix folio dirtying for XFILE_ALLOC callers
  xfs: fix di_onlink checking for V1/V2 inodes
parents 35667a29 a24cae8f
...@@ -749,7 +749,7 @@ xfs_finobt_count_blocks( ...@@ -749,7 +749,7 @@ xfs_finobt_count_blocks(
if (error) if (error)
return error; return error;
cur = xfs_inobt_init_cursor(pag, tp, agbp); cur = xfs_finobt_init_cursor(pag, tp, agbp);
error = xfs_btree_count_blocks(cur, tree_blocks); error = xfs_btree_count_blocks(cur, tree_blocks);
xfs_btree_del_cursor(cur, error); xfs_btree_del_cursor(cur, error);
xfs_trans_brelse(tp, agbp); xfs_trans_brelse(tp, agbp);
......
...@@ -514,12 +514,18 @@ xfs_dinode_verify( ...@@ -514,12 +514,18 @@ xfs_dinode_verify(
return __this_address; return __this_address;
} }
if (dip->di_version > 1) { /*
* Historical note: xfsprogs in the 3.2 era set up its incore inodes to
* have di_nlink track the link count, even if the actual filesystem
* only supported V1 inodes (i.e. di_onlink). When writing out the
* ondisk inode, it would set both the ondisk di_nlink and di_onlink to
* the the incore di_nlink value, which is why we cannot check for
* di_nlink==0 on a V1 inode. V2/3 inodes would get written out with
* di_onlink==0, so we can check that.
*/
if (dip->di_version >= 2) {
if (dip->di_onlink) if (dip->di_onlink)
return __this_address; return __this_address;
} else {
if (dip->di_nlink)
return __this_address;
} }
/* don't allow invalid i_size */ /* don't allow invalid i_size */
......
...@@ -293,7 +293,7 @@ xfile_get_folio( ...@@ -293,7 +293,7 @@ xfile_get_folio(
* (potentially last) reference in xfile_put_folio. * (potentially last) reference in xfile_put_folio.
*/ */
if (flags & XFILE_ALLOC) if (flags & XFILE_ALLOC)
folio_set_dirty(folio); folio_mark_dirty(folio);
return folio; return folio;
} }
......
...@@ -158,8 +158,7 @@ static int ...@@ -158,8 +158,7 @@ static int
xfs_trim_gather_extents( xfs_trim_gather_extents(
struct xfs_perag *pag, struct xfs_perag *pag,
struct xfs_trim_cur *tcur, struct xfs_trim_cur *tcur,
struct xfs_busy_extents *extents, struct xfs_busy_extents *extents)
uint64_t *blocks_trimmed)
{ {
struct xfs_mount *mp = pag->pag_mount; struct xfs_mount *mp = pag->pag_mount;
struct xfs_trans *tp; struct xfs_trans *tp;
...@@ -280,7 +279,6 @@ xfs_trim_gather_extents( ...@@ -280,7 +279,6 @@ xfs_trim_gather_extents(
xfs_extent_busy_insert_discard(pag, fbno, flen, xfs_extent_busy_insert_discard(pag, fbno, flen,
&extents->extent_list); &extents->extent_list);
*blocks_trimmed += flen;
next_extent: next_extent:
if (tcur->by_bno) if (tcur->by_bno)
error = xfs_btree_increment(cur, 0, &i); error = xfs_btree_increment(cur, 0, &i);
...@@ -327,8 +325,7 @@ xfs_trim_perag_extents( ...@@ -327,8 +325,7 @@ xfs_trim_perag_extents(
struct xfs_perag *pag, struct xfs_perag *pag,
xfs_agblock_t start, xfs_agblock_t start,
xfs_agblock_t end, xfs_agblock_t end,
xfs_extlen_t minlen, xfs_extlen_t minlen)
uint64_t *blocks_trimmed)
{ {
struct xfs_trim_cur tcur = { struct xfs_trim_cur tcur = {
.start = start, .start = start,
...@@ -354,8 +351,7 @@ xfs_trim_perag_extents( ...@@ -354,8 +351,7 @@ xfs_trim_perag_extents(
extents->owner = extents; extents->owner = extents;
INIT_LIST_HEAD(&extents->extent_list); INIT_LIST_HEAD(&extents->extent_list);
error = xfs_trim_gather_extents(pag, &tcur, extents, error = xfs_trim_gather_extents(pag, &tcur, extents);
blocks_trimmed);
if (error) { if (error) {
kfree(extents); kfree(extents);
break; break;
...@@ -389,8 +385,7 @@ xfs_trim_datadev_extents( ...@@ -389,8 +385,7 @@ xfs_trim_datadev_extents(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_daddr_t start, xfs_daddr_t start,
xfs_daddr_t end, xfs_daddr_t end,
xfs_extlen_t minlen, xfs_extlen_t minlen)
uint64_t *blocks_trimmed)
{ {
xfs_agnumber_t start_agno, end_agno; xfs_agnumber_t start_agno, end_agno;
xfs_agblock_t start_agbno, end_agbno; xfs_agblock_t start_agbno, end_agbno;
...@@ -411,8 +406,7 @@ xfs_trim_datadev_extents( ...@@ -411,8 +406,7 @@ xfs_trim_datadev_extents(
if (start_agno == end_agno) if (start_agno == end_agno)
agend = end_agbno; agend = end_agbno;
error = xfs_trim_perag_extents(pag, start_agbno, agend, minlen, error = xfs_trim_perag_extents(pag, start_agbno, agend, minlen);
blocks_trimmed);
if (error) if (error)
last_error = error; last_error = error;
...@@ -431,9 +425,6 @@ struct xfs_trim_rtdev { ...@@ -431,9 +425,6 @@ struct xfs_trim_rtdev {
/* list of rt extents to free */ /* list of rt extents to free */
struct list_head extent_list; struct list_head extent_list;
/* pointer to count of blocks trimmed */
uint64_t *blocks_trimmed;
/* minimum length that caller allows us to trim */ /* minimum length that caller allows us to trim */
xfs_rtblock_t minlen_fsb; xfs_rtblock_t minlen_fsb;
...@@ -551,7 +542,6 @@ xfs_trim_gather_rtextent( ...@@ -551,7 +542,6 @@ xfs_trim_gather_rtextent(
busyp->length = rlen; busyp->length = rlen;
INIT_LIST_HEAD(&busyp->list); INIT_LIST_HEAD(&busyp->list);
list_add_tail(&busyp->list, &tr->extent_list); list_add_tail(&busyp->list, &tr->extent_list);
*tr->blocks_trimmed += rlen;
tr->restart_rtx = rec->ar_startext + rec->ar_extcount; tr->restart_rtx = rec->ar_startext + rec->ar_extcount;
return 0; return 0;
...@@ -562,13 +552,11 @@ xfs_trim_rtdev_extents( ...@@ -562,13 +552,11 @@ xfs_trim_rtdev_extents(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_daddr_t start, xfs_daddr_t start,
xfs_daddr_t end, xfs_daddr_t end,
xfs_daddr_t minlen, xfs_daddr_t minlen)
uint64_t *blocks_trimmed)
{ {
struct xfs_rtalloc_rec low = { }; struct xfs_rtalloc_rec low = { };
struct xfs_rtalloc_rec high = { }; struct xfs_rtalloc_rec high = { };
struct xfs_trim_rtdev tr = { struct xfs_trim_rtdev tr = {
.blocks_trimmed = blocks_trimmed,
.minlen_fsb = XFS_BB_TO_FSB(mp, minlen), .minlen_fsb = XFS_BB_TO_FSB(mp, minlen),
}; };
struct xfs_trans *tp; struct xfs_trans *tp;
...@@ -634,7 +622,7 @@ xfs_trim_rtdev_extents( ...@@ -634,7 +622,7 @@ xfs_trim_rtdev_extents(
return error; return error;
} }
#else #else
# define xfs_trim_rtdev_extents(m,s,e,n,b) (-EOPNOTSUPP) # define xfs_trim_rtdev_extents(...) (-EOPNOTSUPP)
#endif /* CONFIG_XFS_RT */ #endif /* CONFIG_XFS_RT */
/* /*
...@@ -661,7 +649,6 @@ xfs_ioc_trim( ...@@ -661,7 +649,6 @@ xfs_ioc_trim(
xfs_daddr_t start, end; xfs_daddr_t start, end;
xfs_extlen_t minlen; xfs_extlen_t minlen;
xfs_rfsblock_t max_blocks; xfs_rfsblock_t max_blocks;
uint64_t blocks_trimmed = 0;
int error, last_error = 0; int error, last_error = 0;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
...@@ -706,15 +693,13 @@ xfs_ioc_trim( ...@@ -706,15 +693,13 @@ xfs_ioc_trim(
end = start + BTOBBT(range.len) - 1; end = start + BTOBBT(range.len) - 1;
if (bdev_max_discard_sectors(mp->m_ddev_targp->bt_bdev)) { if (bdev_max_discard_sectors(mp->m_ddev_targp->bt_bdev)) {
error = xfs_trim_datadev_extents(mp, start, end, minlen, error = xfs_trim_datadev_extents(mp, start, end, minlen);
&blocks_trimmed);
if (error) if (error)
last_error = error; last_error = error;
} }
if (rt_bdev && !xfs_trim_should_stop()) { if (rt_bdev && !xfs_trim_should_stop()) {
error = xfs_trim_rtdev_extents(mp, start, end, minlen, error = xfs_trim_rtdev_extents(mp, start, end, minlen);
&blocks_trimmed);
if (error) if (error)
last_error = error; last_error = error;
} }
...@@ -722,7 +707,8 @@ xfs_ioc_trim( ...@@ -722,7 +707,8 @@ xfs_ioc_trim(
if (last_error) if (last_error)
return last_error; return last_error;
range.len = XFS_FSB_TO_B(mp, blocks_trimmed); range.len = min_t(unsigned long long, range.len,
XFS_FSB_TO_B(mp, max_blocks));
if (copy_to_user(urange, &range, sizeof(range))) if (copy_to_user(urange, &range, sizeof(range)))
return -EFAULT; return -EFAULT;
return 0; return 0;
......
...@@ -71,7 +71,7 @@ xfs_fsmap_owner_to_rmap( ...@@ -71,7 +71,7 @@ xfs_fsmap_owner_to_rmap(
switch (src->fmr_owner) { switch (src->fmr_owner) {
case 0: /* "lowest owner id possible" */ case 0: /* "lowest owner id possible" */
case -1ULL: /* "highest owner id possible" */ case -1ULL: /* "highest owner id possible" */
dest->rm_owner = 0; dest->rm_owner = src->fmr_owner;
break; break;
case XFS_FMR_OWN_FREE: case XFS_FMR_OWN_FREE:
dest->rm_owner = XFS_RMAP_OWN_NULL; dest->rm_owner = XFS_RMAP_OWN_NULL;
...@@ -162,6 +162,7 @@ struct xfs_getfsmap_info { ...@@ -162,6 +162,7 @@ struct xfs_getfsmap_info {
xfs_daddr_t next_daddr; /* next daddr we expect */ xfs_daddr_t next_daddr; /* next daddr we expect */
/* daddr of low fsmap key when we're using the rtbitmap */ /* daddr of low fsmap key when we're using the rtbitmap */
xfs_daddr_t low_daddr; xfs_daddr_t low_daddr;
xfs_daddr_t end_daddr; /* daddr of high fsmap key */
u64 missing_owner; /* owner of holes */ u64 missing_owner; /* owner of holes */
u32 dev; /* device id */ u32 dev; /* device id */
/* /*
...@@ -182,6 +183,7 @@ struct xfs_getfsmap_dev { ...@@ -182,6 +183,7 @@ struct xfs_getfsmap_dev {
int (*fn)(struct xfs_trans *tp, int (*fn)(struct xfs_trans *tp,
const struct xfs_fsmap *keys, const struct xfs_fsmap *keys,
struct xfs_getfsmap_info *info); struct xfs_getfsmap_info *info);
sector_t nr_sectors;
}; };
/* Compare two getfsmap device handlers. */ /* Compare two getfsmap device handlers. */
...@@ -252,7 +254,7 @@ xfs_getfsmap_rec_before_start( ...@@ -252,7 +254,7 @@ xfs_getfsmap_rec_before_start(
const struct xfs_rmap_irec *rec, const struct xfs_rmap_irec *rec,
xfs_daddr_t rec_daddr) xfs_daddr_t rec_daddr)
{ {
if (info->low_daddr != -1ULL) if (info->low_daddr != XFS_BUF_DADDR_NULL)
return rec_daddr < info->low_daddr; return rec_daddr < info->low_daddr;
if (info->low.rm_blockcount) if (info->low.rm_blockcount)
return xfs_rmap_compare(rec, &info->low) < 0; return xfs_rmap_compare(rec, &info->low) < 0;
...@@ -294,6 +296,18 @@ xfs_getfsmap_helper( ...@@ -294,6 +296,18 @@ xfs_getfsmap_helper(
return 0; return 0;
} }
/*
* For an info->last query, we're looking for a gap between the last
* mapping emitted and the high key specified by userspace. If the
* user's query spans less than 1 fsblock, then info->high and
* info->low will have the same rm_startblock, which causes rec_daddr
* and next_daddr to be the same. Therefore, use the end_daddr that
* we calculated from userspace's high key to synthesize the record.
* Note that if the btree query found a mapping, there won't be a gap.
*/
if (info->last && info->end_daddr != XFS_BUF_DADDR_NULL)
rec_daddr = info->end_daddr;
/* Are we just counting mappings? */ /* Are we just counting mappings? */
if (info->head->fmh_count == 0) { if (info->head->fmh_count == 0) {
if (info->head->fmh_entries == UINT_MAX) if (info->head->fmh_entries == UINT_MAX)
...@@ -904,17 +918,21 @@ xfs_getfsmap( ...@@ -904,17 +918,21 @@ xfs_getfsmap(
/* Set up our device handlers. */ /* Set up our device handlers. */
memset(handlers, 0, sizeof(handlers)); memset(handlers, 0, sizeof(handlers));
handlers[0].nr_sectors = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev); handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
if (use_rmap) if (use_rmap)
handlers[0].fn = xfs_getfsmap_datadev_rmapbt; handlers[0].fn = xfs_getfsmap_datadev_rmapbt;
else else
handlers[0].fn = xfs_getfsmap_datadev_bnobt; handlers[0].fn = xfs_getfsmap_datadev_bnobt;
if (mp->m_logdev_targp != mp->m_ddev_targp) { if (mp->m_logdev_targp != mp->m_ddev_targp) {
handlers[1].nr_sectors = XFS_FSB_TO_BB(mp,
mp->m_sb.sb_logblocks);
handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev); handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
handlers[1].fn = xfs_getfsmap_logdev; handlers[1].fn = xfs_getfsmap_logdev;
} }
#ifdef CONFIG_XFS_RT #ifdef CONFIG_XFS_RT
if (mp->m_rtdev_targp) { if (mp->m_rtdev_targp) {
handlers[2].nr_sectors = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev); handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
handlers[2].fn = xfs_getfsmap_rtdev_rtbitmap; handlers[2].fn = xfs_getfsmap_rtdev_rtbitmap;
} }
...@@ -946,6 +964,7 @@ xfs_getfsmap( ...@@ -946,6 +964,7 @@ xfs_getfsmap(
info.next_daddr = head->fmh_keys[0].fmr_physical + info.next_daddr = head->fmh_keys[0].fmr_physical +
head->fmh_keys[0].fmr_length; head->fmh_keys[0].fmr_length;
info.end_daddr = XFS_BUF_DADDR_NULL;
info.fsmap_recs = fsmap_recs; info.fsmap_recs = fsmap_recs;
info.head = head; info.head = head;
...@@ -966,8 +985,11 @@ xfs_getfsmap( ...@@ -966,8 +985,11 @@ xfs_getfsmap(
* low key, zero out the low key so that we get * low key, zero out the low key so that we get
* everything from the beginning. * everything from the beginning.
*/ */
if (handlers[i].dev == head->fmh_keys[1].fmr_device) if (handlers[i].dev == head->fmh_keys[1].fmr_device) {
dkeys[1] = head->fmh_keys[1]; dkeys[1] = head->fmh_keys[1];
info.end_daddr = min(handlers[i].nr_sectors - 1,
dkeys[1].fmr_physical);
}
if (handlers[i].dev > head->fmh_keys[0].fmr_device) if (handlers[i].dev > head->fmh_keys[0].fmr_device)
memset(&dkeys[0], 0, sizeof(struct xfs_fsmap)); memset(&dkeys[0], 0, sizeof(struct xfs_fsmap));
...@@ -983,7 +1005,7 @@ xfs_getfsmap( ...@@ -983,7 +1005,7 @@ xfs_getfsmap(
info.dev = handlers[i].dev; info.dev = handlers[i].dev;
info.last = false; info.last = false;
info.pag = NULL; info.pag = NULL;
info.low_daddr = -1ULL; info.low_daddr = XFS_BUF_DADDR_NULL;
info.low.rm_blockcount = 0; info.low.rm_blockcount = 0;
error = handlers[i].fn(tp, dkeys, &info); error = handlers[i].fn(tp, dkeys, &info);
if (error) if (error)
......
...@@ -784,6 +784,39 @@ xfs_alloc_rsum_cache( ...@@ -784,6 +784,39 @@ xfs_alloc_rsum_cache(
xfs_warn(mp, "could not allocate realtime summary cache"); xfs_warn(mp, "could not allocate realtime summary cache");
} }
/*
* If we changed the rt extent size (meaning there was no rt volume previously)
* and the root directory had EXTSZINHERIT and RTINHERIT set, it's possible
* that the extent size hint on the root directory is no longer congruent with
* the new rt extent size. Log the rootdir inode to fix this.
*/
static int
xfs_growfs_rt_fixup_extsize(
struct xfs_mount *mp)
{
struct xfs_inode *ip = mp->m_rootip;
struct xfs_trans *tp;
int error = 0;
xfs_ilock(ip, XFS_IOLOCK_EXCL);
if (!(ip->i_diflags & XFS_DIFLAG_RTINHERIT) ||
!(ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT))
goto out_iolock;
error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_ichange, 0, 0, false,
&tp);
if (error)
goto out_iolock;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = xfs_trans_commit(tp);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
out_iolock:
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return error;
}
/* /*
* Visible (exported) functions. * Visible (exported) functions.
*/ */
...@@ -812,6 +845,7 @@ xfs_growfs_rt( ...@@ -812,6 +845,7 @@ xfs_growfs_rt(
xfs_extlen_t rsumblocks; /* current number of rt summary blks */ xfs_extlen_t rsumblocks; /* current number of rt summary blks */
xfs_sb_t *sbp; /* old superblock */ xfs_sb_t *sbp; /* old superblock */
uint8_t *rsum_cache; /* old summary cache */ uint8_t *rsum_cache; /* old summary cache */
xfs_agblock_t old_rextsize = mp->m_sb.sb_rextsize;
sbp = &mp->m_sb; sbp = &mp->m_sb;
...@@ -821,34 +855,39 @@ xfs_growfs_rt( ...@@ -821,34 +855,39 @@ xfs_growfs_rt(
/* Needs to have been mounted with an rt device. */ /* Needs to have been mounted with an rt device. */
if (!XFS_IS_REALTIME_MOUNT(mp)) if (!XFS_IS_REALTIME_MOUNT(mp))
return -EINVAL; return -EINVAL;
if (!mutex_trylock(&mp->m_growlock))
return -EWOULDBLOCK;
/* /*
* Mount should fail if the rt bitmap/summary files don't load, but * Mount should fail if the rt bitmap/summary files don't load, but
* we'll check anyway. * we'll check anyway.
*/ */
error = -EINVAL;
if (!mp->m_rbmip || !mp->m_rsumip) if (!mp->m_rbmip || !mp->m_rsumip)
return -EINVAL; goto out_unlock;
/* Shrink not supported. */ /* Shrink not supported. */
if (in->newblocks <= sbp->sb_rblocks) if (in->newblocks <= sbp->sb_rblocks)
return -EINVAL; goto out_unlock;
/* Can only change rt extent size when adding rt volume. */ /* Can only change rt extent size when adding rt volume. */
if (sbp->sb_rblocks > 0 && in->extsize != sbp->sb_rextsize) if (sbp->sb_rblocks > 0 && in->extsize != sbp->sb_rextsize)
return -EINVAL; goto out_unlock;
/* Range check the extent size. */ /* Range check the extent size. */
if (XFS_FSB_TO_B(mp, in->extsize) > XFS_MAX_RTEXTSIZE || if (XFS_FSB_TO_B(mp, in->extsize) > XFS_MAX_RTEXTSIZE ||
XFS_FSB_TO_B(mp, in->extsize) < XFS_MIN_RTEXTSIZE) XFS_FSB_TO_B(mp, in->extsize) < XFS_MIN_RTEXTSIZE)
return -EINVAL; goto out_unlock;
/* Unsupported realtime features. */ /* Unsupported realtime features. */
error = -EOPNOTSUPP;
if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp)) if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp))
return -EOPNOTSUPP; goto out_unlock;
nrblocks = in->newblocks; nrblocks = in->newblocks;
error = xfs_sb_validate_fsb_count(sbp, nrblocks); error = xfs_sb_validate_fsb_count(sbp, nrblocks);
if (error) if (error)
return error; goto out_unlock;
/* /*
* Read in the last block of the device, make sure it exists. * Read in the last block of the device, make sure it exists.
*/ */
...@@ -856,7 +895,7 @@ xfs_growfs_rt( ...@@ -856,7 +895,7 @@ xfs_growfs_rt(
XFS_FSB_TO_BB(mp, nrblocks - 1), XFS_FSB_TO_BB(mp, nrblocks - 1),
XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL); XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
if (error) if (error)
return error; goto out_unlock;
xfs_buf_relse(bp); xfs_buf_relse(bp);
/* /*
...@@ -864,8 +903,10 @@ xfs_growfs_rt( ...@@ -864,8 +903,10 @@ xfs_growfs_rt(
*/ */
nrextents = nrblocks; nrextents = nrblocks;
do_div(nrextents, in->extsize); do_div(nrextents, in->extsize);
if (!xfs_validate_rtextents(nrextents)) if (!xfs_validate_rtextents(nrextents)) {
return -EINVAL; error = -EINVAL;
goto out_unlock;
}
nrbmblocks = xfs_rtbitmap_blockcount(mp, nrextents); nrbmblocks = xfs_rtbitmap_blockcount(mp, nrextents);
nrextslog = xfs_compute_rextslog(nrextents); nrextslog = xfs_compute_rextslog(nrextents);
nrsumlevels = nrextslog + 1; nrsumlevels = nrextslog + 1;
...@@ -876,8 +917,11 @@ xfs_growfs_rt( ...@@ -876,8 +917,11 @@ xfs_growfs_rt(
* the log. This prevents us from getting a log overflow, * the log. This prevents us from getting a log overflow,
* since we'll log basically the whole summary file at once. * since we'll log basically the whole summary file at once.
*/ */
if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1)) if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1)) {
return -EINVAL; error = -EINVAL;
goto out_unlock;
}
/* /*
* Get the old block counts for bitmap and summary inodes. * Get the old block counts for bitmap and summary inodes.
* These can't change since other growfs callers are locked out. * These can't change since other growfs callers are locked out.
...@@ -889,10 +933,10 @@ xfs_growfs_rt( ...@@ -889,10 +933,10 @@ xfs_growfs_rt(
*/ */
error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, mp->m_rbmip); error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, mp->m_rbmip);
if (error) if (error)
return error; goto out_unlock;
error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, mp->m_rsumip); error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, mp->m_rsumip);
if (error) if (error)
return error; goto out_unlock;
rsum_cache = mp->m_rsum_cache; rsum_cache = mp->m_rsum_cache;
if (nrbmblocks != sbp->sb_rbmblocks) if (nrbmblocks != sbp->sb_rbmblocks)
...@@ -1036,6 +1080,12 @@ xfs_growfs_rt( ...@@ -1036,6 +1080,12 @@ xfs_growfs_rt(
if (error) if (error)
goto out_free; goto out_free;
if (old_rextsize != in->extsize) {
error = xfs_growfs_rt_fixup_extsize(mp);
if (error)
goto out_free;
}
/* Update secondary superblocks now the physical grow has completed */ /* Update secondary superblocks now the physical grow has completed */
error = xfs_update_secondary_sbs(mp); error = xfs_update_secondary_sbs(mp);
...@@ -1059,6 +1109,8 @@ xfs_growfs_rt( ...@@ -1059,6 +1109,8 @@ xfs_growfs_rt(
} }
} }
out_unlock:
mutex_unlock(&mp->m_growlock);
return 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