diff options
Diffstat (limited to 'fs/xfs/xfs_inode.c')
| -rw-r--r-- | fs/xfs/xfs_inode.c | 82 | 
1 files changed, 47 insertions, 35 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 61d1cb7dc10d..6f95bdb408ce 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -749,7 +749,6 @@ xfs_ialloc(  	xfs_nlink_t	nlink,  	dev_t		rdev,  	prid_t		prid, -	int		okalloc,  	xfs_buf_t	**ialloc_context,  	xfs_inode_t	**ipp)  { @@ -765,7 +764,7 @@ xfs_ialloc(  	 * Call the space management code to pick  	 * the on-disk inode to be allocated.  	 */ -	error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, +	error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode,  			    ialloc_context, &ino);  	if (error)  		return error; @@ -957,7 +956,6 @@ xfs_dir_ialloc(  	xfs_nlink_t	nlink,  	dev_t		rdev,  	prid_t		prid,		/* project id */ -	int		okalloc,	/* ok to allocate new space */  	xfs_inode_t	**ipp,		/* pointer to inode; it will be  					   locked. */  	int		*committed) @@ -988,8 +986,8 @@ xfs_dir_ialloc(  	 * transaction commit so that no other process can steal  	 * the inode(s) that we've just allocated.  	 */ -	code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, okalloc, -			  &ialloc_context, &ip); +	code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, &ialloc_context, +			&ip);  	/*  	 * Return an error if we were unable to allocate a new inode. @@ -1061,7 +1059,7 @@ xfs_dir_ialloc(  		 * this call should always succeed.  		 */  		code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, -				  okalloc, &ialloc_context, &ip); +				  &ialloc_context, &ip);  		/*  		 * If we get an error at this point, return to the caller @@ -1182,11 +1180,6 @@ xfs_create(  		xfs_flush_inodes(mp);  		error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp);  	} -	if (error == -ENOSPC) { -		/* No space at all so try a "no-allocation" reservation */ -		resblks = 0; -		error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp); -	}  	if (error)  		goto out_release_inode; @@ -1203,19 +1196,13 @@ xfs_create(  	if (error)  		goto out_trans_cancel; -	if (!resblks) { -		error = xfs_dir_canenter(tp, dp, name); -		if (error) -			goto out_trans_cancel; -	} -  	/*  	 * A newly created regular or special file just has one directory  	 * entry pointing to them, but a directory also the "." entry  	 * pointing to itself.  	 */ -	error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, -			       prid, resblks > 0, &ip, NULL); +	error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, prid, &ip, +			NULL);  	if (error)  		goto out_trans_cancel; @@ -1340,11 +1327,6 @@ xfs_create_tmpfile(  	tres = &M_RES(mp)->tr_create_tmpfile;  	error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp); -	if (error == -ENOSPC) { -		/* No space at all so try a "no-allocation" reservation */ -		resblks = 0; -		error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp); -	}  	if (error)  		goto out_release_inode; @@ -1353,8 +1335,7 @@ xfs_create_tmpfile(  	if (error)  		goto out_trans_cancel; -	error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, -				prid, resblks > 0, &ip, NULL); +	error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip, NULL);  	if (error)  		goto out_trans_cancel; @@ -1506,6 +1487,24 @@ xfs_link(  	return error;  } +/* Clear the reflink flag and the cowblocks tag if possible. */ +static void +xfs_itruncate_clear_reflink_flags( +	struct xfs_inode	*ip) +{ +	struct xfs_ifork	*dfork; +	struct xfs_ifork	*cfork; + +	if (!xfs_is_reflink_inode(ip)) +		return; +	dfork = XFS_IFORK_PTR(ip, XFS_DATA_FORK); +	cfork = XFS_IFORK_PTR(ip, XFS_COW_FORK); +	if (dfork->if_bytes == 0 && cfork->if_bytes == 0) +		ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; +	if (cfork->if_bytes == 0) +		xfs_inode_clear_cowblocks_tag(ip); +} +  /*   * Free up the underlying blocks past new_size.  The new size must be smaller   * than the current size.  This routine can be used both for the attribute and @@ -1602,15 +1601,7 @@ xfs_itruncate_extents(  	if (error)  		goto out; -	/* -	 * Clear the reflink flag if there are no data fork blocks and -	 * there are no extents staged in the cow fork. -	 */ -	if (xfs_is_reflink_inode(ip) && ip->i_cnextents == 0) { -		if (ip->i_d.di_nblocks == 0) -			ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; -		xfs_inode_clear_cowblocks_tag(ip); -	} +	xfs_itruncate_clear_reflink_flags(ip);  	/*  	 * Always re-log the inode so that our permanent transaction can keep @@ -2401,6 +2392,24 @@ retry:  }  /* + * Free any local-format buffers sitting around before we reset to + * extents format. + */ +static inline void +xfs_ifree_local_data( +	struct xfs_inode	*ip, +	int			whichfork) +{ +	struct xfs_ifork	*ifp; + +	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) +		return; + +	ifp = XFS_IFORK_PTR(ip, whichfork); +	xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); +} + +/*   * This is called to return an inode to the inode free list.   * The inode should already be truncated to 0 length and have   * no pages associated with it.  This routine also assumes that @@ -2437,6 +2446,9 @@ xfs_ifree(  	if (error)  		return error; +	xfs_ifree_local_data(ip, XFS_DATA_FORK); +	xfs_ifree_local_data(ip, XFS_ATTR_FORK); +  	VFS_I(ip)->i_mode = 0;		/* mark incore inode as free */  	ip->i_d.di_flags = 0;  	ip->i_d.di_dmevmask = 0;  |