diff options
-rw-r--r-- | fs/xfs/xfs_attr.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 124 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_iops.c | 47 | ||||
-rw-r--r-- | fs/xfs/xfs_qm_syscalls.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_trace.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 17 |
7 files changed, 65 insertions, 142 deletions
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 1e5d97f86ea8..08b9ac644c31 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
@@ -827,10 +827,6 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
827 | if (error) | 827 | if (error) |
828 | goto out; | 828 | goto out; |
829 | 829 | ||
830 | /* | ||
831 | * Commit the last in the sequence of transactions. | ||
832 | */ | ||
833 | xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); | ||
834 | error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); | 830 | error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); |
835 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 831 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
836 | 832 | ||
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 9dda7cc32848..ccd619a993f6 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -1166,52 +1166,6 @@ xfs_ialloc( | |||
1166 | } | 1166 | } |
1167 | 1167 | ||
1168 | /* | 1168 | /* |
1169 | * Check to make sure that there are no blocks allocated to the | ||
1170 | * file beyond the size of the file. We don't check this for | ||
1171 | * files with fixed size extents or real time extents, but we | ||
1172 | * at least do it for regular files. | ||
1173 | */ | ||
1174 | #ifdef DEBUG | ||
1175 | STATIC void | ||
1176 | xfs_isize_check( | ||
1177 | struct xfs_inode *ip, | ||
1178 | xfs_fsize_t isize) | ||
1179 | { | ||
1180 | struct xfs_mount *mp = ip->i_mount; | ||
1181 | xfs_fileoff_t map_first; | ||
1182 | int nimaps; | ||
1183 | xfs_bmbt_irec_t imaps[2]; | ||
1184 | int error; | ||
1185 | |||
1186 | if (!S_ISREG(ip->i_d.di_mode)) | ||
1187 | return; | ||
1188 | |||
1189 | if (XFS_IS_REALTIME_INODE(ip)) | ||
1190 | return; | ||
1191 | |||
1192 | if (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) | ||
1193 | return; | ||
1194 | |||
1195 | nimaps = 2; | ||
1196 | map_first = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); | ||
1197 | /* | ||
1198 | * The filesystem could be shutting down, so bmapi may return | ||
1199 | * an error. | ||
1200 | */ | ||
1201 | error = xfs_bmapi_read(ip, map_first, | ||
1202 | (XFS_B_TO_FSB(mp, | ||
1203 | (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - map_first), | ||
1204 | imaps, &nimaps, XFS_BMAPI_ENTIRE); | ||
1205 | if (error) | ||
1206 | return; | ||
1207 | ASSERT(nimaps == 1); | ||
1208 | ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK); | ||
1209 | } | ||
1210 | #else /* DEBUG */ | ||
1211 | #define xfs_isize_check(ip, isize) | ||
1212 | #endif /* DEBUG */ | ||
1213 | |||
1214 | /* | ||
1215 | * Free up the underlying blocks past new_size. The new size must be smaller | 1169 | * Free up the underlying blocks past new_size. The new size must be smaller |
1216 | * than the current size. This routine can be used both for the attribute and | 1170 | * than the current size. This routine can be used both for the attribute and |
1217 | * data fork, and does not modify the inode size, which is left to the caller. | 1171 | * data fork, and does not modify the inode size, which is left to the caller. |
@@ -1258,6 +1212,8 @@ xfs_itruncate_extents( | |||
1258 | ASSERT(ip->i_itemp->ili_lock_flags == 0); | 1212 | ASSERT(ip->i_itemp->ili_lock_flags == 0); |
1259 | ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); | 1213 | ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); |
1260 | 1214 | ||
1215 | trace_xfs_itruncate_extents_start(ip, new_size); | ||
1216 | |||
1261 | /* | 1217 | /* |
1262 | * Since it is possible for space to become allocated beyond | 1218 | * Since it is possible for space to become allocated beyond |
1263 | * the end of the file (in a crash where the space is allocated | 1219 | * the end of the file (in a crash where the space is allocated |
@@ -1325,6 +1281,14 @@ xfs_itruncate_extents( | |||
1325 | goto out; | 1281 | goto out; |
1326 | } | 1282 | } |
1327 | 1283 | ||
1284 | /* | ||
1285 | * Always re-log the inode so that our permanent transaction can keep | ||
1286 | * on rolling it forward in the log. | ||
1287 | */ | ||
1288 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
1289 | |||
1290 | trace_xfs_itruncate_extents_end(ip, new_size); | ||
1291 | |||
1328 | out: | 1292 | out: |
1329 | *tpp = tp; | 1293 | *tpp = tp; |
1330 | return error; | 1294 | return error; |
@@ -1338,74 +1302,6 @@ out_bmap_cancel: | |||
1338 | goto out; | 1302 | goto out; |
1339 | } | 1303 | } |
1340 | 1304 | ||
1341 | int | ||
1342 | xfs_itruncate_data( | ||
1343 | struct xfs_trans **tpp, | ||
1344 | struct xfs_inode *ip, | ||
1345 | xfs_fsize_t new_size) | ||
1346 | { | ||
1347 | int error; | ||
1348 | |||
1349 | trace_xfs_itruncate_data_start(ip, new_size); | ||
1350 | |||
1351 | /* | ||
1352 | * The first thing we do is set the size to new_size permanently on | ||
1353 | * disk. This way we don't have to worry about anyone ever being able | ||
1354 | * to look at the data being freed even in the face of a crash. | ||
1355 | * What we're getting around here is the case where we free a block, it | ||
1356 | * is allocated to another file, it is written to, and then we crash. | ||
1357 | * If the new data gets written to the file but the log buffers | ||
1358 | * containing the free and reallocation don't, then we'd end up with | ||
1359 | * garbage in the blocks being freed. As long as we make the new_size | ||
1360 | * permanent before actually freeing any blocks it doesn't matter if | ||
1361 | * they get written to. | ||
1362 | */ | ||
1363 | if (ip->i_d.di_nextents > 0) { | ||
1364 | /* | ||
1365 | * If we are not changing the file size then do not update | ||
1366 | * the on-disk file size - we may be called from | ||
1367 | * xfs_inactive_free_eofblocks(). If we update the on-disk | ||
1368 | * file size and then the system crashes before the contents | ||
1369 | * of the file are flushed to disk then the files may be | ||
1370 | * full of holes (ie NULL files bug). | ||
1371 | */ | ||
1372 | if (ip->i_size != new_size) { | ||
1373 | ip->i_d.di_size = new_size; | ||
1374 | ip->i_size = new_size; | ||
1375 | xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); | ||
1376 | } | ||
1377 | } | ||
1378 | |||
1379 | error = xfs_itruncate_extents(tpp, ip, XFS_DATA_FORK, new_size); | ||
1380 | if (error) | ||
1381 | return error; | ||
1382 | |||
1383 | /* | ||
1384 | * If we are not changing the file size then do not update the on-disk | ||
1385 | * file size - we may be called from xfs_inactive_free_eofblocks(). | ||
1386 | * If we update the on-disk file size and then the system crashes | ||
1387 | * before the contents of the file are flushed to disk then the files | ||
1388 | * may be full of holes (ie NULL files bug). | ||
1389 | */ | ||
1390 | xfs_isize_check(ip, new_size); | ||
1391 | if (ip->i_size != new_size) { | ||
1392 | ip->i_d.di_size = new_size; | ||
1393 | ip->i_size = new_size; | ||
1394 | } | ||
1395 | |||
1396 | ASSERT(new_size != 0 || ip->i_delayed_blks == 0); | ||
1397 | ASSERT(new_size != 0 || ip->i_d.di_nextents == 0); | ||
1398 | |||
1399 | /* | ||
1400 | * Always re-log the inode so that our permanent transaction can keep | ||
1401 | * on rolling it forward in the log. | ||
1402 | */ | ||
1403 | xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); | ||
1404 | |||
1405 | trace_xfs_itruncate_data_end(ip, new_size); | ||
1406 | return 0; | ||
1407 | } | ||
1408 | |||
1409 | /* | 1305 | /* |
1410 | * This is called when the inode's link count goes to 0. | 1306 | * This is called when the inode's link count goes to 0. |
1411 | * We place the on-disk inode on a list in the AGI. It | 1307 | * We place the on-disk inode on a list in the AGI. It |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index f0e6b151ba37..440f2acebfa8 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -491,8 +491,6 @@ int xfs_ifree(struct xfs_trans *, xfs_inode_t *, | |||
491 | struct xfs_bmap_free *); | 491 | struct xfs_bmap_free *); |
492 | int xfs_itruncate_extents(struct xfs_trans **, struct xfs_inode *, | 492 | int xfs_itruncate_extents(struct xfs_trans **, struct xfs_inode *, |
493 | int, xfs_fsize_t); | 493 | int, xfs_fsize_t); |
494 | int xfs_itruncate_data(struct xfs_trans **, struct xfs_inode *, | ||
495 | xfs_fsize_t); | ||
496 | int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); | 494 | int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); |
497 | 495 | ||
498 | void xfs_iext_realloc(xfs_inode_t *, int, int); | 496 | void xfs_iext_realloc(xfs_inode_t *, int, int); |
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index f9babd179223..f02eaa298d3c 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -750,6 +750,7 @@ xfs_setattr_size( | |||
750 | struct xfs_mount *mp = ip->i_mount; | 750 | struct xfs_mount *mp = ip->i_mount; |
751 | struct inode *inode = VFS_I(ip); | 751 | struct inode *inode = VFS_I(ip); |
752 | int mask = iattr->ia_valid; | 752 | int mask = iattr->ia_valid; |
753 | xfs_off_t oldsize, newsize; | ||
753 | struct xfs_trans *tp; | 754 | struct xfs_trans *tp; |
754 | int error; | 755 | int error; |
755 | uint lock_flags; | 756 | uint lock_flags; |
@@ -777,11 +778,13 @@ xfs_setattr_size( | |||
777 | lock_flags |= XFS_IOLOCK_EXCL; | 778 | lock_flags |= XFS_IOLOCK_EXCL; |
778 | xfs_ilock(ip, lock_flags); | 779 | xfs_ilock(ip, lock_flags); |
779 | 780 | ||
781 | oldsize = ip->i_size; | ||
782 | newsize = iattr->ia_size; | ||
783 | |||
780 | /* | 784 | /* |
781 | * Short circuit the truncate case for zero length files. | 785 | * Short circuit the truncate case for zero length files. |
782 | */ | 786 | */ |
783 | if (iattr->ia_size == 0 && | 787 | if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) { |
784 | ip->i_size == 0 && ip->i_d.di_nextents == 0) { | ||
785 | if (!(mask & (ATTR_CTIME|ATTR_MTIME))) | 788 | if (!(mask & (ATTR_CTIME|ATTR_MTIME))) |
786 | goto out_unlock; | 789 | goto out_unlock; |
787 | 790 | ||
@@ -807,14 +810,14 @@ xfs_setattr_size( | |||
807 | * the inode to the transaction, because the inode cannot be unlocked | 810 | * the inode to the transaction, because the inode cannot be unlocked |
808 | * once it is a part of the transaction. | 811 | * once it is a part of the transaction. |
809 | */ | 812 | */ |
810 | if (iattr->ia_size > ip->i_size) { | 813 | if (newsize > oldsize) { |
811 | /* | 814 | /* |
812 | * Do the first part of growing a file: zero any data in the | 815 | * Do the first part of growing a file: zero any data in the |
813 | * last block that is beyond the old EOF. We need to do this | 816 | * last block that is beyond the old EOF. We need to do this |
814 | * before the inode is joined to the transaction to modify | 817 | * before the inode is joined to the transaction to modify |
815 | * i_size. | 818 | * i_size. |
816 | */ | 819 | */ |
817 | error = xfs_zero_eof(ip, iattr->ia_size, ip->i_size); | 820 | error = xfs_zero_eof(ip, newsize, oldsize); |
818 | if (error) | 821 | if (error) |
819 | goto out_unlock; | 822 | goto out_unlock; |
820 | } | 823 | } |
@@ -833,8 +836,8 @@ xfs_setattr_size( | |||
833 | * here and prevents waiting for other data not within the range we | 836 | * here and prevents waiting for other data not within the range we |
834 | * care about here. | 837 | * care about here. |
835 | */ | 838 | */ |
836 | if (ip->i_size != ip->i_d.di_size && iattr->ia_size > ip->i_d.di_size) { | 839 | if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) { |
837 | error = xfs_flush_pages(ip, ip->i_d.di_size, iattr->ia_size, 0, | 840 | error = xfs_flush_pages(ip, ip->i_d.di_size, newsize, 0, |
838 | FI_NONE); | 841 | FI_NONE); |
839 | if (error) | 842 | if (error) |
840 | goto out_unlock; | 843 | goto out_unlock; |
@@ -845,8 +848,7 @@ xfs_setattr_size( | |||
845 | */ | 848 | */ |
846 | inode_dio_wait(inode); | 849 | inode_dio_wait(inode); |
847 | 850 | ||
848 | error = -block_truncate_page(inode->i_mapping, iattr->ia_size, | 851 | error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks); |
849 | xfs_get_blocks); | ||
850 | if (error) | 852 | if (error) |
851 | goto out_unlock; | 853 | goto out_unlock; |
852 | 854 | ||
@@ -857,7 +859,7 @@ xfs_setattr_size( | |||
857 | if (error) | 859 | if (error) |
858 | goto out_trans_cancel; | 860 | goto out_trans_cancel; |
859 | 861 | ||
860 | truncate_setsize(inode, iattr->ia_size); | 862 | truncate_setsize(inode, newsize); |
861 | 863 | ||
862 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; | 864 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; |
863 | lock_flags |= XFS_ILOCK_EXCL; | 865 | lock_flags |= XFS_ILOCK_EXCL; |
@@ -876,19 +878,30 @@ xfs_setattr_size( | |||
876 | * these flags set. For all other operations the VFS set these flags | 878 | * these flags set. For all other operations the VFS set these flags |
877 | * explicitly if it wants a timestamp update. | 879 | * explicitly if it wants a timestamp update. |
878 | */ | 880 | */ |
879 | if (iattr->ia_size != ip->i_size && | 881 | if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) { |
880 | (!(mask & (ATTR_CTIME | ATTR_MTIME)))) { | ||
881 | iattr->ia_ctime = iattr->ia_mtime = | 882 | iattr->ia_ctime = iattr->ia_mtime = |
882 | current_fs_time(inode->i_sb); | 883 | current_fs_time(inode->i_sb); |
883 | mask |= ATTR_CTIME | ATTR_MTIME; | 884 | mask |= ATTR_CTIME | ATTR_MTIME; |
884 | } | 885 | } |
885 | 886 | ||
886 | if (iattr->ia_size > ip->i_size) { | 887 | /* |
887 | ip->i_d.di_size = iattr->ia_size; | 888 | * The first thing we do is set the size to new_size permanently on |
888 | ip->i_size = iattr->ia_size; | 889 | * disk. This way we don't have to worry about anyone ever being able |
889 | } else if (iattr->ia_size <= ip->i_size || | 890 | * to look at the data being freed even in the face of a crash. |
890 | (iattr->ia_size == 0 && ip->i_d.di_nextents)) { | 891 | * What we're getting around here is the case where we free a block, it |
891 | error = xfs_itruncate_data(&tp, ip, iattr->ia_size); | 892 | * is allocated to another file, it is written to, and then we crash. |
893 | * If the new data gets written to the file but the log buffers | ||
894 | * containing the free and reallocation don't, then we'd end up with | ||
895 | * garbage in the blocks being freed. As long as we make the new size | ||
896 | * permanent before actually freeing any blocks it doesn't matter if | ||
897 | * they get written to. | ||
898 | */ | ||
899 | ip->i_d.di_size = newsize; | ||
900 | ip->i_size = newsize; | ||
901 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
902 | |||
903 | if (newsize <= oldsize) { | ||
904 | error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, newsize); | ||
892 | if (error) | 905 | if (error) |
893 | goto out_trans_abort; | 906 | goto out_trans_abort; |
894 | 907 | ||
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c index 5cc3dde1bc90..27378650b5cb 100644 --- a/fs/xfs/xfs_qm_syscalls.c +++ b/fs/xfs/xfs_qm_syscalls.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "xfs_mount.h" | 31 | #include "xfs_mount.h" |
32 | #include "xfs_bmap_btree.h" | 32 | #include "xfs_bmap_btree.h" |
33 | #include "xfs_inode.h" | 33 | #include "xfs_inode.h" |
34 | #include "xfs_inode_item.h" | ||
34 | #include "xfs_itable.h" | 35 | #include "xfs_itable.h" |
35 | #include "xfs_bmap.h" | 36 | #include "xfs_bmap.h" |
36 | #include "xfs_rtalloc.h" | 37 | #include "xfs_rtalloc.h" |
@@ -263,13 +264,19 @@ xfs_qm_scall_trunc_qfile( | |||
263 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 264 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
264 | xfs_trans_ijoin(tp, ip, 0); | 265 | xfs_trans_ijoin(tp, ip, 0); |
265 | 266 | ||
266 | error = xfs_itruncate_data(&tp, ip, 0); | 267 | ip->i_d.di_size = 0; |
268 | ip->i_size = 0; | ||
269 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
270 | |||
271 | error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); | ||
267 | if (error) { | 272 | if (error) { |
268 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | | 273 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | |
269 | XFS_TRANS_ABORT); | 274 | XFS_TRANS_ABORT); |
270 | goto out_unlock; | 275 | goto out_unlock; |
271 | } | 276 | } |
272 | 277 | ||
278 | ASSERT(ip->i_d.di_nextents == 0); | ||
279 | |||
273 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 280 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
274 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 281 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
275 | 282 | ||
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index a9d5b1e06efe..297f9fa6fb64 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h | |||
@@ -1090,8 +1090,8 @@ DECLARE_EVENT_CLASS(xfs_itrunc_class, | |||
1090 | DEFINE_EVENT(xfs_itrunc_class, name, \ | 1090 | DEFINE_EVENT(xfs_itrunc_class, name, \ |
1091 | TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), \ | 1091 | TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), \ |
1092 | TP_ARGS(ip, new_size)) | 1092 | TP_ARGS(ip, new_size)) |
1093 | DEFINE_ITRUNC_EVENT(xfs_itruncate_data_start); | 1093 | DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_start); |
1094 | DEFINE_ITRUNC_EVENT(xfs_itruncate_data_end); | 1094 | DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_end); |
1095 | 1095 | ||
1096 | TRACE_EVENT(xfs_pagecache_inval, | 1096 | TRACE_EVENT(xfs_pagecache_inval, |
1097 | TP_PROTO(struct xfs_inode *ip, xfs_off_t start, xfs_off_t finish), | 1097 | TP_PROTO(struct xfs_inode *ip, xfs_off_t start, xfs_off_t finish), |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index f2fea868d4db..96ff03421753 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -226,7 +226,14 @@ xfs_free_eofblocks( | |||
226 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 226 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
227 | xfs_trans_ijoin(tp, ip, 0); | 227 | xfs_trans_ijoin(tp, ip, 0); |
228 | 228 | ||
229 | error = xfs_itruncate_data(&tp, ip, ip->i_size); | 229 | /* |
230 | * Do not update the on-disk file size. If we update the | ||
231 | * on-disk file size and then the system crashes before the | ||
232 | * contents of the file are flushed to disk then the files | ||
233 | * may be full of holes (ie NULL files bug). | ||
234 | */ | ||
235 | error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, | ||
236 | ip->i_size); | ||
230 | if (error) { | 237 | if (error) { |
231 | /* | 238 | /* |
232 | * If we get an error at this point we simply don't | 239 | * If we get an error at this point we simply don't |
@@ -670,13 +677,19 @@ xfs_inactive( | |||
670 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 677 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
671 | xfs_trans_ijoin(tp, ip, 0); | 678 | xfs_trans_ijoin(tp, ip, 0); |
672 | 679 | ||
673 | error = xfs_itruncate_data(&tp, ip, 0); | 680 | ip->i_d.di_size = 0; |
681 | ip->i_size = 0; | ||
682 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
683 | |||
684 | error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); | ||
674 | if (error) { | 685 | if (error) { |
675 | xfs_trans_cancel(tp, | 686 | xfs_trans_cancel(tp, |
676 | XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); | 687 | XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); |
677 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); | 688 | xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); |
678 | return VN_INACTIVE_CACHE; | 689 | return VN_INACTIVE_CACHE; |
679 | } | 690 | } |
691 | |||
692 | ASSERT(ip->i_d.di_nextents == 0); | ||
680 | } else if (S_ISLNK(ip->i_d.di_mode)) { | 693 | } else if (S_ISLNK(ip->i_d.di_mode)) { |
681 | 694 | ||
682 | /* | 695 | /* |