On 07/03/2017 06:03, Davidlohr Bueso wrote:
+static inline int wait_for_ranges(struct range_rwlock_tree *tree,
+ struct range_rwlock *lock, long state)
+{
+ int ret = 0;
+
+ while (true) {
+ set_current_state(state);
+
+ if (unlikely(signal_pending_state(state, current))) {
+ unsigned long flags;
+
+ ret = -EINTR;
+ /*
+ * We're not taking the lock after all, cleanup
+ * after ourselves.
+ */
+ spin_lock_irqsave(&tree->lock, flags);
+ lock->reader = false;
+ __range_tree_remove(tree, lock);
+ spin_unlock_irqrestore(&tree->lock, flags);
+ break;
+ }
+
+ /* do we need to go to sleep? */
+ if (!lock->blocking_ranges)
+ break;
Hi Davidlohr,
While building a kernel on top of a patched kernel using full range lock
in the place of mmap_sem, I found that fork() sometimes failed returning
ENOMEM.
It happens that if fork() get called at the time signal is sent to the
calling process, the call to range_write_lock_interruptible() is failing
even if there is no contention on the lock. This is because we check for
the signal pending before checking for the lock contention in
wait_for_ranges().
The loop here should rather be :
while (true) {
/* do we need to go to sleep? */
if (!lock->blocking_ranges)
break;
if (unlikely(signal_pending_state(state, current))) {
unsigned long flags;
ret = -EINTR;
/*
* We're not taking the lock after all, cleanup
* after ourselves.
*/
spin_lock_irqsave(&tree->lock, flags);
lock->reader = false;
__range_tree_remove(tree, lock);
spin_unlock_irqrestore(&tree->lock, flags);
break;
}
set_current_state(state);
schedule();
}
I also moved the call to set_current_state() before calling schedule(),
not sure this has to be done this way, but my system seems to work fine
like this.