mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
xfs: Replace per-ag array with a radix tree
The use of an array for the per-ag structures requires reallocation of the array when growing the filesystem. This requires locking access to the array to avoid use after free situations, and the locking is difficult to get right. To avoid needing to reallocate an array, change the per-ag structures to an allocated object per ag and index them using a tree structure. The AGs are always densely indexed (hence the use of an array), but the number supported is 2^32 and lookups tend to be random and hence indexing needs to scale. A simple choice is a radix tree - it works well with this sort of index. This change also removes another large contiguous allocation from the mount/growfs path in XFS. The growing process now needs to change to only initialise the new AGs required for the extra space, and as such only needs to exclusively lock the tree for inserts. The rest of the code only needs to lock the tree while doing lookups, and hence this will remove all the deadlocks that currently occur on the m_perag_lock as it is now an innermost lock. The lock is also changed to a spinlock from a read/write lock as the hold time is now extremely short. To complete the picture, the per-ag structures will need to be reference counted to ensure that we don't free/modify them while they are still in use. This will be done in subsequent patch. Signed-off-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
parent
44b56e0a1a
commit
1c1c6ebcf5
@ -2276,7 +2276,6 @@ xfs_alloc_vextent(
|
|||||||
* These three force us into a single a.g.
|
* These three force us into a single a.g.
|
||||||
*/
|
*/
|
||||||
args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
args->pag = xfs_perag_get(mp, args->agno);
|
args->pag = xfs_perag_get(mp, args->agno);
|
||||||
args->minleft = 0;
|
args->minleft = 0;
|
||||||
error = xfs_alloc_fix_freelist(args, 0);
|
error = xfs_alloc_fix_freelist(args, 0);
|
||||||
@ -2286,14 +2285,12 @@ xfs_alloc_vextent(
|
|||||||
goto error0;
|
goto error0;
|
||||||
}
|
}
|
||||||
if (!args->agbp) {
|
if (!args->agbp) {
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
trace_xfs_alloc_vextent_noagbp(args);
|
trace_xfs_alloc_vextent_noagbp(args);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
|
args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
|
||||||
if ((error = xfs_alloc_ag_vextent(args)))
|
if ((error = xfs_alloc_ag_vextent(args)))
|
||||||
goto error0;
|
goto error0;
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
break;
|
break;
|
||||||
case XFS_ALLOCTYPE_START_BNO:
|
case XFS_ALLOCTYPE_START_BNO:
|
||||||
/*
|
/*
|
||||||
@ -2345,7 +2342,6 @@ xfs_alloc_vextent(
|
|||||||
* Loop over allocation groups twice; first time with
|
* Loop over allocation groups twice; first time with
|
||||||
* trylock set, second time without.
|
* trylock set, second time without.
|
||||||
*/
|
*/
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
args->pag = xfs_perag_get(mp, args->agno);
|
args->pag = xfs_perag_get(mp, args->agno);
|
||||||
if (no_min) args->minleft = 0;
|
if (no_min) args->minleft = 0;
|
||||||
@ -2408,7 +2404,6 @@ xfs_alloc_vextent(
|
|||||||
}
|
}
|
||||||
xfs_perag_put(args->pag);
|
xfs_perag_put(args->pag);
|
||||||
}
|
}
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) {
|
if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) {
|
||||||
if (args->agno == sagno)
|
if (args->agno == sagno)
|
||||||
mp->m_agfrotor = (mp->m_agfrotor + 1) %
|
mp->m_agfrotor = (mp->m_agfrotor + 1) %
|
||||||
@ -2438,7 +2433,6 @@ xfs_alloc_vextent(
|
|||||||
return 0;
|
return 0;
|
||||||
error0:
|
error0:
|
||||||
xfs_perag_put(args->pag);
|
xfs_perag_put(args->pag);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2463,7 +2457,6 @@ xfs_free_extent(
|
|||||||
args.agno = XFS_FSB_TO_AGNO(args.mp, bno);
|
args.agno = XFS_FSB_TO_AGNO(args.mp, bno);
|
||||||
ASSERT(args.agno < args.mp->m_sb.sb_agcount);
|
ASSERT(args.agno < args.mp->m_sb.sb_agcount);
|
||||||
args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
|
args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno);
|
||||||
down_read(&args.mp->m_peraglock);
|
|
||||||
args.pag = xfs_perag_get(args.mp, args.agno);
|
args.pag = xfs_perag_get(args.mp, args.agno);
|
||||||
if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING)))
|
if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING)))
|
||||||
goto error0;
|
goto error0;
|
||||||
@ -2475,7 +2468,6 @@ xfs_free_extent(
|
|||||||
error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
|
error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
|
||||||
error0:
|
error0:
|
||||||
xfs_perag_put(args.pag);
|
xfs_perag_put(args.pag);
|
||||||
up_read(&args.mp->m_peraglock);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2629,14 +2629,12 @@ xfs_bmap_btalloc(
|
|||||||
if (startag == NULLAGNUMBER)
|
if (startag == NULLAGNUMBER)
|
||||||
startag = ag = 0;
|
startag = ag = 0;
|
||||||
notinit = 0;
|
notinit = 0;
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
pag = xfs_perag_get(mp, ag);
|
pag = xfs_perag_get(mp, ag);
|
||||||
while (blen < ap->alen) {
|
while (blen < ap->alen) {
|
||||||
if (!pag->pagf_init &&
|
if (!pag->pagf_init &&
|
||||||
(error = xfs_alloc_pagf_init(mp, args.tp,
|
(error = xfs_alloc_pagf_init(mp, args.tp,
|
||||||
ag, XFS_ALLOC_FLAG_TRYLOCK))) {
|
ag, XFS_ALLOC_FLAG_TRYLOCK))) {
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -2669,10 +2667,8 @@ xfs_bmap_btalloc(
|
|||||||
|
|
||||||
error = xfs_filestream_new_ag(ap, &ag);
|
error = xfs_filestream_new_ag(ap, &ag);
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
if (error) {
|
if (error)
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
/* loop again to set 'blen'*/
|
/* loop again to set 'blen'*/
|
||||||
startag = NULLAGNUMBER;
|
startag = NULLAGNUMBER;
|
||||||
@ -2688,7 +2684,6 @@ xfs_bmap_btalloc(
|
|||||||
pag = xfs_perag_get(mp, ag);
|
pag = xfs_perag_get(mp, ag);
|
||||||
}
|
}
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
/*
|
/*
|
||||||
* Since the above loop did a BUF_TRYLOCK, it is
|
* Since the above loop did a BUF_TRYLOCK, it is
|
||||||
* possible that there is space for this request.
|
* possible that there is space for this request.
|
||||||
|
@ -253,8 +253,7 @@ next_ag:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the allocation group number for a file or a directory, updating inode
|
* Set the allocation group number for a file or a directory, updating inode
|
||||||
* references and per-AG references as appropriate. Must be called with the
|
* references and per-AG references as appropriate.
|
||||||
* m_peraglock held in read mode.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
_xfs_filestream_update_ag(
|
_xfs_filestream_update_ag(
|
||||||
@ -456,10 +455,10 @@ xfs_filestream_unmount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the mount point's m_perag array is going to be reallocated, all
|
* If the mount point's m_perag tree is going to be modified, all
|
||||||
* outstanding cache entries must be flushed to avoid accessing reference count
|
* outstanding cache entries must be flushed to avoid accessing reference count
|
||||||
* addresses that have been freed. The call to xfs_filestream_flush() must be
|
* addresses that have been freed. The call to xfs_filestream_flush() must be
|
||||||
* made inside the block that holds the m_peraglock in write mode to do the
|
* made inside the block that holds the m_perag_lock in write mode to do the
|
||||||
* reallocation.
|
* reallocation.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -531,7 +530,6 @@ xfs_filestream_associate(
|
|||||||
|
|
||||||
mp = pip->i_mount;
|
mp = pip->i_mount;
|
||||||
cache = mp->m_filestream;
|
cache = mp->m_filestream;
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have a problem, Houston.
|
* We have a problem, Houston.
|
||||||
@ -548,10 +546,8 @@ xfs_filestream_associate(
|
|||||||
*
|
*
|
||||||
* So, if we can't get the iolock without sleeping then just give up
|
* So, if we can't get the iolock without sleeping then just give up
|
||||||
*/
|
*/
|
||||||
if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) {
|
if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL))
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
/* If the parent directory is already in the cache, use its AG. */
|
/* If the parent directory is already in the cache, use its AG. */
|
||||||
item = xfs_mru_cache_lookup(cache, pip->i_ino);
|
item = xfs_mru_cache_lookup(cache, pip->i_ino);
|
||||||
@ -606,7 +602,6 @@ exit_did_pick:
|
|||||||
|
|
||||||
exit:
|
exit:
|
||||||
xfs_iunlock(pip, XFS_IOLOCK_EXCL);
|
xfs_iunlock(pip, XFS_IOLOCK_EXCL);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
return -err;
|
return -err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,27 +167,14 @@ xfs_growfs_data_private(
|
|||||||
}
|
}
|
||||||
new = nb - mp->m_sb.sb_dblocks;
|
new = nb - mp->m_sb.sb_dblocks;
|
||||||
oagcount = mp->m_sb.sb_agcount;
|
oagcount = mp->m_sb.sb_agcount;
|
||||||
|
|
||||||
|
/* allocate the new per-ag structures */
|
||||||
if (nagcount > oagcount) {
|
if (nagcount > oagcount) {
|
||||||
void *new_perag, *old_perag;
|
error = xfs_initialize_perag(mp, nagcount, &nagimax);
|
||||||
|
if (error)
|
||||||
xfs_filestream_flush(mp);
|
return error;
|
||||||
|
|
||||||
new_perag = kmem_zalloc(sizeof(xfs_perag_t) * nagcount,
|
|
||||||
KM_MAYFAIL);
|
|
||||||
if (!new_perag)
|
|
||||||
return XFS_ERROR(ENOMEM);
|
|
||||||
|
|
||||||
down_write(&mp->m_peraglock);
|
|
||||||
memcpy(new_perag, mp->m_perag, sizeof(xfs_perag_t) * oagcount);
|
|
||||||
old_perag = mp->m_perag;
|
|
||||||
mp->m_perag = new_perag;
|
|
||||||
|
|
||||||
mp->m_flags |= XFS_MOUNT_32BITINODES;
|
|
||||||
nagimax = xfs_initialize_perag(mp, nagcount);
|
|
||||||
up_write(&mp->m_peraglock);
|
|
||||||
|
|
||||||
kmem_free(old_perag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
|
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
|
||||||
tp->t_flags |= XFS_TRANS_RESERVE;
|
tp->t_flags |= XFS_TRANS_RESERVE;
|
||||||
if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
|
if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
|
||||||
@ -196,6 +183,11 @@ xfs_growfs_data_private(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write new AG headers to disk. Non-transactional, but written
|
||||||
|
* synchronously so they are completed prior to the growfs transaction
|
||||||
|
* being logged.
|
||||||
|
*/
|
||||||
nfree = 0;
|
nfree = 0;
|
||||||
for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) {
|
for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) {
|
||||||
/*
|
/*
|
||||||
@ -359,6 +351,12 @@ xfs_growfs_data_private(
|
|||||||
goto error0;
|
goto error0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update changed superblock fields transactionally. These are not
|
||||||
|
* seen by the rest of the world until the transaction commit applies
|
||||||
|
* them atomically to the superblock.
|
||||||
|
*/
|
||||||
if (nagcount > oagcount)
|
if (nagcount > oagcount)
|
||||||
xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
|
||||||
if (nb > mp->m_sb.sb_dblocks)
|
if (nb > mp->m_sb.sb_dblocks)
|
||||||
@ -369,9 +367,9 @@ xfs_growfs_data_private(
|
|||||||
if (dpct)
|
if (dpct)
|
||||||
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
|
||||||
error = xfs_trans_commit(tp, 0);
|
error = xfs_trans_commit(tp, 0);
|
||||||
if (error) {
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
/* New allocation groups fully initialized, so update mount struct */
|
/* New allocation groups fully initialized, so update mount struct */
|
||||||
if (nagimax)
|
if (nagimax)
|
||||||
mp->m_maxagi = nagimax;
|
mp->m_maxagi = nagimax;
|
||||||
@ -381,6 +379,8 @@ xfs_growfs_data_private(
|
|||||||
mp->m_maxicount = icount << mp->m_sb.sb_inopblog;
|
mp->m_maxicount = icount << mp->m_sb.sb_inopblog;
|
||||||
} else
|
} else
|
||||||
mp->m_maxicount = 0;
|
mp->m_maxicount = 0;
|
||||||
|
|
||||||
|
/* update secondary superblocks. */
|
||||||
for (agno = 1; agno < nagcount; agno++) {
|
for (agno = 1; agno < nagcount; agno++) {
|
||||||
error = xfs_read_buf(mp, mp->m_ddev_targp,
|
error = xfs_read_buf(mp, mp->m_ddev_targp,
|
||||||
XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
|
XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
|
||||||
|
@ -383,11 +383,9 @@ xfs_ialloc_ag_alloc(
|
|||||||
newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0);
|
newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0);
|
||||||
be32_add_cpu(&agi->agi_count, newlen);
|
be32_add_cpu(&agi->agi_count, newlen);
|
||||||
be32_add_cpu(&agi->agi_freecount, newlen);
|
be32_add_cpu(&agi->agi_freecount, newlen);
|
||||||
down_read(&args.mp->m_peraglock);
|
|
||||||
pag = xfs_perag_get(args.mp, agno);
|
pag = xfs_perag_get(args.mp, agno);
|
||||||
pag->pagi_freecount += newlen;
|
pag->pagi_freecount += newlen;
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
up_read(&args.mp->m_peraglock);
|
|
||||||
agi->agi_newino = cpu_to_be32(newino);
|
agi->agi_newino = cpu_to_be32(newino);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -489,7 +487,6 @@ xfs_ialloc_ag_select(
|
|||||||
*/
|
*/
|
||||||
agno = pagno;
|
agno = pagno;
|
||||||
flags = XFS_ALLOC_FLAG_TRYLOCK;
|
flags = XFS_ALLOC_FLAG_TRYLOCK;
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
pag = xfs_perag_get(mp, agno);
|
pag = xfs_perag_get(mp, agno);
|
||||||
if (!pag->pagi_init) {
|
if (!pag->pagi_init) {
|
||||||
@ -531,7 +528,6 @@ xfs_ialloc_ag_select(
|
|||||||
goto nextag;
|
goto nextag;
|
||||||
}
|
}
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
return agbp;
|
return agbp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -544,18 +540,14 @@ nextag:
|
|||||||
* No point in iterating over the rest, if we're shutting
|
* No point in iterating over the rest, if we're shutting
|
||||||
* down.
|
* down.
|
||||||
*/
|
*/
|
||||||
if (XFS_FORCED_SHUTDOWN(mp)) {
|
if (XFS_FORCED_SHUTDOWN(mp))
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
agno++;
|
agno++;
|
||||||
if (agno >= agcount)
|
if (agno >= agcount)
|
||||||
agno = 0;
|
agno = 0;
|
||||||
if (agno == pagno) {
|
if (agno == pagno) {
|
||||||
if (flags == 0) {
|
if (flags == 0)
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -777,16 +769,13 @@ nextag:
|
|||||||
*inop = NULLFSINO;
|
*inop = NULLFSINO;
|
||||||
return noroom ? ENOSPC : 0;
|
return noroom ? ENOSPC : 0;
|
||||||
}
|
}
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
pag = xfs_perag_get(mp, tagno);
|
pag = xfs_perag_get(mp, tagno);
|
||||||
if (pag->pagi_inodeok == 0) {
|
if (pag->pagi_inodeok == 0) {
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
goto nextag;
|
goto nextag;
|
||||||
}
|
}
|
||||||
error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp);
|
error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp);
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
if (error)
|
if (error)
|
||||||
goto nextag;
|
goto nextag;
|
||||||
agi = XFS_BUF_TO_AGI(agbp);
|
agi = XFS_BUF_TO_AGI(agbp);
|
||||||
@ -1015,9 +1004,7 @@ alloc_inode:
|
|||||||
goto error0;
|
goto error0;
|
||||||
be32_add_cpu(&agi->agi_freecount, -1);
|
be32_add_cpu(&agi->agi_freecount, -1);
|
||||||
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
|
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
pag->pagi_freecount--;
|
pag->pagi_freecount--;
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
|
|
||||||
error = xfs_check_agi_freecount(cur, agi);
|
error = xfs_check_agi_freecount(cur, agi);
|
||||||
if (error)
|
if (error)
|
||||||
@ -1100,9 +1087,7 @@ xfs_difree(
|
|||||||
/*
|
/*
|
||||||
* Get the allocation group header.
|
* Get the allocation group header.
|
||||||
*/
|
*/
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
|
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
cmn_err(CE_WARN,
|
cmn_err(CE_WARN,
|
||||||
"xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.",
|
"xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.",
|
||||||
@ -1169,11 +1154,9 @@ xfs_difree(
|
|||||||
be32_add_cpu(&agi->agi_count, -ilen);
|
be32_add_cpu(&agi->agi_count, -ilen);
|
||||||
be32_add_cpu(&agi->agi_freecount, -(ilen - 1));
|
be32_add_cpu(&agi->agi_freecount, -(ilen - 1));
|
||||||
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT);
|
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT);
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
pag = xfs_perag_get(mp, agno);
|
pag = xfs_perag_get(mp, agno);
|
||||||
pag->pagi_freecount -= ilen - 1;
|
pag->pagi_freecount -= ilen - 1;
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen);
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen);
|
||||||
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1));
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1));
|
||||||
|
|
||||||
@ -1202,11 +1185,9 @@ xfs_difree(
|
|||||||
*/
|
*/
|
||||||
be32_add_cpu(&agi->agi_freecount, 1);
|
be32_add_cpu(&agi->agi_freecount, 1);
|
||||||
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
|
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
pag = xfs_perag_get(mp, agno);
|
pag = xfs_perag_get(mp, agno);
|
||||||
pag->pagi_freecount++;
|
pag->pagi_freecount++;
|
||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1328,9 +1309,7 @@ xfs_imap(
|
|||||||
xfs_buf_t *agbp; /* agi buffer */
|
xfs_buf_t *agbp; /* agi buffer */
|
||||||
int i; /* temp state */
|
int i; /* temp state */
|
||||||
|
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
|
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
|
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
|
||||||
"xfs_ialloc_read_agi() returned "
|
"xfs_ialloc_read_agi() returned "
|
||||||
|
@ -420,9 +420,7 @@ xfs_bulkstat(
|
|||||||
while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
|
while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
|
||||||
cond_resched();
|
cond_resched();
|
||||||
bp = NULL;
|
bp = NULL;
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
|
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
/*
|
/*
|
||||||
* Skip this allocation group and go to the next one.
|
* Skip this allocation group and go to the next one.
|
||||||
@ -849,9 +847,7 @@ xfs_inumbers(
|
|||||||
agbp = NULL;
|
agbp = NULL;
|
||||||
while (left > 0 && agno < mp->m_sb.sb_agcount) {
|
while (left > 0 && agno < mp->m_sb.sb_agcount) {
|
||||||
if (agbp == NULL) {
|
if (agbp == NULL) {
|
||||||
down_read(&mp->m_peraglock);
|
|
||||||
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
|
error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
|
||||||
up_read(&mp->m_peraglock);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
/*
|
/*
|
||||||
* If we can't read the AGI of this ag,
|
* If we can't read the AGI of this ag,
|
||||||
|
@ -209,13 +209,16 @@ STATIC void
|
|||||||
xfs_free_perag(
|
xfs_free_perag(
|
||||||
xfs_mount_t *mp)
|
xfs_mount_t *mp)
|
||||||
{
|
{
|
||||||
if (mp->m_perag) {
|
xfs_agnumber_t agno;
|
||||||
int agno;
|
struct xfs_perag *pag;
|
||||||
|
|
||||||
for (agno = 0; agno < mp->m_maxagi; agno++)
|
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
|
||||||
if (mp->m_perag[agno].pagb_list)
|
spin_lock(&mp->m_perag_lock);
|
||||||
kmem_free(mp->m_perag[agno].pagb_list);
|
pag = radix_tree_delete(&mp->m_perag_tree, agno);
|
||||||
kmem_free(mp->m_perag);
|
spin_unlock(&mp->m_perag_lock);
|
||||||
|
ASSERT(pag);
|
||||||
|
kmem_free(pag->pagb_list);
|
||||||
|
kmem_free(pag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,10 +392,11 @@ xfs_initialize_perag_icache(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xfs_agnumber_t
|
int
|
||||||
xfs_initialize_perag(
|
xfs_initialize_perag(
|
||||||
xfs_mount_t *mp,
|
xfs_mount_t *mp,
|
||||||
xfs_agnumber_t agcount)
|
xfs_agnumber_t agcount,
|
||||||
|
xfs_agnumber_t *maxagi)
|
||||||
{
|
{
|
||||||
xfs_agnumber_t index, max_metadata;
|
xfs_agnumber_t index, max_metadata;
|
||||||
xfs_perag_t *pag;
|
xfs_perag_t *pag;
|
||||||
@ -405,6 +409,33 @@ xfs_initialize_perag(
|
|||||||
agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
|
agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
|
||||||
ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);
|
ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Walk the current per-ag tree so we don't try to initialise AGs
|
||||||
|
* that already exist (growfs case). Allocate and insert all the
|
||||||
|
* AGs we don't find ready for initialisation.
|
||||||
|
*/
|
||||||
|
for (index = 0; index < agcount; index++) {
|
||||||
|
pag = xfs_perag_get(mp, index);
|
||||||
|
if (pag) {
|
||||||
|
xfs_perag_put(pag);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
|
||||||
|
if (!pag)
|
||||||
|
return -ENOMEM;
|
||||||
|
if (radix_tree_preload(GFP_NOFS))
|
||||||
|
return -ENOMEM;
|
||||||
|
spin_lock(&mp->m_perag_lock);
|
||||||
|
if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
|
||||||
|
BUG();
|
||||||
|
spin_unlock(&mp->m_perag_lock);
|
||||||
|
kmem_free(pag);
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
spin_unlock(&mp->m_perag_lock);
|
||||||
|
radix_tree_preload_end();
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear the mount flag if no inode can overflow 32 bits
|
/* Clear the mount flag if no inode can overflow 32 bits
|
||||||
* on this filesystem, or if specifically requested..
|
* on this filesystem, or if specifically requested..
|
||||||
*/
|
*/
|
||||||
@ -454,7 +485,9 @@ xfs_initialize_perag(
|
|||||||
xfs_perag_put(pag);
|
xfs_perag_put(pag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return index;
|
if (maxagi)
|
||||||
|
*maxagi = index;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1155,13 +1188,13 @@ xfs_mountfs(
|
|||||||
/*
|
/*
|
||||||
* Allocate and initialize the per-ag data.
|
* Allocate and initialize the per-ag data.
|
||||||
*/
|
*/
|
||||||
init_rwsem(&mp->m_peraglock);
|
spin_lock_init(&mp->m_perag_lock);
|
||||||
mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t),
|
INIT_RADIX_TREE(&mp->m_perag_tree, GFP_NOFS);
|
||||||
KM_MAYFAIL);
|
error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
|
||||||
if (!mp->m_perag)
|
if (error) {
|
||||||
|
cmn_err(CE_WARN, "XFS: Failed per-ag init: %d", error);
|
||||||
goto out_remove_uuid;
|
goto out_remove_uuid;
|
||||||
|
}
|
||||||
mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount);
|
|
||||||
|
|
||||||
if (!sbp->sb_logblocks) {
|
if (!sbp->sb_logblocks) {
|
||||||
cmn_err(CE_WARN, "XFS: no log defined");
|
cmn_err(CE_WARN, "XFS: no log defined");
|
||||||
|
@ -207,8 +207,8 @@ typedef struct xfs_mount {
|
|||||||
uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */
|
uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */
|
||||||
uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */
|
uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */
|
||||||
uint m_in_maxlevels; /* max inobt btree levels. */
|
uint m_in_maxlevels; /* max inobt btree levels. */
|
||||||
struct xfs_perag *m_perag; /* per-ag accounting info */
|
struct radix_tree_root m_perag_tree; /* per-ag accounting info */
|
||||||
struct rw_semaphore m_peraglock; /* lock for m_perag (pointer) */
|
spinlock_t m_perag_lock; /* lock for m_perag_tree */
|
||||||
struct mutex m_growlock; /* growfs mutex */
|
struct mutex m_growlock; /* growfs mutex */
|
||||||
int m_fixedfsid[2]; /* unchanged for life of FS */
|
int m_fixedfsid[2]; /* unchanged for life of FS */
|
||||||
uint m_dmevmask; /* DMI events for this FS */
|
uint m_dmevmask; /* DMI events for this FS */
|
||||||
@ -389,7 +389,12 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
|
|||||||
static inline struct xfs_perag *
|
static inline struct xfs_perag *
|
||||||
xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno)
|
xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno)
|
||||||
{
|
{
|
||||||
return &mp->m_perag[agno];
|
struct xfs_perag *pag;
|
||||||
|
|
||||||
|
spin_lock(&mp->m_perag_lock);
|
||||||
|
pag = radix_tree_lookup(&mp->m_perag_tree, agno);
|
||||||
|
spin_unlock(&mp->m_perag_lock);
|
||||||
|
return pag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@ -450,7 +455,8 @@ extern struct xfs_dmops xfs_dmcore_xfs;
|
|||||||
#endif /* __KERNEL__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
extern void xfs_mod_sb(struct xfs_trans *, __int64_t);
|
extern void xfs_mod_sb(struct xfs_trans *, __int64_t);
|
||||||
extern xfs_agnumber_t xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t);
|
extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t,
|
||||||
|
xfs_agnumber_t *);
|
||||||
extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
|
extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
|
||||||
extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
|
extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user