Skip to content

Commit

Permalink
[XFS] Make hole punching at EOF atomic.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Vlad Apostolov <[email protected]>
Signed-off-by: Tim Shimmin <[email protected]>
  • Loading branch information
David Chinner authored and Tim Shimmin committed Jul 14, 2007
1 parent 511105b commit 92dfe8d
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 13 deletions.
14 changes: 11 additions & 3 deletions fs/xfs/xfs_rw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}

/*
* 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.
*/
Expand All @@ -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 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,
cred_t *credp);
cred_t *credp);
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,
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__ */
28 changes: 18 additions & 10 deletions fs/xfs/xfs_vnodeops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,13 +1201,15 @@ xfs_fsync(
}

/*
* This is called by xfs_inactive to free any blocks beyond eof,
* when the link count isn't zero.
* This is called by xfs_inactive to free any blocks beyond eof
* when the link count isn't zero and by xfs_dm_punch_hole() when
* punching a hole to EOF.
*/
STATIC int
xfs_inactive_free_eofblocks(
int
xfs_free_eofblocks(
xfs_mount_t *mp,
xfs_inode_t *ip)
xfs_inode_t *ip,
int flags)
{
xfs_trans_t *tp;
int error;
Expand All @@ -1216,6 +1218,7 @@ xfs_inactive_free_eofblocks(
xfs_filblks_t map_len;
int nimaps;
xfs_bmbt_irec_t imap;
int use_iolock = (flags & XFS_FREE_EOF_LOCK);

/*
* Figure out if there are any blocks beyond the end
Expand Down Expand Up @@ -1256,11 +1259,13 @@ xfs_inactive_free_eofblocks(
* cache and we can't
* 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,
ip->i_size);
if (error) {
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
if (use_iolock)
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return error;
}

Expand Down Expand Up @@ -1297,7 +1302,8 @@ xfs_inactive_free_eofblocks(
error = xfs_trans_commit(tp,
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;
}
Expand Down Expand Up @@ -1573,7 +1579,8 @@ xfs_release(
(ip->i_df.if_flags & XFS_IFEXTENTS)) &&
(!(ip->i_d.di_flags &
(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;
/* Update linux inode block count after free above */
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
Expand Down Expand Up @@ -1654,7 +1661,8 @@ xfs_inactive(
(!(ip->i_d.di_flags &
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
(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;
/* Update linux inode block count after free above */
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
Expand Down

0 comments on commit 92dfe8d

Please sign in to comment.