diff options
author | Tao Ma <tao.ma@oracle.com> | 2008-08-28 21:00:19 -0400 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-10-13 19:57:06 -0400 |
commit | 08413899db89d8d636c2a2d4ba5c356ab587d7ef (patch) | |
tree | 82e65ffa9b0b30d0206259ae99e0fbc8db667936 /fs/ocfs2/xattr.c | |
parent | 28b8ca0b7f70b1b048d03dc0b9d87f58619e9791 (diff) |
ocfs2: Resolve deadlock in ocfs2_xattr_free_block.
In ocfs2_xattr_free_block, we take a cluster lock on xb_alloc_inode while we
have a transaction open. This will deadlock the downconvert thread, so fix
it.
We can clean up how xattr blocks are removed while here - this patch also
moves the mechanism of releasing xattr block (including both value, xattr
tree and xattr block) into this function.
Signed-off-by: Tao Ma <tao.ma@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r-- | fs/ocfs2/xattr.c | 152 |
1 files changed, 82 insertions, 70 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 38e3e5e216bd..b2e25a828e38 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -1427,51 +1427,6 @@ out: | |||
1427 | 1427 | ||
1428 | } | 1428 | } |
1429 | 1429 | ||
1430 | static int ocfs2_xattr_free_block(handle_t *handle, | ||
1431 | struct ocfs2_super *osb, | ||
1432 | struct ocfs2_xattr_block *xb) | ||
1433 | { | ||
1434 | struct inode *xb_alloc_inode; | ||
1435 | struct buffer_head *xb_alloc_bh = NULL; | ||
1436 | u64 blk = le64_to_cpu(xb->xb_blkno); | ||
1437 | u16 bit = le16_to_cpu(xb->xb_suballoc_bit); | ||
1438 | u64 bg_blkno = ocfs2_which_suballoc_group(blk, bit); | ||
1439 | int ret = 0; | ||
1440 | |||
1441 | xb_alloc_inode = ocfs2_get_system_file_inode(osb, | ||
1442 | EXTENT_ALLOC_SYSTEM_INODE, | ||
1443 | le16_to_cpu(xb->xb_suballoc_slot)); | ||
1444 | if (!xb_alloc_inode) { | ||
1445 | ret = -ENOMEM; | ||
1446 | mlog_errno(ret); | ||
1447 | goto out; | ||
1448 | } | ||
1449 | mutex_lock(&xb_alloc_inode->i_mutex); | ||
1450 | |||
1451 | ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1); | ||
1452 | if (ret < 0) { | ||
1453 | mlog_errno(ret); | ||
1454 | goto out_mutex; | ||
1455 | } | ||
1456 | ret = ocfs2_extend_trans(handle, OCFS2_SUBALLOC_FREE); | ||
1457 | if (ret < 0) { | ||
1458 | mlog_errno(ret); | ||
1459 | goto out_unlock; | ||
1460 | } | ||
1461 | ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh, | ||
1462 | bit, bg_blkno, 1); | ||
1463 | if (ret < 0) | ||
1464 | mlog_errno(ret); | ||
1465 | out_unlock: | ||
1466 | ocfs2_inode_unlock(xb_alloc_inode, 1); | ||
1467 | brelse(xb_alloc_bh); | ||
1468 | out_mutex: | ||
1469 | mutex_unlock(&xb_alloc_inode->i_mutex); | ||
1470 | iput(xb_alloc_inode); | ||
1471 | out: | ||
1472 | return ret; | ||
1473 | } | ||
1474 | |||
1475 | static int ocfs2_remove_value_outside(struct inode*inode, | 1430 | static int ocfs2_remove_value_outside(struct inode*inode, |
1476 | struct buffer_head *bh, | 1431 | struct buffer_head *bh, |
1477 | struct ocfs2_xattr_header *header) | 1432 | struct ocfs2_xattr_header *header) |
@@ -1533,6 +1488,84 @@ static int ocfs2_xattr_block_remove(struct inode *inode, | |||
1533 | return ret; | 1488 | return ret; |
1534 | } | 1489 | } |
1535 | 1490 | ||
1491 | static int ocfs2_xattr_free_block(struct inode *inode, | ||
1492 | u64 block) | ||
1493 | { | ||
1494 | struct inode *xb_alloc_inode; | ||
1495 | struct buffer_head *xb_alloc_bh = NULL; | ||
1496 | struct buffer_head *blk_bh = NULL; | ||
1497 | struct ocfs2_xattr_block *xb; | ||
1498 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
1499 | handle_t *handle; | ||
1500 | int ret = 0; | ||
1501 | u64 blk, bg_blkno; | ||
1502 | u16 bit; | ||
1503 | |||
1504 | ret = ocfs2_read_block(osb, block, &blk_bh, | ||
1505 | OCFS2_BH_CACHED, inode); | ||
1506 | if (ret < 0) { | ||
1507 | mlog_errno(ret); | ||
1508 | goto out; | ||
1509 | } | ||
1510 | |||
1511 | /*Verify the signature of xattr block*/ | ||
1512 | if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, | ||
1513 | strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { | ||
1514 | ret = -EFAULT; | ||
1515 | goto out; | ||
1516 | } | ||
1517 | |||
1518 | ret = ocfs2_xattr_block_remove(inode, blk_bh); | ||
1519 | if (ret < 0) { | ||
1520 | mlog_errno(ret); | ||
1521 | goto out; | ||
1522 | } | ||
1523 | |||
1524 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | ||
1525 | blk = le64_to_cpu(xb->xb_blkno); | ||
1526 | bit = le16_to_cpu(xb->xb_suballoc_bit); | ||
1527 | bg_blkno = ocfs2_which_suballoc_group(blk, bit); | ||
1528 | |||
1529 | xb_alloc_inode = ocfs2_get_system_file_inode(osb, | ||
1530 | EXTENT_ALLOC_SYSTEM_INODE, | ||
1531 | le16_to_cpu(xb->xb_suballoc_slot)); | ||
1532 | if (!xb_alloc_inode) { | ||
1533 | ret = -ENOMEM; | ||
1534 | mlog_errno(ret); | ||
1535 | goto out; | ||
1536 | } | ||
1537 | mutex_lock(&xb_alloc_inode->i_mutex); | ||
1538 | |||
1539 | ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1); | ||
1540 | if (ret < 0) { | ||
1541 | mlog_errno(ret); | ||
1542 | goto out_mutex; | ||
1543 | } | ||
1544 | |||
1545 | handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE); | ||
1546 | if (IS_ERR(handle)) { | ||
1547 | ret = PTR_ERR(handle); | ||
1548 | mlog_errno(ret); | ||
1549 | goto out_unlock; | ||
1550 | } | ||
1551 | |||
1552 | ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh, | ||
1553 | bit, bg_blkno, 1); | ||
1554 | if (ret < 0) | ||
1555 | mlog_errno(ret); | ||
1556 | |||
1557 | ocfs2_commit_trans(osb, handle); | ||
1558 | out_unlock: | ||
1559 | ocfs2_inode_unlock(xb_alloc_inode, 1); | ||
1560 | brelse(xb_alloc_bh); | ||
1561 | out_mutex: | ||
1562 | mutex_unlock(&xb_alloc_inode->i_mutex); | ||
1563 | iput(xb_alloc_inode); | ||
1564 | out: | ||
1565 | brelse(blk_bh); | ||
1566 | return ret; | ||
1567 | } | ||
1568 | |||
1536 | /* | 1569 | /* |
1537 | * ocfs2_xattr_remove() | 1570 | * ocfs2_xattr_remove() |
1538 | * | 1571 | * |
@@ -1540,9 +1573,6 @@ static int ocfs2_xattr_block_remove(struct inode *inode, | |||
1540 | */ | 1573 | */ |
1541 | int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | 1574 | int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) |
1542 | { | 1575 | { |
1543 | struct ocfs2_xattr_block *xb; | ||
1544 | struct buffer_head *blk_bh = NULL; | ||
1545 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
1546 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | 1576 | struct ocfs2_inode_info *oi = OCFS2_I(inode); |
1547 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | 1577 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
1548 | handle_t *handle; | 1578 | handle_t *handle; |
@@ -1561,22 +1591,10 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |||
1561 | goto out; | 1591 | goto out; |
1562 | } | 1592 | } |
1563 | } | 1593 | } |
1564 | if (di->i_xattr_loc) { | ||
1565 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | ||
1566 | le64_to_cpu(di->i_xattr_loc), | ||
1567 | &blk_bh, OCFS2_BH_CACHED, inode); | ||
1568 | if (ret < 0) { | ||
1569 | mlog_errno(ret); | ||
1570 | return ret; | ||
1571 | } | ||
1572 | /*Verify the signature of xattr block*/ | ||
1573 | if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, | ||
1574 | strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { | ||
1575 | ret = -EFAULT; | ||
1576 | goto out; | ||
1577 | } | ||
1578 | 1594 | ||
1579 | ret = ocfs2_xattr_block_remove(inode, blk_bh); | 1595 | if (di->i_xattr_loc) { |
1596 | ret = ocfs2_xattr_free_block(inode, | ||
1597 | le64_to_cpu(di->i_xattr_loc)); | ||
1580 | if (ret < 0) { | 1598 | if (ret < 0) { |
1581 | mlog_errno(ret); | 1599 | mlog_errno(ret); |
1582 | goto out; | 1600 | goto out; |
@@ -1597,11 +1615,7 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |||
1597 | goto out_commit; | 1615 | goto out_commit; |
1598 | } | 1616 | } |
1599 | 1617 | ||
1600 | if (di->i_xattr_loc) { | 1618 | di->i_xattr_loc = 0; |
1601 | xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | ||
1602 | ocfs2_xattr_free_block(handle, osb, xb); | ||
1603 | di->i_xattr_loc = cpu_to_le64(0); | ||
1604 | } | ||
1605 | 1619 | ||
1606 | spin_lock(&oi->ip_lock); | 1620 | spin_lock(&oi->ip_lock); |
1607 | oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL); | 1621 | oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL); |
@@ -1614,8 +1628,6 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |||
1614 | out_commit: | 1628 | out_commit: |
1615 | ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); | 1629 | ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); |
1616 | out: | 1630 | out: |
1617 | brelse(blk_bh); | ||
1618 | |||
1619 | return ret; | 1631 | return ret; |
1620 | } | 1632 | } |
1621 | 1633 | ||