aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorZhi Yong Wu <wuzhy@linux.vnet.ibm.com>2013-12-17 19:22:41 -0500
committerBen Myers <bpm@sgi.com>2014-01-06 14:52:53 -0500
commitab29743117f9f4c22ac44c13c1647fb24fb2bafe (patch)
tree2c3dde038b7b275cdaad65246f516b7d416b8218 /fs/xfs
parent99b6436bc29e4f10e4388c27a3e4810191cc4788 (diff)
xfs: allow linkat() on O_TMPFILE files
The VFS allows an anonymous temporary file to be named at a later time via a linkat() syscall. The inodes for O_TMPFILE files are are marked with a special flag I_LINKABLE and have a zero link count. To support this in XFS, xfs_link() detects if this flag I_LINKABLE is set and behaves appropriately when detected. So in this case, its transaciton reservation takes into account the additional overhead of removing the inode from the unlinked list. Then the inode is removed from the unlinked list and the directory entry is added. Finally its link count is bumped accordingly. 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/xfs')
-rw-r--r--fs/xfs/xfs_inode.c10
-rw-r--r--fs/xfs/xfs_trans_resv.c19
2 files changed, 26 insertions, 3 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index ac133ea91c4b..b08b5a84cf0a 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -61,6 +61,8 @@ kmem_zone_t *xfs_inode_zone;
61 61
62STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); 62STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);
63 63
64STATIC int xfs_iunlink_remove(xfs_trans_t *, xfs_inode_t *);
65
64/* 66/*
65 * helper function to extract extent size hint from inode 67 * helper function to extract extent size hint from inode
66 */ 68 */
@@ -1118,7 +1120,7 @@ xfs_bumplink(
1118{ 1120{
1119 xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); 1121 xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
1120 1122
1121 ASSERT(ip->i_d.di_nlink > 0); 1123 ASSERT(ip->i_d.di_nlink > 0 || (VFS_I(ip)->i_state & I_LINKABLE));
1122 ip->i_d.di_nlink++; 1124 ip->i_d.di_nlink++;
1123 inc_nlink(VFS_I(ip)); 1125 inc_nlink(VFS_I(ip));
1124 if ((ip->i_d.di_version == 1) && 1126 if ((ip->i_d.di_version == 1) &&
@@ -1504,6 +1506,12 @@ xfs_link(
1504 1506
1505 xfs_bmap_init(&free_list, &first_block); 1507 xfs_bmap_init(&free_list, &first_block);
1506 1508
1509 if (sip->i_d.di_nlink == 0) {
1510 error = xfs_iunlink_remove(tp, sip);
1511 if (error)
1512 goto abort_return;
1513 }
1514
1507 error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino, 1515 error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
1508 &first_block, &free_list, resblks); 1516 &first_block, &free_list, resblks);
1509 if (error) 1517 if (error)
diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c
index bd3b4b7831b7..76f9a02bc36b 100644
--- a/fs/xfs/xfs_trans_resv.c
+++ b/fs/xfs/xfs_trans_resv.c
@@ -204,6 +204,20 @@ xfs_calc_rename_reservation(
204} 204}
205 205
206/* 206/*
207 * For removing an inode from unlinked list at first, we can modify:
208 * the agi hash list and counters: sector size
209 * the on disk inode before ours in the agi hash list: inode cluster size
210 */
211STATIC uint
212xfs_calc_iunlink_remove_reservation(
213 struct xfs_mount *mp)
214{
215 return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
216 MAX((__uint16_t)XFS_FSB_TO_B(mp, 1),
217 (__uint16_t)XFS_INODE_CLUSTER_SIZE(mp));
218}
219
220/*
207 * For creating a link to an inode: 221 * For creating a link to an inode:
208 * the parent directory inode: inode size 222 * the parent directory inode: inode size
209 * the linked inode: inode size 223 * the linked inode: inode size
@@ -220,6 +234,7 @@ xfs_calc_link_reservation(
220 struct xfs_mount *mp) 234 struct xfs_mount *mp)
221{ 235{
222 return XFS_DQUOT_LOGRES(mp) + 236 return XFS_DQUOT_LOGRES(mp) +
237 xfs_calc_iunlink_remove_reservation(mp) +
223 MAX((xfs_calc_inode_res(mp, 2) + 238 MAX((xfs_calc_inode_res(mp, 2) +
224 xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), 239 xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
225 XFS_FSB_TO_B(mp, 1))), 240 XFS_FSB_TO_B(mp, 1))),
@@ -410,9 +425,9 @@ xfs_calc_ifree_reservation(
410{ 425{
411 return XFS_DQUOT_LOGRES(mp) + 426 return XFS_DQUOT_LOGRES(mp) +
412 xfs_calc_inode_res(mp, 1) + 427 xfs_calc_inode_res(mp, 1) +
413 xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + 428 xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
414 xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) + 429 xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) +
415 max_t(uint, XFS_FSB_TO_B(mp, 1), XFS_INODE_CLUSTER_SIZE(mp)) + 430 xfs_calc_iunlink_remove_reservation(mp) +
416 xfs_calc_buf_res(1, 0) + 431 xfs_calc_buf_res(1, 0) +
417 xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) + 432 xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
418 mp->m_in_maxlevels, 0) + 433 mp->m_in_maxlevels, 0) +