mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 06:12:08 +00:00
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>
This commit is contained in:
parent
99b6436bc2
commit
ab29743117
@ -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)
|
||||
|
@ -203,6 +203,20 @@ xfs_calc_rename_reservation(
|
||||
XFS_FSB_TO_B(mp, 1))));
|
||||
}
|
||||
|
||||
/*
|
||||
* For removing an inode from unlinked list at first, we can modify:
|
||||
* the agi hash list and counters: sector size
|
||||
* the on disk inode before ours in the agi hash list: inode cluster size
|
||||
*/
|
||||
STATIC uint
|
||||
xfs_calc_iunlink_remove_reservation(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
|
||||
MAX((__uint16_t)XFS_FSB_TO_B(mp, 1),
|
||||
(__uint16_t)XFS_INODE_CLUSTER_SIZE(mp));
|
||||
}
|
||||
|
||||
/*
|
||||
* For creating a link to an inode:
|
||||
* the parent directory inode: inode size
|
||||
@ -220,6 +234,7 @@ xfs_calc_link_reservation(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
return XFS_DQUOT_LOGRES(mp) +
|
||||
xfs_calc_iunlink_remove_reservation(mp) +
|
||||
MAX((xfs_calc_inode_res(mp, 2) +
|
||||
xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
|
||||
XFS_FSB_TO_B(mp, 1))),
|
||||
@ -410,9 +425,9 @@ xfs_calc_ifree_reservation(
|
||||
{
|
||||
return XFS_DQUOT_LOGRES(mp) +
|
||||
xfs_calc_inode_res(mp, 1) +
|
||||
xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
|
||||
xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
|
||||
xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) +
|
||||
max_t(uint, XFS_FSB_TO_B(mp, 1), XFS_INODE_CLUSTER_SIZE(mp)) +
|
||||
xfs_calc_iunlink_remove_reservation(mp) +
|
||||
xfs_calc_buf_res(1, 0) +
|
||||
xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
|
||||
mp->m_in_maxlevels, 0) +
|
||||
|
Loading…
Reference in New Issue
Block a user