@@ -725,7 +725,6 @@ static void __locks_delete_block(struct file_lock *waiter)
725
725
{
726
726
locks_delete_global_blocked (waiter );
727
727
list_del_init (& waiter -> fl_blocked_member );
728
- waiter -> fl_blocker = NULL ;
729
728
}
730
729
731
730
static void __locks_wake_up_blocks (struct file_lock * blocker )
@@ -740,6 +739,13 @@ static void __locks_wake_up_blocks(struct file_lock *blocker)
740
739
waiter -> fl_lmops -> lm_notify (waiter );
741
740
else
742
741
wake_up (& waiter -> fl_wait );
742
+
743
+ /*
744
+ * The setting of fl_blocker to NULL marks the "done"
745
+ * point in deleting a block. Paired with acquire at the top
746
+ * of locks_delete_block().
747
+ */
748
+ smp_store_release (& waiter -> fl_blocker , NULL );
743
749
}
744
750
}
745
751
@@ -753,11 +759,42 @@ int locks_delete_block(struct file_lock *waiter)
753
759
{
754
760
int status = - ENOENT ;
755
761
762
+ /*
763
+ * If fl_blocker is NULL, it won't be set again as this thread "owns"
764
+ * the lock and is the only one that might try to claim the lock.
765
+ *
766
+ * We use acquire/release to manage fl_blocker so that we can
767
+ * optimize away taking the blocked_lock_lock in many cases.
768
+ *
769
+ * The smp_load_acquire guarantees two things:
770
+ *
771
+ * 1/ that fl_blocked_requests can be tested locklessly. If something
772
+ * was recently added to that list it must have been in a locked region
773
+ * *before* the locked region when fl_blocker was set to NULL.
774
+ *
775
+ * 2/ that no other thread is accessing 'waiter', so it is safe to free
776
+ * it. __locks_wake_up_blocks is careful not to touch waiter after
777
+ * fl_blocker is released.
778
+ *
779
+ * If a lockless check of fl_blocker shows it to be NULL, we know that
780
+ * no new locks can be inserted into its fl_blocked_requests list, and
781
+ * can avoid doing anything further if the list is empty.
782
+ */
783
+ if (!smp_load_acquire (& waiter -> fl_blocker ) &&
784
+ list_empty (& waiter -> fl_blocked_requests ))
785
+ return status ;
786
+
756
787
spin_lock (& blocked_lock_lock );
757
788
if (waiter -> fl_blocker )
758
789
status = 0 ;
759
790
__locks_wake_up_blocks (waiter );
760
791
__locks_delete_block (waiter );
792
+
793
+ /*
794
+ * The setting of fl_blocker to NULL marks the "done" point in deleting
795
+ * a block. Paired with acquire at the top of this function.
796
+ */
797
+ smp_store_release (& waiter -> fl_blocker , NULL );
761
798
spin_unlock (& blocked_lock_lock );
762
799
return status ;
763
800
}
@@ -1350,7 +1387,8 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
1350
1387
error = posix_lock_inode (inode , fl , NULL );
1351
1388
if (error != FILE_LOCK_DEFERRED )
1352
1389
break ;
1353
- error = wait_event_interruptible (fl -> fl_wait , !fl -> fl_blocker );
1390
+ error = wait_event_interruptible (fl -> fl_wait ,
1391
+ list_empty (& fl -> fl_blocked_member ));
1354
1392
if (error )
1355
1393
break ;
1356
1394
}
@@ -1435,7 +1473,8 @@ int locks_mandatory_area(struct inode *inode, struct file *filp, loff_t start,
1435
1473
error = posix_lock_inode (inode , & fl , NULL );
1436
1474
if (error != FILE_LOCK_DEFERRED )
1437
1475
break ;
1438
- error = wait_event_interruptible (fl .fl_wait , !fl .fl_blocker );
1476
+ error = wait_event_interruptible (fl .fl_wait ,
1477
+ list_empty (& fl .fl_blocked_member ));
1439
1478
if (!error ) {
1440
1479
/*
1441
1480
* If we've been sleeping someone might have
@@ -1638,7 +1677,8 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
1638
1677
1639
1678
locks_dispose_list (& dispose );
1640
1679
error = wait_event_interruptible_timeout (new_fl -> fl_wait ,
1641
- !new_fl -> fl_blocker , break_time );
1680
+ list_empty (& new_fl -> fl_blocked_member ),
1681
+ break_time );
1642
1682
1643
1683
percpu_down_read (& file_rwsem );
1644
1684
spin_lock (& ctx -> flc_lock );
@@ -2122,7 +2162,8 @@ static int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
2122
2162
error = flock_lock_inode (inode , fl );
2123
2163
if (error != FILE_LOCK_DEFERRED )
2124
2164
break ;
2125
- error = wait_event_interruptible (fl -> fl_wait , !fl -> fl_blocker );
2165
+ error = wait_event_interruptible (fl -> fl_wait ,
2166
+ list_empty (& fl -> fl_blocked_member ));
2126
2167
if (error )
2127
2168
break ;
2128
2169
}
@@ -2399,7 +2440,8 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd,
2399
2440
error = vfs_lock_file (filp , cmd , fl , NULL );
2400
2441
if (error != FILE_LOCK_DEFERRED )
2401
2442
break ;
2402
- error = wait_event_interruptible (fl -> fl_wait , !fl -> fl_blocker );
2443
+ error = wait_event_interruptible (fl -> fl_wait ,
2444
+ list_empty (& fl -> fl_blocked_member ));
2403
2445
if (error )
2404
2446
break ;
2405
2447
}
0 commit comments