From: Tejun Heo <htejun@gmail.com>
To: ebiederm@xmission.com, cornelia.huck@de.ibm.com, greg@kroah.com,
stern@rowland.harvard.edu, kay.sievers@vrfy.org,
linux-kernel@vger.kernel.org, htejun@gmail.com
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 06/22] sysfs: restructure addrm helpers
Date: Thu, 20 Sep 2007 17:05:39 +0900 [thread overview]
Message-ID: <11902755391812-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11902755392688-git-send-email-htejun@gmail.com>
Restruct addrm helpers such that it can remove nodes under different
parents at one go.
sysfs_addrm_start() now doesn't take @sd. It now only initializes
@acxt and lock sysfs_mutex. Parent inode lookup now lives in
sysfs_addrm_get_parent_inode() and sysfs_add/remove_one() call them
directly. The function unlocks i_mutex of the previous inode and
grabs and locks the inode for the specified @parent_sd. This allows
sysfs_add/remove_one() to be called for any node.
This will be used to recursively remove sysfs nodes.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
fs/sysfs/dir.c | 144 +++++++++++++++++++++++++++++++++------------------
fs/sysfs/file.c | 4 +-
fs/sysfs/inode.c | 2 +-
fs/sysfs/symlink.c | 4 +-
fs/sysfs/sysfs.h | 10 ++--
5 files changed, 103 insertions(+), 61 deletions(-)
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 7a6be9a..b1cf090 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -375,6 +375,27 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
return NULL;
}
+/**
+ * sysfs_addrm_start - prepare for sysfs_dirent add/remove
+ * @acxt: pointer to sysfs_addrm_cxt to be used
+ *
+ * This function is called when the caller is about to add or
+ * remove sysfs_dirents. This function initializes @acxt and
+ * acquires sysfs_mutex. @acxt is used to keep and pass context
+ * to other addrm functions.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep). sysfs_mutex is locked on
+ * return.
+ */
+void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt)
+{
+ memset(acxt, 0, sizeof(*acxt));
+ acxt->removed_tail = &acxt->removed;
+
+ mutex_lock(&sysfs_mutex);
+}
+
static int sysfs_ilookup_test(struct inode *inode, void *arg)
{
struct sysfs_dirent *sd = arg;
@@ -382,39 +403,53 @@ static int sysfs_ilookup_test(struct inode *inode, void *arg)
}
/**
- * sysfs_addrm_start - prepare for sysfs_dirent add/remove
- * @acxt: pointer to sysfs_addrm_cxt to be used
- * @parent_sd: parent sysfs_dirent
+ * sysfs_addrm_get_parent_inode - get parent inode for add/rm
+ * @acxt: addrm context to prepare parent inode for
+ * @new_parent: parent to prepare (can be NULL)
*
- * This function is called when the caller is about to add or
- * remove sysfs_dirent under @parent_sd. This function acquires
- * sysfs_mutex, grabs inode for @parent_sd if available and lock
- * i_mutex of it. @acxt is used to keep and pass context to
- * other addrm functions.
+ * Release inode of the current @acxt->parent_sd and prepare
+ * inode of @new_parent. If @new_parent is NULL, the current
+ * parent inode is released.
*
* LOCKING:
- * Kernel thread context (may sleep). sysfs_mutex is locked on
- * return. i_mutex of parent inode is locked on return if
- * available.
+ * mutex_lock(sysfs_mutex). Returns with i_mutex of @new_parent
+ * locked if available. sysfs_mutex might be released and
+ * regrabbed.
+ *
+ * RETURNS:
+ * inode of @new_parent if available, NULL otherwise.
*/
-void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
- struct sysfs_dirent *parent_sd)
+static struct inode *sysfs_addrm_get_parent_inode(struct sysfs_addrm_cxt *acxt,
+ struct sysfs_dirent *new_parent)
{
struct inode *inode;
- memset(acxt, 0, sizeof(*acxt));
- acxt->parent_sd = parent_sd;
- acxt->removed_tail = &acxt->removed;
+ /* nothing to do if new equals current */
+ if (new_parent == acxt->parent_sd)
+ goto out;
+
+ /* if we're holding inode of the current parent, release it */
+ if ((inode = acxt->parent_inode)) {
+ mutex_unlock(&inode->i_mutex);
+ iput(inode);
+ }
+
+ acxt->parent_sd = NULL;
+ acxt->parent_inode = NULL;
+
+ if (!new_parent)
+ goto out;
+
+ /* make @new_parent the current one */
+ acxt->parent_sd = new_parent;
/* Lookup parent inode. inode initialization and I_NEW
- * clearing are protected by sysfs_mutex. By grabbing it and
- * looking up with _nowait variant, inode state can be
+ * clearing are protected by sysfs_mutex. By looking up with
+ * _nowait variant while holding it, inode state can be
* determined reliably.
*/
- mutex_lock(&sysfs_mutex);
-
- inode = ilookup5_nowait(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
- parent_sd);
+ inode = ilookup5_nowait(sysfs_sb, new_parent->s_ino, sysfs_ilookup_test,
+ new_parent);
if (inode && !(inode->i_state & I_NEW)) {
/* parent inode available */
@@ -431,16 +466,19 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
}
} else
iput(inode);
+ out:
+ return acxt->parent_inode;
}
/**
* sysfs_add_one - add sysfs_dirent to parent
* @acxt: addrm context to use
+ * @parent: parent sysfs_dirent to add sysfs_dirent under
* @sd: sysfs_dirent to be added
*
- * Get @acxt->parent_sd and set sd->s_parent to it and increment
- * nlink of parent inode if @sd is a directory and link into the
- * children list of the parent.
+ * Get @parent and set sd->s_parent to it and increment nlink of
+ * parent inode if @sd is a directory and link into the children
+ * list of the parent.
*
* This function should be called between calls to
* sysfs_addrm_start() and sysfs_addrm_finish() and should be
@@ -453,20 +491,26 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
* 0 on success, -EEXIST if entry with the given name already
* exists.
*/
-int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
+int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *parent,
+ struct sysfs_dirent *sd)
{
- if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
- return -EEXIST;
+ struct inode *parent_inode;
- sd->s_parent = sysfs_get(acxt->parent_sd);
+ if (sysfs_find_dirent(parent, sd->s_name))
+ return -EEXIST;
- if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
- inc_nlink(acxt->parent_inode);
+ parent_inode = sysfs_addrm_get_parent_inode(acxt, parent);
- acxt->cnt++;
+ sd->s_parent = sysfs_get(parent);
sysfs_link_sibling(sd);
+ if (parent_inode) {
+ parent_inode->i_ctime = parent_inode->i_mtime = CURRENT_TIME;
+ if (sysfs_type(sd) == SYSFS_DIR)
+ inc_nlink(parent_inode);
+ }
+
return 0;
}
@@ -487,8 +531,12 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
*/
void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{
+ struct inode *parent_inode;
+
BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED);
+ parent_inode = sysfs_addrm_get_parent_inode(acxt, sd->s_parent);
+
sysfs_unlink_sibling(sd);
sd->s_flags |= SYSFS_FLAG_REMOVED;
@@ -497,10 +545,11 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
acxt->removed_tail = &sd->s_sibling;
*acxt->removed_tail = NULL;
- if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
- drop_nlink(acxt->parent_inode);
-
- acxt->cnt++;
+ if (parent_inode) {
+ parent_inode->i_ctime = parent_inode->i_mtime = CURRENT_TIME;
+ if (sysfs_type(sd) == SYSFS_DIR)
+ drop_nlink(parent_inode);
+ }
}
/**
@@ -568,18 +617,11 @@ repeat:
*/
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
{
- /* release resources acquired by sysfs_addrm_start() */
+ /* Release resources acquired by
+ * sysfs_addrm_get_parent_inode() and sysfs_addrm_start().
+ */
+ sysfs_addrm_get_parent_inode(acxt, NULL);
mutex_unlock(&sysfs_mutex);
- if (acxt->parent_inode) {
- struct inode *inode = acxt->parent_inode;
-
- /* if added/removed, update timestamps on the parent */
- if (acxt->cnt)
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-
- mutex_unlock(&inode->i_mutex);
- iput(inode);
- }
/* kill removed sysfs_dirents */
while (acxt->removed) {
@@ -695,8 +737,8 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
sd->s_dir.kobj = kobj;
/* link in */
- sysfs_addrm_start(&acxt, parent_sd);
- rc = sysfs_add_one(&acxt, sd);
+ sysfs_addrm_start(&acxt);
+ rc = sysfs_add_one(&acxt, parent_sd, sd);
sysfs_addrm_finish(&acxt);
if (rc == 0)
@@ -778,7 +820,7 @@ static void remove_dir(struct sysfs_dirent *sd)
{
struct sysfs_addrm_cxt acxt;
- sysfs_addrm_start(&acxt, sd->s_parent);
+ sysfs_addrm_start(&acxt);
sysfs_remove_one(&acxt, sd);
sysfs_addrm_finish(&acxt);
}
@@ -798,7 +840,7 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
return;
pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
- sysfs_addrm_start(&acxt, dir_sd);
+ sysfs_addrm_start(&acxt);
pos = &dir_sd->s_dir.children;
while (*pos) {
struct sysfs_dirent *sd = *pos;
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 8d8e1ee..fb77d54 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -581,8 +581,8 @@ int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
return -ENOMEM;
sd->s_attr.attr = (void *)attr;
- sysfs_addrm_start(&acxt, dir_sd);
- rc = sysfs_add_one(&acxt, sd);
+ sysfs_addrm_start(&acxt);
+ rc = sysfs_add_one(&acxt, dir_sd, sd);
sysfs_addrm_finish(&acxt);
if (rc)
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 2210cf0..95bde29 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -214,7 +214,7 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
if (!dir_sd)
return -ENOENT;
- sysfs_addrm_start(&acxt, dir_sd);
+ sysfs_addrm_start(&acxt);
sd = sysfs_find_dirent(dir_sd, name);
if (sd)
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 982085c..897cc2f 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -90,8 +90,8 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
sd->s_symlink.target_sd = target_sd;
target_sd = NULL; /* reference is now owned by the symlink */
- sysfs_addrm_start(&acxt, parent_sd);
- error = sysfs_add_one(&acxt, sd);
+ sysfs_addrm_start(&acxt);
+ error = sysfs_add_one(&acxt, parent_sd, sd);
sysfs_addrm_finish(&acxt);
if (error)
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index db1a433..1f3915f 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -66,13 +66,13 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
}
/*
- * Context structure to be used while adding/removing nodes.
+ * Context structure to be used while adding/removing nodes. Don't
+ * dereference outside of addrm functions.
*/
struct sysfs_addrm_cxt {
struct sysfs_dirent *parent_sd;
struct inode *parent_inode;
struct sysfs_dirent *removed, **removed_tail;
- int cnt;
};
/*
@@ -97,9 +97,9 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
void sysfs_put_active(struct sysfs_dirent *sd);
struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
void sysfs_put_active_two(struct sysfs_dirent *sd);
-void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
- struct sysfs_dirent *parent_sd);
-int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
+void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt);
+int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *parent,
+ struct sysfs_dirent *sd);
void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
--
1.5.0.3
next prev parent reply other threads:[~2007-09-20 8:08 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-09-20 8:05 [PATCHSET 3/4] sysfs: divorce sysfs from kobject and driver model Tejun Heo
2007-09-20 8:05 ` [PATCH 05/22] sysfs: implement sysfs_find_child() Tejun Heo
2007-09-20 8:05 ` [PATCH 03/22] sysfs: make sysfs_new_dirent() normalize @mode and determine file type Tejun Heo
2007-09-20 8:05 ` [PATCH 01/22] sysfs: make sysfs_root a pointer Tejun Heo
2007-09-20 8:05 ` Tejun Heo [this message]
2007-09-20 8:05 ` [PATCH 04/22] sysfs: make SYSFS_COPY_NAME a flag Tejun Heo
2007-09-20 8:05 ` [PATCH 02/22] sysfs: separate out sysfs-kobject.h and fs/sysfs/kobject.c Tejun Heo
2007-09-20 8:05 ` [PATCH 14/22] sysfs: s/symlink/link/g Tejun Heo
2007-09-20 8:05 ` [PATCH 11/22] sysfs: implement sysfs_dirent based file interface Tejun Heo
2007-09-20 8:05 ` [PATCH 13/22] sysfs: implement sysfs_dirent based bin interface Tejun Heo
2007-09-20 8:05 ` [PATCH 09/22] sysfs: rename internal function sysfs_add_file() Tejun Heo
2007-09-20 8:05 ` [PATCH 10/22] sysfs: drop kobj and attr from file related symbols Tejun Heo
2007-09-20 8:05 ` [PATCH 07/22] sysfs: implement sysfs_dirent based remove interface sysfs_remove() Tejun Heo
2007-09-20 8:05 ` [PATCH 12/22] sysfs: drop kobj and attr from bin related symbols Tejun Heo
2007-09-20 8:05 ` [PATCH 08/22] sysfs: implement sysfs_dirent based directory interface Tejun Heo
2007-09-20 8:05 ` [PATCH 17/22] sysfs: s/sysfs_rename_mutex/sysfs_op_mutex/ and protect all tree modifying ops Tejun Heo
2007-09-20 8:05 ` [PATCH 15/22] sysfs: implement sysfs_dirent based link interface Tejun Heo
2007-09-20 8:05 ` [PATCH 16/22] sysfs: convert group implementation to use sd-based interface Tejun Heo
2007-09-20 8:05 ` [PATCH 18/22] kobject: implement __kobject_set_name() Tejun Heo
2007-09-20 8:05 ` [PATCH 19/22] sysfs: implement sysfs_dirent based rename - sysfs_rename() Tejun Heo
2007-09-20 8:05 ` [PATCH 21/22] sysfs: kill sysfs_hash_and_remove() Tejun Heo
2007-09-20 8:05 ` [PATCH 22/22] sysfs: move sysfs_assoc_lock into fs/sysfs/kobject.c and make it static Tejun Heo
2007-09-20 8:05 ` [PATCH 20/22] sysfs: kill now unused __sysfs_add_file() Tejun Heo
2007-09-25 22:17 ` [PATCHSET 3/4] sysfs: divorce sysfs from kobject and driver model Greg KH
2007-09-27 11:35 ` Tejun Heo
2007-09-27 19:25 ` Eric W. Biederman
2007-09-29 22:06 ` Tejun Heo
2007-10-05 6:23 ` Greg KH
2007-10-05 12:12 ` Eric W. Biederman
2007-10-05 13:03 ` [Devel] " Kirill Korotaev
2007-10-05 13:24 ` Eric W. Biederman
2007-10-09 22:51 ` Greg KH
[not found] ` <20071009225139.GF21228-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2007-10-10 13:16 ` Eric W. Biederman
2007-10-10 13:16 ` Eric W. Biederman
2007-10-10 20:44 ` Greg KH
2007-10-10 21:16 ` Eric W. Biederman
2007-10-16 22:18 ` sukadev
2007-10-16 23:54 ` Eric W. Biederman
2007-10-05 12:44 ` Eric W. Biederman
2007-10-09 22:53 ` Greg KH
2007-10-05 6:18 ` Greg KH
2007-10-05 8:00 ` Tejun Heo
2007-10-09 9:29 ` Cornelia Huck
2007-10-09 22:26 ` Greg KH
2007-10-09 23:20 ` Roland Dreier
2007-10-09 23:28 ` Greg KH
2007-10-10 9:11 ` Cornelia Huck
2007-10-10 9:05 ` Cornelia Huck
2007-10-09 22:48 ` Greg KH
2007-10-10 15:38 ` Alan Stern
2007-10-10 16:16 ` Cornelia Huck
2007-10-10 17:24 ` Martin Bligh
2007-10-10 17:30 ` Greg KH
2007-10-10 18:26 ` Martin Bligh
2007-10-10 18:44 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11902755391812-git-send-email-htejun@gmail.com \
--to=htejun@gmail.com \
--cc=cornelia.huck@de.ibm.com \
--cc=ebiederm@xmission.com \
--cc=greg@kroah.com \
--cc=kay.sievers@vrfy.org \
--cc=linux-kernel@vger.kernel.org \
--cc=stern@rowland.harvard.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.