lkml.org 
[lkml]   [2009]   [May]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 06/26] sysfs: Don't hold addrm_start/addrm_finish over multiple removals.
    From: Eric W. Biederman <ebiederm@xmission.com>

    With respect to the basic integrity of the sysfs data structures holding
    the locks across the deletion of multiple sysfs_dirents is unnecessary.

    Upper layers are required to coordinate their activity so that they
    do not add or delete entries in sysfs directories as they are being
    removed, and I have seen nothing to indicate the don't. The upper layers
    can not rely on sysfs doing anything for them as it is a compile option
    and may not be there. So the previous atomic delete of the directory
    entries and the directory serves no useful purpose.

    By removing the only case where addrm_start/addrm_finish are held
    over multiple dirent removals I simplify the requirements and
    pave the way removing sysfs_addrm_start and sysfs_addrm_finish
    completely.

    Additionally add some comments explaining some of the thinking behind
    sysfs_dirent removal in __sysfs_remove_dir.

    Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
    ---
    fs/sysfs/dir.c | 36 +++++++++++++++++++++++++-----------
    1 files changed, 25 insertions(+), 11 deletions(-)

    diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
    index 60482be..3e3a87f 100644
    --- a/fs/sysfs/dir.c
    +++ b/fs/sysfs/dir.c
    @@ -762,23 +762,37 @@ void sysfs_remove_subdir(struct sysfs_dirent *sd)
    remove_dir(sd);
    }

    +static struct sysfs_dirent *get_dirent_to_remove(struct sysfs_dirent *dir_sd)
    +{
    + struct sysfs_dirent *sd;
    +
    + mutex_lock(&sysfs_mutex);
    + for (sd = dir_sd->s_dir.children; sd; sd = sd->s_sibling) {
    + /* Directories might be owned by someone else
    + * making recursive directory removal unsafe.
    + */
    + if (sysfs_type(sd) == SYSFS_DIR)
    + continue;
    + break;
    + }
    + sysfs_get(sd);
    + mutex_unlock(&sysfs_mutex);
    +
    + return sd;
    +}

    static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
    {
    struct sysfs_addrm_cxt acxt;
    - struct sysfs_dirent **pos;
    -
    - sysfs_addrm_start(&acxt, dir_sd);
    - pos = &dir_sd->s_dir.children;
    - while (*pos) {
    - struct sysfs_dirent *sd = *pos;
    + struct sysfs_dirent *sd;

    - if (sysfs_type(sd) != SYSFS_DIR)
    - sysfs_remove_one(&acxt, sd);
    - else
    - pos = &(*pos)->s_sibling;
    + /* Remove children that we think are safe */
    + while ((sd = get_dirent_to_remove(dir_sd))) {
    + sysfs_addrm_start(&acxt, sd->s_parent);
    + sysfs_remove_one(&acxt, sd);
    + sysfs_addrm_finish(&acxt);
    + sysfs_put(sd);
    }
    - sysfs_addrm_finish(&acxt);

    remove_dir(dir_sd);
    }
    --
    1.6.3.1.54.g99dd.dirty


    \
     
     \ /
      Last update: 2009-05-29 22:25    [W:2.292 / U:0.388 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site