diff options
-rw-r--r-- | fs/xfs/xfs_iomap.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 9072794e3a42..0a530853b53d 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include "xfs_iomap.h" | 42 | #include "xfs_iomap.h" |
43 | #include "xfs_trace.h" | 43 | #include "xfs_trace.h" |
44 | #include "xfs_icache.h" | 44 | #include "xfs_icache.h" |
45 | #include "xfs_dquot_item.h" | ||
46 | #include "xfs_dquot.h" | ||
45 | 47 | ||
46 | 48 | ||
47 | #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ | 49 | #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ |
@@ -366,6 +368,61 @@ xfs_iomap_eof_prealloc_initial_size( | |||
366 | return XFS_B_TO_FSB(mp, offset); | 368 | return XFS_B_TO_FSB(mp, offset); |
367 | } | 369 | } |
368 | 370 | ||
371 | STATIC bool | ||
372 | xfs_quota_need_throttle( | ||
373 | struct xfs_inode *ip, | ||
374 | int type, | ||
375 | xfs_fsblock_t alloc_blocks) | ||
376 | { | ||
377 | struct xfs_dquot *dq = xfs_inode_dquot(ip, type); | ||
378 | |||
379 | if (!dq || !xfs_this_quota_on(ip->i_mount, type)) | ||
380 | return false; | ||
381 | |||
382 | /* no hi watermark, no throttle */ | ||
383 | if (!dq->q_prealloc_hi_wmark) | ||
384 | return false; | ||
385 | |||
386 | /* under the lo watermark, no throttle */ | ||
387 | if (dq->q_res_bcount + alloc_blocks < dq->q_prealloc_lo_wmark) | ||
388 | return false; | ||
389 | |||
390 | return true; | ||
391 | } | ||
392 | |||
393 | STATIC void | ||
394 | xfs_quota_calc_throttle( | ||
395 | struct xfs_inode *ip, | ||
396 | int type, | ||
397 | xfs_fsblock_t *qblocks, | ||
398 | int *qshift) | ||
399 | { | ||
400 | int64_t freesp; | ||
401 | int shift = 0; | ||
402 | struct xfs_dquot *dq = xfs_inode_dquot(ip, type); | ||
403 | |||
404 | /* over hi wmark, squash the prealloc completely */ | ||
405 | if (dq->q_res_bcount >= dq->q_prealloc_hi_wmark) { | ||
406 | *qblocks = 0; | ||
407 | return; | ||
408 | } | ||
409 | |||
410 | freesp = dq->q_prealloc_hi_wmark - dq->q_res_bcount; | ||
411 | if (freesp < dq->q_low_space[XFS_QLOWSP_5_PCNT]) { | ||
412 | shift = 2; | ||
413 | if (freesp < dq->q_low_space[XFS_QLOWSP_3_PCNT]) | ||
414 | shift += 2; | ||
415 | if (freesp < dq->q_low_space[XFS_QLOWSP_1_PCNT]) | ||
416 | shift += 2; | ||
417 | } | ||
418 | |||
419 | /* only overwrite the throttle values if we are more aggressive */ | ||
420 | if ((freesp >> shift) < (*qblocks >> *qshift)) { | ||
421 | *qblocks = freesp; | ||
422 | *qshift = shift; | ||
423 | } | ||
424 | } | ||
425 | |||
369 | /* | 426 | /* |
370 | * If we don't have a user specified preallocation size, dynamically increase | 427 | * If we don't have a user specified preallocation size, dynamically increase |
371 | * the preallocation size as the size of the file grows. Cap the maximum size | 428 | * the preallocation size as the size of the file grows. Cap the maximum size |
@@ -383,11 +440,14 @@ xfs_iomap_prealloc_size( | |||
383 | xfs_fsblock_t alloc_blocks = 0; | 440 | xfs_fsblock_t alloc_blocks = 0; |
384 | int shift = 0; | 441 | int shift = 0; |
385 | int64_t freesp; | 442 | int64_t freesp; |
443 | xfs_fsblock_t qblocks; | ||
444 | int qshift = 0; | ||
386 | 445 | ||
387 | alloc_blocks = xfs_iomap_eof_prealloc_initial_size(mp, ip, offset, | 446 | alloc_blocks = xfs_iomap_eof_prealloc_initial_size(mp, ip, offset, |
388 | imap, nimaps); | 447 | imap, nimaps); |
389 | if (!alloc_blocks) | 448 | if (!alloc_blocks) |
390 | goto check_writeio; | 449 | goto check_writeio; |
450 | qblocks = alloc_blocks; | ||
391 | 451 | ||
392 | /* | 452 | /* |
393 | * MAXEXTLEN is not a power of two value but we round the prealloc down | 453 | * MAXEXTLEN is not a power of two value but we round the prealloc down |
@@ -412,6 +472,28 @@ xfs_iomap_prealloc_size( | |||
412 | if (freesp < mp->m_low_space[XFS_LOWSP_1_PCNT]) | 472 | if (freesp < mp->m_low_space[XFS_LOWSP_1_PCNT]) |
413 | shift++; | 473 | shift++; |
414 | } | 474 | } |
475 | |||
476 | /* | ||
477 | * Check each quota to cap the prealloc size and provide a shift | ||
478 | * value to throttle with. | ||
479 | */ | ||
480 | if (xfs_quota_need_throttle(ip, XFS_DQ_USER, alloc_blocks)) | ||
481 | xfs_quota_calc_throttle(ip, XFS_DQ_USER, &qblocks, &qshift); | ||
482 | if (xfs_quota_need_throttle(ip, XFS_DQ_GROUP, alloc_blocks)) | ||
483 | xfs_quota_calc_throttle(ip, XFS_DQ_GROUP, &qblocks, &qshift); | ||
484 | if (xfs_quota_need_throttle(ip, XFS_DQ_PROJ, alloc_blocks)) | ||
485 | xfs_quota_calc_throttle(ip, XFS_DQ_PROJ, &qblocks, &qshift); | ||
486 | |||
487 | /* | ||
488 | * The final prealloc size is set to the minimum of free space available | ||
489 | * in each of the quotas and the overall filesystem. | ||
490 | * | ||
491 | * The shift throttle value is set to the maximum value as determined by | ||
492 | * the global low free space values and per-quota low free space values. | ||
493 | */ | ||
494 | alloc_blocks = MIN(alloc_blocks, qblocks); | ||
495 | shift = MAX(shift, qshift); | ||
496 | |||
415 | if (shift) | 497 | if (shift) |
416 | alloc_blocks >>= shift; | 498 | alloc_blocks >>= shift; |
417 | /* | 499 | /* |