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 | 110 | ||
110 | #define XFS_TRANS_TYPES \ | 111 | #define XFS_TRANS_TYPES \ |
@@ -112,6 +113,7 @@ extern const struct xfs_buf_ops xfs_symlink_buf_ops; | |||
112 | { XFS_TRANS_SETATTR_SIZE, "SETATTR_SIZE" }, \ | 113 | { XFS_TRANS_SETATTR_SIZE, "SETATTR_SIZE" }, \ |
113 | { XFS_TRANS_INACTIVE, "INACTIVE" }, \ | 114 | { XFS_TRANS_INACTIVE, "INACTIVE" }, \ |
114 | { XFS_TRANS_CREATE, "CREATE" }, \ | 115 | { XFS_TRANS_CREATE, "CREATE" }, \ |
116 | { XFS_TRANS_CREATE_TMPFILE, "CREATE_TMPFILE" }, \ | ||
115 | { XFS_TRANS_CREATE_TRUNC, "CREATE_TRUNC" }, \ | 117 | { XFS_TRANS_CREATE_TRUNC, "CREATE_TRUNC" }, \ |
116 | { XFS_TRANS_TRUNCATE_FILE, "TRUNCATE_FILE" }, \ | 118 | { XFS_TRANS_TRUNCATE_FILE, "TRUNCATE_FILE" }, \ |
117 | { XFS_TRANS_REMOVE, "REMOVE" }, \ | 119 | { XFS_TRANS_REMOVE, "REMOVE" }, \ |
diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c index 2fd59c0dae66..bd3b4b7831b7 100644 --- a/fs/xfs/xfs_trans_resv.c +++ b/fs/xfs/xfs_trans_resv.c | |||
@@ -229,6 +229,18 @@ xfs_calc_link_reservation( | |||
229 | } | 229 | } |
230 | 230 | ||
231 | /* | 231 | /* |
232 | * For adding an inode to unlinked list we can modify: | ||
233 | * the agi hash list: sector size | ||
234 | * the unlinked inode: inode size | ||
235 | */ | ||
236 | STATIC uint | ||
237 | xfs_calc_iunlink_add_reservation(xfs_mount_t *mp) | ||
238 | { | ||
239 | return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + | ||
240 | xfs_calc_inode_res(mp, 1); | ||
241 | } | ||
242 | |||
243 | /* | ||
232 | * For removing a directory entry we can modify: | 244 | * For removing a directory entry we can modify: |
233 | * the parent directory inode: inode size | 245 | * the parent directory inode: inode size |
234 | * the removed inode: inode size | 246 | * the removed inode: inode size |
@@ -245,10 +257,11 @@ xfs_calc_remove_reservation( | |||
245 | struct xfs_mount *mp) | 257 | struct xfs_mount *mp) |
246 | { | 258 | { |
247 | return XFS_DQUOT_LOGRES(mp) + | 259 | return XFS_DQUOT_LOGRES(mp) + |
248 | MAX((xfs_calc_inode_res(mp, 2) + | 260 | xfs_calc_iunlink_add_reservation(mp) + |
261 | MAX((xfs_calc_inode_res(mp, 1) + | ||
249 | xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), | 262 | xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), |
250 | XFS_FSB_TO_B(mp, 1))), | 263 | XFS_FSB_TO_B(mp, 1))), |
251 | (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + | 264 | (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + |
252 | xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2), | 265 | xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2), |
253 | XFS_FSB_TO_B(mp, 1)))); | 266 | XFS_FSB_TO_B(mp, 1)))); |
254 | } | 267 | } |
@@ -343,6 +356,20 @@ xfs_calc_create_reservation( | |||
343 | 356 | ||
344 | } | 357 | } |
345 | 358 | ||
359 | STATIC uint | ||
360 | xfs_calc_create_tmpfile_reservation( | ||
361 | struct xfs_mount *mp) | ||
362 | { | ||
363 | uint res = XFS_DQUOT_LOGRES(mp); | ||
364 | |||
365 | if (xfs_sb_version_hascrc(&mp->m_sb)) | ||
366 | res += xfs_calc_icreate_resv_alloc(mp); | ||
367 | else | ||
368 | res += xfs_calc_create_resv_alloc(mp); | ||
369 | |||
370 | return res + xfs_calc_iunlink_add_reservation(mp); | ||
371 | } | ||
372 | |||
346 | /* | 373 | /* |
347 | * Making a new directory is the same as creating a new file. | 374 | * Making a new directory is the same as creating a new file. |
348 | */ | 375 | */ |
@@ -729,6 +756,11 @@ xfs_trans_resv_calc( | |||
729 | resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; | 756 | resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; |
730 | resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; | 757 | resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; |
731 | 758 | ||
759 | resp->tr_create_tmpfile.tr_logres = | ||
760 | xfs_calc_create_tmpfile_reservation(mp); | ||
761 | resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT; | ||
762 | resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES; | ||
763 | |||
732 | resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); | 764 | resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); |
733 | resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; | 765 | resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; |
734 | resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; | 766 | resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; |
diff --git a/fs/xfs/xfs_trans_resv.h b/fs/xfs/xfs_trans_resv.h index de7de9aaad8a..285621d583f0 100644 --- a/fs/xfs/xfs_trans_resv.h +++ b/fs/xfs/xfs_trans_resv.h | |||
@@ -38,6 +38,7 @@ struct xfs_trans_resv { | |||
38 | struct xfs_trans_res tr_remove; /* unlink trans */ | 38 | struct xfs_trans_res tr_remove; /* unlink trans */ |
39 | struct xfs_trans_res tr_symlink; /* symlink trans */ | 39 | struct xfs_trans_res tr_symlink; /* symlink trans */ |
40 | struct xfs_trans_res tr_create; /* create trans */ | 40 | struct xfs_trans_res tr_create; /* create trans */ |
41 | struct xfs_trans_res tr_create_tmpfile; /* create O_TMPFILE trans */ | ||
41 | struct xfs_trans_res tr_mkdir; /* mkdir trans */ | 42 | struct xfs_trans_res tr_mkdir; /* mkdir trans */ |
42 | struct xfs_trans_res tr_ifree; /* inode free trans */ | 43 | struct xfs_trans_res tr_ifree; /* inode free trans */ |
43 | struct xfs_trans_res tr_ichange; /* inode update trans */ | 44 | struct xfs_trans_res tr_ichange; /* inode update trans */ |
@@ -100,6 +101,7 @@ struct xfs_trans_resv { | |||
100 | #define XFS_ITRUNCATE_LOG_COUNT 2 | 101 | #define XFS_ITRUNCATE_LOG_COUNT 2 |
101 | #define XFS_INACTIVE_LOG_COUNT 2 | 102 | #define XFS_INACTIVE_LOG_COUNT 2 |
102 | #define XFS_CREATE_LOG_COUNT 2 | 103 | #define XFS_CREATE_LOG_COUNT 2 |
104 | #define XFS_CREATE_TMPFILE_LOG_COUNT 2 | ||
103 | #define XFS_MKDIR_LOG_COUNT 3 | 105 | #define XFS_MKDIR_LOG_COUNT 3 |
104 | #define XFS_SYMLINK_LOG_COUNT 3 | 106 | #define XFS_SYMLINK_LOG_COUNT 3 |
105 | #define XFS_REMOVE_LOG_COUNT 2 | 107 | #define XFS_REMOVE_LOG_COUNT 2 |