Commit 135e21a5 authored by Dave Kleikamp's avatar Dave Kleikamp

JFS: Prevent hang in __lock_metapage

Remove the hold_metapage call from txLog to prevent a hang.
While investigating this one, I audited all functions that held
metapage locks and found several error paths that did not release
them correctly.  These are fixed as well.
parent db80df6e
......@@ -1526,6 +1526,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
if (n == 4) {
jfs_error(bmp->db_ipbmap->i_sb,
"dbAllocAG: failed descending stree");
release_metapage(mp);
return -EIO;
}
}
......@@ -3310,7 +3311,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
int i, i0 = TRUE, j, j0 = TRUE, k, n;
s64 newsize;
s64 p;
struct metapage *mp, *l2mp, *l1mp, *l0mp;
struct metapage *mp, *l2mp, *l1mp = NULL, *l0mp = NULL;
struct dmapctl *l2dcp, *l1dcp, *l0dcp;
struct dmap *dp;
s8 *l0leaf, *l1leaf, *l2leaf;
......@@ -3513,6 +3514,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
*/
*l1leaf = dbInitDmapCtl(l0dcp, 0, ++i);
write_metapage(l0mp);
l0mp = NULL;
if (nblocks)
l1leaf++; /* continue for next L0 */
......@@ -3536,6 +3538,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
*/
*l2leaf = dbInitDmapCtl(l1dcp, 1, ++j);
write_metapage(l1mp);
l1mp = NULL;
if (nblocks)
l2leaf++; /* continue for next L1 */
......@@ -3554,17 +3557,20 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
jfs_error(ipbmap->i_sb,
"dbExtendFS: function has not returned as expected");
errout:
if (l0mp)
release_metapage(l0mp);
if (l1mp)
release_metapage(l1mp);
release_metapage(l2mp);
return -EIO;
/*
* finalize bmap control page
*/
finalize:
finalize:
return 0;
errout:
return -EIO;
}
......
......@@ -1423,8 +1423,10 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
*/
if (nextbn != 0) {
DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
if (rc)
if (rc) {
discard_metapage(rmp);
return rc;
}
BT_MARK_DIRTY(mp, ip);
/*
......@@ -2235,8 +2237,10 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
pxdlock->index = 1;
/* update sibling pointers */
if ((rc = dtRelink(tid, ip, fp)))
if ((rc = dtRelink(tid, ip, fp))) {
BT_PUTPAGE(fmp);
return rc;
}
xlen = lengthPXD(&fp->header.self);
ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
......@@ -2307,8 +2311,10 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
pxdlock->index = 1;
/* update sibling pointers */
if ((rc = dtRelink(tid, ip, p)))
if ((rc = dtRelink(tid, ip, p))) {
DT_PUTPAGE(mp);
return rc;
}
xlen = lengthPXD(&p->header.self);
ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
......@@ -2621,8 +2627,10 @@ static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd,
/*
* descend down to leftmost child page
*/
if (p->header.flag & BT_LEAF)
if (p->header.flag & BT_LEAF) {
DT_PUTPAGE(mp);
return -ESTALE;
}
/* get the leftmost entry */
stbl = DT_GETSTBL(p);
......
......@@ -1546,6 +1546,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
0);
if (rem >= INOSPEREXT) {
IREAD_UNLOCK(ipimap);
release_metapage(mp);
AG_UNLOCK(imap, agno);
jfs_error(ip->i_sb,
"diAlloc: can't find free bit "
......@@ -1840,6 +1841,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
*/
if (!iagp->nfreeinos) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb,
"diAllocIno: nfreeinos = 0, but iag on freelist");
return -EIO;
......@@ -1851,6 +1853,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
for (sword = 0;; sword++) {
if (sword >= SMAPSZ) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb,
"diAllocIno: free inode not found in summary map");
return -EIO;
......@@ -1866,6 +1869,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0);
if (rem >= EXTSPERSUM) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb, "diAllocIno: no free extent found");
return -EIO;
}
......@@ -1876,6 +1880,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0);
if (rem >= INOSPEREXT) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb, "diAllocIno: free inode not found");
return -EIO;
}
......@@ -2839,12 +2844,14 @@ diUpdatePMap(struct inode *ipimap,
* and should be free in persistent map;
*/
if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
release_metapage(mp);
jfs_error(ipimap->i_sb,
"diUpdatePMap: the inode is not allocated in "
"the working map");
return -EIO;
}
if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) {
release_metapage(mp);
jfs_error(ipimap->i_sb,
"diUpdatePMap: the inode is not free in the "
"persistent map");
......
......@@ -1356,9 +1356,6 @@ static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd)
lrd->log.redopage.fileset = cpu_to_le32(JFS_IP(ip)->fileset);
lrd->log.redopage.inode = cpu_to_le32(ip->i_ino);
if (tlck->mp)
hold_metapage(tlck->mp, 0);
/* write log record of page from the tlock */
switch (tlck->type & tlckTYPE) {
case tlckXTREE:
......@@ -1384,8 +1381,6 @@ static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd)
default:
jfs_err("UFO tlock:0x%p", tlck);
}
if (tlck->mp)
release_metapage(tlck->mp);
}
return rc;
......@@ -1535,6 +1530,7 @@ static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* the last entry, so don't bother logging this
*/
mp->lid = 0;
hold_metapage(mp, 0);
atomic_dec(&mp->nohomeok);
discard_metapage(mp);
tlck->mp = 0;
......
This diff is collapsed.
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