op 19-05-14 15:42, Thomas Hellstrom schreef:
Hi, Maarten!
Some nitpicks, and that krealloc within rcu lock still worries me. Otherwise looks good.
/Thomas
On 04/23/2014 12:15 PM, Maarten Lankhorst wrote:
@@ -55,8 +60,8 @@ int reservation_object_reserve_shared(struct reservation_object *obj) kfree(obj->staged); obj->staged = NULL; return 0;
}
max = old->shared_max * 2;
} else
max = old->shared_max * 2;
Perhaps as a separate reformatting patch?
I'll fold it in to the patch that added reservation_object_reserve_shared.
+int reservation_object_get_fences_rcu(struct reservation_object *obj,
struct fence **pfence_excl,
unsigned *pshared_count,
struct fence ***pshared)
+{
- unsigned shared_count = 0;
- unsigned retry = 1;
- struct fence **shared = NULL, *fence_excl = NULL;
- int ret = 0;
- while (retry) {
struct reservation_object_list *fobj;
unsigned seq;
seq = read_seqcount_begin(&obj->seq);
rcu_read_lock();
fobj = rcu_dereference(obj->fence);
if (fobj) {
struct fence **nshared;
shared_count = ACCESS_ONCE(fobj->shared_count);
ACCESS_ONCE() shouldn't be needed inside the seqlock?
Yes it is, shared_count may be increased, leading to potential different sizes for krealloc and memcpy if the ACCESS_ONCE is removed. I could use shared_max here instead, which stays the same, but it would waste more memory.
nshared = krealloc(shared, sizeof(*shared) *
shared_count, GFP_KERNEL);
Again, krealloc should be a sleeping function, and not suitable within a RCU read lock? I still think this krealloc should be moved to the start of the retry loop, and we should start with a suitable guess of shared_count (perhaps 0?) It's not like we're going to waste a lot of memory....
But shared_count is only known when holding the rcu lock.
What about this change?
@@ -254,16 +254,27 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj, fobj = rcu_dereference(obj->fence); if (fobj) { struct fence **nshared; + size_t sz;
shared_count = ACCESS_ONCE(fobj->shared_count); - nshared = krealloc(shared, sizeof(*shared) * shared_count, GFP_KERNEL); + sz = sizeof(*shared) * shared_count; + + nshared = krealloc(shared, sz, + GFP_NOWAIT | __GFP_NOWARN); if (!nshared) { + rcu_read_unlock(); + nshared = krealloc(shared, sz, GFP_KERNEL) + if (nshared) { + shared = nshared; + continue; + } + ret = -ENOMEM; - shared_count = retry = 0; - goto unlock; + shared_count = 0; + break; } shared = nshared; - memcpy(shared, fobj->shared, sizeof(*shared) * shared_count); + memcpy(shared, fobj->shared, sz); } else shared_count = 0; fence_excl = rcu_dereference(obj->fence_excl);
/*
* There could be a read_seqcount_retry here, but nothing cares
* about whether it's the old or newer fence pointers that are
* signale. That race could still have happened after checking
Typo.
Oops.