diff options
| -rw-r--r-- | fs/xfs/xfs_inode.c | 107 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_iops.c | 16 | ||||
| -rw-r--r-- | fs/xfs/xfs_shared.h | 4 | ||||
| -rw-r--r-- | fs/xfs/xfs_trans_resv.c | 36 | ||||
| -rw-r--r-- | fs/xfs/xfs_trans_resv.h | 2 |
6 files changed, 164 insertions, 3 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index c79b875f0354..ac133ea91c4b 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -1333,6 +1333,113 @@ xfs_create( | |||
| 1333 | } | 1333 | } |
| 1334 | 1334 | ||
| 1335 | int | 1335 | int |
| 1336 | xfs_create_tmpfile( | ||
| 1337 | struct xfs_inode *dp, | ||
| 1338 | struct dentry *dentry, | ||
| 1339 | umode_t mode) | ||
| 1340 | { | ||
| 1341 | struct xfs_mount *mp = dp->i_mount; | ||
| 1342 | struct xfs_inode *ip = NULL; | ||
| 1343 | struct xfs_trans *tp = NULL; | ||
| 1344 | int error; | ||
| 1345 | uint cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | ||
| 1346 | prid_t prid; | ||
| 1347 | struct xfs_dquot *udqp = NULL; | ||
| 1348 | struct xfs_dquot *gdqp = NULL; | ||
| 1349 | struct xfs_dquot *pdqp = NULL; | ||
| 1350 | struct xfs_trans_res *tres; | ||
| 1351 | uint resblks; | ||
| 1352 | |||
| 1353 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
| 1354 | return XFS_ERROR(EIO); | ||
| 1355 | |||
| 1356 | prid = xfs_get_initial_prid(dp); | ||
| 1357 | |||
| 1358 | /* | ||
| 1359 | * Make sure that we have allocated dquot(s) on disk. | ||
| 1360 | */ | ||
| 1361 | error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()), | ||
| 1362 | xfs_kgid_to_gid(current_fsgid()), prid, | ||
| 1363 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, | ||
| 1364 | &udqp, &gdqp, &pdqp); | ||
| 1365 | if (error) | ||
| 1366 | return error; | ||
| 1367 | |||
| 1368 | resblks = XFS_IALLOC_SPACE_RES(mp); | ||
| 1369 | tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE_TMPFILE); | ||
| 1370 | |||
| 1371 | tres = &M_RES(mp)->tr_create_tmpfile; | ||
| 1372 | error = xfs_trans_reserve(tp, tres, resblks, 0); | ||
| 1373 | if (error == ENOSPC) { | ||
| 1374 | /* No space at all so try a "no-allocation" reservation */ | ||
| 1375 | resblks = 0; | ||
| 1376 | error = xfs_trans_reserve(tp, tres, 0, 0); | ||
| 1377 | } | ||
| 1378 | if (error) { | ||
| 1379 | cancel_flags = 0; | ||
| 1380 | goto out_trans_cancel; | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, | ||
| 1384 | pdqp, resblks, 1, 0); | ||
| 1385 | if (error) | ||
| 1386 | goto out_trans_cancel; | ||
| 1387 | |||
| 1388 | error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, | ||
| 1389 | prid, resblks > 0, &ip, NULL); | ||
| 1390 | if (error) { | ||
| 1391 | if (error == ENOSPC) | ||
| 1392 | goto out_trans_cancel; | ||
| 1393 | goto out_trans_abort; | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | if (mp->m_flags & XFS_MOUNT_WSYNC) | ||
| 1397 | xfs_trans_set_sync(tp); | ||
| 1398 | |||
| 1399 | /* | ||
| 1400 | * Attach the dquot(s) to the inodes and modify them incore. | ||
| 1401 | * These ids of the inode couldn't have changed since the new | ||
| 1402 | * inode has been locked ever since it was created. | ||
| 1403 | */ | ||
| 1404 | xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); | ||
| 1405 | |||
| 1406 | ip->i_d.di_nlink--; | ||
| 1407 | d_tmpfile(dentry, VFS_I(ip)); | ||
| 1408 | error = xfs_iunlink(tp, ip); | ||
| 1409 | if (error) | ||
| 1410 | goto out_trans_abort; | ||
| 1411 | |||
| 1412 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | ||
| 1413 | if (error) | ||
| 1414 | goto out_release_inode; | ||
| 1415 | |||
| 1416 | xfs_qm_dqrele(udqp); | ||
| 1417 | xfs_qm_dqrele(gdqp); | ||
| 1418 | xfs_qm_dqrele(pdqp); | ||
| 1419 | |||
| 1420 | return 0; | ||
| 1421 | |||
| 1422 | out_trans_abort: | ||
| 1423 | cancel_flags |= XFS_TRANS_ABORT; | ||
| 1424 | out_trans_cancel: | ||
| 1425 | xfs_trans_cancel(tp, cancel_flags); | ||
| 1426 | out_release_inode: | ||
| 1427 | /* | ||
| 1428 | * Wait until after the current transaction is aborted to | ||
| 1429 | * release the inode. This prevents recursive transactions | ||
| 1430 | * and deadlocks from xfs_inactive. | ||
| 1431 | */ | ||
| 1432 | if (ip) | ||
| 1433 | IRELE(ip); | ||
| 1434 | |||
| 1435 | xfs_qm_dqrele(udqp); | ||
| 1436 | xfs_qm_dqrele(gdqp); | ||
| 1437 | xfs_qm_dqrele(pdqp); | ||
| 1438 | |||
| 1439 | return error; | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | int | ||
| 1336 | xfs_link( | 1443 | xfs_link( |
| 1337 | xfs_inode_t *tdp, | 1444 | xfs_inode_t *tdp, |
| 1338 | xfs_inode_t *sip, | 1445 | xfs_inode_t *sip, |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 6c58349494e7..3a978208f30b 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
| @@ -333,6 +333,8 @@ int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, | |||
| 333 | struct xfs_inode **ipp, struct xfs_name *ci_name); | 333 | struct xfs_inode **ipp, struct xfs_name *ci_name); |
| 334 | int xfs_create(struct xfs_inode *dp, struct xfs_name *name, | 334 | int xfs_create(struct xfs_inode *dp, struct xfs_name *name, |
| 335 | umode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp); | 335 | umode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp); |
| 336 | int xfs_create_tmpfile(struct xfs_inode *dp, struct dentry *dentry, | ||
| 337 | umode_t mode); | ||
| 336 | int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, | 338 | int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, |
| 337 | struct xfs_inode *ip); | 339 | struct xfs_inode *ip); |
| 338 | int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, | 340 | int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, |
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 0ce1d759156e..cb06cc4d0003 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include "xfs_da_btree.h" | 39 | #include "xfs_da_btree.h" |
| 40 | #include "xfs_dir2_priv.h" | 40 | #include "xfs_dir2_priv.h" |
| 41 | #include "xfs_dinode.h" | 41 | #include "xfs_dinode.h" |
| 42 | #include "xfs_trans_space.h" | ||
| 42 | 43 | ||
| 43 | #include <linux/capability.h> | 44 | #include <linux/capability.h> |
| 44 | #include <linux/xattr.h> | 45 | #include <linux/xattr.h> |
| @@ -1043,6 +1044,19 @@ xfs_vn_fiemap( | |||
| 1043 | return 0; | 1044 | return 0; |
| 1044 | } | 1045 | } |
| 1045 | 1046 | ||
| 1047 | STATIC int | ||
| 1048 | xfs_vn_tmpfile( | ||
| 1049 | struct inode *dir, | ||
| 1050 | struct dentry *dentry, | ||
| 1051 | umode_t mode) | ||
| 1052 | { | ||
| 1053 | int error; | ||
| 1054 | |||
| 1055 | error = xfs_create_tmpfile(XFS_I(dir), dentry, mode); | ||
| 1056 | |||
| 1057 | return -error; | ||
| 1058 | } | ||
| 1059 | |||
| 1046 | static const struct inode_operations xfs_inode_operations = { | 1060 | static const struct inode_operations xfs_inode_operations = { |
| 1047 | .get_acl = xfs_get_acl, | 1061 | .get_acl = xfs_get_acl, |
| 1048 | .getattr = xfs_vn_getattr, | 1062 | .getattr = xfs_vn_getattr, |
| @@ -1079,6 +1093,7 @@ static const struct inode_operations xfs_dir_inode_operations = { | |||
| 1079 | .removexattr = generic_removexattr, | 1093 | .removexattr = generic_removexattr, |
| 1080 | .listxattr = xfs_vn_listxattr, | 1094 | .listxattr = xfs_vn_listxattr, |
| 1081 | .update_time = xfs_vn_update_time, | 1095 | .update_time = xfs_vn_update_time, |
| 1096 | .tmpfile = xfs_vn_tmpfile, | ||
| 1082 | }; | 1097 | }; |
| 1083 | 1098 | ||
| 1084 | static const struct inode_operations xfs_dir_ci_inode_operations = { | 1099 | static const struct inode_operations xfs_dir_ci_inode_operations = { |
| @@ -1105,6 +1120,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { | |||
| 1105 | .removexattr = generic_removexattr, | 1120 | .removexattr = generic_removexattr, |
| 1106 | .listxattr = xfs_vn_listxattr, | 1121 | .listxattr = xfs_vn_listxattr, |
| 1107 | .update_time = xfs_vn_update_time, | 1122 | .update_time = xfs_vn_update_time, |
| 1123 | .tmpfile = xfs_vn_tmpfile, | ||
| 1108 | }; | 1124 | }; |
| 1109 | 1125 | ||
| 1110 | static const struct inode_operations xfs_symlink_inode_operations = { | 1126 | static const struct inode_operations xfs_symlink_inode_operations = { |
diff --git a/fs/xfs/xfs_shared.h b/fs/xfs/xfs_shared.h index 8c5035a13df1..4484e5151395 100644 --- a/fs/xfs/xfs_shared.h +++ b/fs/xfs/xfs_shared.h | |||
| @@ -104,7 +104,8 @@ extern const struct xfs_buf_ops xfs_symlink_buf_ops; | |||
| 104 | #define XFS_TRANS_SB_COUNT 41 | 104 | #define XFS_TRANS_SB_COUNT 41 |
| 105 | #define XFS_TRANS_CHECKPOINT 42 | 105 | #define XFS_TRANS_CHECKPOINT 42 |
| 106 | #define XFS_TRANS_ICREATE 43 | 106 | #define XFS_TRANS_ICREATE 43 |
| 107 | #define XFS_TRANS_TYPE_MAX 43 | 107 | #define XFS_TRANS_CREATE_TMPFILE 44 |
| 108 | #define XFS_TRANS_TYPE_MAX 44 | ||
| 108 | /* new transaction types need to be reflected in xfs_logprint(8) */ | 109 | /* new transaction types need to be reflected in xfs_logprint(8) */ |
| 109 | |||
