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