aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2009-02-09 02:38:02 -0500
committerChristoph Hellwig <hch@brick.lst.de>2009-02-09 02:38:02 -0500
commit517b5e8c8516a25a0df3b530fd183eb493a96698 (patch)
treec9634c27127410f5522f78d854bd6b9e68f0e3dc /fs/xfs/xfs_vnodeops.c
parenta568778739030fb68805dda1af2f4ebbc3adad7d (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.c351
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:
1559std_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
2116int
2117xfs_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
2290std_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
2318int 2133int
2319xfs_symlink( 2134xfs_symlink(
2320 xfs_inode_t *dp, 2135 xfs_inode_t *dp,