diff options
author | Christoph Hellwig <hch@lst.de> | 2009-02-09 02:38:02 -0500 |
---|---|---|
committer | Christoph Hellwig <hch@brick.lst.de> | 2009-02-09 02:38:02 -0500 |
commit | 517b5e8c8516a25a0df3b530fd183eb493a96698 (patch) | |
tree | c9634c27127410f5522f78d854bd6b9e68f0e3dc /fs/xfs/xfs_vnodeops.c | |
parent | a568778739030fb68805dda1af2f4ebbc3adad7d (diff) |
xfs: merge xfs_mkdir into xfs_create
xfs_create and xfs_mkdir only have minor differences, so merge both of them
into a sigle function. While we're at it also make the error handling code
more straight-forward.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 351 |
1 files changed, 83 insertions, 268 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index bc0a0a75b1d6..59de04954bc8 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -1387,23 +1387,28 @@ xfs_create( | |||
1387 | xfs_inode_t **ipp, | 1387 | xfs_inode_t **ipp, |
1388 | cred_t *credp) | 1388 | cred_t *credp) |
1389 | { | 1389 | { |
1390 | xfs_mount_t *mp = dp->i_mount; | 1390 | int is_dir = S_ISDIR(mode); |
1391 | xfs_inode_t *ip; | 1391 | struct xfs_mount *mp = dp->i_mount; |
1392 | xfs_trans_t *tp; | 1392 | struct xfs_inode *ip = NULL; |
1393 | struct xfs_trans *tp = NULL; | ||
1393 | int error; | 1394 | int error; |
1394 | xfs_bmap_free_t free_list; | 1395 | xfs_bmap_free_t free_list; |
1395 | xfs_fsblock_t first_block; | 1396 | xfs_fsblock_t first_block; |
1396 | boolean_t unlock_dp_on_error = B_FALSE; | 1397 | boolean_t unlock_dp_on_error = B_FALSE; |
1397 | int dm_event_sent = 0; | ||
1398 | uint cancel_flags; | 1398 | uint cancel_flags; |
1399 | int committed; | 1399 | int committed; |
1400 | xfs_prid_t prid; | 1400 | xfs_prid_t prid; |
1401 | struct xfs_dquot *udqp, *gdqp; | 1401 | struct xfs_dquot *udqp = NULL; |
1402 | struct xfs_dquot *gdqp = NULL; | ||
1402 | uint resblks; | 1403 | uint resblks; |
1404 | uint log_res; | ||
1405 | uint log_count; | ||
1403 | 1406 | ||
1404 | ASSERT(!*ipp); | ||
1405 | xfs_itrace_entry(dp); | 1407 | xfs_itrace_entry(dp); |
1406 | 1408 | ||
1409 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1410 | return XFS_ERROR(EIO); | ||
1411 | |||
1407 | if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { | 1412 | if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { |
1408 | error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, | 1413 | error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, |
1409 | dp, DM_RIGHT_NULL, NULL, | 1414 | dp, DM_RIGHT_NULL, NULL, |
@@ -1412,84 +1417,97 @@ xfs_create( | |||
1412 | 1417 | ||
1413 | if (error) | 1418 | if (error) |
1414 | return error; | 1419 | return error; |
1415 | dm_event_sent = 1; | ||
1416 | } | 1420 | } |
1417 | 1421 | ||
1418 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1419 | return XFS_ERROR(EIO); | ||
1420 | |||
1421 | /* Return through std_return after this point. */ | ||
1422 | |||
1423 | udqp = gdqp = NULL; | ||
1424 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | 1422 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
1425 | prid = dp->i_d.di_projid; | 1423 | prid = dp->i_d.di_projid; |
1426 | else | 1424 | else |
1427 | prid = (xfs_prid_t)dfltprid; | 1425 | prid = dfltprid; |
1428 | 1426 | ||
1429 | /* | 1427 | /* |
1430 | * Make sure that we have allocated dquot(s) on disk. | 1428 | * Make sure that we have allocated dquot(s) on disk. |
1431 | */ | 1429 | */ |
1432 | error = XFS_QM_DQVOPALLOC(mp, dp, | 1430 | error = XFS_QM_DQVOPALLOC(mp, dp, |
1433 | current_fsuid(), current_fsgid(), prid, | 1431 | current_fsuid(), current_fsgid(), prid, |
1434 | XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); | 1432 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); |
1435 | if (error) | 1433 | if (error) |
1436 | goto std_return; | 1434 | goto std_return; |
1437 | 1435 | ||
1438 | ip = NULL; | 1436 | if (is_dir) { |
1437 | rdev = 0; | ||
1438 | resblks = XFS_MKDIR_SPACE_RES(mp, name->len); | ||
1439 | log_res = XFS_MKDIR_LOG_RES(mp); | ||
1440 | log_count = XFS_MKDIR_LOG_COUNT; | ||
1441 | tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR); | ||
1442 | } else { | ||
1443 | resblks = XFS_CREATE_SPACE_RES(mp, name->len); | ||
1444 | log_res = XFS_CREATE_LOG_RES(mp); | ||
1445 | log_count = XFS_CREATE_LOG_COUNT; | ||
1446 | tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE); | ||
1447 | } | ||
1439 | 1448 | ||
1440 | tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE); | ||
1441 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 1449 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
1442 | resblks = XFS_CREATE_SPACE_RES(mp, name->len); | 1450 | |
1443 | /* | 1451 | /* |
1444 | * Initially assume that the file does not exist and | 1452 | * Initially assume that the file does not exist and |
1445 | * reserve the resources for that case. If that is not | 1453 | * reserve the resources for that case. If that is not |
1446 | * the case we'll drop the one we have and get a more | 1454 | * the case we'll drop the one we have and get a more |
1447 | * appropriate transaction later. | 1455 | * appropriate transaction later. |
1448 | */ | 1456 | */ |
1449 | error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0, | 1457 | error = xfs_trans_reserve(tp, resblks, log_res, 0, |
1450 | XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); | 1458 | XFS_TRANS_PERM_LOG_RES, log_count); |
1451 | if (error == ENOSPC) { | 1459 | if (error == ENOSPC) { |
1452 | resblks = 0; | 1460 | resblks = 0; |
1453 | error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0, | 1461 | error = xfs_trans_reserve(tp, 0, log_res, 0, |
1454 | XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); | 1462 | XFS_TRANS_PERM_LOG_RES, log_count); |
1455 | } | 1463 | } |
1456 | if (error) { | 1464 | if (error) { |
1457 | cancel_flags = 0; | 1465 | cancel_flags = 0; |
1458 | goto error_return; | 1466 | goto out_trans_cancel; |
1459 | } | 1467 | } |
1460 | 1468 | ||
1461 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); | 1469 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); |
1462 | unlock_dp_on_error = B_TRUE; | 1470 | unlock_dp_on_error = B_TRUE; |
1463 | 1471 | ||
1464 | xfs_bmap_init(&free_list, &first_block); | 1472 | /* |
1473 | * Check for directory link count overflow. | ||
1474 | */ | ||
1475 | if (is_dir && dp->i_d.di_nlink >= XFS_MAXLINK) { | ||
1476 | error = XFS_ERROR(EMLINK); | ||
1477 | goto out_trans_cancel; | ||
1478 | } | ||
1465 | 1479 | ||
1466 | ASSERT(ip == NULL); | 1480 | xfs_bmap_init(&free_list, &first_block); |
1467 | 1481 | ||
1468 | /* | 1482 | /* |
1469 | * Reserve disk quota and the inode. | 1483 | * Reserve disk quota and the inode. |
1470 | */ | 1484 | */ |
1471 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); | 1485 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); |
1472 | if (error) | 1486 | if (error) |
1473 | goto error_return; | 1487 | goto out_trans_cancel; |
1474 | 1488 | ||
1475 | error = xfs_dir_canenter(tp, dp, name, resblks); | 1489 | error = xfs_dir_canenter(tp, dp, name, resblks); |
1476 | if (error) | 1490 | if (error) |
1477 | goto error_return; | 1491 | goto out_trans_cancel; |
1478 | error = xfs_dir_ialloc(&tp, dp, mode, 1, | 1492 | |
1479 | rdev, credp, prid, resblks > 0, | 1493 | /* |
1480 | &ip, &committed); | 1494 | * A newly created regular or special file just has one directory |
1495 | * entry pointing to them, but a directory also the "." entry | ||
1496 | * pointing to itself. | ||
1497 | */ | ||
1498 | error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, credp, | ||
1499 | prid, resblks > 0, &ip, &committed); | ||
1481 | if (error) { | 1500 | if (error) { |
1482 | if (error == ENOSPC) | 1501 | if (error == ENOSPC) |
1483 | goto error_return; | 1502 | goto out_trans_cancel; |
1484 | goto abort_return; | 1503 | goto out_trans_abort; |
1485 | } | 1504 | } |
1486 | xfs_itrace_ref(ip); | ||
1487 | 1505 | ||
1488 | /* | 1506 | /* |
1489 | * At this point, we've gotten a newly allocated inode. | 1507 | * At this point, we've gotten a newly allocated inode. |
1490 | * It is locked (and joined to the transaction). | 1508 | * It is locked (and joined to the transaction). |
1491 | */ | 1509 | */ |
1492 | 1510 | xfs_itrace_ref(ip); | |
1493 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | 1511 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
1494 | 1512 | ||
1495 | /* | 1513 | /* |
@@ -1508,19 +1526,28 @@ xfs_create( | |||
1508 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); | 1526 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); |
1509 | if (error) { | 1527 | if (error) { |
1510 | ASSERT(error != ENOSPC); | 1528 | ASSERT(error != ENOSPC); |
1511 | goto abort_return; | 1529 | goto out_trans_abort; |
1512 | } | 1530 | } |
1513 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 1531 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
1514 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 1532 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
1515 | 1533 | ||
1534 | if (is_dir) { | ||
1535 | error = xfs_dir_init(tp, ip, dp); | ||
1536 | if (error) | ||
1537 | goto out_bmap_cancel; | ||
1538 | |||
1539 | error = xfs_bumplink(tp, dp); | ||
1540 | if (error) | ||
1541 | goto out_bmap_cancel; | ||
1542 | } | ||
1543 | |||
1516 | /* | 1544 | /* |
1517 | * If this is a synchronous mount, make sure that the | 1545 | * If this is a synchronous mount, make sure that the |
1518 | * create transaction goes to disk before returning to | 1546 | * create transaction goes to disk before returning to |
1519 | * the user. | 1547 | * the user. |
1520 | */ | 1548 | */ |
1521 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 1549 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) |
1522 | xfs_trans_set_sync(tp); | 1550 | xfs_trans_set_sync(tp); |
1523 | } | ||
1524 | 1551 | ||
1525 | /* | 1552 | /* |
1526 | * Attach the dquot(s) to the inodes and modify them incore. | 1553 | * Attach the dquot(s) to the inodes and modify them incore. |
@@ -1537,16 +1564,13 @@ xfs_create( | |||
1537 | IHOLD(ip); | 1564 | IHOLD(ip); |
1538 | 1565 | ||
1539 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 1566 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
1540 | if (error) { | 1567 | if (error) |
1541 | xfs_bmap_cancel(&free_list); | 1568 | goto out_abort_rele; |
1542 | goto abort_rele; | ||
1543 | } | ||
1544 | 1569 | ||
1545 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 1570 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
1546 | if (error) { | 1571 | if (error) { |
1547 | IRELE(ip); | 1572 | IRELE(ip); |
1548 | tp = NULL; | 1573 | goto out_dqrele; |
1549 | goto error_return; | ||
1550 | } | 1574 | } |
1551 | 1575 | ||
1552 | XFS_QM_DQRELE(mp, udqp); | 1576 | XFS_QM_DQRELE(mp, udqp); |
@@ -1555,26 +1579,22 @@ xfs_create( | |||
1555 | *ipp = ip; | 1579 | *ipp = ip; |
1556 | 1580 | ||
1557 | /* Fallthrough to std_return with error = 0 */ | 1581 | /* Fallthrough to std_return with error = 0 */ |
1558 | 1582 | std_return: | |
1559 | std_return: | 1583 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { |
1560 | if ((*ipp || (error != 0 && dm_event_sent != 0)) && | 1584 | XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, dp, DM_RIGHT_NULL, |
1561 | DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { | 1585 | ip, DM_RIGHT_NULL, name->name, NULL, mode, |
1562 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, | 1586 | error, 0); |
1563 | dp, DM_RIGHT_NULL, | ||
1564 | *ipp ? ip : NULL, | ||
1565 | DM_RIGHT_NULL, name->name, NULL, | ||
1566 | mode, error, 0); | ||
1567 | } | 1587 | } |
1588 | |||
1568 | return error; | 1589 | return error; |
1569 | 1590 | ||
1570 | abort_return: | 1591 | out_bmap_cancel: |
1592 | xfs_bmap_cancel(&free_list); | ||
1593 | out_trans_abort: | ||
1571 | cancel_flags |= XFS_TRANS_ABORT; | 1594 | cancel_flags |= XFS_TRANS_ABORT; |
1572 | /* FALLTHROUGH */ | 1595 | out_trans_cancel: |
1573 | 1596 | xfs_trans_cancel(tp, cancel_flags); | |
1574 | error_return: | 1597 | out_dqrele: |
1575 | if (tp != NULL) | ||
1576 | xfs_trans_cancel(tp, cancel_flags); | ||
1577 | |||
1578 | XFS_QM_DQRELE(mp, udqp); | 1598 | XFS_QM_DQRELE(mp, udqp); |
1579 | XFS_QM_DQRELE(mp, gdqp); | 1599 | XFS_QM_DQRELE(mp, gdqp); |
1580 | 1600 | ||
@@ -1583,20 +1603,18 @@ std_return: | |||
1583 | 1603 | ||
1584 | goto std_return; | 1604 | goto std_return; |
1585 | 1605 | ||
1586 | abort_rele: | 1606 | out_abort_rele: |
1587 | /* | 1607 | /* |
1588 | * Wait until after the current transaction is aborted to | 1608 | * Wait until after the current transaction is aborted to |
1589 | * release the inode. This prevents recursive transactions | 1609 | * release the inode. This prevents recursive transactions |
1590 | * and deadlocks from xfs_inactive. | 1610 | * and deadlocks from xfs_inactive. |
1591 | */ | 1611 | */ |
1612 | xfs_bmap_cancel(&free_list); | ||
1592 | cancel_flags |= XFS_TRANS_ABORT; | 1613 | cancel_flags |= XFS_TRANS_ABORT; |
1593 | xfs_trans_cancel(tp, cancel_flags); | 1614 | xfs_trans_cancel(tp, cancel_flags); |
1594 | IRELE(ip); | 1615 | IRELE(ip); |
1595 | 1616 | unlock_dp_on_error = B_FALSE; | |
1596 | XFS_QM_DQRELE(mp, udqp); | 1617 | goto out_dqrele; |
1597 | XFS_QM_DQRELE(mp, gdqp); | ||
1598 | |||
1599 | goto std_return; | ||
1600 | } | 1618 | } |
1601 | 1619 | ||
1602 | #ifdef DEBUG | 1620 | #ifdef DEBUG |
@@ -2112,209 +2130,6 @@ std_return: | |||
2112 | goto std_return; | 2130 | goto std_return; |
2113 | } | 2131 | } |
2114 | 2132 | ||
2115 | |||
2116 | int | ||
2117 | xfs_mkdir( | ||
2118 | xfs_inode_t *dp, | ||
2119 | struct xfs_name *dir_name, | ||
2120 | mode_t mode, | ||
2121 | xfs_inode_t **ipp, | ||
2122 | cred_t *credp) | ||
2123 | { | ||
2124 | xfs_mount_t *mp = dp->i_mount; | ||
2125 | xfs_inode_t *cdp; /* inode of created dir */ | ||
2126 | xfs_trans_t *tp; | ||
2127 | int cancel_flags; | ||
2128 | int error; | ||
2129 | int committed; | ||
2130 | xfs_bmap_free_t free_list; | ||
2131 | xfs_fsblock_t first_block; | ||
2132 | boolean_t unlock_dp_on_error = B_FALSE; | ||
2133 | boolean_t created = B_FALSE; | ||
2134 | int dm_event_sent = 0; | ||
2135 | xfs_prid_t prid; | ||
2136 | struct xfs_dquot *udqp, *gdqp; | ||
2137 | uint resblks; | ||
2138 | |||
2139 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
2140 | return XFS_ERROR(EIO); | ||
2141 | |||
2142 | tp = NULL; | ||
2143 | |||
2144 | if (DM_EVENT_ENABLED(dp, DM_EVENT_CREATE)) { | ||
2145 | error = XFS_SEND_NAMESP(mp, DM_EVENT_CREATE, | ||
2146 | dp, DM_RIGHT_NULL, NULL, | ||
2147 | DM_RIGHT_NULL, dir_name->name, NULL, | ||
2148 | mode, 0, 0); | ||
2149 | if (error) | ||
2150 | return error; | ||
2151 | dm_event_sent = 1; | ||
2152 | } | ||
2153 | |||
2154 | /* Return through std_return after this point. */ | ||
2155 | |||
2156 | xfs_itrace_entry(dp); | ||
2157 | |||
2158 | mp = dp->i_mount; | ||
2159 | udqp = gdqp = NULL; | ||
2160 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | ||
2161 | prid = dp->i_d.di_projid; | ||
2162 | else | ||
2163 | prid = (xfs_prid_t)dfltprid; | ||
2164 | |||
2165 | /* | ||
2166 | * Make sure that we have allocated dquot(s) on disk. | ||
2167 | */ | ||
2168 | error = XFS_QM_DQVOPALLOC(mp, dp, | ||
2169 | current_fsuid(), current_fsgid(), prid, | ||
2170 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); | ||
2171 | if (error) | ||
2172 | goto std_return; | ||
2173 | |||
2174 | tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR); | ||
2175 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | ||
2176 | resblks = XFS_MKDIR_SPACE_RES(mp, dir_name->len); | ||
2177 | error = xfs_trans_reserve(tp, resblks, XFS_MKDIR_LOG_RES(mp), 0, | ||
2178 | XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT); | ||
2179 | if (error == ENOSPC) { | ||
2180 | resblks = 0; | ||
2181 | error = xfs_trans_reserve(tp, 0, XFS_MKDIR_LOG_RES(mp), 0, | ||
2182 | XFS_TRANS_PERM_LOG_RES, | ||
2183 | XFS_MKDIR_LOG_COUNT); | ||
2184 | } | ||
2185 | if (error) { | ||
2186 | cancel_flags = 0; | ||
2187 | goto error_return; | ||
2188 | } | ||
2189 | |||
2190 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); | ||
2191 | unlock_dp_on_error = B_TRUE; | ||
2192 | |||
2193 | /* | ||
2194 | * Check for directory link count overflow. | ||
2195 | */ | ||
2196 | if (dp->i_d.di_nlink >= XFS_MAXLINK) { | ||
2197 | error = XFS_ERROR(EMLINK); | ||
2198 | goto error_return; | ||
2199 | } | ||
2200 | |||
2201 | /* | ||
2202 | * Reserve disk quota and the inode. | ||
2203 | */ | ||
2204 | error = XFS_TRANS_RESERVE_QUOTA(mp, tp, udqp, gdqp, resblks, 1, 0); | ||
2205 | if (error) | ||
2206 | goto error_return; | ||
2207 | |||
2208 | error = xfs_dir_canenter(tp, dp, dir_name, resblks); | ||
2209 | if (error) | ||
2210 | goto error_return; | ||
2211 | /* | ||
2212 | * create the directory inode. | ||
2213 | */ | ||
2214 | error = xfs_dir_ialloc(&tp, dp, mode, 2, | ||
2215 | 0, credp, prid, resblks > 0, | ||
2216 | &cdp, NULL); | ||
2217 | if (error) { | ||
2218 | if (error == ENOSPC) | ||
2219 | goto error_return; | ||
2220 | goto abort_return; | ||
2221 | } | ||
2222 | xfs_itrace_ref(cdp); | ||
2223 | |||
2224 | /* | ||
2225 | * Now we add the directory inode to the transaction. | ||
2226 | * We waited until now since xfs_dir_ialloc might start | ||
2227 | * a new transaction. Had we joined the transaction | ||
2228 | * earlier, the locks might have gotten released. An error | ||
2229 | * from here on will result in the transaction cancel | ||
2230 | * unlocking dp so don't do it explicitly in the error path. | ||
2231 | */ | ||
2232 | IHOLD(dp); | ||
2233 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); | ||
2234 | unlock_dp_on_error = B_FALSE; | ||
2235 | |||
2236 | xfs_bmap_init(&free_list, &first_block); | ||
2237 | |||
2238 | error = xfs_dir_createname(tp, dp, dir_name, cdp->i_ino, | ||
2239 | &first_block, &free_list, resblks ? | ||
2240 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); | ||
2241 | if (error) { | ||
2242 | ASSERT(error != ENOSPC); | ||
2243 | goto error1; | ||
2244 | } | ||
2245 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
2246 | |||
2247 | error = xfs_dir_init(tp, cdp, dp); | ||
2248 | if (error) | ||
2249 | goto error2; | ||
2250 | |||
2251 | error = xfs_bumplink(tp, dp); | ||
2252 | if (error) | ||
2253 | goto error2; | ||
2254 | |||
2255 | created = B_TRUE; | ||
2256 | |||
2257 | *ipp = cdp; | ||
2258 | IHOLD(cdp); | ||
2259 | |||
2260 | /* | ||
2261 | * Attach the dquots to the new inode and modify the icount incore. | ||
2262 | */ | ||
2263 | XFS_QM_DQVOPCREATE(mp, tp, cdp, udqp, gdqp); | ||
2264 | |||
2265 | /* | ||
2266 | * If this is a synchronous mount, make sure that the | ||
2267 | * mkdir transaction goes to disk before returning to | ||
2268 | * the user. | ||
2269 | */ | ||
2270 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | ||
2271 | xfs_trans_set_sync(tp); | ||
2272 | } | ||
2273 | |||
2274 | error = xfs_bmap_finish(&tp, &free_list, &committed); | ||
2275 | if (error) { | ||
2276 | IRELE(cdp); | ||
2277 | goto error2; | ||
2278 | } | ||
2279 | |||
2280 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | ||
2281 | XFS_QM_DQRELE(mp, udqp); | ||
2282 | XFS_QM_DQRELE(mp, gdqp); | ||
2283 | if (error) { | ||
2284 | IRELE(cdp); | ||
2285 | } | ||
2286 | |||
2287 | /* Fall through to std_return with error = 0 or errno from | ||
2288 | * xfs_trans_commit. */ | ||
2289 | |||
2290 | std_return: | ||
2291 | if ((created || (error != 0 && dm_event_sent != 0)) && | ||
2292 | DM_EVENT_ENABLED(dp, DM_EVENT_POSTCREATE)) { | ||
2293 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTCREATE, | ||
2294 | dp, DM_RIGHT_NULL, | ||
2295 | created ? cdp : NULL, | ||
2296 | DM_RIGHT_NULL, | ||
2297 | dir_name->name, NULL, | ||
2298 | mode, error, 0); | ||
2299 | } | ||
2300 | return error; | ||
2301 | |||
2302 | error2: | ||
2303 | error1: | ||
2304 | xfs_bmap_cancel(&free_list); | ||
2305 | abort_return: | ||
2306 | cancel_flags |= XFS_TRANS_ABORT; | ||
2307 | error_return: | ||
2308 | xfs_trans_cancel(tp, cancel_flags); | ||
2309 | XFS_QM_DQRELE(mp, udqp); | ||
2310 | XFS_QM_DQRELE(mp, gdqp); | ||
2311 | |||
2312 | if (unlock_dp_on_error) | ||
2313 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
2314 | |||
2315 | goto std_return; | ||
2316 | } | ||
2317 | |||
2318 | int | 2133 | int |
2319 | xfs_symlink( | 2134 | xfs_symlink( |
2320 | xfs_inode_t *dp, | 2135 | xfs_inode_t *dp, |