[XFS] Make hole punching at EOF atomic.
If hole punching at EOF is done as two steps (i.e. truncate then extend) the file is in a transient state between the two steps where an application can see the incorrect file size. Punching a hole to EOF needs to be treated in teh same way as all other hole punching cases so that the file size is never seen to change. SGI-PV: 962012 SGI-Modid: xfs-linux-melb:xfs-kern:28641a Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Vlad Apostolov <vapo@sgi.com> Signed-off-by: Tim Shimmin <tes@sgi.com>
This commit is contained in:
parent
511105b3d7
commit
92dfe8d266
|
@ -71,6 +71,12 @@ xfs_fsb_to_db_io(struct xfs_iocore *io, xfs_fsblock_t fsb)
|
||||||
XFS_FSB_TO_DADDR((io)->io_mount, (fsb)));
|
XFS_FSB_TO_DADDR((io)->io_mount, (fsb)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags for xfs_free_eofblocks
|
||||||
|
*/
|
||||||
|
#define XFS_FREE_EOF_LOCK (1<<0)
|
||||||
|
#define XFS_FREE_EOF_NOLOCK (1<<1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes for functions in xfs_rw.c.
|
* Prototypes for functions in xfs_rw.c.
|
||||||
*/
|
*/
|
||||||
|
@ -91,10 +97,12 @@ extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp,
|
||||||
extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
|
extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
|
||||||
extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
|
extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
|
||||||
extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags,
|
extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags,
|
||||||
cred_t *credp);
|
cred_t *credp);
|
||||||
extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf,
|
extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf,
|
||||||
xfs_off_t offset, cred_t *credp, int flags);
|
xfs_off_t offset, cred_t *credp, int flags);
|
||||||
extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state,
|
extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state,
|
||||||
cred_t *credp);
|
cred_t *credp);
|
||||||
|
extern int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip,
|
||||||
|
int flags);
|
||||||
|
|
||||||
#endif /* __XFS_RW_H__ */
|
#endif /* __XFS_RW_H__ */
|
||||||
|
|
|
@ -1201,13 +1201,15 @@ xfs_fsync(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is called by xfs_inactive to free any blocks beyond eof,
|
* This is called by xfs_inactive to free any blocks beyond eof
|
||||||
* when the link count isn't zero.
|
* when the link count isn't zero and by xfs_dm_punch_hole() when
|
||||||
|
* punching a hole to EOF.
|
||||||
*/
|
*/
|
||||||
STATIC int
|
int
|
||||||
xfs_inactive_free_eofblocks(
|
xfs_free_eofblocks(
|
||||||
xfs_mount_t *mp,
|
xfs_mount_t *mp,
|
||||||
xfs_inode_t *ip)
|
xfs_inode_t *ip,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
xfs_trans_t *tp;
|
xfs_trans_t *tp;
|
||||||
int error;
|
int error;
|
||||||
|
@ -1216,6 +1218,7 @@ xfs_inactive_free_eofblocks(
|
||||||
xfs_filblks_t map_len;
|
xfs_filblks_t map_len;
|
||||||
int nimaps;
|
int nimaps;
|
||||||
xfs_bmbt_irec_t imap;
|
xfs_bmbt_irec_t imap;
|
||||||
|
int use_iolock = (flags & XFS_FREE_EOF_LOCK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Figure out if there are any blocks beyond the end
|
* Figure out if there are any blocks beyond the end
|
||||||
|
@ -1256,11 +1259,13 @@ xfs_inactive_free_eofblocks(
|
||||||
* cache and we can't
|
* cache and we can't
|
||||||
* do that within a transaction.
|
* do that within a transaction.
|
||||||
*/
|
*/
|
||||||
xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
if (use_iolock)
|
||||||
|
xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
||||||
error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
|
error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
|
||||||
ip->i_size);
|
ip->i_size);
|
||||||
if (error) {
|
if (error) {
|
||||||
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
if (use_iolock)
|
||||||
|
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,7 +1302,8 @@ xfs_inactive_free_eofblocks(
|
||||||
error = xfs_trans_commit(tp,
|
error = xfs_trans_commit(tp,
|
||||||
XFS_TRANS_RELEASE_LOG_RES);
|
XFS_TRANS_RELEASE_LOG_RES);
|
||||||
}
|
}
|
||||||
xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
|
xfs_iunlock(ip, (use_iolock ? (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)
|
||||||
|
: XFS_ILOCK_EXCL));
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -1573,7 +1579,8 @@ xfs_release(
|
||||||
(ip->i_df.if_flags & XFS_IFEXTENTS)) &&
|
(ip->i_df.if_flags & XFS_IFEXTENTS)) &&
|
||||||
(!(ip->i_d.di_flags &
|
(!(ip->i_d.di_flags &
|
||||||
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
|
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
|
||||||
if ((error = xfs_inactive_free_eofblocks(mp, ip)))
|
error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);
|
||||||
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
/* Update linux inode block count after free above */
|
/* Update linux inode block count after free above */
|
||||||
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
|
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
|
||||||
|
@ -1654,7 +1661,8 @@ xfs_inactive(
|
||||||
(!(ip->i_d.di_flags &
|
(!(ip->i_d.di_flags &
|
||||||
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
|
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
|
||||||
(ip->i_delayed_blks != 0)))) {
|
(ip->i_delayed_blks != 0)))) {
|
||||||
if ((error = xfs_inactive_free_eofblocks(mp, ip)))
|
error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);
|
||||||
|
if (error)
|
||||||
return VN_INACTIVE_CACHE;
|
return VN_INACTIVE_CACHE;
|
||||||
/* Update linux inode block count after free above */
|
/* Update linux inode block count after free above */
|
||||||
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
|
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
|
||||||
|
|
Loading…
Reference in a new issue