This was showing whilst running in an SMP kernel. The address
associated with the rlock_list can be deallocated from the vm_map
after the call to free() resulting in a page fault failure. Altered
usage of for loops to while loops to manage the list iteration more
carefully and avoid the free memory read errors.
---
libfshelp/rlock-tweak.c | 36 ++++++++++++++++--------------------
1 file changed, 16 insertions(+), 20 deletions(-)
diff --git a/libfshelp/rlock-tweak.c b/libfshelp/rlock-tweak.c
index 8be889938..d42354157 100644
--- a/libfshelp/rlock-tweak.c
+++ b/libfshelp/rlock-tweak.c
@@ -61,9 +61,10 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
return l;
}
- inline void
+ inline struct rlock_list *
rele_lock (struct rlock_list *l, int wake_waiters)
{
+ struct rlock_list *next = l->po.next;
list_unlink (po, l);
list_unlink (node, l);
@@ -72,19 +73,19 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
pthread_cond_destroy(&l->wait);
free (l);
+ return next;
}
error_t
unlock_region (loff_t start, loff_t len)
{
- struct rlock_list *l;
+ struct rlock_list *l = *po->locks;
- for (l = *po->locks; l; l = l->po.next)
+ while (l)
{
if (l->len != 0 && l->start + l->len <= start)
/* We start after the locked region ends. */
{
- continue;
}
else if (len != 0 && start + len <= l->start)
/* We end before this region starts. Since we are sorted,
@@ -98,7 +99,7 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
&& l->start + l->len <= start + len)))
/* We wrap the locked region; consume it. */
{
- rele_lock (l, 1);
+ l = rele_lock (l, 1);
continue;
}
else if (start <= l->start
@@ -135,8 +136,6 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
l->waiting = 0;
pthread_cond_broadcast (&l->wait);
}
-
- continue;
}
else if (l->start < start
&& (l->len == 0
@@ -170,6 +169,8 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
}
else
assert (! "Impossible!");
+
+ l = l->po.next;
}
return 0;
@@ -196,9 +197,9 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
inline error_t
merge_in (loff_t start, loff_t len, int type)
{
- struct rlock_list *l;
+ struct rlock_list *l = *po->locks;
- for (l = *po->locks; l; l = l->po.next)
+ while (l)
{
if (l->start <= start
&& (l->len == 0
@@ -235,7 +236,7 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
if (! tail)
{
if (head)
- rele_lock (head, 0);
+ (void) rele_lock (head, 0);
return ENOMEM;
}
}
@@ -258,7 +259,7 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
start = l->start;
len = l->len;
- rele_lock (l, 1);
+ l = rele_lock (l, 1);
continue;
}
else
@@ -277,7 +278,7 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
if (type == l->type || type == F_WRLCK)
{
- rele_lock (l, 1);
+ l = rele_lock (l, 1);
/* Try to merge more. */
continue;
}
@@ -301,8 +302,6 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
if (len != 0)
len = start + len - (l->start + l->len);
start = l->start + l->len;
-
- continue;
}
else
/* Our end is silently consumed. */
@@ -328,7 +327,7 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
len += start - l->start;
start = l->start;
- rele_lock (l, 1);
+ l = rele_lock (l, 1);
/* Try to merge in more. */
continue;
@@ -338,7 +337,6 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
intersection) and we are not the same type. */
{
/* The is nothing to do except continue the search. */
- continue;
}
else if (type == F_WRLCK)
/* We comsume the intersection. */
@@ -349,7 +347,6 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
/* Don't create the lock now; we might be able to
consume more locks. */
- continue;
}
else
/* We are dominated; the locked region comsumes the
@@ -366,7 +363,6 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
/* There is still a chance that we can consume more
locks. */
- continue;
}
}
else if (start < l->start
@@ -393,7 +389,6 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
region, however, we are not the same type. Just
insert it. */
{
- continue;
}
else if (type == F_WRLCK)
/* We consume the intersection. */
@@ -441,8 +436,9 @@ fshelp_rlock_tweak (struct rlock_box *box, pthread_mutex_t
*mutex,
{
assert (start >= l->start + l->len);
assert (l->len != 0);
- continue;
}
+
+ l = l->po.next;
}
return (gen_lock (start, len, type) ? 0 : ENOMEM);
--
2.47.3