All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <htejun@gmail.com>
To: gregkh@suse.de, dmitry.torokhov@gmail.com,
	cornelia.huck@de.ibm.com, oneukum@suse.de, rpurdie@rpsys.net,
	stern@rowland.harvard.edu, maneesh@in.ibm.com,
	linux-kernel@vger.kernel.org, htejun@gmail.com
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 3/3] sysfs: use singly-linked list for sysfs_dirent tree
Date: Tue, 29 May 2007 01:24:06 +0900	[thread overview]
Message-ID: <11803694462460-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <118036944617-git-send-email-htejun@gmail.com>

Make sysfs_dirent use singly linked list for its tree structure.
sysfs_link_sibling() and sysfs_unlink_sibling() functions are added to
handle simpler cases.  It adds some complexity and cpu cycle overhead
but reduced memory footprint is worthwhile on big machines.

This change reduces the sizeof sysfs_dirent from 104 to 88 on 64bit
and from 60 to 52 on 32bit.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 fs/sysfs/dir.c   |  146 +++++++++++++++++++++++++++++++++++++----------------
 fs/sysfs/inode.c |   12 +++--
 fs/sysfs/mount.c |    3 -
 fs/sysfs/sysfs.h |    4 +-
 4 files changed, 111 insertions(+), 54 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 40596a0..b4074ad 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -22,6 +22,48 @@ static spinlock_t sysfs_ino_lock = SPIN_
 static DEFINE_IDA(sysfs_ino_ida);
 
 /**
+ *	sysfs_link_sibling - link sysfs_dirent into sibling list
+ *	@sd: sysfs_dirent of interest
+ *
+ *	Link @sd into its sibling list which starts from
+ *	sd->s_parent->s_children.
+ *
+ *	Locking:
+ *	mutex_lock(sd->s_parent->dentry->d_inode->i_mutex)
+ */
+static void sysfs_link_sibling(struct sysfs_dirent *sd)
+{
+	struct sysfs_dirent *parent_sd = sd->s_parent;
+
+	BUG_ON(sd->s_sibling);
+	sd->s_sibling = parent_sd->s_children;
+	parent_sd->s_children = sd;
+}
+
+/**
+ *	sysfs_unlink_sibling - unlink sysfs_dirent from sibling list
+ *	@sd: sysfs_dirent of interest
+ *
+ *	Unlink @sd from its sibling list which starts from
+ *	sd->s_parent->s_children.
+ *
+ *	Locking:
+ *	mutex_lock(sd->s_parent->dentry->d_inode->i_mutex)
+ */
+static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
+{
+	struct sysfs_dirent **pos;
+
+	for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) {
+		if (*pos == sd) {
+			*pos = sd->s_sibling;
+			sd->s_sibling = NULL;
+			break;
+		}
+	}
+}
+
+/**
  *	sysfs_get_active - get an active reference to sysfs_dirent
  *	@sd: sysfs_dirent to get an active reference to
  *
@@ -73,9 +115,9 @@ void sysfs_put_active(struct sysfs_diren
 		return;
 
 	/* atomic_dec_return() is a mb(), we'll always see the updated
-	 * sd->s_sibling.next.
+	 * sd->s_sibling.
 	 */
-	cmpl = (void *)sd->s_sibling.next;
+	cmpl = (void *)sd->s_sibling;
 	complete(cmpl);
 }
 
@@ -129,18 +171,18 @@ void sysfs_deactivate(struct sysfs_diren
 	DECLARE_COMPLETION_ONSTACK(wait);
 	int v;
 
-	BUG_ON(!list_empty(&sd->s_sibling));
-	sd->s_sibling.next = (void *)&wait;
+	BUG_ON(sd->s_sibling);
+	sd->s_sibling = (void *)&wait;
 
 	/* atomic_add_return() is a mb(), put_active() will always see
-	 * the updated sd->s_sibling.next.
+	 * the updated sd->s_sibling.
 	 */
 	v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active);
 
 	if (v != SD_DEACTIVATED_BIAS)
 		wait_for_completion(&wait);
 
-	INIT_LIST_HEAD(&sd->s_sibling);
+	sd->s_sibling = NULL;
 }
 
 static int sysfs_alloc_ino(ino_t *pino)
