• Roland McGrath's avatar
    [PATCH] make rlimit settings per-process instead of per-thread · 31180071
    Roland McGrath authored
    
    
    POSIX specifies that the limit settings provided by getrlimit/setrlimit are
    shared by the whole process, not specific to individual threads.  This
    patch changes the behavior of those calls to comply with POSIX.
    
    I've moved the struct rlimit array from task_struct to signal_struct, as it
    has the correct sharing properties.  (This reduces kernel memory usage per
    thread in multithreaded processes by around 100/200 bytes for 32/64
    machines respectively.)  I took a fairly minimal approach to the locking
    issues with the newly shared struct rlimit array.  It turns out that all
    the code that is checking limits really just needs to look at one word at a
    time (one rlim_cur field, usually).  It's only the few places like
    getrlimit itself (and fork), that require atomicity in accessing a whole
    struct rlimit, so I just used a spin lock for them and no locking for most
    of the checks.  If it turns out that readers of struct rlimit need more
    atomicity where they are now cheap, or less overhead where they are now
    atomic (e.g. fork), then seqcount is certainly the right thing to use for
    them instead of readers using the spin lock.  Though it's in signal_struct,
    I didn't use siglock since the access to rlimits never needs to disable
    irqs and doesn't overlap with other siglock uses.  Instead of adding
    something new, I overloaded task_lock(task->group_leader) for this; it is
    used for other things that are not likely to happen simultaneously with
    limit tweaking.  To me that seems preferable to adding a word, but it would
    be trivial (and arguably cleaner) to add a separate lock for these users
    (or e.g. just use seqlock, which adds two words but is optimal for readers).
    
    Most of the changes here are just the trivial s/->rlim/->signal->rlim/. 
    
    I stumbled across what must be a long-standing bug, in reparent_to_init.
    It does:
    	memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim)));
    when surely it was intended to be:
    	memcpy(current->rlim, init_task.rlim, sizeof(current->rlim));
    As rlim is an array, the * in the sizeof expression gets the size of the
    first element, so this just changes the first limit (RLIMIT_CPU).  This is
    for kernel threads, where it's clear that resetting all the rlimits is what
    you want.  With that fixed, the setting of RLIMIT_FSIZE in nfsd is
    superfluous since it will now already have been reset to RLIM_INFINITY.
    
    The other subtlety is removing:
    	tsk->rlim[RLIMIT_CPU].rlim_cur = RLIM_INFINITY;
    in exit_notify, which was to avoid a race signalling during self-reaping
    exit.  As the limit is now shared, a dying thread should not change it for
    others.  Instead, I avoid that race by checking current->state before the
    RLIMIT_CPU check.  (Adding one new conditional in that path is now required
    one way or another, since if not for this check there would also be a new
    race with self-reaping exit later on clearing current->signal that would
    have to be checked for.)
    
    The one loose end left by this patch is with process accounting.
    do_acct_process temporarily resets the RLIMIT_FSIZE limit while writing the
    accounting record.  I left this as it was, but it is now changing a limit
    that might be shared by other threads still running.  I left this in a
    dubious state because it seems to me that processing accounting may already
    be more generally a dubious state when it comes to NPTL threads.  I would
    think you would want one record per process, with aggregate data about all
    threads that ever lived in it, not a separate record for each thread.
    I don't use process accounting myself, but if anyone is interested in
    testing it out I could provide a patch to change it this way.
    
    One final note, this is not 100% to POSIX compliance in regards to rlimits.
    POSIX specifies that RLIMIT_CPU refers to a whole process in aggregate, not
    to each individual thread.  I will provide patches later on to achieve that
    change, assuming this patch goes in first.
    Signed-off-by: default avatarRoland McGrath <roland@redhat.com>
    Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
    31180071
memory.c 47.3 KB