From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Eric W. Biederman" Subject: [PATCH 04/20] sysfs: Handle the general case of removing of directories with subdirectories Date: Wed, 20 May 2009 17:27:58 -0700 Message-ID: <1242865694-2100-4-git-send-email-ebiederm@xmission.com> References: <1242865694-2100-1-git-send-email-ebiederm@xmission.com> <1242865694-2100-2-git-send-email-ebiederm@xmission.com> <1242865694-2100-3-git-send-email-ebiederm@xmission.com> Cc: , Tejun Heo , Cornelia Huck , , "Eric W. Biederman" , "Eric W. Biederman" To: Andrew Morton , Greg Kroah-Hartman Return-path: Received: from out01.mta.xmission.com ([166.70.13.231]:46315 "EHLO out01.mta.xmission.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753558AbZEUA2Q (ORCPT ); Wed, 20 May 2009 20:28:16 -0400 In-Reply-To: <1242865694-2100-3-git-send-email-ebiederm@xmission.com> Sender: linux-fsdevel-owner@vger.kernel.org List-ID: From: Eric W. Biederman Modify sysfs to properly remove directories containing attributes and subdirectories. The code is relatively simple and means we don't have to worry about what might use this logic. In a quick survey I have only found /sys/dev/char and /sys/dev/block that are removing non-enmpty directories today (and they are exclusively filled with symlinks). So only removing empty directories does not appear to be an option. I don't hold sysfs_mutex across the entire operation as that is unneeded for coherence at the sysfs level and some level of coordination is expected at the upper layers. Signed-off-by: Eric W. Biederman --- fs/sysfs/dir.c | 54 ++++++++++++++++++++++++++---------------------------- 1 files changed, 26 insertions(+), 28 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index b95cc07..50702b3 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -732,43 +732,41 @@ const struct inode_operations sysfs_dir_inode_operations = { .setattr = sysfs_setattr, }; -static void remove_dir(struct sysfs_dirent *sd) +static struct sysfs_dirent *sysfs_get_one(struct sysfs_dirent *dir_sd) { - struct sysfs_addrm_cxt acxt; - - sysfs_addrm_start(&acxt, sd->s_parent); - sysfs_remove_one(&acxt, sd); - sysfs_addrm_finish(&acxt); -} - -void sysfs_remove_subdir(struct sysfs_dirent *sd) -{ - remove_dir(sd); + struct sysfs_dirent *sd = dir_sd; + mutex_lock(&sysfs_mutex); + while ((sysfs_type(sd) == SYSFS_DIR) && sd->s_dir.children) + sd = sd->s_dir.children; + if (sd != dir_sd) + sysfs_get(sd); + else + sd = NULL; + mutex_unlock(&sysfs_mutex); + return sd; } - -static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd) +static void remove_dir(struct sysfs_dirent *dir_sd) { struct sysfs_addrm_cxt acxt; - struct sysfs_dirent **pos; - - if (!dir_sd) - return; + struct sysfs_dirent *sd; pr_debug("sysfs %s: removing dir\n", dir_sd->s_name); - sysfs_addrm_start(&acxt, dir_sd); - pos = &dir_sd->s_dir.children; - while (*pos) { - struct sysfs_dirent *sd = *pos; - if (sysfs_type(sd) != SYSFS_DIR) - sysfs_remove_one(&acxt, sd); - else - pos = &(*pos)->s_sibling; + while ((sd = sysfs_get_one(dir_sd))) { + sysfs_addrm_start(&acxt, sd->s_parent); + sysfs_remove_one(&acxt, sd); + sysfs_addrm_finish(&acxt); + sysfs_put(sd); } + sysfs_addrm_start(&acxt, dir_sd->s_parent); + sysfs_remove_one(&acxt, dir_sd); sysfs_addrm_finish(&acxt); +} - remove_dir(dir_sd); +void sysfs_remove_subdir(struct sysfs_dirent *sd) +{ + remove_dir(sd); } /** @@ -788,7 +786,7 @@ void sysfs_remove_dir(struct kobject * kobj) kobj->sd = NULL; spin_unlock(&sysfs_assoc_lock); - __sysfs_remove_dir(sd); + remove_dir(sd); } int sysfs_rename_dir(struct kobject * kobj, const char *new_name) -- 1.6.1.2.350.g88cc