|
|
|
@ -42,7 +42,6 @@ |
|
|
|
|
#include "xfs_bmap_util.h" |
|
|
|
|
#include "xfs_error.h" |
|
|
|
|
#include "xfs_quota.h" |
|
|
|
|
#include "xfs_dinode.h" |
|
|
|
|
#include "xfs_filestream.h" |
|
|
|
|
#include "xfs_cksum.h" |
|
|
|
|
#include "xfs_trace.h" |
|
|
|
@ -62,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 |
|
|
|
|
*/ |
|
|
|
@ -1115,7 +1116,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) && |
|
|
|
@ -1165,10 +1166,7 @@ xfs_create( |
|
|
|
|
if (XFS_FORCED_SHUTDOWN(mp)) |
|
|
|
|
return XFS_ERROR(EIO); |
|
|
|
|
|
|
|
|
|
if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
|
|
|
|
prid = xfs_get_projid(dp); |
|
|
|
|
else |
|
|
|
|
prid = XFS_PROJID_DEFAULT; |
|
|
|
|
prid = xfs_get_initial_prid(dp); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure that we have allocated dquot(s) on disk. |
|
|
|
@ -1332,6 +1330,113 @@ xfs_create( |
|
|
|
|
return error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
xfs_create_tmpfile( |
|
|
|
|
struct xfs_inode *dp, |
|
|
|
|
struct dentry *dentry, |
|
|
|
|
umode_t mode) |
|
|
|
|
{ |
|
|
|
|
struct xfs_mount *mp = dp->i_mount; |
|
|
|
|
struct xfs_inode *ip = NULL; |
|
|
|
|
struct xfs_trans *tp = NULL; |
|
|
|
|
int error; |
|
|
|
|
uint cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
|
|
|
|
prid_t prid; |
|
|
|
|
struct xfs_dquot *udqp = NULL; |
|
|
|
|
struct xfs_dquot *gdqp = NULL; |
|
|
|
|
struct xfs_dquot *pdqp = NULL; |
|
|
|
|
struct xfs_trans_res *tres; |
|
|
|
|
uint resblks; |
|
|
|
|
|
|
|
|
|
if (XFS_FORCED_SHUTDOWN(mp)) |
|
|
|
|
return XFS_ERROR(EIO); |
|
|
|
|
|
|
|
|
|
prid = xfs_get_initial_prid(dp); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure that we have allocated dquot(s) on disk. |
|
|
|
|
*/ |
|
|
|
|
error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()), |
|
|
|
|
xfs_kgid_to_gid(current_fsgid()), prid, |
|
|
|
|
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, |
|
|
|
|
&udqp, &gdqp, &pdqp); |
|
|
|
|
if (error) |
|
|
|
|
return error; |
|
|
|
|
|
|
|
|
|
resblks = XFS_IALLOC_SPACE_RES(mp); |
|
|
|
|
tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE_TMPFILE); |
|
|
|
|
|
|
|
|
|
tres = &M_RES(mp)->tr_create_tmpfile; |
|
|
|
|
error = xfs_trans_reserve(tp, tres, resblks, 0); |
|
|
|
|
if (error == ENOSPC) { |
|
|
|
|
/* No space at all so try a "no-allocation" reservation */ |
|
|
|
|
resblks = 0; |
|
|
|
|
error = xfs_trans_reserve(tp, tres, 0, 0); |
|
|
|
|
} |
|
|
|
|
if (error) { |
|
|
|
|
cancel_flags = 0; |
|
|
|
|
goto out_trans_cancel; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, |
|
|
|
|
pdqp, resblks, 1, 0); |
|
|
|
|
if (error) |
|
|
|
|
goto out_trans_cancel; |
|
|
|
|
|
|
|
|
|
error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, |
|
|
|
|
prid, resblks > 0, &ip, NULL); |
|
|
|
|
if (error) { |
|
|
|
|
if (error == ENOSPC) |
|
|
|
|
goto out_trans_cancel; |
|
|
|
|
goto out_trans_abort; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (mp->m_flags & XFS_MOUNT_WSYNC) |
|
|
|
|
xfs_trans_set_sync(tp); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Attach the dquot(s) to the inodes and modify them incore. |
|
|
|
|
* These ids of the inode couldn't have changed since the new |
|
|
|
|
* inode has been locked ever since it was created. |
|
|
|
|
*/ |
|
|
|
|
xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); |
|
|
|
|
|
|
|
|
|
ip->i_d.di_nlink--; |
|
|
|
|
d_tmpfile(dentry, VFS_I(ip)); |
|
|
|
|
error = xfs_iunlink(tp, ip); |
|
|
|
|
if (error) |
|
|
|
|
goto out_trans_abort; |
|
|
|
|
|
|
|
|
|
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
|
|
|
|
if (error) |
|
|
|
|
goto out_release_inode; |
|
|
|
|
|
|
|
|
|
xfs_qm_dqrele(udqp); |
|
|
|
|
xfs_qm_dqrele(gdqp); |
|
|
|
|
xfs_qm_dqrele(pdqp); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
out_trans_abort: |
|
|
|
|
cancel_flags |= XFS_TRANS_ABORT; |
|
|
|
|
out_trans_cancel: |
|
|
|
|
xfs_trans_cancel(tp, cancel_flags); |
|
|
|
|
out_release_inode: |
|
|
|
|
/*
|
|
|
|
|
* Wait until after the current transaction is aborted to |
|
|
|
|
* release the inode. This prevents recursive transactions |
|
|
|
|
* and deadlocks from xfs_inactive. |
|
|
|
|
*/ |
|
|
|
|
if (ip) |
|
|
|
|
IRELE(ip); |
|
|
|
|
|
|
|
|
|
xfs_qm_dqrele(udqp); |
|
|
|
|
xfs_qm_dqrele(gdqp); |
|
|
|
|
xfs_qm_dqrele(pdqp); |
|
|
|
|
|
|
|
|
|
return error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
xfs_link( |
|
|
|
|
xfs_inode_t *tdp, |
|
|
|
@ -1397,6 +1502,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) |
|
|
|
|