diff options
author | Dave Chinner <dchinner@redhat.com> | 2015-03-24 23:03:32 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2015-03-24 23:03:32 -0400 |
commit | 95afcf5c7bca93fb84d260f70c304f35ef4c3114 (patch) | |
tree | 00953639906542d16ddb87c1b07141debee5eb50 | |
parent | 444a702231412e82fb1c09679adc159301e9242c (diff) |
xfs: clean up inode locking for RENAME_WHITEOUT
When doing RENAME_WHITEOUT, we now have to lock 5 inodes into the
rename transaction. This means we need to update
xfs_sort_for_rename() and xfs_lock_inodes() to handle up to 5
inodes. Because of the vagaries of rename, this means we could have
anywhere between 3 and 5 inodes locked into the transaction....
While xfs_lock_inodes() does not need anything other than an assert
telling us we are passing more inodes that we ever thought we should
see, it could do with a logic rework to remove all the indenting.
This is not a functional change - it just makes the code a lot
easier to read.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/xfs/xfs_inode.c | 145 |
1 files changed, 67 insertions, 78 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index d0414f305967..d0a98bafcbac 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -329,15 +329,14 @@ xfs_lock_inumorder(int lock_mode, int subclass) | |||
329 | } | 329 | } |
330 | 330 | ||
331 | /* | 331 | /* |
332 | * The following routine will lock n inodes in exclusive mode. | 332 | * The following routine will lock n inodes in exclusive mode. We assume the |
333 | * We assume the caller calls us with the inodes in i_ino order. | 333 | * caller calls us with the inodes in i_ino order. |
334 | * | 334 | * |
335 | * We need to detect deadlock where an inode that we lock | 335 | * We need to detect deadlock where an inode that we lock is in the AIL and we |
336 | * is in the AIL and we start waiting for another inode that is locked | 336 | * start waiting for another inode that is locked by a thread in a long running |
337 | * by a thread in a long running transaction (such as truncate). This can | 337 | * transaction (such as truncate). This can result in deadlock since the long |
338 | * result in deadlock since the long running trans might need to wait | 338 | * running trans might need to wait for the inode we just locked in order to |
339 | * for the inode we just locked in order to push the tail and free space | 339 | * push the tail and free space in the log. |
340 | * in the log. | ||
341 | */ | 340 | */ |
342 | void | 341 | void |
343 | xfs_lock_inodes( | 342 | xfs_lock_inodes( |
@@ -348,30 +347,27 @@ xfs_lock_inodes( | |||
348 | int attempts = 0, i, j, try_lock; | 347 | int attempts = 0, i, j, try_lock; |
349 | xfs_log_item_t *lp; | 348 | xfs_log_item_t *lp; |
350 | 349 | ||
351 | ASSERT(ips && (inodes >= 2)); /* we need at least two */ | 350 | /* currently supports between 2 and 5 inodes */ |
351 | ASSERT(ips && inodes >= 2 && inodes <= 5); | ||
352 | 352 | ||
353 | try_lock = 0; | 353 | try_lock = 0; |
354 | i = 0; | 354 | i = 0; |
355 | |||
356 | again: | 355 | again: |
357 | for (; i < inodes; i++) { | 356 | for (; i < inodes; i++) { |
358 | ASSERT(ips[i]); | 357 | ASSERT(ips[i]); |
359 | 358 | ||
360 | if (i && (ips[i] == ips[i-1])) /* Already locked */ | 359 | if (i && (ips[i] == ips[i - 1])) /* Already locked */ |
361 | continue; | 360 | continue; |
362 | 361 | ||
363 | /* | 362 | /* |
364 | * If try_lock is not set yet, make sure all locked inodes | 363 | * If try_lock is not set yet, make sure all locked inodes are |
365 | * are not in the AIL. | 364 | * not in the AIL. If any are, set try_lock to be used later. |
366 | * If any are, set try_lock to be used later. | ||
367 | */ | 365 | */ |
368 | |||
369 | if (!try_lock) { | 366 | if (!try_lock) { |
370 | for (j = (i - 1); j >= 0 && !try_lock; j--) { | 367 | for (j = (i - 1); j >= 0 && !try_lock; j--) { |
371 | lp = (xfs_log_item_t *)ips[j]->i_itemp; | 368 | lp = (xfs_log_item_t *)ips[j]->i_itemp; |
372 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { | 369 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) |
373 | try_lock++; | 370 | try_lock++; |
374 | } | ||
375 | } | 371 | } |
376 | } | 372 | } |
377 | 373 | ||
@@ -381,51 +377,42 @@ again: | |||
381 | * we can't get any, we must release all we have | 377 | * we can't get any, we must release all we have |
382 | * and try again. | 378 | * and try again. |
383 | */ | 379 | */ |
380 | if (!try_lock) { | ||
381 | xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i)); | ||
382 | continue; | ||
383 | } | ||
384 | |||
385 | /* try_lock means we have an inode locked that is in the AIL. */ | ||
386 | ASSERT(i != 0); | ||
387 | if (xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) | ||
388 | continue; | ||
384 | 389 | ||
385 | if (try_lock) { | 390 | /* |
386 | /* try_lock must be 0 if i is 0. */ | 391 | * Unlock all previous guys and try again. xfs_iunlock will try |
392 | * to push the tail if the inode is in the AIL. | ||
393 | */ | ||
394 | attempts++; | ||
395 | for (j = i - 1; j >= 0; j--) { | ||
387 | /* | 396 | /* |
388 | * try_lock means we have an inode locked | 397 | * Check to see if we've already unlocked this one. Not |
389 | * that is in the AIL. | 398 | * the first one going back, and the inode ptr is the |
399 | * same. | ||
390 | */ | 400 | */ |
391 | ASSERT(i != 0); | 401 | if (j != (i - 1) && ips[j] == ips[j + 1]) |
392 | if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) { | 402 | continue; |
393 | attempts++; | 403 | |
394 | 404 | xfs_iunlock(ips[j], lock_mode); | |
395 | /* | 405 | } |
396 | * Unlock all previous guys and try again. | ||
397 | * xfs_iunlock will try to push the tail | ||
398 | * if the inode is in the AIL. | ||
399 | */ | ||
400 | |||
401 | for(j = i - 1; j >= 0; j--) { | ||
402 | |||
403 | /* | ||
404 | * Check to see if we've already | ||
405 | * unlocked this one. | ||
406 | * Not the first one going back, | ||
407 | * and the inode ptr is the same. | ||
408 | */ | ||
409 | if ((j != (i - 1)) && ips[j] == | ||
410 | ips[j+1]) | ||
411 | continue; | ||
412 | |||
413 | xfs_iunlock(ips[j], lock_mode); | ||
414 | } | ||
415 | 406 | ||
416 | if ((attempts % 5) == 0) { | 407 | if ((attempts % 5) == 0) { |
417 | delay(1); /* Don't just spin the CPU */ | 408 | delay(1); /* Don't just spin the CPU */ |
418 | #ifdef DEBUG | 409 | #ifdef DEBUG |
419 | xfs_lock_delays++; | 410 | xfs_lock_delays++; |
420 | #endif | 411 | #endif |
421 | } | ||
422 | i = 0; | ||
423 | try_lock = 0; | ||
424 | goto again; | ||
425 | } | ||
426 | } else { | ||
427 | xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i)); | ||
428 | } | 412 | } |
413 | i = 0; | ||
414 | try_lock = 0; | ||
415 | goto again; | ||
429 | } | 416 | } |
430 | 417 | ||
431 | #ifdef DEBUG | 418 | #ifdef DEBUG |
@@ -2615,19 +2602,22 @@ xfs_remove( | |||
2615 | /* | 2602 | /* |
2616 | * Enter all inodes for a rename transaction into a sorted array. | 2603 | * Enter all inodes for a rename transaction into a sorted array. |
2617 | */ | 2604 | */ |
2605 | #define __XFS_SORT_INODES 5 | ||
2618 | STATIC void | 2606 | STATIC void |
2619 | xfs_sort_for_rename( | 2607 | xfs_sort_for_rename( |
2620 | xfs_inode_t *dp1, /* in: old (source) directory inode */ | 2608 | struct xfs_inode *dp1, /* in: old (source) directory inode */ |
2621 | xfs_inode_t *dp2, /* in: new (target) directory inode */ | 2609 | struct xfs_inode *dp2, /* in: new (target) directory inode */ |
2622 | xfs_inode_t *ip1, /* in: inode of old entry */ | 2610 | struct xfs_inode *ip1, /* in: inode of old entry */ |
2623 | xfs_inode_t *ip2, /* in: inode of new entry, if it | 2611 | struct xfs_inode *ip2, /* in: inode of new entry */ |
2624 | already exists, NULL otherwise. */ | 2612 | struct xfs_inode *wip, /* in: whiteout inode */ |
2625 | xfs_inode_t **i_tab,/* out: array of inode returned, sorted */ | 2613 | struct xfs_inode **i_tab,/* out: sorted array of inodes */ |
2626 | int *num_inodes) /* out: number of inodes in array */ | 2614 | int *num_inodes) /* in/out: inodes in array */ |
2627 | { | 2615 | { |
2628 | xfs_inode_t *temp; | ||
2629 | int i, j; | 2616 | int i, j; |
2630 | 2617 | ||
2618 | ASSERT(*num_inodes == __XFS_SORT_INODES); | ||
2619 | memset(i_tab, 0, *num_inodes * sizeof(struct xfs_inode *)); | ||
2620 | |||
2631 | /* | 2621 | /* |
2632 | * i_tab contains a list of pointers to inodes. We initialize | 2622 | * i_tab contains a list of pointers to inodes. We initialize |
2633 | * the table here & we'll sort it. We will then use it to | 2623 | * the table here & we'll sort it. We will then use it to |
@@ -2635,25 +2625,24 @@ xfs_sort_for_rename( | |||
2635 | * | 2625 | * |
2636 | * Note that the table may contain duplicates. e.g., dp1 == dp2. | 2626 | * Note that the table may contain duplicates. e.g., dp1 == dp2. |
2637 | */ | 2627 | */ |
2638 | i_tab[0] = dp1; | 2628 | i = 0; |
2639 | i_tab[1] = dp2; | 2629 | i_tab[i++] = dp1; |
2640 | i_tab[2] = ip1; | 2630 | i_tab[i++] = dp2; |
2641 | if (ip2) { | 2631 | i_tab[i++] = ip1; |
2642 | *num_inodes = 4; | 2632 | if (ip2) |
2643 | i_tab[3] = ip2; | 2633 | i_tab[i++] = ip2; |
2644 | } else { | 2634 | if (wip) |
2645 | *num_inodes = 3; | 2635 | i_tab[i++] = wip; |
2646 | i_tab[3] = NULL; | 2636 | *num_inodes = i; |
2647 | } | ||
2648 | 2637 | ||
2649 | /* | 2638 | /* |
2650 | * Sort the elements via bubble sort. (Remember, there are at | 2639 | * Sort the elements via bubble sort. (Remember, there are at |
2651 | * most 4 elements to sort, so this is adequate.) | 2640 | * most 5 elements to sort, so this is adequate.) |
2652 | */ | 2641 | */ |
2653 | for (i = 0; i < *num_inodes; i++) { | 2642 | for (i = 0; i < *num_inodes; i++) { |
2654 | for (j = 1; j < *num_inodes; j++) { | 2643 | for (j = 1; j < *num_inodes; j++) { |
2655 | if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { | 2644 | if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { |
2656 | temp = i_tab[j]; | 2645 | struct xfs_inode *temp = i_tab[j]; |
2657 | i_tab[j] = i_tab[j-1]; | 2646 | i_tab[j] = i_tab[j-1]; |
2658 | i_tab[j-1] = temp; | 2647 | i_tab[j-1] = temp; |
2659 | } | 2648 | } |
@@ -2801,16 +2790,16 @@ xfs_rename( | |||
2801 | xfs_fsblock_t first_block; | 2790 | xfs_fsblock_t first_block; |
2802 | int cancel_flags; | 2791 | int cancel_flags; |
2803 | int committed; | 2792 | int committed; |
2804 | xfs_inode_t *inodes[4]; | 2793 | xfs_inode_t *inodes[__XFS_SORT_INODES]; |
2794 | int num_inodes = __XFS_SORT_INODES; | ||
2805 | int spaceres; | 2795 | int spaceres; |
2806 | int num_inodes; | ||
2807 | 2796 | ||
2808 | trace_xfs_rename(src_dp, target_dp, src_name, target_name); | 2797 | trace_xfs_rename(src_dp, target_dp, src_name, target_name); |
2809 | 2798 | ||
2810 | new_parent = (src_dp != target_dp); | 2799 | new_parent = (src_dp != target_dp); |
2811 | src_is_directory = S_ISDIR(src_ip->i_d.di_mode); | 2800 | src_is_directory = S_ISDIR(src_ip->i_d.di_mode); |
2812 | 2801 | ||
2813 | xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, | 2802 | xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, NULL, |
2814 | inodes, &num_inodes); | 2803 | inodes, &num_inodes); |
2815 | 2804 | ||
2816 | xfs_bmap_init(&free_list, &first_block); | 2805 | xfs_bmap_init(&free_list, &first_block); |