diff options
-rw-r--r-- | fs/xfs/linux-2.6/xfs_trace.h | 34 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 163 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 11 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 27 |
4 files changed, 4 insertions, 231 deletions
diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h index d48b7a579ae1..cac41e423451 100644 --- a/fs/xfs/linux-2.6/xfs_trace.h +++ b/fs/xfs/linux-2.6/xfs_trace.h | |||
@@ -1029,40 +1029,6 @@ DEFINE_SIMPLE_IO_EVENT(xfs_delalloc_enospc); | |||
1029 | DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert); | 1029 | DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert); |
1030 | DEFINE_SIMPLE_IO_EVENT(xfs_get_blocks_notfound); | 1030 | DEFINE_SIMPLE_IO_EVENT(xfs_get_blocks_notfound); |
1031 | 1031 | ||
1032 | |||
1033 | TRACE_EVENT(xfs_itruncate_start, | ||
1034 | TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size, int flag, | ||
1035 | xfs_off_t toss_start, xfs_off_t toss_finish), | ||
1036 | TP_ARGS(ip, new_size, flag, toss_start, toss_finish), | ||
1037 | TP_STRUCT__entry( | ||
1038 | __field(dev_t, dev) | ||
1039 | __field(xfs_ino_t, ino) | ||
1040 | __field(xfs_fsize_t, size) | ||
1041 | __field(xfs_fsize_t, new_size) | ||
1042 | __field(xfs_off_t, toss_start) | ||
1043 | __field(xfs_off_t, toss_finish) | ||
1044 | __field(int, flag) | ||
1045 | ), | ||
1046 | TP_fast_assign( | ||
1047 | __entry->dev = VFS_I(ip)->i_sb->s_dev; | ||
1048 | __entry->ino = ip->i_ino; | ||
1049 | __entry->size = ip->i_d.di_size; | ||
1050 | __entry->new_size = new_size; | ||
1051 | __entry->toss_start = toss_start; | ||
1052 | __entry->toss_finish = toss_finish; | ||
1053 | __entry->flag = flag; | ||
1054 | ), | ||
1055 | TP_printk("dev %d:%d ino 0x%llx %s size 0x%llx new_size 0x%llx " | ||
1056 | "toss start 0x%llx toss finish 0x%llx", | ||
1057 | MAJOR(__entry->dev), MINOR(__entry->dev), | ||
1058 | __entry->ino, | ||
1059 | __print_flags(__entry->flag, "|", XFS_ITRUNC_FLAGS), | ||
1060 | __entry->size, | ||
1061 | __entry->new_size, | ||
1062 | __entry->toss_start, | ||
1063 | __entry->toss_finish) | ||
1064 | ); | ||
1065 | |||
1066 | DECLARE_EVENT_CLASS(xfs_itrunc_class, | 1032 | DECLARE_EVENT_CLASS(xfs_itrunc_class, |
1067 | TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), | 1033 | TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), |
1068 | TP_ARGS(ip, new_size), | 1034 | TP_ARGS(ip, new_size), |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index a098a20ca63e..82a282ab63dc 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -1217,165 +1217,8 @@ xfs_isize_check( | |||
1217 | #endif /* DEBUG */ | 1217 | #endif /* DEBUG */ |
1218 | 1218 | ||
1219 | /* | 1219 | /* |
1220 | * Calculate the last possible buffered byte in a file. This must | 1220 | * Free up the underlying blocks past new_size. The new size must be |
1221 | * include data that was buffered beyond the EOF by the write code. | 1221 | * smaller than the current size. |
1222 | * This also needs to deal with overflowing the xfs_fsize_t type | ||
1223 | * which can happen for sizes near the limit. | ||
1224 | * | ||
1225 | * We also need to take into account any blocks beyond the EOF. It | ||
1226 | * may be the case that they were buffered by a write which failed. | ||
1227 | * In that case the pages will still be in memory, but the inode size | ||
1228 | * will never have been updated. | ||
1229 | */ | ||
1230 | STATIC xfs_fsize_t | ||
1231 | xfs_file_last_byte( | ||
1232 | xfs_inode_t *ip) | ||
1233 | { | ||
1234 | xfs_mount_t *mp; | ||
1235 | xfs_fsize_t last_byte; | ||
1236 | xfs_fileoff_t last_block; | ||
1237 | xfs_fileoff_t size_last_block; | ||
1238 | int error; | ||
1239 | |||
1240 | ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)); | ||
1241 | |||
1242 | mp = ip->i_mount; | ||
1243 | /* | ||
1244 | * Only check for blocks beyond the EOF if the extents have | ||
1245 | * been read in. This eliminates the need for the inode lock, | ||
1246 | * and it also saves us from looking when it really isn't | ||
1247 | * necessary. | ||
1248 | */ | ||
1249 | if (ip->i_df.if_flags & XFS_IFEXTENTS) { | ||
1250 | xfs_ilock(ip, XFS_ILOCK_SHARED); | ||
1251 | error = xfs_bmap_last_offset(NULL, ip, &last_block, | ||
1252 | XFS_DATA_FORK); | ||
1253 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
1254 | if (error) { | ||
1255 | last_block = 0; | ||
1256 | } | ||
1257 | } else { | ||
1258 | last_block = 0; | ||
1259 | } | ||
1260 | size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_size); | ||
1261 | last_block = XFS_FILEOFF_MAX(last_block, size_last_block); | ||
1262 | |||
1263 | last_byte = XFS_FSB_TO_B(mp, last_block); | ||
1264 | if (last_byte < 0) { | ||
1265 | return XFS_MAXIOFFSET(mp); | ||
1266 | } | ||
1267 | last_byte += (1 << mp->m_writeio_log); | ||
1268 | if (last_byte < 0) { | ||
1269 | return XFS_MAXIOFFSET(mp); | ||
1270 | } | ||
1271 | return last_byte; | ||
1272 | } | ||
1273 | |||
1274 | /* | ||
1275 | * Start the truncation of the file to new_size. The new size | ||
1276 | * must be smaller than the current size. This routine will | ||
1277 | * clear the buffer and page caches of file data in the removed | ||
1278 | * range, and xfs_itruncate_finish() will remove the underlying | ||
1279 | * disk blocks. | ||
1280 | * | ||
1281 | * The inode must have its I/O lock locked EXCLUSIVELY, and it | ||
1282 | * must NOT have the inode lock held at all. This is because we're | ||
1283 | * calling into the buffer/page cache code and we can't hold the | ||
1284 | * inode lock when we do so. | ||
1285 | * | ||
1286 | * We need to wait for any direct I/Os in flight to complete before we | ||
1287 | * proceed with the truncate. This is needed to prevent the extents | ||
1288 | * being read or written by the direct I/Os from being removed while the | ||
1289 | * I/O is in flight as there is no other method of synchronising | ||
1290 | * direct I/O with the truncate operation. Also, because we hold | ||
1291 | * the IOLOCK in exclusive mode, we prevent new direct I/Os from being | ||
1292 | * started until the truncate completes and drops the lock. Essentially, | ||
1293 | * the xfs_ioend_wait() call forms an I/O barrier that provides strict | ||
1294 | * ordering between direct I/Os and the truncate operation. | ||
1295 | * | ||
1296 | * The flags parameter can have either the value XFS_ITRUNC_DEFINITE | ||
1297 | * or XFS_ITRUNC_MAYBE. The XFS_ITRUNC_MAYBE value should be used | ||
1298 | * in the case that the caller is locking things out of order and | ||
1299 | * may not be able to call xfs_itruncate_finish() with the inode lock | ||
1300 | * held without dropping the I/O lock. If the caller must drop the | ||
1301 | * I/O lock before calling xfs_itruncate_finish(), then xfs_itruncate_start() | ||
1302 | * must be called again with all the same restrictions as the initial | ||
1303 | * call. | ||
1304 | */ | ||
1305 | int | ||
1306 | xfs_itruncate_start( | ||
1307 | xfs_inode_t *ip, | ||
1308 | uint flags, | ||
1309 | xfs_fsize_t new_size) | ||
1310 | { | ||
1311 | xfs_fsize_t last_byte; | ||
1312 | xfs_off_t toss_start; | ||
1313 | xfs_mount_t *mp; | ||
1314 | int error = 0; | ||
1315 | |||
1316 | ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); | ||
1317 | ASSERT((new_size == 0) || (new_size <= ip->i_size)); | ||
1318 | ASSERT((flags == XFS_ITRUNC_DEFINITE) || | ||
1319 | (flags == XFS_ITRUNC_MAYBE)); | ||
1320 | |||
1321 | mp = ip->i_mount; | ||
1322 | |||
1323 | /* wait for the completion of any pending DIOs */ | ||
1324 | if (new_size == 0 || new_size < ip->i_size) | ||
1325 | xfs_ioend_wait(ip); | ||
1326 | |||
1327 | /* | ||
1328 | * Call toss_pages or flushinval_pages to get rid of pages | ||
1329 | * overlapping the region being removed. We have to use | ||
1330 | * the less efficient flushinval_pages in the case that the | ||
1331 | * caller may not be able to finish the truncate without | ||
1332 | * dropping the inode's I/O lock. Make sure | ||
1333 | * to catch any pages brought in by buffers overlapping | ||
1334 | * the EOF by searching out beyond the isize by our | ||
1335 | * block size. We round new_size up to a block boundary | ||
1336 | * so that we don't toss things on the same block as | ||
1337 | * new_size but before it. | ||
1338 | * | ||
1339 | * Before calling toss_page or flushinval_pages, make sure to | ||
1340 | * call remapf() over the same region if the file is mapped. | ||
1341 | * This frees up mapped file references to the pages in the | ||
1342 | * given range and for the flushinval_pages case it ensures | ||
1343 | * that we get the latest mapped changes flushed out. | ||
1344 | */ | ||
1345 | toss_start = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); | ||
1346 | toss_start = XFS_FSB_TO_B(mp, toss_start); | ||
1347 | if (toss_start < 0) { | ||
1348 | /* | ||
1349 | * The place to start tossing is beyond our maximum | ||
1350 | * file size, so there is no way that the data extended | ||
1351 | * out there. | ||
1352 | */ | ||
1353 | return 0; | ||
1354 | } | ||
1355 | last_byte = xfs_file_last_byte(ip); | ||
1356 | trace_xfs_itruncate_start(ip, new_size, flags, toss_start, last_byte); | ||
1357 | if (last_byte > toss_start) { | ||
1358 | if (flags & XFS_ITRUNC_DEFINITE) { | ||
1359 | xfs_tosspages(ip, toss_start, | ||
1360 | -1, FI_REMAPF_LOCKED); | ||
1361 | } else { | ||
1362 | error = xfs_flushinval_pages(ip, toss_start, | ||
1363 | -1, FI_REMAPF_LOCKED); | ||
1364 | } | ||
1365 | } | ||
1366 | |||
1367 | #ifdef DEBUG | ||
1368 | if (new_size == 0) { | ||
1369 | ASSERT(VN_CACHED(VFS_I(ip)) == 0); | ||
1370 | } | ||
1371 | #endif | ||
1372 | return error; | ||
1373 | } | ||
1374 | |||
1375 | /* | ||
1376 | * Shrink the file to the given new_size. The new size must be smaller than | ||
1377 | * the current size. This will free up the underlying blocks in the removed | ||
1378 | * range after a call to xfs_itruncate_start() or xfs_atruncate_start(). | ||
1379 | * | 1222 | * |
1380 | * The transaction passed to this routine must have made a permanent log | 1223 | * The transaction passed to this routine must have made a permanent log |
1381 | * reservation of at least XFS_ITRUNCATE_LOG_RES. This routine may commit the | 1224 | * reservation of at least XFS_ITRUNCATE_LOG_RES. This routine may commit the |
@@ -1387,7 +1230,7 @@ xfs_itruncate_start( | |||
1387 | * will be "held" within the returned transaction. This routine does NOT | 1230 | * will be "held" within the returned transaction. This routine does NOT |
1388 | * require any disk space to be reserved for it within the transaction. | 1231 | * require any disk space to be reserved for it within the transaction. |
1389 | * | 1232 | * |
1390 | * The fork parameter must be either xfs_attr_fork or xfs_data_fork, and it | 1233 | * The fork parameter must be either XFS_ATTR_FORK or XFS_DATA_FORK, and it |
1391 | * indicates the fork which is to be truncated. For the attribute fork we only | 1234 | * indicates the fork which is to be truncated. For the attribute fork we only |
1392 | * support truncation to size 0. | 1235 | * support truncation to size 0. |
1393 | * | 1236 | * |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 964cfea77686..6efd471c8724 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -458,16 +458,6 @@ static inline void xfs_ifunlock(xfs_inode_t *ip) | |||
458 | extern struct lock_class_key xfs_iolock_reclaimable; | 458 | extern struct lock_class_key xfs_iolock_reclaimable; |
459 | 459 | ||
460 | /* | 460 | /* |
461 | * Flags for xfs_itruncate_start(). | ||
462 | */ | ||
463 | #define XFS_ITRUNC_DEFINITE 0x1 | ||
464 | #define XFS_ITRUNC_MAYBE 0x2 | ||
465 | |||
466 | #define XFS_ITRUNC_FLAGS \ | ||
467 | { XFS_ITRUNC_DEFINITE, "DEFINITE" }, \ | ||
468 | { XFS_ITRUNC_MAYBE, "MAYBE" } | ||
469 | |||
470 | /* | ||
471 | * For multiple groups support: if S_ISGID bit is set in the parent | 461 | * For multiple groups support: if S_ISGID bit is set in the parent |
472 | * directory, group of new file is set to that of the parent, and | 462 | * directory, group of new file is set to that of the parent, and |
473 | * new subdirectory gets S_ISGID bit from parent. | 463 | * new subdirectory gets S_ISGID bit from parent. |
@@ -501,7 +491,6 @@ uint xfs_ip2xflags(struct xfs_inode *); | |||
501 | uint xfs_dic2xflags(struct xfs_dinode *); | 491 | uint xfs_dic2xflags(struct xfs_dinode *); |
502 | int xfs_ifree(struct xfs_trans *, xfs_inode_t *, | 492 | int xfs_ifree(struct xfs_trans *, xfs_inode_t *, |
503 | struct xfs_bmap_free *); | 493 | struct xfs_bmap_free *); |
504 | int xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t); | ||
505 | int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, | 494 | int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, |
506 | xfs_fsize_t, int, int); | 495 | xfs_fsize_t, int, int); |
507 | int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); | 496 | int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index a4f56a42ef90..45b8ac662aee 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -197,13 +197,6 @@ xfs_free_eofblocks( | |||
197 | */ | 197 | */ |
198 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); | 198 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); |
199 | 199 | ||
200 | /* | ||
201 | * Do the xfs_itruncate_start() call before | ||
202 | * reserving any log space because | ||
203 | * itruncate_start will call into the buffer | ||
204 | * cache and we can't | ||
205 | * do that within a transaction. | ||
206 | */ | ||
207 | if (flags & XFS_FREE_EOF_TRYLOCK) { | 200 | if (flags & XFS_FREE_EOF_TRYLOCK) { |
208 | if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) { | 201 | if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) { |
209 | xfs_trans_cancel(tp, 0); | 202 | xfs_trans_cancel(tp, 0); |
@@ -212,13 +205,6 @@ xfs_free_eofblocks( | |||
212 | } else { | 205 | } else { |
213 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 206 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
214 | } | 207 | } |
215 | error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, | ||
216 | ip->i_size); | ||
217 | if (error) { | ||
218 | xfs_trans_cancel(tp, 0); | ||
219 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
220 | return error; | ||
221 | } | ||
222 | 208 | ||
223 | error = xfs_trans_reserve(tp, 0, | 209 | error = xfs_trans_reserve(tp, 0, |
224 | XFS_ITRUNCATE_LOG_RES(mp), | 210 | XFS_ITRUNCATE_LOG_RES(mp), |
@@ -660,20 +646,9 @@ xfs_inactive( | |||
660 | 646 | ||
661 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); | 647 | tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); |
662 | if (truncate) { | 648 | if (truncate) { |
663 | /* | ||
664 | * Do the xfs_itruncate_start() call before | ||
665 | * reserving any log space because itruncate_start | ||
666 | * will call into the buffer cache and we can't | ||
667 | * do that within a transaction. | ||
668 | */ | ||
669 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 649 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
670 | 650 | ||
671 | error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); | 651 | xfs_ioend_wait(ip); |
672 | if (error) { | ||
673 | xfs_trans_cancel(tp, 0); | ||
674 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
675 | return VN_INACTIVE_CACHE; | ||
676 | } | ||
677 | 652 | ||
678 | error = xfs_trans_reserve(tp, 0, | 653 | error = xfs_trans_reserve(tp, 0, |
679 | XFS_ITRUNCATE_LOG_RES(mp), | 654 | XFS_ITRUNCATE_LOG_RES(mp), |