diff options
-rw-r--r-- | fs/xfs/libxfs/xfs_attr_leaf.c | 8 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_attr_leaf.h | 2 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 31 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_ialloc.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_attr_inactive.c | 83 | ||||
-rw-r--r-- | fs/xfs/xfs_file.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 22 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 34 | ||||
-rw-r--r-- | include/linux/percpu_counter.h | 13 | ||||
-rw-r--r-- | lib/percpu_counter.c | 6 |
10 files changed, 127 insertions, 83 deletions
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 04e79d57bca6..e9d401ce93bb 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c | |||
@@ -574,8 +574,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) | |||
574 | * After the last attribute is removed revert to original inode format, | 574 | * After the last attribute is removed revert to original inode format, |
575 | * making all literal area available to the data fork once more. | 575 | * making all literal area available to the data fork once more. |
576 | */ | 576 | */ |
577 | STATIC void | 577 | void |
578 | xfs_attr_fork_reset( | 578 | xfs_attr_fork_remove( |
579 | struct xfs_inode *ip, | 579 | struct xfs_inode *ip, |
580 | struct xfs_trans *tp) | 580 | struct xfs_trans *tp) |
581 | { | 581 | { |
@@ -641,7 +641,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) | |||
641 | (mp->m_flags & XFS_MOUNT_ATTR2) && | 641 | (mp->m_flags & XFS_MOUNT_ATTR2) && |
642 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && | 642 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && |
643 | !(args->op_flags & XFS_DA_OP_ADDNAME)) { | 643 | !(args->op_flags & XFS_DA_OP_ADDNAME)) { |
644 | xfs_attr_fork_reset(dp, args->trans); | 644 | xfs_attr_fork_remove(dp, args->trans); |
645 | } else { | 645 | } else { |
646 | xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); | 646 | xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); |
647 | dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); | 647 | dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); |
@@ -905,7 +905,7 @@ xfs_attr3_leaf_to_shortform( | |||
905 | if (forkoff == -1) { | 905 | if (forkoff == -1) { |
906 | ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); | 906 | ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); |
907 | ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); | 907 | ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); |
908 | xfs_attr_fork_reset(dp, args->trans); | 908 | xfs_attr_fork_remove(dp, args->trans); |
909 | goto out; | 909 | goto out; |
910 | } | 910 | } |
911 | 911 | ||
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h index 025c4b820c03..882c8d338891 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.h +++ b/fs/xfs/libxfs/xfs_attr_leaf.h | |||
@@ -53,7 +53,7 @@ int xfs_attr_shortform_remove(struct xfs_da_args *args); | |||
53 | int xfs_attr_shortform_list(struct xfs_attr_list_context *context); | 53 | int xfs_attr_shortform_list(struct xfs_attr_list_context *context); |
54 | int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); | 54 | int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); |
55 | int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes); | 55 | int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes); |
56 | 56 | void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp); | |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Internal routines when attribute fork size == XFS_LBSIZE(mp). | 59 | * Internal routines when attribute fork size == XFS_LBSIZE(mp). |
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index aeffeaaac0ec..f1026e86dabc 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
@@ -3224,12 +3224,24 @@ xfs_bmap_extsize_align( | |||
3224 | align_alen += temp; | 3224 | align_alen += temp; |
3225 | align_off -= temp; | 3225 | align_off -= temp; |
3226 | } | 3226 | } |
3227 | |||
3228 | /* Same adjustment for the end of the requested area. */ | ||
3229 | temp = (align_alen % extsz); | ||
3230 | if (temp) | ||
3231 | align_alen += extsz - temp; | ||
3232 | |||
3227 | /* | 3233 | /* |
3228 | * Same adjustment for the end of the requested area. | 3234 | * For large extent hint sizes, the aligned extent might be larger than |
3235 | * MAXEXTLEN. In that case, reduce the size by an extsz so that it pulls | ||
3236 | * the length back under MAXEXTLEN. The outer allocation loops handle | ||
3237 | * short allocation just fine, so it is safe to do this. We only want to | ||
3238 | * do it when we are forced to, though, because it means more allocation | ||
3239 | * operations are required. | ||
3229 | */ | 3240 | */ |
3230 | if ((temp = (align_alen % extsz))) { | 3241 | while (align_alen > MAXEXTLEN) |
3231 | align_alen += extsz - temp; | 3242 | align_alen -= extsz; |
3232 | } | 3243 | ASSERT(align_alen <= MAXEXTLEN); |
3244 | |||
3233 | /* | 3245 | /* |
3234 | * If the previous block overlaps with this proposed allocation | 3246 | * If the previous block overlaps with this proposed allocation |
3235 | * then move the start forward without adjusting the length. | 3247 | * then move the start forward without adjusting the length. |
@@ -3318,7 +3330,9 @@ xfs_bmap_extsize_align( | |||
3318 | return -EINVAL; | 3330 | return -EINVAL; |
3319 | } else { | 3331 | } else { |
3320 | ASSERT(orig_off >= align_off); | 3332 | ASSERT(orig_off >= align_off); |
3321 | ASSERT(orig_end <= align_off + align_alen); | 3333 | /* see MAXEXTLEN handling above */ |
3334 | ASSERT(orig_end <= align_off + align_alen || | ||
3335 | align_alen + extsz > MAXEXTLEN); | ||
3322 | } | 3336 | } |
3323 | 3337 | ||
3324 | #ifdef DEBUG | 3338 | #ifdef DEBUG |
@@ -4099,13 +4113,6 @@ xfs_bmapi_reserve_delalloc( | |||
4099 | /* Figure out the extent size, adjust alen */ | 4113 | /* Figure out the extent size, adjust alen */ |
4100 | extsz = xfs_get_extsz_hint(ip); | 4114 | extsz = xfs_get_extsz_hint(ip); |
4101 | if (extsz) { | 4115 | if (extsz) { |
4102 | /* | ||
4103 | * Make sure we don't exceed a single extent length when we | ||
4104 | * align the extent by reducing length we are going to | ||
4105 | * allocate by the maximum amount extent size aligment may | ||
4106 | * require. | ||
4107 | */ | ||
4108 | alen = XFS_FILBLKS_MIN(len, MAXEXTLEN - (2 * extsz - 1)); | ||
4109 | error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof, | 4116 | error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof, |
4110 | 1, 0, &aoff, &alen); | 4117 | 1, 0, &aoff, &alen); |
4111 | ASSERT(!error); | 4118 | ASSERT(!error); |
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 07349a183a11..1c9e75521250 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c | |||
@@ -376,7 +376,7 @@ xfs_ialloc_ag_alloc( | |||
376 | */ | 376 | */ |
377 | newlen = args.mp->m_ialloc_inos; | 377 | newlen = args.mp->m_ialloc_inos; |
378 | if (args.mp->m_maxicount && | 378 | if (args.mp->m_maxicount && |
379 | percpu_counter_read(&args.mp->m_icount) + newlen > | 379 | percpu_counter_read_positive(&args.mp->m_icount) + newlen > |
380 | args.mp->m_maxicount) | 380 | args.mp->m_maxicount) |
381 | return -ENOSPC; | 381 | return -ENOSPC; |
382 | args.minlen = args.maxlen = args.mp->m_ialloc_blks; | 382 | args.minlen = args.maxlen = args.mp->m_ialloc_blks; |
@@ -1339,10 +1339,13 @@ xfs_dialloc( | |||
1339 | * If we have already hit the ceiling of inode blocks then clear | 1339 | * If we have already hit the ceiling of inode blocks then clear |
1340 | * okalloc so we scan all available agi structures for a free | 1340 | * okalloc so we scan all available agi structures for a free |
1341 | * inode. | 1341 | * inode. |
1342 | * | ||
1343 | * Read rough value of mp->m_icount by percpu_counter_read_positive, | ||
1344 | * which will sacrifice the preciseness but improve the performance. | ||
1342 | */ | 1345 | */ |
1343 | if (mp->m_maxicount && | 1346 | if (mp->m_maxicount && |
1344 | percpu_counter_read(&mp->m_icount) + mp->m_ialloc_inos > | 1347 | percpu_counter_read_positive(&mp->m_icount) + mp->m_ialloc_inos |
1345 | mp->m_maxicount) { | 1348 | > mp->m_maxicount) { |
1346 | noroom = 1; | 1349 | noroom = 1; |
1347 | okalloc = 0; | 1350 | okalloc = 0; |
1348 | } | 1351 | } |
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c index f9c1c64782d3..3fbf167cfb4c 100644 --- a/fs/xfs/xfs_attr_inactive.c +++ b/fs/xfs/xfs_attr_inactive.c | |||
@@ -380,23 +380,31 @@ xfs_attr3_root_inactive( | |||
380 | return error; | 380 | return error; |
381 | } | 381 | } |
382 | 382 | ||
383 | /* | ||
384 | * xfs_attr_inactive kills all traces of an attribute fork on an inode. It | ||
385 | * removes both the on-disk and in-memory inode fork. Note that this also has to | ||
386 | * handle the condition of inodes without attributes but with an attribute fork | ||
387 | * configured, so we can't use xfs_inode_hasattr() here. | ||
388 | * | ||
389 | * The in-memory attribute fork is removed even on error. | ||
390 | */ | ||
383 | int | 391 | int |
384 | xfs_attr_inactive(xfs_inode_t *dp) | 392 | xfs_attr_inactive( |
393 | struct xfs_inode *dp) | ||
385 | { | 394 | { |
386 | xfs_trans_t *trans; | 395 | struct xfs_trans *trans; |
387 | xfs_mount_t *mp; | 396 | struct xfs_mount *mp; |
388 | int error; | 397 | int cancel_flags = 0; |
398 | int lock_mode = XFS_ILOCK_SHARED; | ||
399 | int error = 0; | ||
389 | 400 | ||
390 | mp = dp->i_mount; | 401 | mp = dp->i_mount; |
391 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); | 402 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); |
392 | 403 | ||
393 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 404 | xfs_ilock(dp, lock_mode); |
394 | if (!xfs_inode_hasattr(dp) || | 405 | if (!XFS_IFORK_Q(dp)) |
395 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 406 | goto out_destroy_fork; |
396 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 407 | xfs_iunlock(dp, lock_mode); |
397 | return 0; | ||
398 | } | ||
399 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
400 | 408 | ||
401 | /* | 409 | /* |
402 | * Start our first transaction of the day. | 410 | * Start our first transaction of the day. |
@@ -408,13 +416,18 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
408 | * the inode in every transaction to let it float upward through | 416 | * the inode in every transaction to let it float upward through |
409 | * the log. | 417 | * the log. |
410 | */ | 418 | */ |
419 | lock_mode = 0; | ||
411 | trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); | 420 | trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); |
412 | error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0); | 421 | error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0); |
413 | if (error) { | 422 | if (error) |
414 | xfs_trans_cancel(trans, 0); | 423 | goto out_cancel; |
415 | return error; | 424 | |
416 | } | 425 | lock_mode = XFS_ILOCK_EXCL; |
417 | xfs_ilock(dp, XFS_ILOCK_EXCL); | 426 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT; |
427 | xfs_ilock(dp, lock_mode); | ||
428 | |||
429 | if (!XFS_IFORK_Q(dp)) | ||
430 | goto out_cancel; | ||
418 | 431 | ||
419 | /* | 432 | /* |
420 | * No need to make quota reservations here. We expect to release some | 433 | * No need to make quota reservations here. We expect to release some |
@@ -422,29 +435,31 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
422 | */ | 435 | */ |
423 | xfs_trans_ijoin(trans, dp, 0); | 436 | xfs_trans_ijoin(trans, dp, 0); |
424 | 437 | ||
425 | /* | 438 | /* invalidate and truncate the attribute fork extents */ |
426 | * Decide on what work routines to call based on the inode size. | 439 | if (dp->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) { |
427 | */ | 440 | error = xfs_attr3_root_inactive(&trans, dp); |
428 | if (!xfs_inode_hasattr(dp) || | 441 | if (error) |
429 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 442 | goto out_cancel; |
430 | error = 0; | 443 | |
431 | goto out; | 444 | error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0); |
445 | if (error) | ||
446 | goto out_cancel; | ||
432 | } | 447 | } |
433 | error = xfs_attr3_root_inactive(&trans, dp); | ||
434 | if (error) | ||
435 | goto out; | ||
436 | 448 | ||
437 | error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0); | 449 | /* Reset the attribute fork - this also destroys the in-core fork */ |
438 | if (error) | 450 | xfs_attr_fork_remove(dp, trans); |
439 | goto out; | ||
440 | 451 | ||
441 | error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); | 452 | error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); |
442 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 453 | xfs_iunlock(dp, lock_mode); |
443 | |||
444 | return error; | 454 | return error; |
445 | 455 | ||
446 | out: | 456 | out_cancel: |
447 | xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | 457 | xfs_trans_cancel(trans, cancel_flags); |
448 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 458 | out_destroy_fork: |
459 | /* kill the in-core attr fork before we drop the inode lock */ | ||
460 | if (dp->i_afp) | ||
461 | xfs_idestroy_fork(dp, XFS_ATTR_FORK); | ||
462 | if (lock_mode) | ||
463 | xfs_iunlock(dp, lock_mode); | ||
449 | return error; | 464 | return error; |
450 | } | 465 | } |
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 8121e75352ee..3b7591224f4a 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -124,7 +124,7 @@ xfs_iozero( | |||
124 | status = 0; | 124 | status = 0; |
125 | } while (count); | 125 | } while (count); |
126 | 126 | ||
127 | return (-status); | 127 | return status; |
128 | } | 128 | } |
129 | 129 | ||
130 | int | 130 | int |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index d6ebc85192b7..539a85fddbc2 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -1946,21 +1946,17 @@ xfs_inactive( | |||
1946 | /* | 1946 | /* |
1947 | * If there are attributes associated with the file then blow them away | 1947 | * If there are attributes associated with the file then blow them away |
1948 | * now. The code calls a routine that recursively deconstructs the | 1948 | * now. The code calls a routine that recursively deconstructs the |
1949 | * attribute fork. We need to just commit the current transaction | 1949 | * attribute fork. If also blows away the in-core attribute fork. |
1950 | * because we can't use it for xfs_attr_inactive(). | ||
1951 | */ | 1950 | */ |
1952 | if (ip->i_d.di_anextents > 0) { | 1951 | if (XFS_IFORK_Q(ip)) { |
1953 | ASSERT(ip->i_d.di_forkoff != 0); | ||
1954 | |||
1955 | error = xfs_attr_inactive(ip); | 1952 | error = xfs_attr_inactive(ip); |
1956 | if (error) | 1953 | if (error) |
1957 | return; | 1954 | return; |
1958 | } | 1955 | } |
1959 | 1956 | ||
1960 | if (ip->i_afp) | 1957 | ASSERT(!ip->i_afp); |
1961 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | ||
1962 | |||
1963 | ASSERT(ip->i_d.di_anextents == 0); | 1958 | ASSERT(ip->i_d.di_anextents == 0); |
1959 | ASSERT(ip->i_d.di_forkoff == 0); | ||
1964 | 1960 | ||
1965 | /* | 1961 | /* |
1966 | * Free the inode. | 1962 | * Free the inode. |
@@ -2883,7 +2879,13 @@ xfs_rename_alloc_whiteout( | |||
2883 | if (error) | 2879 | if (error) |
2884 | return error; | 2880 | return error; |
2885 | 2881 | ||
2886 | /* Satisfy xfs_bumplink that this is a real tmpfile */ | 2882 | /* |
2883 | * Prepare the tmpfile inode as if it were created through the VFS. | ||
2884 | * Otherwise, the link increment paths will complain about nlink 0->1. | ||
2885 | * Drop the link count as done by d_tmpfile(), complete the inode setup | ||
2886 | * and flag it as linkable. | ||
2887 | */ | ||
2888 | drop_nlink(VFS_I(tmpfile)); | ||
2887 | xfs_finish_inode_setup(tmpfile); | 2889 | xfs_finish_inode_setup(tmpfile); |
2888 | VFS_I(tmpfile)->i_state |= I_LINKABLE; | 2890 | VFS_I(tmpfile)->i_state |= I_LINKABLE; |
2889 | 2891 | ||
@@ -3151,7 +3153,7 @@ xfs_rename( | |||
3151 | * intermediate state on disk. | 3153 | * intermediate state on disk. |
3152 | */ | 3154 | */ |
3153 | if (wip) { | 3155 | if (wip) { |
3154 | ASSERT(wip->i_d.di_nlink == 0); | 3156 | ASSERT(VFS_I(wip)->i_nlink == 0 && wip->i_d.di_nlink == 0); |
3155 | error = xfs_bumplink(tp, wip); | 3157 | error = xfs_bumplink(tp, wip); |
3156 | if (error) | 3158 | if (error) |
3157 | goto out_trans_abort; | 3159 | goto out_trans_abort; |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 2ce7ee3b4ec1..6f23fbdfb365 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -1084,14 +1084,18 @@ xfs_log_sbcount(xfs_mount_t *mp) | |||
1084 | return xfs_sync_sb(mp, true); | 1084 | return xfs_sync_sb(mp, true); |
1085 | } | 1085 | } |
1086 | 1086 | ||
1087 | /* | ||
1088 | * Deltas for the inode count are +/-64, hence we use a large batch size | ||
1089 | * of 128 so we don't need to take the counter lock on every update. | ||
1090 | */ | ||
1091 | #define XFS_ICOUNT_BATCH 128 | ||
1087 | int | 1092 | int |
1088 | xfs_mod_icount( | 1093 | xfs_mod_icount( |
1089 | struct xfs_mount *mp, | 1094 | struct xfs_mount *mp, |
1090 | int64_t delta) | 1095 | int64_t delta) |
1091 | { | 1096 | { |
1092 | /* deltas are +/-64, hence the large batch size of 128. */ | 1097 | __percpu_counter_add(&mp->m_icount, delta, XFS_ICOUNT_BATCH); |
1093 | __percpu_counter_add(&mp->m_icount, delta, 128); | 1098 | if (__percpu_counter_compare(&mp->m_icount, 0, XFS_ICOUNT_BATCH) < 0) { |
1094 | if (percpu_counter_compare(&mp->m_icount, 0) < 0) { | ||
1095 | ASSERT(0); | 1099 | ASSERT(0); |
1096 | percpu_counter_add(&mp->m_icount, -delta); | 1100 | percpu_counter_add(&mp->m_icount, -delta); |
1097 | return -EINVAL; | 1101 | return -EINVAL; |
@@ -1113,6 +1117,14 @@ xfs_mod_ifree( | |||
1113 | return 0; | 1117 | return 0; |
1114 | } | 1118 | } |
1115 | 1119 | ||
1120 | /* | ||
1121 | * Deltas for the block count can vary from 1 to very large, but lock contention | ||
1122 | * only occurs on frequent small block count updates such as in the delayed | ||
1123 | * allocation path for buffered writes (page a time updates). Hence we set | ||
1124 | * a large batch count (1024) to minimise global counter updates except when | ||
1125 | * we get near to ENOSPC and we have to be very accurate with our updates. | ||
1126 | */ | ||
1127 | #define XFS_FDBLOCKS_BATCH 1024 | ||
1116 | int | 1128 | int |
1117 | xfs_mod_fdblocks( | 1129 | xfs_mod_fdblocks( |
1118 | struct xfs_mount *mp, | 1130 | struct xfs_mount *mp, |
@@ -1151,25 +1163,19 @@ xfs_mod_fdblocks( | |||
1151 | * Taking blocks away, need to be more accurate the closer we | 1163 | * Taking blocks away, need to be more accurate the closer we |
1152 | * are to zero. | 1164 | * are to zero. |
1153 | * | 1165 | * |
1154 | * batch size is set to a maximum of 1024 blocks - if we are | ||
1155 | * allocating of freeing extents larger than this then we aren't | ||
1156 | * going to be hammering the counter lock so a lock per update | ||
1157 | * is not a problem. | ||
1158 | * | ||
1159 | * If the counter has a value of less than 2 * max batch size, | 1166 | * If the counter has a value of less than 2 * max batch size, |
1160 | * then make everything serialise as we are real close to | 1167 | * then make everything serialise as we are real close to |
1161 | * ENOSPC. | 1168 | * ENOSPC. |
1162 | */ | 1169 | */ |
1163 | #define __BATCH 1024 | 1170 | if (__percpu_counter_compare(&mp->m_fdblocks, 2 * XFS_FDBLOCKS_BATCH, |
1164 | if (percpu_counter_compare(&mp->m_fdblocks, 2 * __BATCH) < 0) | 1171 | XFS_FDBLOCKS_BATCH) < 0) |
1165 | batch = 1; | 1172 | batch = 1; |
1166 | else | 1173 | else |
1167 | batch = __BATCH; | 1174 | batch = XFS_FDBLOCKS_BATCH; |
1168 | #undef __BATCH | ||
1169 | 1175 | ||
1170 | __percpu_counter_add(&mp->m_fdblocks, delta, batch); | 1176 | __percpu_counter_add(&mp->m_fdblocks, delta, batch); |
1171 | if (percpu_counter_compare(&mp->m_fdblocks, | 1177 | if (__percpu_counter_compare(&mp->m_fdblocks, XFS_ALLOC_SET_ASIDE(mp), |
1172 | XFS_ALLOC_SET_ASIDE(mp)) >= 0) { | 1178 | XFS_FDBLOCKS_BATCH) >= 0) { |
1173 | /* we had space! */ | 1179 | /* we had space! */ |
1174 | return 0; | 1180 | return 0; |
1175 | } | 1181 | } |
diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h index 50e50095c8d1..84a109449610 100644 --- a/include/linux/percpu_counter.h +++ b/include/linux/percpu_counter.h | |||
@@ -41,7 +41,12 @@ void percpu_counter_destroy(struct percpu_counter *fbc); | |||
41 | void percpu_counter_set(struct percpu_counter *fbc, s64 amount); | 41 | void percpu_counter_set(struct percpu_counter *fbc, s64 amount); |
42 | void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch); | 42 | void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch); |
43 | s64 __percpu_counter_sum(struct percpu_counter *fbc); | 43 | s64 __percpu_counter_sum(struct percpu_counter *fbc); |
44 | int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs); | 44 | int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch); |
45 | |||
46 | static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) | ||
47 | { | ||
48 | return __percpu_counter_compare(fbc, rhs, percpu_counter_batch); | ||
49 | } | ||
45 | 50 | ||
46 | static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount) | 51 | static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount) |
47 | { | 52 | { |
@@ -116,6 +121,12 @@ static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) | |||
116 | return 0; | 121 | return 0; |
117 | } | 122 | } |
118 | 123 | ||
124 | static inline int | ||
125 | __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch) | ||
126 | { | ||
127 | return percpu_counter_compare(fbc, rhs); | ||
128 | } | ||
129 | |||
119 | static inline void | 130 | static inline void |
120 | percpu_counter_add(struct percpu_counter *fbc, s64 amount) | 131 | percpu_counter_add(struct percpu_counter *fbc, s64 amount) |
121 | { | 132 | { |
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c index 48144cdae819..f051d69f0910 100644 --- a/lib/percpu_counter.c +++ b/lib/percpu_counter.c | |||
@@ -197,13 +197,13 @@ static int percpu_counter_hotcpu_callback(struct notifier_block *nb, | |||
197 | * Compare counter against given value. | 197 | * Compare counter against given value. |
198 | * Return 1 if greater, 0 if equal and -1 if less | 198 | * Return 1 if greater, 0 if equal and -1 if less |
199 | */ | 199 | */ |
200 | int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) | 200 | int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch) |
201 | { | 201 | { |
202 | s64 count; | 202 | s64 count; |
203 | 203 | ||
204 | count = percpu_counter_read(fbc); | 204 | count = percpu_counter_read(fbc); |
205 | /* Check to see if rough count will be sufficient for comparison */ | 205 | /* Check to see if rough count will be sufficient for comparison */ |
206 | if (abs(count - rhs) > (percpu_counter_batch*num_online_cpus())) { | 206 | if (abs(count - rhs) > (batch * num_online_cpus())) { |
207 | if (count > rhs) | 207 | if (count > rhs) |
208 | return 1; | 208 | return 1; |
209 | else | 209 | else |
@@ -218,7 +218,7 @@ int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) | |||
218 | else | 218 | else |
219 | return 0; | 219 | return 0; |
220 | } | 220 | } |
221 | EXPORT_SYMBOL(percpu_counter_compare); | 221 | EXPORT_SYMBOL(__percpu_counter_compare); |
222 | 222 | ||
223 | static int __init percpu_counter_startup(void) | 223 | static int __init percpu_counter_startup(void) |
224 | { | 224 | { |