aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2007-05-24 01:22:19 -0400
committerTim Shimmin <tes@chook.melbourne.sgi.com>2007-07-14 01:23:40 -0400
commit92dfe8d266eaf35a50607a0e0dcf525e1d367c80 (patch)
treea9149b1bcad2142b14b8b25c06c64a0ae7399f64 /fs
parent511105b3d7c2440ee84fc3f90d200569aac88162 (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.h14
-rw-r--r--fs/xfs/xfs_vnodeops.c28
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 */
77extern int xfs_write_clear_setuid(struct xfs_inode *ip); 83extern int xfs_write_clear_setuid(struct xfs_inode *ip);
@@ -91,10 +97,12 @@ extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp,
91extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); 97extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
92extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); 98extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
93extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags, 99extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags,
94 cred_t *credp); 100 cred_t *credp);
95extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf, 101extern 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);
97extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state, 103extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state,
98 cred_t *credp); 104 cred_t *credp);
105extern 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 */
1207STATIC int 1208int
1208xfs_inactive_free_eofblocks( 1209xfs_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,