diff options
Diffstat (limited to 'fs/xfs/xfs_inode.c')
| -rw-r--r-- | fs/xfs/xfs_inode.c | 123 |
1 files changed, 117 insertions, 6 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 3a137e9f9a7d..5e7a38fa6ee6 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -42,7 +42,6 @@ | |||
| 42 | #include "xfs_bmap_util.h" | 42 | #include "xfs_bmap_util.h" |
| 43 | #include "xfs_error.h" | 43 | #include "xfs_error.h" |
| 44 | #include "xfs_quota.h" | 44 | #include "xfs_quota.h" |
| 45 | #include "xfs_dinode.h" | ||
| 46 | #include "xfs_filestream.h" | 45 | #include "xfs_filestream.h" |
| 47 | #include "xfs_cksum.h" | 46 | #include "xfs_cksum.h" |
| 48 | #include "xfs_trace.h" | 47 | #include "xfs_trace.h" |
| @@ -62,6 +61,8 @@ kmem_zone_t *xfs_inode_zone; | |||
| 62 | 61 | ||
| 63 | STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); | 62 | STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); |
| 64 | 63 | ||
| 64 | STATIC int xfs_iunlink_remove(xfs_trans_t *, xfs_inode_t *); | ||
| 65 | |||
| 65 | /* | 66 | /* |
| 66 | * helper function to extract extent size hint from inode | 67 | * helper function to extract extent size hint from inode |
| 67 | */ | 68 | */ |
| @@ -1115,7 +1116,7 @@ xfs_bumplink( | |||
| 1115 | { | 1116 | { |
| 1116 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); | 1117 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); |
| 1117 | 1118 | ||
| 1118 | ASSERT(ip->i_d.di_nlink > 0); | 1119 | ASSERT(ip->i_d.di_nlink > 0 || (VFS_I(ip)->i_state & I_LINKABLE)); |
| 1119 | ip->i_d.di_nlink++; | 1120 | ip->i_d.di_nlink++; |
| 1120 | inc_nlink(VFS_I(ip)); | 1121 | inc_nlink(VFS_I(ip)); |
| 1121 | if ((ip->i_d.di_version == 1) && | 1122 | if ((ip->i_d.di_version == 1) && |
| @@ -1165,10 +1166,7 @@ xfs_create( | |||
| 1165 | if (XFS_FORCED_SHUTDOWN(mp)) | 1166 | if (XFS_FORCED_SHUTDOWN(mp)) |
| 1166 | return XFS_ERROR(EIO); | 1167 | return XFS_ERROR(EIO); |
| 1167 | 1168 | ||
| 1168 | if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | 1169 | prid = xfs_get_initial_prid(dp); |
| 1169 | prid = xfs_get_projid(dp); | ||
| 1170 | else | ||
| 1171 | prid = XFS_PROJID_DEFAULT; | ||
| 1172 | 1170 | ||
| 1173 | /* | 1171 | /* |
| 1174 | * Make sure that we have allocated dquot(s) on disk. | 1172 | * Make sure that we have allocated dquot(s) on disk. |
| @@ -1333,6 +1331,113 @@ xfs_create( | |||
| 1333 | } | 1331 | } |
| 1334 | 1332 | ||
| 1335 | int | 1333 | int |
| 1334 | xfs_create_tmpfile( | ||
| 1335 | struct xfs_inode *dp, | ||
| 1336 | struct dentry *dentry, | ||
| 1337 | umode_t mode) | ||
| 1338 | { | ||
| 1339 | struct xfs_mount *mp = dp->i_mount; | ||
| 1340 | struct xfs_inode *ip = NULL; | ||
| 1341 | struct xfs_trans *tp = NULL; | ||
| 1342 | int error; | ||
| 1343 | uint cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | ||
| 1344 | prid_t prid; | ||
| 1345 | struct xfs_dquot *udqp = NULL; | ||
| 1346 | struct xfs_dquot *gdqp = NULL; | ||
| 1347 | struct xfs_dquot *pdqp = NULL; | ||
| 1348 | struct xfs_trans_res *tres; | ||
| 1349 | uint resblks; | ||
| 1350 | |||
| 1351 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
| 1352 | return XFS_ERROR(EIO); | ||
| 1353 | |||
| 1354 | prid = xfs_get_initial_prid(dp); | ||
| 1355 | |||
| 1356 | /* | ||
| 1357 | * Make sure that we have allocated dquot(s) on disk. | ||
| 1358 | */ | ||
| 1359 | error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()), | ||
| 1360 | xfs_kgid_to_gid(current_fsgid()), prid, | ||
| 1361 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, | ||
| 1362 | &udqp, &gdqp, &pdqp); | ||
| 1363 | if (error) | ||
| 1364 | return error; | ||
| 1365 | |||
| 1366 | resblks = XFS_IALLOC_SPACE_RES(mp); | ||
| 1367 | tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE_TMPFILE); | ||
| 1368 | |||
| 1369 | tres = &M_RES(mp)->tr_create_tmpfile; | ||
| 1370 | error = xfs_trans_reserve(tp, tres, resblks, 0); | ||
| 1371 | if (error == ENOSPC) { | ||
| 1372 | /* No space at all so try a "no-allocation" reservation */ | ||
| 1373 | resblks = 0; | ||
| 1374 | error = xfs_trans_reserve(tp, tres, 0, 0); | ||
| 1375 | } | ||
| 1376 | if (error) { | ||
| 1377 | cancel_flags = 0; | ||
| 1378 | goto out_trans_cancel; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, | ||
| 1382 | pdqp, resblks, 1, 0); | ||
| 1383 | if (error) | ||
| 1384 | goto out_trans_cancel; | ||
| 1385 | |||
| 1386 | error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, | ||
| 1387 | prid, resblks > 0, &ip, NULL); | ||
| 1388 | if (error) { | ||
| 1389 | if (error == ENOSPC) | ||
| 1390 | goto out_trans_cancel; | ||
| 1391 | goto out_trans_abort; | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | if (mp->m_flags & XFS_MOUNT_WSYNC) | ||
| 1395 | xfs_trans_set_sync(tp); | ||
| 1396 | |||
| 1397 | /* | ||
| 1398 | * Attach the dquot(s) to the inodes and modify them incore. | ||
| 1399 | * These ids of the inode couldn't have changed since the new | ||
| 1400 | * inode has been locked ever since it was created. | ||
| 1401 | */ | ||
| 1402 | xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); | ||
| 1403 | |||
| 1404 | ip->i_d.di_nlink--; | ||
| 1405 | d_tmpfile(dentry, VFS_I(ip)); | ||
| 1406 | error = xfs_iunlink(tp, ip); | ||
| 1407 | if (error) | ||
| 1408 | goto out_trans_abort; | ||
| 1409 | |||
| 1410 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | ||
| 1411 | if (error) | ||
| 1412 | goto out_release_inode; | ||
| 1413 | |||
| 1414 | xfs_qm_dqrele(udqp); | ||
| 1415 | xfs_qm_dqrele(gdqp); | ||
| 1416 | xfs_qm_dqrele(pdqp); | ||
| 1417 | |||
| 1418 | return 0; | ||
| 1419 | |||
| 1420 | out_trans_abort: | ||
| 1421 | cancel_flags |= XFS_TRANS_ABORT; | ||
| 1422 | out_trans_cancel: | ||
| 1423 | xfs_trans_cancel(tp, cancel_flags); | ||
| 1424 | out_release_inode: | ||
| 1425 | /* | ||
| 1426 | * Wait until after the current transaction is aborted to | ||
| 1427 | * release the inode. This prevents recursive transactions | ||
| 1428 | * and deadlocks from xfs_inactive. | ||
| 1429 | */ | ||
| 1430 | if (ip) | ||
| 1431 | IRELE(ip); | ||
| 1432 | |||
| 1433 | xfs_qm_dqrele(udqp); | ||
| 1434 | xfs_qm_dqrele(gdqp); | ||
| 1435 | xfs_qm_dqrele(pdqp); | ||
| 1436 | |||
| 1437 | return error; | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | int | ||
| 1336 | xfs_link( | 1441 | xfs_link( |
| 1337 | xfs_inode_t *tdp, | 1442 | xfs_inode_t *tdp, |
| 1338 | xfs_inode_t *sip, | 1443 | xfs_inode_t *sip, |
| @@ -1397,6 +1502,12 @@ xfs_link( | |||
| 1397 | 1502 | ||
| 1398 | xfs_bmap_init(&free_list, &first_block); | 1503 | xfs_bmap_init(&free_list, &first_block); |
| 1399 | 1504 | ||
| 1505 | if (sip->i_d.di_nlink == 0) { | ||
| 1506 | error = xfs_iunlink_remove(tp, sip); | ||
| 1507 | if (error) | ||
| 1508 | goto abort_return; | ||
| 1509 | } | ||
| 1510 | |||
| 1400 | error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino, | 1511 | error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino, |
| 1401 | &first_block, &free_list, resblks); | 1512 | &first_block, &free_list, resblks); |
| 1402 | if (error) | 1513 | if (error) |
