aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorZhi Yong Wu <wuzhy@linux.vnet.ibm.com>2013-12-17 19:22:40 -0500
committerBen Myers <bpm@sgi.com>2014-01-06 14:50:06 -0500
commit99b6436bc29e4f10e4388c27a3e4810191cc4788 (patch)
treea9dc0d6a5b4cec023772eff4b9fbac0ead093135 /fs
parent163467d3753e77e1d77da75727975cc3803a1dbc (diff)
xfs: add O_TMPFILE support
Add two functions xfs_create_tmpfile() and xfs_vn_tmpfile() to support O_TMPFILE file creation. In contrast to xfs_create(), xfs_create_tmpfile() has a different log reservation to the regular file creation because there is no directory modification, and doesn't check if an entry can be added to the directory, but the reservation quotas is required appropriately, and finally its inode is added to the unlinked list. xfs_vn_tmpfile() add one O_TMPFILE method to VFS interface and directly invoke xfs_create_tmpfile(). Signed-off-by: Zhi Yong Wu <wuzhy@linux.vnet.ibm.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs')
-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