diff options
-rw-r--r-- | fs/xfs/xfs_fsops.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.c | 84 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 21 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 14 |
4 files changed, 110 insertions, 10 deletions
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index a7c116e814af..f56d30e8040c 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
@@ -374,6 +374,7 @@ xfs_growfs_data_private( | |||
374 | mp->m_maxicount = icount << mp->m_sb.sb_inopblog; | 374 | mp->m_maxicount = icount << mp->m_sb.sb_inopblog; |
375 | } else | 375 | } else |
376 | mp->m_maxicount = 0; | 376 | mp->m_maxicount = 0; |
377 | xfs_set_low_space_thresholds(mp); | ||
377 | 378 | ||
378 | /* update secondary superblocks. */ | 379 | /* update secondary superblocks. */ |
379 | for (agno = 1; agno < nagcount; agno++) { | 380 | for (agno = 1; agno < nagcount; agno++) { |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 22b62a179e89..55582bd66659 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -267,6 +267,9 @@ error_out: | |||
267 | * If the caller is doing a write at the end of the file, then extend the | 267 | * If the caller is doing a write at the end of the file, then extend the |
268 | * allocation out to the file system's write iosize. We clean up any extra | 268 | * allocation out to the file system's write iosize. We clean up any extra |
269 | * space left over when the file is closed in xfs_inactive(). | 269 | * space left over when the file is closed in xfs_inactive(). |
270 | * | ||
271 | * If we find we already have delalloc preallocation beyond EOF, don't do more | ||
272 | * preallocation as it it not needed. | ||
270 | */ | 273 | */ |
271 | STATIC int | 274 | STATIC int |
272 | xfs_iomap_eof_want_preallocate( | 275 | xfs_iomap_eof_want_preallocate( |
@@ -282,6 +285,7 @@ xfs_iomap_eof_want_preallocate( | |||
282 | xfs_filblks_t count_fsb; | 285 | xfs_filblks_t count_fsb; |
283 | xfs_fsblock_t firstblock; | 286 | xfs_fsblock_t firstblock; |
284 | int n, error, imaps; | 287 | int n, error, imaps; |
288 | int found_delalloc = 0; | ||
285 | 289 | ||
286 | *prealloc = 0; | 290 | *prealloc = 0; |
287 | if ((offset + count) <= ip->i_size) | 291 | if ((offset + count) <= ip->i_size) |
@@ -306,12 +310,60 @@ xfs_iomap_eof_want_preallocate( | |||
306 | return 0; | 310 | return 0; |
307 | start_fsb += imap[n].br_blockcount; | 311 | start_fsb += imap[n].br_blockcount; |
308 | count_fsb -= imap[n].br_blockcount; | 312 | count_fsb -= imap[n].br_blockcount; |
313 | |||
314 | if (imap[n].br_startblock == DELAYSTARTBLOCK) | ||
315 | found_delalloc = 1; | ||
309 | } | 316 | } |
310 | } | 317 | } |
311 | *prealloc = 1; | 318 | if (!found_delalloc) |
319 | *prealloc = 1; | ||
312 | return 0; | 320 | return 0; |
313 | } | 321 | } |
314 | 322 | ||
323 | /* | ||
324 | * If we don't have a user specified preallocation size, dynamically increase | ||
325 | * the preallocation size as the size of the file grows. Cap the maximum size | ||
326 | * at a single extent or less if the filesystem is near full. The closer the | ||
327 | * filesystem is to full, the smaller the maximum prealocation. | ||
328 | */ | ||
329 | STATIC xfs_fsblock_t | ||
330 | xfs_iomap_prealloc_size( | ||
331 | struct xfs_mount *mp, | ||
332 | struct xfs_inode *ip) | ||
333 | { | ||
334 | xfs_fsblock_t alloc_blocks = 0; | ||
335 | |||
336 | if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) { | ||
337 | int shift = 0; | ||
338 | int64_t freesp; | ||
339 | |||
340 | alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size); | ||
341 | alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN, | ||
342 | rounddown_pow_of_two(alloc_blocks)); | ||
343 | |||
344 | xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT); | ||
345 | freesp = mp->m_sb.sb_fdblocks; | ||
346 | if (freesp < mp->m_low_space[XFS_LOWSP_5_PCNT]) { | ||
347 | shift = 2; | ||
348 | if (freesp < mp->m_low_space[XFS_LOWSP_4_PCNT]) | ||
349 | shift++; | ||
350 | if (freesp < mp->m_low_space[XFS_LOWSP_3_PCNT]) | ||
351 | shift++; | ||
352 | if (freesp < mp->m_low_space[XFS_LOWSP_2_PCNT]) | ||
353 | shift++; | ||
354 | if (freesp < mp->m_low_space[XFS_LOWSP_1_PCNT]) | ||
355 | shift++; | ||
356 | } | ||
357 | if (shift) | ||
358 | alloc_blocks >>= shift; | ||
359 | } | ||
360 | |||
361 | if (alloc_blocks < mp->m_writeio_blocks) | ||
362 | alloc_blocks = mp->m_writeio_blocks; | ||
363 | |||
364 | return alloc_blocks; | ||
365 | } | ||
366 | |||
315 | int | 367 | int |
316 | xfs_iomap_write_delay( | 368 | xfs_iomap_write_delay( |
317 | xfs_inode_t *ip, | 369 | xfs_inode_t *ip, |
@@ -344,6 +396,7 @@ xfs_iomap_write_delay( | |||
344 | extsz = xfs_get_extsz_hint(ip); | 396 | extsz = xfs_get_extsz_hint(ip); |
345 | offset_fsb = XFS_B_TO_FSBT(mp, offset); | 397 | offset_fsb = XFS_B_TO_FSBT(mp, offset); |
346 | 398 | ||
399 | |||
347 | error = xfs_iomap_eof_want_preallocate(mp, ip, offset, count, | 400 | error = xfs_iomap_eof_want_preallocate(mp, ip, offset, count, |
348 | imap, XFS_WRITE_IMAPS, &prealloc); | 401 | imap, XFS_WRITE_IMAPS, &prealloc); |
349 | if (error) | 402 | if (error) |
@@ -351,9 +404,11 @@ xfs_iomap_write_delay( | |||
351 | 404 | ||
352 | retry: | 405 | retry: |
353 | if (prealloc) { | 406 | if (prealloc) { |
407 | xfs_fsblock_t alloc_blocks = xfs_iomap_prealloc_size(mp, ip); | ||
408 | |||
354 | aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1)); | 409 | aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1)); |
355 | ioalign = XFS_B_TO_FSBT(mp, aligned_offset); | 410 | ioalign = XFS_B_TO_FSBT(mp, aligned_offset); |
356 | last_fsb = ioalign + mp->m_writeio_blocks; | 411 | last_fsb = ioalign + alloc_blocks; |
357 | } else { | 412 | } else { |
358 | last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); | 413 | last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); |
359 | } | 414 | } |
@@ -371,22 +426,31 @@ retry: | |||
371 | XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | | 426 | XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | |
372 | XFS_BMAPI_ENTIRE, &firstblock, 1, imap, | 427 | XFS_BMAPI_ENTIRE, &firstblock, 1, imap, |
373 | &nimaps, NULL); | 428 | &nimaps, NULL); |
374 | if (error && (error != ENOSPC)) | 429 | switch (error) { |
430 | case 0: | ||
431 | case ENOSPC: | ||
432 | case EDQUOT: | ||
433 | break; | ||
434 | default: | ||
375 | return XFS_ERROR(error); | 435 | return XFS_ERROR(error); |
436 | } | ||
376 | 437 | ||
377 | /* | 438 | /* |
378 | * If bmapi returned us nothing, and if we didn't get back EDQUOT, | 439 | * If bmapi returned us nothing, we got either ENOSPC or EDQUOT. For |
379 | * then we must have run out of space - flush all other inodes with | 440 | * ENOSPC, * flush all other inodes with delalloc blocks to free up |
380 | * delalloc blocks and retry without EOF preallocation. | 441 | * some of the excess reserved metadata space. For both cases, retry |
442 | * without EOF preallocation. | ||
381 | */ | 443 | */ |
382 | if (nimaps == 0) { | 444 | if (nimaps == 0) { |
383 | trace_xfs_delalloc_enospc(ip, offset, count); | 445 | trace_xfs_delalloc_enospc(ip, offset, count); |
384 | if (flushed) | 446 | if (flushed) |
385 | return XFS_ERROR(ENOSPC); | 447 | return XFS_ERROR(error ? error : ENOSPC); |
386 | 448 | ||
387 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 449 | if (error == ENOSPC) { |
388 | xfs_flush_inodes(ip); | 450 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
389 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 451 | xfs_flush_inodes(ip); |
452 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
453 | } | ||
390 | 454 | ||
391 | flushed = 1; | 455 | flushed = 1; |
392 | error = 0; | 456 | error = 0; |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 19e9dfa1c254..40579fdf0d0a 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -975,6 +975,24 @@ xfs_set_rw_sizes(xfs_mount_t *mp) | |||
975 | } | 975 | } |
976 | 976 | ||
977 | /* | 977 | /* |
978 | * precalculate the low space thresholds for dynamic speculative preallocation. | ||
979 | */ | ||
980 | void | ||
981 | xfs_set_low_space_thresholds( | ||
982 | struct xfs_mount *mp) | ||
983 | { | ||
984 | int i; | ||
985 | |||
986 | for (i = 0; i < XFS_LOWSP_MAX; i++) { | ||
987 | __uint64_t space = mp->m_sb.sb_dblocks; | ||
988 | |||
989 | do_div(space, 100); | ||
990 | mp->m_low_space[i] = space * (i + 1); | ||
991 | } | ||
992 | } | ||
993 | |||
994 | |||
995 | /* | ||
978 | * Set whether we're using inode alignment. | 996 | * Set whether we're using inode alignment. |
979 | */ | 997 | */ |
980 | STATIC void | 998 | STATIC void |
@@ -1196,6 +1214,9 @@ xfs_mountfs( | |||
1196 | */ | 1214 | */ |
1197 | xfs_set_rw_sizes(mp); | 1215 | xfs_set_rw_sizes(mp); |
1198 | 1216 | ||
1217 | /* set the low space thresholds for dynamic preallocation */ | ||
1218 | xfs_set_low_space_thresholds(mp); | ||
1219 | |||
1199 | /* | 1220 | /* |
1200 | * Set the inode cluster size. | 1221 | * Set the inode cluster size. |
1201 | * This may still be overridden by the file system | 1222 | * This may still be overridden by the file system |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 5861b4980740..a62e8971539d 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -103,6 +103,16 @@ extern int xfs_icsb_modify_counters(struct xfs_mount *, xfs_sb_field_t, | |||
103 | xfs_mod_incore_sb(mp, field, delta, rsvd) | 103 | xfs_mod_incore_sb(mp, field, delta, rsvd) |
104 | #endif | 104 | #endif |
105 | 105 | ||
106 | /* dynamic preallocation free space thresholds, 5% down to 1% */ | ||
107 | enum { | ||
108 | XFS_LOWSP_1_PCNT = 0, | ||
109 | XFS_LOWSP_2_PCNT, | ||
110 | XFS_LOWSP_3_PCNT, | ||
111 | XFS_LOWSP_4_PCNT, | ||
112 | XFS_LOWSP_5_PCNT, | ||
113 | XFS_LOWSP_MAX, | ||
114 | }; | ||
115 | |||
106 | typedef struct xfs_mount { | 116 | typedef struct xfs_mount { |
107 | struct super_block *m_super; | 117 | struct super_block *m_super; |
108 | xfs_tid_t m_tid; /* next unused tid for fs */ | 118 | xfs_tid_t m_tid; /* next unused tid for fs */ |
@@ -202,6 +212,8 @@ typedef struct xfs_mount { | |||
202 | __int64_t m_update_flags; /* sb flags we need to update | 212 | __int64_t m_update_flags; /* sb flags we need to update |
203 | on the next remount,rw */ | 213 | on the next remount,rw */ |
204 | struct shrinker m_inode_shrink; /* inode reclaim shrinker */ | 214 | struct shrinker m_inode_shrink; /* inode reclaim shrinker */ |
215 | int64_t m_low_space[XFS_LOWSP_MAX]; | ||
216 | /* low free space thresholds */ | ||
205 | } xfs_mount_t; | 217 | } xfs_mount_t; |
206 | 218 | ||
207 | /* | 219 | /* |
@@ -379,6 +391,8 @@ extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t); | |||
379 | 391 | ||
380 | extern int xfs_dev_is_read_only(struct xfs_mount *, char *); | 392 | extern int xfs_dev_is_read_only(struct xfs_mount *, char *); |
381 | 393 | ||
394 | extern void xfs_set_low_space_thresholds(struct xfs_mount *); | ||
395 | |||
382 | #endif /* __KERNEL__ */ | 396 | #endif /* __KERNEL__ */ |
383 | 397 | ||
384 | extern void xfs_mod_sb(struct xfs_trans *, __int64_t); | 398 | extern void xfs_mod_sb(struct xfs_trans *, __int64_t); |