@@ -237,8 +279,6 @@ struct sysfs_dirent *sysfs_new_dirent(co
 	atomic_set(&sd->s_count, 1);
 	atomic_set(&sd->s_active, 0);
 	atomic_set(&sd->s_event, 1);
-	INIT_LIST_HEAD(&sd->s_children);
-	INIT_LIST_HEAD(&sd->s_sibling);
 
 	sd->s_name = name;
 	sd->s_mode = mode;
@@ -273,7 +313,7 @@ void sysfs_attach_dirent(struct sysfs_di
 
 	if (parent_sd) {
 		sd->s_parent = sysfs_get(parent_sd);
-		list_add(&sd->s_sibling, &parent_sd->s_children);
+		sysfs_link_sibling(sd);
 	}
 }
 
@@ -289,7 +329,7 @@ int sysfs_dirent_exist(struct sysfs_dire
 {
 	struct sysfs_dirent * sd;
 
-	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
 		if (sd->s_type) {
 			if (strcmp(sd->s_name, new))
 				continue;
@@ -409,7 +449,7 @@ static struct dentry * sysfs_lookup(stru
 	struct inode *inode;
 	int found = 0;
 
-	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
 		if ((sd->s_type & SYSFS_NOT_PINNED) &&
 		    !strcmp(sd->s_name, dentry->d_name.name)) {
 			found = 1;
@@ -458,7 +498,7 @@ static void remove_dir(struct dentry * d
 
 	mutex_lock(&parent->d_inode->i_mutex);
 
- 	list_del_init(&sd->s_sibling);
+	sysfs_unlink_sibling(sd);
 
 	pr_debug(" o %s removing done (%d)\n",d->d_name.name,
 		 atomic_read(&d->d_count));
@@ -478,9 +518,9 @@ void sysfs_remove_subdir(struct dentry *
 
 static void __sysfs_remove_dir(struct dentry *dentry)
 {
-	LIST_HEAD(removed);
-	struct sysfs_dirent * parent_sd;
-	struct sysfs_dirent * sd, * tmp;
+	struct sysfs_dirent *removed = NULL;
+	struct sysfs_dirent *parent_sd;
+	struct sysfs_dirent **pos;
 
 	if (!dentry)
 		return;
@@ -488,15 +528,25 @@ static void __sysfs_remove_dir(struct de
 	pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
 	mutex_lock(&dentry->d_inode->i_mutex);
 	parent_sd = dentry->d_fsdata;
-	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
-		if (!sd->s_type || !(sd->s_type & SYSFS_NOT_PINNED))
-			continue;
-		list_move(&sd->s_sibling, &removed);
+	pos = &parent_sd->s_children;
+	while (*pos) {
+		struct sysfs_dirent *sd = *pos;
+
+		if (sd->s_type && (sd->s_type & SYSFS_NOT_PINNED)) {
+			*pos = sd->s_sibling;
+			sd->s_sibling = removed;
+			removed = sd;
+		} else
+			pos = &(*pos)->s_sibling;
 	}
 	mutex_unlock(&dentry->d_inode->i_mutex);
 
-	list_for_each_entry_safe(sd, tmp, &removed, s_sibling) {
-		list_del_init(&sd->s_sibling);
+	while (removed) {
+		struct sysfs_dirent *sd = removed;
+
+		removed = sd->s_sibling;
+		sd->s_sibling = NULL;
+
 		sysfs_drop_dentry(sd);
 		sysfs_deactivate(sd);
 		sysfs_put(sd);
@@ -577,11 +627,11 @@ int sysfs_rename_dir(struct kobject * ko
 	d_add(new_dentry, NULL);
 	d_move(kobj->dentry, new_dentry);
 
-	list_del_init(&sd->s_sibling);
+	sysfs_unlink_sibling(sd);
 	sysfs_get(parent_sd);
 	sysfs_put(sd->s_parent);
 	sd->s_parent = parent_sd;
-	list_add(&sd->s_sibling, &parent_sd->s_children);
+	sysfs_link_sibling(sd);
 
 	error = 0;
 	goto out_unlock;
@@ -633,11 +683,11 @@ again:
 	dput(new_dentry);
 
 	/* Remove from old parent's list and insert into new parent's list. */
-	list_del_init(&sd->s_sibling);
+	sysfs_unlink_sibling(sd);
 	sysfs_get(new_parent_sd);
 	sysfs_put(sd->s_parent);
 	sd->s_parent = new_parent_sd;
-	list_add(&sd->s_sibling, &new_parent_sd->s_children);
+	sysfs_link_sibling(sd);
 
 out:
 	mutex_unlock(&new_parent_dentry->d_inode->i_mutex);
@@ -668,7 +718,7 @@ static int sysfs_dir_close(struct inode
 	struct sysfs_dirent * cursor = file->private_data;
 
 	mutex_lock(&dentry->d_inode->i_mutex);
-	list_del_init(&cursor->s_sibling);
+	sysfs_unlink_sibling(cursor);
 	mutex_unlock(&dentry->d_inode->i_mutex);
 
 	release_sysfs_dirent(cursor);
@@ -687,7 +737,7 @@ static int sysfs_readdir(struct file * f
 	struct dentry *dentry = filp->f_path.dentry;
 	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
 	struct sysfs_dirent *cursor = filp->private_data;
-	struct list_head *p, *q = &cursor->s_sibling;
+	struct sysfs_dirent **pos;
 	ino_t ino;
 	int i = filp->f_pos;
 
@@ -710,16 +760,21 @@ static int sysfs_readdir(struct file * f
 			i++;
 			/* fallthrough */
 		default:
+			pos = &parent_sd->s_children;
+			while (*pos != cursor)
+				pos = &(*pos)->s_sibling;
+
+			/* unlink cursor */
+			*pos = cursor->s_sibling;
+
 			if (filp->f_pos == 2)
-				list_move(q, &parent_sd->s_children);
+				pos = &parent_sd->s_children;
 
-			for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
-				struct sysfs_dirent *next;
+			for ( ; *pos; pos = &(*pos)->s_sibling) {
+				struct sysfs_dirent *next = *pos;
 				const char * name;
 				int len;
 
-				next = list_entry(p, struct sysfs_dirent,
-						   s_sibling);
 				if (!next->s_type)
 					continue;
 
@@ -729,12 +784,14 @@ static int sysfs_readdir(struct file * f
 
 				if (filldir(dirent, name, len, filp->f_pos, ino,
 						 dt_type(next)) < 0)
-					return 0;
+					break;
 
-				list_move(q, p);
-				p = q;
 				filp->f_pos++;
 			}
+
+			/* put cursor back in */
+			cursor->s_sibling = *pos;
+			*pos = cursor;
 	}
 	return 0;
 }
@@ -759,20 +816,21 @@ static loff_t sysfs_dir_lseek(struct fil
 		if (file->f_pos >= 2) {
 			struct sysfs_dirent *sd = dentry->d_fsdata;
 			struct sysfs_dirent *cursor = file->private_data;
-			struct list_head *p;
+			struct sysfs_dirent **pos;
 			loff_t n = file->f_pos - 2;
 
-			list_del(&cursor->s_sibling);
-			p = sd->s_children.next;
-			while (n && p != &sd->s_children) {
-				struct sysfs_dirent *next;
-				next = list_entry(p, struct sysfs_dirent,
-						   s_sibling);
+			sysfs_unlink_sibling(cursor);
+
+			pos = &sd->s_children;
+			while (n && *pos) {
+				struct sysfs_dirent *next = *pos;
 				if (next->s_type)
 					n--;
-				p = p->next;
+				pos = &(*pos)->s_sibling;
 			}
-			list_add_tail(&cursor->s_sibling, p);
+
+			cursor->s_sibling = *pos;
+			*pos = cursor;
 		}
 	}
 	mutex_unlock(&dentry->d_inode->i_mutex);
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 167c7fb..4d79a61 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -283,8 +283,8 @@ void sysfs_drop_dentry(struct sysfs_dire
 
 int sysfs_hash_and_remove(struct dentry * dir, const char * name)
 {
-	struct sysfs_dirent * sd;
-	struct sysfs_dirent * parent_sd;
+	struct sysfs_dirent **pos, *sd;
+	struct sysfs_dirent *parent_sd = dir->d_fsdata;
 	int found = 0;
 
 	if (!dir)
@@ -294,13 +294,15 @@ int sysfs_hash_and_remove(struct dentry
 		/* no inode means this hasn't been made visible yet */
 		return -ENOENT;
 
-	parent_sd = dir->d_fsdata;
 	mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
-	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+	for (pos = &parent_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
+		sd = *pos;
+
 		if (!sd->s_type)
 			continue;
 		if (!strcmp(sd->s_name, name)) {
-			list_del_init(&sd->s_sibling);
+			*pos = sd->s_sibling;
+			sd->s_sibling = NULL;
 			found = 1;
 			break;
 		}
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 2d6294b..2e66701 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -24,12 +24,9 @@ static const struct super_operations sys
 
 static struct sysfs_dirent sysfs_root = {
 	.s_count	= ATOMIC_INIT(1),
-	.s_sibling	= LIST_HEAD_INIT(sysfs_root.s_sibling),
-	.s_children	= LIST_HEAD_INIT(sysfs_root.s_children),
 	.s_type		= SYSFS_ROOT,
 	.s_mode		= S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
 	.s_ino		= 1,
-	.s_iattr	= NULL,
 };
 
 static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index ae006b0..6f8aaf3 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -23,8 +23,8 @@ struct sysfs_dirent {
 	atomic_t		s_count;
 	atomic_t		s_active;
 	struct sysfs_dirent	* s_parent;
-	struct list_head	s_sibling;
-	struct list_head	s_children;
+	struct sysfs_dirent	* s_sibling;
+	struct sysfs_dirent	* s_children;
 	const char		* s_name;
 
 	union {
-- 
1.4.3.4



  reply	other threads:[~2007-05-28 16:25 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-28 16:24 [PATCHSET 2.6.22-rc2-mm1] sysfs: reduce memory footprint of sysfs_dirent Tejun Heo
2007-05-28 16:24 ` Tejun Heo [this message]
2007-05-28 16:24 ` [PATCH 1/3] sysfs: move s_active functions to fs/sysfs/dir.c Tejun Heo
2007-05-28 16:24 ` [PATCH 2/3] sysfs: slim down sysfs_dirent->s_active Tejun Heo
2007-05-29 16:13   ` Cornelia Huck
2007-05-29 16:04 ` [PATCHSET 2.6.22-rc2-mm1] sysfs: reduce memory footprint of sysfs_dirent Dmitry Torokhov
2007-05-29 16:17   ` Cornelia Huck
2007-05-29 17:23     ` Cornelia Huck

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=11803694462460-git-send-email-htejun@gmail.com \
    --to=htejun@gmail.com \
    --cc=cornelia.huck@de.ibm.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=gregkh@suse.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maneesh@in.ibm.com \
    --cc=oneukum@suse.de \
    --cc=rpurdie@rpsys.net \
    --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.