aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_inode.c107
-rw-r--r--fs/xfs/xfs_inode.h2
-rw-r--r--fs/xfs/xfs_iops.c16
-rw-r--r--fs/xfs/xfs_shared.h4
-rw-r--r--fs/xfs/xfs_trans_resv.c36
-rw-r--r--fs/xfs/xfs_trans_resv.h2
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
1335int 1335int
1336xfs_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
1442int
1336xfs_link( 1443xfs_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);
334int xfs_create(struct xfs_inode *dp, struct xfs_name *name, 334int 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);
336int xfs_create_tmpfile(struct xfs_inode *dp, struct dentry *dentry,
337 umode_t mode);
336int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, 338int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
337 struct xfs_inode *ip); 339 struct xfs_inode *ip);
338int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, 340int 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
1047STATIC int
1048xfs_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
1046static const struct inode_operations xfs_inode_operations = { 1060static 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
1084static const struct inode_operations xfs_dir_ci_inode_operations = { 1099static 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
1110static const struct inode_operations xfs_symlink_inode_operations = { 1126static 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 */
236STATIC uint
237xfs_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
359STATIC uint
360xfs_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