lkml.org 
[lkml]   [2013]   [Apr]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[ 106/171 ] Nest rename_lock inside vfsmount_lock
    3.6.11.2 stable review patch.
    If anyone has any objections, please let me know.

    ------------------

    From: Al Viro <viro@zeniv.linux.org.uk>

    [ Upstream commit 7ea600b5314529f9d1b9d6d3c41cb26fce6a7a4a ]

    ... lest we get livelocks between path_is_under() and d_path() and friends.

    The thing is, wrt fairness lglocks are more similar to rwsems than to rwlocks;
    it is possible to have thread B spin on attempt to take lock shared while thread
    A is already holding it shared, if B is on lower-numbered CPU than A and there's
    a thread C spinning on attempt to take the same lock exclusive.

    As the result, we need consistent ordering between vfsmount_lock (lglock) and
    rename_lock (seq_lock), even though everything that takes both is going to take
    vfsmount_lock only shared.

    Spotted-by: Brad Spengler <spender@grsecurity.net>
    Cc: stable@vger.kernel.org
    Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
    ---
    fs/dcache.c | 16 +++++++++++-----
    1 file changed, 11 insertions(+), 5 deletions(-)

    diff --git a/fs/dcache.c b/fs/dcache.c
    index 693f95b..2488c47 100644
    --- a/fs/dcache.c
    +++ b/fs/dcache.c
    @@ -2583,7 +2583,6 @@ static int prepend_path(const struct path *path,
    bool slash = false;
    int error = 0;

    - br_read_lock(&vfsmount_lock);
    while (dentry != root->dentry || vfsmnt != root->mnt) {
    struct dentry * parent;

    @@ -2613,8 +2612,6 @@ static int prepend_path(const struct path *path,
    if (!error && !slash)
    error = prepend(buffer, buflen, "/", 1);

    -out:
    - br_read_unlock(&vfsmount_lock);
    return error;

    global_root:
    @@ -2631,7 +2628,7 @@ global_root:
    error = prepend(buffer, buflen, "/", 1);
    if (!error)
    error = is_mounted(vfsmnt) ? 1 : 2;
    - goto out;
    + return error;
    }

    /**
    @@ -2658,9 +2655,11 @@ char *__d_path(const struct path *path,
    int error;

    prepend(&res, &buflen, "\0", 1);
    + br_read_lock(&vfsmount_lock);
    write_seqlock(&rename_lock);
    error = prepend_path(path, root, &res, &buflen);
    write_sequnlock(&rename_lock);
    + br_read_unlock(&vfsmount_lock);

    if (error < 0)
    return ERR_PTR(error);
    @@ -2677,9 +2676,11 @@ char *d_absolute_path(const struct path *path,
    int error;

    prepend(&res, &buflen, "\0", 1);
    + br_read_lock(&vfsmount_lock);
    write_seqlock(&rename_lock);
    error = prepend_path(path, &root, &res, &buflen);
    write_sequnlock(&rename_lock);
    + br_read_unlock(&vfsmount_lock);

    if (error > 1)
    error = -EINVAL;
    @@ -2743,11 +2744,13 @@ char *d_path(const struct path *path, char *buf, int buflen)
    return path->dentry->d_op->d_dname(path->dentry, buf, buflen);

    get_fs_root(current->fs, &root);
    + br_read_lock(&vfsmount_lock);
    write_seqlock(&rename_lock);
    error = path_with_deleted(path, &root, &res, &buflen);
    + write_sequnlock(&rename_lock);
    + br_read_unlock(&vfsmount_lock);
    if (error < 0)
    res = ERR_PTR(error);
    - write_sequnlock(&rename_lock);
    path_put(&root);
    return res;
    }
    @@ -2902,6 +2905,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
    get_fs_root_and_pwd(current->fs, &root, &pwd);

    error = -ENOENT;
    + br_read_lock(&vfsmount_lock);
    write_seqlock(&rename_lock);
    if (!d_unlinked(pwd.dentry)) {
    unsigned long len;
    @@ -2911,6 +2915,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
    prepend(&cwd, &buflen, "\0", 1);
    error = prepend_path(&pwd, &root, &cwd, &buflen);
    write_sequnlock(&rename_lock);
    + br_read_unlock(&vfsmount_lock);

    if (error < 0)
    goto out;
    @@ -2931,6 +2936,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
    }
    } else {
    write_sequnlock(&rename_lock);
    + br_read_unlock(&vfsmount_lock);
    }

    out:
    --
    1.7.10.4



    \
     
     \ /
      Last update: 2013-04-12 04:41    [W:6.456 / U:0.048 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site