lkml.org 
[lkml]   [2012]   [Jun]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: deferring __fput()
    On 06/23, Al Viro wrote:
    >
    > You know what... Let's dump that "reverse the list" thing completely.

    Yes, it was never really needed for fifo.

    > What we ought to
    > do instead of that is honestly keeping both the head of the (single-linked) list and
    > pointer to pointer to its last element. Sure, that'll eat one more word in task_struct.
    > And it doesn't matter, since we'll be able to kill something else in there - namely,
    > ->scm_work_list.

    Still it is better to not add the second pointer, task->task_works can
    point to the last work, and last_work->next points to the first one.

    > 1) kill task_work->data; the only user that cares will allocate task_work + struct cred * and
    > use container_of() to get to it.

    OK. See the patch below. I need to cleanup it somehow (and test of course),
    cred.h needs task_work.h but task_work.h needs task_struct.

    And, David, can you suggest the good name for cred->xxx?

    > 2) replace current->task_works with struct task_work *task_works, **last_work and replace
    > hlist_node in task_work with struct task_work *next;

    Yes, but see above.

    > 3) at that point task_work is equal in size (and layout, BTW) to rcu_head.

    Yep.

    > [... snip ...]

    I'll try to understand fput/scm issues later ;)

    Oleg.


    diff --git a/include/linux/cred.h b/include/linux/cred.h
    index ebbed2c..d364255 100644
    --- a/include/linux/cred.h
    +++ b/include/linux/cred.h
    @@ -18,6 +18,7 @@
    #include <linux/selinux.h>
    #include <linux/atomic.h>
    #include <linux/uidgid.h>
    +#include <linux/task_work.h>

    struct user_struct;
    struct cred;
    @@ -149,7 +150,10 @@ struct cred {
    struct user_struct *user; /* real user ID subscription */
    struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
    struct group_info *group_info; /* supplementary groups for euid/fsgid */
    - struct rcu_head rcu; /* RCU deletion hook */
    + union {
    + struct rcu_head rcu; /* RCU deletion hook */
    + struct task_work xxx; /* keyctl_session_to_parent() */
    + };
    };

    extern void __put_cred(struct cred *);
    diff --git a/include/linux/task_work.h b/include/linux/task_work.h
    index 294d5d5..f834e38 100644
    --- a/include/linux/task_work.h
    +++ b/include/linux/task_work.h
    @@ -1,9 +1,6 @@
    #ifndef _LINUX_TASK_WORK_H
    #define _LINUX_TASK_WORK_H

    -#include <linux/list.h>
    -#include <linux/sched.h>
    -
    struct task_work;
    typedef void (*task_work_func_t)(struct task_work *);

    @@ -24,10 +21,14 @@ int task_work_add(struct task_struct *task, struct task_work *twork, bool);
    struct task_work *task_work_cancel(struct task_struct *, task_work_func_t);
    void task_work_run(void);

    -static inline void exit_task_work(struct task_struct *task)
    -{
    - if (unlikely(!hlist_empty(&task->task_works)))
    - task_work_run();
    -}
    +#define exit_task_work(__task) \
    + do { \
    + struct task_struct *task = (__task); \
    + if (unlikely(!hlist_empty(&task->task_works))) \
    + task_work_run(); \
    + } while (0)
    +
    +#include <linux/list.h>
    +#include <linux/sched.h>

    #endif /* _LINUX_TASK_WORK_H */
    diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
    index 0f5b3f0..cc428c9 100644
    --- a/security/keys/keyctl.c
    +++ b/security/keys/keyctl.c
    @@ -1456,8 +1456,8 @@ long keyctl_session_to_parent(void)
    {
    struct task_struct *me, *parent;
    const struct cred *mycred, *pcred;
    - struct task_work *newwork, *oldwork;
    key_ref_t keyring_r;
    + struct task_work *oldwork;
    struct cred *cred;
    int ret;

    @@ -1465,20 +1465,16 @@ long keyctl_session_to_parent(void)
    if (IS_ERR(keyring_r))
    return PTR_ERR(keyring_r);

    - ret = -ENOMEM;
    - newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
    - if (!newwork)
    - goto error_keyring;
    -
    /* our parent is going to need a new cred struct, a new tgcred struct
    * and new security data, so we allocate them here to prevent ENOMEM in
    * our parent */
    + ret = -ENOMEM;
    cred = cred_alloc_blank();
    if (!cred)
    - goto error_newwork;
    + goto error_keyring;

    cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
    - init_task_work(newwork, key_change_session_keyring, cred);
    + init_task_work(&cred->xxx, key_change_session_keyring, NULL);

    me = current;
    rcu_read_lock();
    @@ -1527,24 +1523,19 @@ long keyctl_session_to_parent(void)

    /* the replacement session keyring is applied just prior to userspace
    * restarting */
    - ret = task_work_add(parent, newwork, true);
    + ret = task_work_add(parent, &cred->xxx, true);
    if (!ret)
    - newwork = NULL;
    + cred = NULL;
    unlock:
    write_unlock_irq(&tasklist_lock);
    rcu_read_unlock();
    - if (oldwork) {
    - put_cred(oldwork->data);
    - kfree(oldwork);
    - }
    - if (newwork) {
    - put_cred(newwork->data);
    - kfree(newwork);
    - }
    +
    + if (oldwork)
    + put_cred(container_of(oldwork, struct cred, xxx));
    + if (cred)
    + put_cred(cred);
    return ret;

    -error_newwork:
    - kfree(newwork);
    error_keyring:
    key_ref_put(keyring_r);
    return ret;
    diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
    index 4ad54ee..5596caf 100644
    --- a/security/keys/process_keys.c
    +++ b/security/keys/process_keys.c
    @@ -837,9 +837,8 @@ error:
    void key_change_session_keyring(struct task_work *twork)
    {
    const struct cred *old = current_cred();
    - struct cred *new = twork->data;
    + struct cred *new = container_of(twork, struct cred, xxx);

    - kfree(twork);
    if (unlikely(current->flags & PF_EXITING)) {
    put_cred(new);
    return;


    \
     
     \ /
      Last update: 2012-06-24 18:01    [W:0.034 / U:122.308 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site