Messages in this thread | | | Date | Thu, 8 May 2008 14:45:13 -0700 | From | "Paul Menage" <> | Subject | Re: [-mm][PATCH 3/4] Add rlimit controller accounting and control |
| |
On Thu, May 8, 2008 at 7:35 AM, Balbir Singh <balbir@linux.vnet.ibm.com> wrote: > > I currently intend to use this controller for controlling memory related > rlimits, like address space and mlock'ed memory. How about we use something like > "memrlimit"?
Sounds reasonable.
> > Good suggestion, but it will be hard if not impossible to account the data > correctly as it changes, if we do the accounting/summation at bind time. We'll > need a really big lock to do it, something I want to avoid. Did you have > something else in mind?
Yes, it'll be tricky but I think worthwhile. I believe it can be done without the charge/uncharge code needing to take a global lock, except for when we're actually binding/unbinding, with careful use of RCU.
My first thought for how to do this was that we have a field "bind_transition" that indicates whether we're transitioning between bound and unbound, and a bind_mutex. By default the charge/unpath uses RCU, but by marking that we're in a transition state, the charge path will use the mutex instead. By waiting for all existing chargers that are using RCU to exit, we can then take the lock and synchronize with the chargers.
So the charge/uncharge path would do:
rcu_read_lock(); if (ss->tranistioning) { rcu_read_unlock(); locked = 1; mutex_lock(&ss->bind_mutex); } if (ss->active) { /* do charge/uncharge stuff, which must not block */ } if (locked) { mutex_unlock(&ss->bind_mutex); } else { rcu_read_unlock(); }
and the bind path would do something like:
ss->transitioning = 1; synchronize_rcu(); mutex_lock(&ss->bind_mutex); for_each_mm(mm) { down_read(&mm->mmap_sem); add_charge_for_mm(); up_read(&mm->mmap_sem); } mutex_unlock(&ss->bind_mutex); ss->transitioning = 0;
But this would break because we're nesting mmap_sem inside bind_mutex in the bind path, but in the charge path we're nesting bind_mutex inside mmap_sem. So we'd probably need to define a new bit MMF_RLIMIT_ACCOUNTED in mm->flags to indicate whether that mm's address space usage is accounted for. Once we've done that, we can use mmap_sem to synchronize changes to the per-mm charged status for free, since we already hold mmap_sem whenever we're doing the charging, right? So it becomes simple:
charge path:
if (!test_bit(MMF_RLIMIT_ACCOUNTED, &mm->flags)) return 0; /* do charge/uncharge stuff */
bind path:
while((mm = find_unaccounted_mm()) { down_write(&mm->mmap_sem); add_charge_for_mm(); set_bit(MMF_RLIMIT_ACCOUNTED, &mm->flags); up_write(&mm->mmap_sem); }
Paul
| |