xfs: only lock the rt bitmap inode once per allocation

Currently both xfs_rtpick_extent and xfs_rtallocate_extent call
xfs_trans_iget to grab and lock the rt bitmap inode, which results in a
deadlock since the removal of the lock recursion counters in commit

	"xfs: simplify inode to transaction joining"

Fix this by acquiring and locking the inode in xfs_bmap_rtalloc before
calling into xfs_rtpick_extent and xfs_rtallocate_extent.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
Christoph Hellwig 2011-01-25 09:06:19 +00:00 коммит произвёл Alex Elder
Родитель 24446fc66f
Коммит 04e99455ea
2 изменённых файлов: 24 добавлений и 21 удалений

Просмотреть файл

@ -2333,6 +2333,7 @@ xfs_bmap_rtalloc(
xfs_extlen_t prod = 0; /* product factor for allocators */ xfs_extlen_t prod = 0; /* product factor for allocators */
xfs_extlen_t ralen = 0; /* realtime allocation length */ xfs_extlen_t ralen = 0; /* realtime allocation length */
xfs_extlen_t align; /* minimum allocation alignment */ xfs_extlen_t align; /* minimum allocation alignment */
xfs_inode_t *ip; /* bitmap incore inode */
xfs_rtblock_t rtb; xfs_rtblock_t rtb;
mp = ap->ip->i_mount; mp = ap->ip->i_mount;
@ -2365,6 +2366,16 @@ xfs_bmap_rtalloc(
*/ */
if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN) if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN)
ralen = MAXEXTLEN / mp->m_sb.sb_rextsize; ralen = MAXEXTLEN / mp->m_sb.sb_rextsize;
/*
* Lock out other modifications to the RT bitmap inode.
*/
error = xfs_trans_iget(mp, ap->tp, mp->m_sb.sb_rbmino, 0,
XFS_ILOCK_EXCL, &ip);
if (error)
return error;
ASSERT(ip == mp->m_rbmip);
/* /*
* If it's an allocation to an empty file at offset 0, * If it's an allocation to an empty file at offset 0,
* pick an extent that will space things out in the rt area. * pick an extent that will space things out in the rt area.

Просмотреть файл

@ -2075,15 +2075,15 @@ xfs_rtallocate_extent(
xfs_extlen_t prod, /* extent product factor */ xfs_extlen_t prod, /* extent product factor */
xfs_rtblock_t *rtblock) /* out: start block allocated */ xfs_rtblock_t *rtblock) /* out: start block allocated */
{ {
xfs_mount_t *mp = tp->t_mountp;
int error; /* error value */ int error; /* error value */
xfs_inode_t *ip; /* inode for bitmap file */
xfs_mount_t *mp; /* file system mount structure */
xfs_rtblock_t r; /* result allocated block */ xfs_rtblock_t r; /* result allocated block */
xfs_fsblock_t sb; /* summary file block number */ xfs_fsblock_t sb; /* summary file block number */
xfs_buf_t *sumbp; /* summary file block buffer */ xfs_buf_t *sumbp; /* summary file block buffer */
ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
ASSERT(minlen > 0 && minlen <= maxlen); ASSERT(minlen > 0 && minlen <= maxlen);
mp = tp->t_mountp;
/* /*
* If prod is set then figure out what to do to minlen and maxlen. * If prod is set then figure out what to do to minlen and maxlen.
*/ */
@ -2099,12 +2099,7 @@ xfs_rtallocate_extent(
return 0; return 0;
} }
} }
/*
* Lock out other callers by grabbing the bitmap inode lock.
*/
if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
XFS_ILOCK_EXCL, &ip)))
return error;
sumbp = NULL; sumbp = NULL;
/* /*
* Allocate by size, or near another block, or exactly at some block. * Allocate by size, or near another block, or exactly at some block.
@ -2123,11 +2118,12 @@ xfs_rtallocate_extent(
len, &sumbp, &sb, prod, &r); len, &sumbp, &sb, prod, &r);
break; break;
default: default:
error = EIO;
ASSERT(0); ASSERT(0);
} }
if (error) { if (error)
return error; return error;
}
/* /*
* If it worked, update the superblock. * If it worked, update the superblock.
*/ */
@ -2306,20 +2302,16 @@ xfs_rtpick_extent(
xfs_rtblock_t *pick) /* result rt extent */ xfs_rtblock_t *pick) /* result rt extent */
{ {
xfs_rtblock_t b; /* result block */ xfs_rtblock_t b; /* result block */
int error; /* error return value */
xfs_inode_t *ip; /* bitmap incore inode */
int log2; /* log of sequence number */ int log2; /* log of sequence number */
__uint64_t resid; /* residual after log removed */ __uint64_t resid; /* residual after log removed */
__uint64_t seq; /* sequence number of file creation */ __uint64_t seq; /* sequence number of file creation */
__uint64_t *seqp; /* pointer to seqno in inode */ __uint64_t *seqp; /* pointer to seqno in inode */
if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
XFS_ILOCK_EXCL, &ip)))
return error; seqp = (__uint64_t *)&mp->m_rbmip->i_d.di_atime;
ASSERT(ip == mp->m_rbmip); if (!(mp->m_rbmip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) {
seqp = (__uint64_t *)&ip->i_d.di_atime; mp->m_rbmip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;
if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) {
ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;
*seqp = 0; *seqp = 0;
} }
seq = *seqp; seq = *seqp;
@ -2335,7 +2327,7 @@ xfs_rtpick_extent(
b = mp->m_sb.sb_rextents - len; b = mp->m_sb.sb_rextents - len;
} }
*seqp = seq + 1; *seqp = seq + 1;
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
*pick = b; *pick = b;
return 0; return 0;
} }