diff options
author | David Chinner <dgc@sgi.com> | 2007-05-24 01:22:19 -0400 |
---|---|---|
committer | Tim Shimmin <tes@chook.melbourne.sgi.com> | 2007-07-14 01:23:40 -0400 |
commit | 92dfe8d266eaf35a50607a0e0dcf525e1d367c80 (patch) | |
tree | a9149b1bcad2142b14b8b25c06c64a0ae7399f64 /fs | |
parent | 511105b3d7c2440ee84fc3f90d200569aac88162 (diff) |
[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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_rw.h | 14 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 28 |
2 files changed, 29 insertions, 13 deletions
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h index 188b296ff50c..ba74000931ec 100644 --- a/fs/xfs/xfs_rw.h +++ b/fs/xfs/xfs_rw.h | |||
@@ -72,6 +72,12 @@ xfs_fsb_to_db_io(struct xfs_iocore *io, xfs_fsblock_t fsb) | |||
72 | } | 72 | } |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * Flags for xfs_free_eofblocks | ||
76 | */ | ||
77 | #define XFS_FREE_EOF_LOCK (1<<0) | ||
78 | #define XFS_FREE_EOF_NOLOCK (1<<1) | ||
79 | |||
80 | /* | ||
75 | * Prototypes for functions in xfs_rw.c. | 81 | * Prototypes for functions in xfs_rw.c. |
76 | */ | 82 | */ |
77 | extern int xfs_write_clear_setuid(struct xfs_inode *ip); | 83 | extern int xfs_write_clear_setuid(struct xfs_inode *ip); |
@@ -91,10 +97,12 @@ extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp, | |||
91 | extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); | 97 | extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); |
92 | extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); | 98 | extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); |
93 | extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags, | 99 | extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags, |
94 | cred_t *credp); | 100 | cred_t *credp); |
95 | extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf, | 101 | extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf, |
96 | xfs_off_t offset, cred_t *credp, int flags); | 102 | xfs_off_t offset, cred_t *credp, int flags); |
97 | extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state, | 103 | extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state, |
98 | cred_t *credp); | 104 | cred_t *credp); |
105 | extern int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip, | ||
106 | int flags); | ||
99 | 107 | ||
100 | #endif /* __XFS_RW_H__ */ | 108 | #endif /* __XFS_RW_H__ */ |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 70bc82f65311..6420ca8df5ec 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -1201,13 +1201,15 @@ xfs_fsync( | |||
1201 | } | 1201 | } |
1202 | 1202 | ||
1203 | /* | 1203 | /* |
1204 | * This is called by xfs_inactive to free any blocks beyond eof, | 1204 | * This is called by xfs_inactive to free any blocks beyond eof |
1205 | * when the link count isn't zero. | 1205 | * when the link count isn't zero and by xfs_dm_punch_hole() when |
1206 | * punching a hole to EOF. | ||
1206 | */ | 1207 | */ |
1207 | STATIC int | 1208 | int |
1208 | xfs_inactive_free_eofblocks( | 1209 | xfs_free_eofblocks( |
1209 | xfs_mount_t *mp, | 1210 | xfs_mount_t *mp, |
1210 | xfs_inode_t *ip) | 1211 | xfs_inode_t *ip, |
1212 | int flags) | ||
1211 | { | 1213 | { |
1212 | xfs_trans_t *tp; | 1214 | xfs_trans_t *tp; |
1213 | int error; | 1215 | int error; |
@@ -1216,6 +1218,7 @@ xfs_inactive_free_eofblocks( | |||
1216 | xfs_filblks_t map_len; | 1218 | xfs_filblks_t map_len; |
1217 | int nimaps; | 1219 | int nimaps; |
1218 | xfs_bmbt_irec_t imap; | 1220 | xfs_bmbt_irec_t imap; |
1221 | int use_iolock = (flags & XFS_FREE_EOF_LOCK); | ||
1219 | 1222 | ||
1220 | /* | 1223 | /* |
1221 | * Figure out if there are any blocks beyond the end | 1224 | * Figure out if there are any blocks beyond the end |
@@ -1256,11 +1259,13 @@ xfs_inactive_free_eofblocks( | |||
1256 | * cache and we can't | 1259 | * cache and we can't |
1257 | * do that within a transaction. | 1260 | * do that within a transaction. |
1258 | */ | 1261 | */ |
1259 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 1262 | if (use_iolock) |
1263 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | ||
1260 | error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, | 1264 | error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, |
1261 | ip->i_size); | 1265 | ip->i_size); |
1262 | if (error) { | 1266 | if (error) { |
1263 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 1267 | if (use_iolock) |
1268 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
1264 | return error; | 1269 | return error; |
1265 | } | 1270 | } |
1266 | 1271 | ||
@@ -1297,7 +1302,8 @@ xfs_inactive_free_eofblocks( | |||
1297 | error = xfs_trans_commit(tp, | 1302 | error = xfs_trans_commit(tp, |
1298 | XFS_TRANS_RELEASE_LOG_RES); | 1303 | XFS_TRANS_RELEASE_LOG_RES); |
1299 | } | 1304 | } |
1300 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 1305 | xfs_iunlock(ip, (use_iolock ? (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL) |
1306 | : XFS_ILOCK_EXCL)); | ||
1301 | } | 1307 | } |
1302 | return error; | 1308 | return error; |
1303 | } | 1309 | } |
@@ -1573,7 +1579,8 @@ xfs_release( | |||
1573 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && | 1579 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && |
1574 | (!(ip->i_d.di_flags & | 1580 | (!(ip->i_d.di_flags & |
1575 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { | 1581 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { |
1576 | if ((error = xfs_inactive_free_eofblocks(mp, ip))) | 1582 | error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); |
1583 | if (error) | ||
1577 | return error; | 1584 | return error; |
1578 | /* Update linux inode block count after free above */ | 1585 | /* Update linux inode block count after free above */ |
1579 | vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp, | 1586 | vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp, |
@@ -1654,7 +1661,8 @@ xfs_inactive( | |||
1654 | (!(ip->i_d.di_flags & | 1661 | (!(ip->i_d.di_flags & |
1655 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) || | 1662 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) || |
1656 | (ip->i_delayed_blks != 0)))) { | 1663 | (ip->i_delayed_blks != 0)))) { |
1657 | if ((error = xfs_inactive_free_eofblocks(mp, ip))) | 1664 | error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK); |
1665 | if (error) | ||
1658 | return VN_INACTIVE_CACHE; | 1666 | return VN_INACTIVE_CACHE; |
1659 | /* Update linux inode block count after free above */ | 1667 | /* Update linux inode block count after free above */ |
1660 | vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp, | 1668 | vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp, |