diff options
-rw-r--r-- | fs/locks.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/fs/locks.c b/fs/locks.c index 1d6cb28816be..89d898bce166 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -153,13 +153,15 @@ int lease_break_time = 45; | |||
153 | #define for_each_lock(inode, lockp) \ | 153 | #define for_each_lock(inode, lockp) \ |
154 | for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) | 154 | for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) |
155 | 155 | ||
156 | /* The global file_lock_list is only used for displaying /proc/locks. */ | ||
156 | static LIST_HEAD(file_lock_list); | 157 | static LIST_HEAD(file_lock_list); |
158 | |||
159 | /* The blocked_list is used to find POSIX lock loops for deadlock detection. */ | ||
157 | static LIST_HEAD(blocked_list); | 160 | static LIST_HEAD(blocked_list); |
161 | |||
162 | /* Protects the two list heads above, plus the inode->i_flock list */ | ||
158 | static DEFINE_SPINLOCK(file_lock_lock); | 163 | static DEFINE_SPINLOCK(file_lock_lock); |
159 | 164 | ||
160 | /* | ||
161 | * Protects the two list heads above, plus the inode->i_flock list | ||
162 | */ | ||
163 | void lock_flocks(void) | 165 | void lock_flocks(void) |
164 | { | 166 | { |
165 | spin_lock(&file_lock_lock); | 167 | spin_lock(&file_lock_lock); |
@@ -484,13 +486,37 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2) | |||
484 | return fl1->fl_owner == fl2->fl_owner; | 486 | return fl1->fl_owner == fl2->fl_owner; |
485 | } | 487 | } |
486 | 488 | ||
489 | static inline void | ||
490 | locks_insert_global_locks(struct file_lock *fl) | ||
491 | { | ||
492 | list_add_tail(&fl->fl_link, &file_lock_list); | ||
493 | } | ||
494 | |||
495 | static inline void | ||
496 | locks_delete_global_locks(struct file_lock *fl) | ||
497 | { | ||
498 | list_del_init(&fl->fl_link); | ||
499 | } | ||
500 | |||
501 | static inline void | ||
502 | locks_insert_global_blocked(struct file_lock *waiter) | ||
503 | { | ||
504 | list_add(&waiter->fl_link, &blocked_list); | ||
505 | } | ||
506 | |||
507 | static inline void | ||
508 | locks_delete_global_blocked(struct file_lock *waiter) | ||
509 | { | ||
510 | list_del_init(&waiter->fl_link); | ||
511 | } | ||
512 | |||
487 | /* Remove waiter from blocker's block list. | 513 | /* Remove waiter from blocker's block list. |
488 | * When blocker ends up pointing to itself then the list is empty. | 514 | * When blocker ends up pointing to itself then the list is empty. |
489 | */ | 515 | */ |
490 | static void __locks_delete_block(struct file_lock *waiter) | 516 | static void __locks_delete_block(struct file_lock *waiter) |
491 | { | 517 | { |
518 | locks_delete_global_blocked(waiter); | ||
492 | list_del_init(&waiter->fl_block); | 519 | list_del_init(&waiter->fl_block); |
493 | list_del_init(&waiter->fl_link); | ||
494 | waiter->fl_next = NULL; | 520 | waiter->fl_next = NULL; |
495 | } | 521 | } |
496 | 522 | ||
@@ -512,10 +538,10 @@ static void locks_insert_block(struct file_lock *blocker, | |||
512 | struct file_lock *waiter) | 538 | struct file_lock *waiter) |
513 | { | 539 | { |
514 | BUG_ON(!list_empty(&waiter->fl_block)); | 540 | BUG_ON(!list_empty(&waiter->fl_block)); |
515 | list_add_tail(&waiter->fl_block, &blocker->fl_block); | ||
516 | waiter->fl_next = blocker; | 541 | waiter->fl_next = blocker; |
542 | list_add_tail(&waiter->fl_block, &blocker->fl_block); | ||
517 | if (IS_POSIX(blocker)) | 543 | if (IS_POSIX(blocker)) |
518 | list_add(&waiter->fl_link, &blocked_list); | 544 | locks_insert_global_blocked(request); |
519 | } | 545 | } |
520 | 546 | ||
521 | /* | 547 | /* |
@@ -543,13 +569,13 @@ static void locks_wake_up_blocks(struct file_lock *blocker) | |||
543 | */ | 569 | */ |
544 | static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) | 570 | static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) |
545 | { | 571 | { |
546 | list_add(&fl->fl_link, &file_lock_list); | ||
547 | |||
548 | fl->fl_nspid = get_pid(task_tgid(current)); | 572 | fl->fl_nspid = get_pid(task_tgid(current)); |
549 | 573 | ||
550 | /* insert into file's list */ | 574 | /* insert into file's list */ |
551 | fl->fl_next = *pos; | 575 | fl->fl_next = *pos; |
552 | *pos = fl; | 576 | *pos = fl; |
577 | |||
578 | locks_insert_global_locks(fl); | ||
553 | } | 579 | } |
554 | 580 | ||
555 | /* | 581 | /* |
@@ -562,9 +588,10 @@ static void locks_delete_lock(struct file_lock **thisfl_p) | |||
562 | { | 588 | { |
563 | struct file_lock *fl = *thisfl_p; | 589 | struct file_lock *fl = *thisfl_p; |
564 | 590 | ||
591 | locks_delete_global_locks(fl); | ||
592 | |||
565 | *thisfl_p = fl->fl_next; | 593 | *thisfl_p = fl->fl_next; |
566 | fl->fl_next = NULL; | 594 | fl->fl_next = NULL; |
567 | list_del_init(&fl->fl_link); | ||
568 | 595 | ||
569 | if (fl->fl_nspid) { | 596 | if (fl->fl_nspid) { |
570 | put_pid(fl->fl_nspid); | 597 | put_pid(fl->fl_nspid); |