summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_inode.c
diff options
context:
space:
mode:
authorZhi Yong Wu <wuzhy@linux.vnet.ibm.com>2013-12-18 04:22:41 +0400
committerBen Myers <bpm@sgi.com>2014-01-06 23:52:53 +0400
commitab29743117f9f4c22ac44c13c1647fb24fb2bafe (patch)
tree2c3dde038b7b275cdaad65246f516b7d416b8218 /fs/xfs/xfs_inode.c
parent99b6436bc29e4f10e4388c27a3e4810191cc4788 (diff)
downloadlinux-ab29743117f9f4c22ac44c13c1647fb24fb2bafe.tar.xz
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/xfs_inode.c')
-rw-r--r--fs/xfs/xfs_inode.c10
1 files changed, 9 insertions, 1 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;
STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);
+STATIC int xfs_iunlink_remove(xfs_trans_t *, xfs_inode_t *);
+
/*
* helper function to extract extent size hint from inode
*/
@@ -1118,7 +1120,7 @@ xfs_bumplink(
{
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
- ASSERT(ip->i_d.di_nlink > 0);
+ ASSERT(ip->i_d.di_nlink > 0 || (VFS_I(ip)->i_state & I_LINKABLE));
ip->i_d.di_nlink++;
inc_nlink(VFS_I(ip));
if ((ip->i_d.di_version == 1) &&
@@ -1504,6 +1506,12 @@ xfs_link(
xfs_bmap_init(&free_list, &first_block);
+ if (sip->i_d.di_nlink == 0) {
+ error = xfs_iunlink_remove(tp, sip);
+ if (error)
+ goto abort_return;
+ }
+
error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
&first_block, &free_list, resblks);
if (error)