OpenVZ Forum


Home » Mailing lists » Devel » [PATCH 0/5] On to usable sysfs shadow directory support...
[PATCH 0/5] On to usable sysfs shadow directory support... [message #18080] Fri, 06 April 2007 16:43 Go to next message
ebiederm is currently offline  ebiederm
Messages: 1354
Registered: February 2006
Senior Member
The following patchset has been tested on 2.6.21-rc6 + Kay's
driver-core-fix-namespace-issue-with-devices-assigned-to-classes.patch

It has been tested both with CONFIG_SYSFS_DEPRECATED set and
unset.  Although more testing has been involved with CONFIG_SYSFS_DEPRECATED
unset because that was the hard case.

After the change of network devices from struct class_device to struct device
it has taken me a while to figure out how to get the shadow directory support
to actually work in a maintainable race free manner.  I wound up pushing
a lot more of the logic down into sysfs to accomplish this (primarily shadow
directory creation and deletion).  Which radically change the interfaces to
how I work with shadow directories at the upper levels.

So this patchset:

- fixes some aesthetic issues with Kay's patch.
- Rips out almost all of the old shadow directory support.
- Adds new shadow directory support.
- Adds some shadow directory friendly symlink manipulators
- Adds struct class and struct support for shadow directories.

Eric
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
[PATCH 1/5] kobject: Comment and warning fixes to kobject.c [message #18081 is a reply to message #18080] Fri, 06 April 2007 16:47 Go to previous messageGo to next message
ebiederm is currently offline  ebiederm
Messages: 1354
Registered: February 2006
Senior Member
This dots some i's and crosses some t's after left over from when
kobject_kset_add_dir was built from kobject_add_dir. 

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 lib/kobject.c |   13 ++++++++++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/lib/kobject.c b/lib/kobject.c
index f664551..09cb276 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -488,7 +488,7 @@ static struct kobj_type dir_ktype = {
 };
 
 /**
- *	kobject__kset_add_dir - add sub directory of object.
+ *	kobject_kset_add_dir - add sub directory of object.
  *	@kset:		kset the directory is belongs to.
  *	@parent:	object in which a directory is created.
  *	@name:	directory name.
@@ -514,8 +514,8 @@ struct kobject *kobject_kset_add_dir(struct kset *kset,
 	kobject_set_name(k, name);
 	ret = kobject_register(k);
 	if (ret < 0) {
-		printk(KERN_WARNING "kobject_add_dir: "
-			"kobject_register error: %d\n", ret);
+		printk(KERN_WARNING "%s: kobject_register error: %d\n",
+			__func__, ret);
 		kobject_del(k);
 		return NULL;
 	}
@@ -523,6 +523,13 @@ struct kobject *kobject_kset_add_dir(struct kset *kset,
 	return k;
 }
 
+/**
+ *	kobject_add_dir - add sub directory of object.
+ *	@parent:	object in which a directory is created.
+ *	@name:	directory name.
+ *
+ *	Add a plain directory object as child of given object.
+ */
 struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
 {
 	return kobject_kset_add_dir(NULL, parent, name);
-- 
1.5.0.g53756

_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
[PATCH 2/5] sysfs: Remove first pass at shadow directory support [message #18082 is a reply to message #18081] Fri, 06 April 2007 16:48 Go to previous messageGo to next message
ebiederm is currently offline  ebiederm
Messages: 1354
Registered: February 2006
Senior Member
While shadow directories appear to be a good idea, the current scheme
of controlling their creation and destruction outside of sysfs appears
to be a locking and maintenance nightmare in the face of sysfs directories
dynamically coming and going.  Which can now occur for directories containing
network devices when CONFIG_SYSFS_DEPRECATED is not set.

This patch removes everything from the initial shadow directory support
that allowed the shadow directory creation to be controlled at a higher
level.  So except for a few bits of sysfs_rename_dir everything from
commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 is now gone.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/sysfs/dir.c          |  196 +++++++++--------------------------------------
 fs/sysfs/group.c        |    1 -
 fs/sysfs/inode.c        |   10 ---
 fs/sysfs/mount.c        |    2 +-
 fs/sysfs/sysfs.h        |    5 -
 include/linux/kobject.h |    4 -
 include/linux/sysfs.h   |   24 +-----
 lib/kobject.c           |   43 +---------
 8 files changed, 45 insertions(+), 240 deletions(-)

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 85a6686..d6ab015 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -33,7 +33,8 @@ static struct dentry_operations sysfs_dentry_ops = {
 /*
  * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent
  */
-static struct sysfs_dirent * __sysfs_new_dirent(void * element)
+static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
+						void * element)
 {
 	struct sysfs_dirent * sd;
 
@@ -44,28 +45,12 @@ static struct sysfs_dirent * __sysfs_new_dirent(void * element)
 	atomic_set(&sd->s_count, 1);
 	atomic_set(&sd->s_event, 1);
 	INIT_LIST_HEAD(&sd->s_children);
-	INIT_LIST_HEAD(&sd->s_sibling);
+	list_add(&sd->s_sibling, &parent_sd->s_children);
 	sd->s_element = element;
 
 	return sd;
 }
 
-static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd,
-			      struct sysfs_dirent *sd)
-{
-	if (sd)
-		list_add(&sd->s_sibling, &parent_sd->s_children);
-}
-
-static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd,
-						void * element)
-{
-	struct sysfs_dirent *sd;
-	sd = __sysfs_new_dirent(element);
-	__sysfs_list_dirent(parent_sd, sd);
-	return sd;
-}
-
 /*
  *
  * Return -EEXIST if there is already a sysfs element with the same name for
@@ -92,14 +77,14 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
 }
 
 
-static struct sysfs_dirent *
-__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type)
+int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
+			void * element, umode_t mode, int type)
 {
 	struct sysfs_dirent * sd;
 
-	sd = __sysfs_new_dirent(element);
+	sd = sysfs_new_dirent(parent_sd, element);
 	if (!sd)
-		goto out;
+		return -ENOMEM;
 
 	sd->s_mode = mode;
 	sd->s_type = type;
@@ -109,19 +94,7 @@ __sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type)
 		dentry->d_op = &sysfs_dentry_ops;
 	}
 
-out:
-	return sd;
-}
-
-int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
-			void * element, umode_t mode, int type)
-{
-	struct sysfs_dirent *sd;
-
-	sd = __sysfs_make_dirent(dentry, element, mode, type);
-	__sysfs_list_dirent(parent_sd, sd);
-
-	return sd ? 0 : -ENOMEM;
+	return 0;
 }
 
 static int init_dir(struct inode * inode)
@@ -193,10 +166,9 @@ int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
 /**
  *	sysfs_create_dir - create a directory for an object.
  *	@kobj:		object we're creating directory for. 
- *	@shadow_parent:	parent parent object.
  */
 
-int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
+int sysfs_create_dir(struct kobject * kobj)
 {
 	struct dentry * dentry = NULL;
 	struct dentry * parent;
@@ -204,9 +176,7 @@ int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
 
 	BUG_ON(!kobj);
 
-	if (shadow_parent)
-		parent = shadow_parent;
-	else if (kobj->parent)
+	if (kobj->parent)
 		parent = kobj->parent->dentry;
 	else if (sysfs_mount && sysfs_mount->mnt_sb)
 		parent = sysfs_mount->mnt_sb->s_root;
@@ -327,12 +297,21 @@ void sysfs_remove_subdir(struct dentry * d)
 }
 
 
-static void __sysfs_remove_dir(struct dentry *dentry)
+/**
+ *	sysfs_remove_dir - remove an object's directory.
+ *	@kobj:	object.
+ *
+ *	The only thing special about this is that we remove any files in
+ *	the directory before we remove the directory, and we've inlined
+ *	what used to be sysfs_rmdir() below, instead of calling separately.
+ */
+
+void sysfs_remove_dir(struct kobject * kobj)
 {
+	struct dentry * dentry = dget(kobj->dentry);
 	struct sysfs_dirent * parent_sd;
 	struct sysfs_dirent * sd, * tmp;
 
-	dget(dentry);
 	if (!dentry)
 		return;
 
@@ -353,46 +332,28 @@ static void __sysfs_remove_dir(struct dentry *dentry)
 	 * Drop reference from dget() on entrance.
 	 */
 	dput(dentry);
-}
-
-/**
- *	sysfs_remove_dir - remove an object's directory.
- *	@kobj:	object.
- *
- *	The only thing special about this is that we remove any files in
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_dir(struct kobject * kobj)
-{
-	__sysfs_remove_dir(kobj->dentry);
 	kobj->dentry = NULL;
 }
 
-int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
-		     const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
 	int error = 0;
-	struct dentry * new_dentry;
+	struct inode * inode;
+	struct dentry * new_dentry, * old_parent, * new_parent;
 
-	if (!new_parent)
-		return -EFAULT;
+	if (!kobj->parent)
+		return -EINVAL;
+
+	old_parent = dget(kobj->dentry->d_parent);
+	inode = old_parent->d_inode;
 
 	down_write(&sysfs_rename_sem);
-	mutex_lock(&new_parent->d_inode->i_mutex);
+	mutex_lock(&inode->i_mutex);
 
+	new_parent = kobj->dentry->d_parent;
 	new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
 	if (!IS_ERR(new_dentry)) {
-		/* By allowing two different directories with the
-		 * same d_parent we allow this routine to move
-		 * between different shadows of the same directory
-		 */
-		if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
-			return -EINVAL;
-		else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
-			error = -EINVAL;
-		else if (new_dentry == kobj->dentry)
+		if (new_dentry == kobj->dentry)
 			error = -EINVAL;
 		else if (!new_dentry->d_inode) {
 			error = kobject_set_name(kobj, "%s", new_name);
@@ -414,9 +375,11 @@ int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
 			error = -EEXIST;
 		dput(new_dentry);
 	}
-	mutex_unlock(&new_parent->d_inode->i_mutex);
+	mutex_unlock(&inode->i_mutex);
 	up_write(&sysfs_rename_sem);
 
+	dput(old_parent);
+
 	return error;
 }
 
@@ -595,95 +558,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
 	return offset;
 }
 
-
-/**
- *	sysfs_make_shadowed_dir - Setup so a directory can be shadowed
- *	@kobj:	object we're creating shadow of.
- */
-
-int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	struct inode *inode;
-	struct inode_operations *i_op;
-
-	inode = kobj->dentry->d_inode;
-	if (inode->i_op != &sysfs_dir_inode_operations)
-		return -EINVAL;
-
-	i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
-	if (!i_op)
-		return -ENOMEM;
-
-	memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
-	i_op->follow_link = follow_link;
-
-	/* Locking of inode->i_op?
-	 * Since setting i_op is a single word write and they
-	 * are atomic we should be ok here.
-	 */
-	inode->i_op = i_op;
-	return 0;
-}
-
-/**
- *	sysfs_create_shadow_dir - create a shadow directory for an object.
- *	@kobj:	object we're creating directory for.
- *
- *	sysfs_make_shadowed_dir must already have been called on this
- *	directory.
- */
-
-struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
-{
-	struct sysfs_dirent *sd;
-	struct dentry *parent, *dir, *shadow;
-	struct inode *inode;
-
-	dir = kobj->dentry;
-	inode = dir->d_inode;
-	parent = dir->d_parent;
-	shadow = ERR_PTR(-EINVAL);
-	if (!sysfs_is_shadowed_inode(inode))
-		goto out;
-
-	shadow = d_alloc(parent, &dir->d_name);
-	if (!shadow)
-		goto nomem;
-
-	sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR);
-	if (!sd)
-		goto nomem;
-
-	d_instantiate(shadow, igrab(inode));
-	inc_nlink(inode);
-	inc_nlink(parent->d_inode);
-	shadow->d_op = &sysfs_dentry_ops;
-
-	dget(shadow);		/* Extra count - pin the dentry in core */
-
-out:
-	return shadow;
-nomem:
-	dput(shadow);
-	shadow = ERR_PTR(-ENOMEM);
-	goto out;
-}
-
-/**
- *	sysfs_remove_shadow_dir - remove an object's directory.
- *	@shadow: dentry of shadow directory
- *
- *	The only thing special about this is that we remove any files in
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_shadow_dir(struct dentry *shadow)
-{
-	__sysfs_remove_dir(shadow);
-}
-
 const struct file_operations sysfs_dir_operations = {
 	.open		= sysfs_dir_open,
 	.release	= sysfs_dir_close,
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index b20951c..46a277b 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,7 +13,6 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/err.h>
-#include <linux/fs.h>
 #include <asm/semaphore.h>
 #include "sysfs.h"
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 4de5c6b..69e6e9b 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -33,16 +33,6 @@ static const st
...

[PATCH 3/5] sysfs: Implement sysfs manged shadow directory support. [message #18083 is a reply to message #18082] Fri, 06 April 2007 16:50 Go to previous messageGo to next message
ebiederm is currently offline  ebiederm
Messages: 1354
Registered: February 2006
Senior Member
The problem.  When implementing a network namespace I need to be able
to have multiple network devices with the same name.  Currently this
is a problem for /sys/class/net/*, /sys/devices/virtual/net/*, and
potentially a few other directories of the form /sys/ ... /net/*.

What I want is for each network namespace to have it's own separate
set of directories.  /sys/class/net/, /sys/devices/virtual/net,
and /sys/ ... /net/, and in each set I want to name them
/sys/class/net/, sys/devices/virtual/net/ and /sys/ ... /net/ respectively.

I looked and the VFS actually allows that.  All that is needed is
for /sys/class/net to implement a follow link method to redirect
lookups to the real directory you want.

I am calling the concept of multiple directories all at the same path
in the filesystem shadow directories, the directory entry that
implements the follow_link method the shadow master, and the directories
that are the target of the follow link method shadow directories.

It turns out that just implementing a follow_link method is not
quite enough.  The existince of directories of the form /sys/ ... /net/
can depend on the presence or absence of hotplug hardware, which
means I need a simple race free way to create and destroy these
directories.

To achieve a race free design all shadow directories are created
and managed by sysfs itself.  The upper level code that knows what
shadow directories we need provides just two methods that enable
this:
  current_tag() - that returns a "void *" tag that identifies the context of
	the current process.
  kobject_tag(kobj) - that returns a "void *" tag that identifies the context
	a kobject should be in.
Everything else is left up to sysfs.

For the network namespace current_tag and kobject_tag are essentially
one line functions, and look to remain that.

The work needed in sysfs is more extensive.  At each directory or
symlink creation I need to check if the shadow directory it belongs
in exists and if it does not create it.  Likewise at each symlink
or directory removal I need to check if sysfs directory it is being
removed from is a shadow directory and if this is the last object
in the shadow directory and if so to remove the shadow directory
as well.

I also need a bunch of boiler plate that properly finds, creates, and
removes/frees the shadow directories.

Doing all of that in sysfs isn't bad it is just a bit tedious.  Being race
free is just a manner of ensure we have the directory inode mutex when
we add or remove a shadow directory.  Trying to do this race free
anywhere besides in sysfs is very nasty, and requires unhealthy
amounts of information about how sysfs is implemented.

Currently only directories which hold kobjects, and
symlinks are supported.  There is not enough information
in the current file attribute interfaces to give us anything
to discriminate on which makes it useless, and there are
not potential users which makes it an uniteresting problem
to solve.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/sysfs/bin.c        |    2 +-
 fs/sysfs/dir.c        |  370 ++++++++++++++++++++++++++++++++++++++++++++++---
 fs/sysfs/file.c       |    4 +-
 fs/sysfs/group.c      |   12 +-
 fs/sysfs/inode.c      |   18 ++-
 fs/sysfs/symlink.c    |   11 +-
 fs/sysfs/sysfs.h      |   18 +++-
 include/linux/sysfs.h |   14 ++
 8 files changed, 409 insertions(+), 40 deletions(-)

diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index d3b9f5f..a79ed4c 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -195,7 +195,7 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
 
 void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
 {
-	if (sysfs_hash_and_remove(kobj->dentry, attr->attr.name) < 0) {
+	if (sysfs_hash_and_remove(kobj, kobj->dentry, attr->attr.name) < 0) {
 		printk(KERN_ERR "%s: "
 			"bad dentry or inode or no such file: \"%s\"\n",
 			__FUNCTION__, attr->attr.name);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index d6ab015..0802a73 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -123,21 +123,26 @@ static int init_symlink(struct inode * inode)
 static int create_dir(struct kobject * k, struct dentry * p,
 		      const char * n, struct dentry ** d)
 {
+	struct dentry *parent;
 	int error;
 	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
 
 	mutex_lock(&p->d_inode->i_mutex);
-	*d = lookup_one_len(n, p, strlen(n));
+	parent = sysfs_resolve_for_create(k, p);
+	if (IS_ERR(parent))
+		*d = parent;
+	else
+		*d = lookup_one_len(n, parent, strlen(n));
 	if (!IS_ERR(*d)) {
- 		if (sysfs_dirent_exist(p->d_fsdata, n))
+		if (sysfs_dirent_exist(parent->d_fsdata, n))
   			error = -EEXIST;
   		else
-			error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
+			error = sysfs_make_dirent(parent->d_fsdata, *d, k, mode,
 								SYSFS_DIR);
 		if (!error) {
 			error = sysfs_create(*d, mode, init_dir);
 			if (!error) {
-				inc_nlink(p->d_inode);
+				inc_nlink(parent->d_inode);
 				(*d)->d_op = &sysfs_dentry_ops;
 				d_rehash(*d);
 			}
@@ -288,6 +293,7 @@ static void remove_dir(struct dentry * d)
 		 atomic_read(&d->d_count));
 
 	mutex_unlock(&parent->d_inode->i_mutex);
+	sysfs_prune_shadow(parent);
 	dput(parent);
 }
 
@@ -296,6 +302,55 @@ void sysfs_remove_subdir(struct dentry * d)
 	remove_dir(d);
 }
 
+static void sysfs_empty_dir(struct dentry *dentry)
+{
+	struct sysfs_dirent *parent_sd, *sd, *tmp;
+
+	parent_sd = dentry->d_fsdata;
+	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
+		if (!sd->s_element || !(sd->s_type & SYSFS_NOT_PINNED))
+			continue;
+		list_del_init(&sd->s_sibling);
+		sysfs_drop_dentry(sd, dentry);
+		sysfs_put(sd);
+	}
+}
+
+static void __sysfs_remove_empty_shadow(struct dentry *shadow)
+{
+	struct sysfs_dirent *sd;
+
+	if (d_unhashed(shadow))
+		return;
+
+	sd = shadow->d_fsdata;
+	d_delete(shadow);
+	list_del_init(&sd->s_sibling);
+	simple_rmdir(shadow->d_inode, shadow);
+	sysfs_put(sd);
+}
+
+static void sysfs_remove_empty_shadow(struct dentry *shadow)
+{
+	mutex_lock(&shadow->d_inode->i_mutex);
+	__sysfs_remove_empty_shadow(shadow);
+	mutex_unlock(&shadow->d_inode->i_mutex);
+}
+
+static void sysfs_remove_shadows(struct dentry *dentry)
+{
+	struct sysfs_dirent *parent_sd, *sd, *tmp;
+
+	parent_sd = dentry->d_fsdata;
+	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
+		struct dentry *shadow;
+
+		shadow = dget(sd->s_dentry);
+		sysfs_empty_dir(shadow);
+		__sysfs_remove_empty_shadow(shadow);
+		dput(shadow);
+	}
+}
 
 /**
  *	sysfs_remove_dir - remove an object's directory.
@@ -309,22 +364,16 @@ void sysfs_remove_subdir(struct dentry * d)
 void sysfs_remove_dir(struct kobject * kobj)
 {
 	struct dentry * dentry = dget(kobj->dentry);
-	struct sysfs_dirent * parent_sd;
-	struct sysfs_dirent * sd, * tmp;
 
 	if (!dentry)
 		return;
 
 	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_element || !(sd->s_type & SYSFS_NOT_PINNED))
-			continue;
-		list_del_init(&sd->s_sibling);
-		sysfs_drop_dentry(sd, dentry);
-		sysfs_put(sd);
-	}
+	if (dentry->d_inode->i_op == &sysfs_dir_inode_operations)
+		sysfs_empty_dir(dentry);
+	else
+		sysfs_remove_shadows(dentry);
 	mutex_unlock(&dentry->d_inode->i_mutex);
 
 	remove_dir(dentry);
@@ -350,7 +399,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 	down_write(&sysfs_rename_sem);
 	mutex_lock(&inode->i_mutex);
 
-	new_parent = kobj->dentry->d_parent;
+	new_parent = sysfs_resolve_for_create(kobj, kobj->dentry->d_parent);
 	new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
 	if (!IS_ERR(new_dentry)) {
 		if (new_dentry == kobj->dentry)
@@ -378,6 +427,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 	mutex_unlock(&inode->i_mutex);
 	up_write(&sysfs_rename_sem);
 
+	sysfs_prune_shadow(old_parent);
 	dput(old_parent);
 
 	return error;
@@ -385,24 +435,35 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 
 int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
 {
+	struct inode *old_parent_inode, *new_parent_inode;
 	struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry;
 	struct sysfs_dirent *new_parent_sd, *sd;
 	int error;
 
-	old_parent_dentry = kobj->parent ?
-		kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
+	old_parent_dentry = kobj->dentry->d_parent;
 	new_parent_dentry = new_parent ?
 		new_parent->dentry : sysfs_mount->mnt_sb->s_root;
 
-	if (old_parent_dentry->d_inode == new_parent_dentry->d_inode)
+	old_parent_inode = old_parent_dentry->d_inode;
+	new_parent_inode = new_parent_dentry->d_inode;
+
+	if (old_parent_inode == new_parent_inode)
 		return 0;	/* nothing to move */
+
+	dget(old_parent_dentry);
 again:
-	mutex_lock(&old_parent_dentry->d_inode->i_mutex);
-	if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) {
-		mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
+	mutex_lock(&old_parent_inode->i_mutex);
+	if (!mutex_trylock(&new_parent_inode->i_mutex)) {
+		mutex_unlock(&old_parent_inode->i_mutex);
 		goto again;
 	}
 
+	new_parent_dentry = sysfs_resolve_for_create(kobj, new_parent_dentry);
+	if (IS_ERR(new_parent_dentry)) {
+		error = PTR_ERR(new_parent_dentry);
+		goto out;
+	}
+
 	new_parent_sd = new_parent_dentry->d_fsdata;
 	sd = kobj->dentry->d_fsdata;
 
@@ -422,8 +483,11 @@ again:
 	list_add(&sd->s_sibling, &new_parent_sd->s_children);
 
 out:
-	mutex_unlock(&new_
...

[PATCH 4/5] sysfs: Implement sysfs_delete_link and sysfs_rename_link [message #18084 is a reply to message #18083] Fri, 06 April 2007 16:51 Go to previous messageGo to next message
ebiederm is currently offline  ebiederm
Messages: 1354
Registered: February 2006
Senior Member
When removing a symlink sysfs_remove_link does not provide enough
information to figure out which shadow directory the symlink falls in.
So I need sysfs_delete_link which is passed the target of the symlink
to delete. 

Further half the time when we are removing a symlink the code is
actually renaming the symlink but not doing so explicitly because we
don't have a symlink rename method.  So I have added sysfs_rename_link
as well.

Both of these functions now have enough information to find a symlink
in a shadow directory.  The only restriction is that they must be
called before the target kobject is renamed or deleted.  If they are
called later I loose track of which tag the target kobject was marked
with and can no longer find the old symlink to remove it.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/sysfs/symlink.c    |   31 +++++++++++++++++++++++++++++++
 include/linux/sysfs.h |   18 ++++++++++++++++++
 2 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 2885ebb..faff190 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -110,6 +110,21 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
 
 
 /**
+ *	sysfs_delete_link - remove symlink in object's directory.
+ *	@kobj:	object we're acting for.
+ *	@targ:	object we're pointing to.
+ *	@name:	name of the symlink to remove.
+ *
+ *	Unlike sysfs_remove_link sysfs_delete_link has enough information
+ *	to successfully delete symlinks in shadow directories.
+ */
+void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
+			const char *name)
+{
+	sysfs_hash_and_remove(targ, kobj->dentry,name);
+}
+
+/**
  *	sysfs_remove_link - remove symlink in object's directory.
  *	@kobj:	object we're acting for.
  *	@name:	name of the symlink to remove.
@@ -120,6 +135,22 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
 	sysfs_hash_and_remove(kobj, kobj->dentry,name);
 }
 
+/**
+ *	sysfs_rename_link - rename symlink in object's directory.
+ *	@kobj:	object we're acting for.
+ *	@targ:	object we're pointing to.
+ *	@old:	previous name of the symlink.
+ *	@new:	new name of the symlink.
+ *
+ *	A helper function for the common rename symlink idiom.
+ */
+int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
+			const char *old, const char *new)
+{
+	sysfs_delete_link(kobj, targ, old);
+	return sysfs_create_link(kobj, targ, new);
+}
+
 static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
 				 char *path)
 {
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index cda7b81..c29b38d 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -116,6 +116,13 @@ sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * n
 extern void
 sysfs_remove_link(struct kobject *, const char * name);
 
+extern int
+sysfs_rename_link(struct kobject *kobj, struct kobject *target,
+			const char *old_name, const char *new_name);
+
+extern void
+sysfs_delete_link(struct kobject *dir, struct kobject *targ, const char *name);
+
 int __must_check sysfs_create_bin_file(struct kobject *kobj,
 					struct bin_attribute *attr);
 void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
@@ -191,6 +198,17 @@ static inline void sysfs_remove_link(struct kobject * k, const char * name)
 	;
 }
 
+static inline int
+sysfs_rename_link(struct kobject * k, struct kobject *t,
+			const char *old_name, const char * new_name)
+{
+	return 0;
+}
+
+static inline void
+sysfs_delete_link(struct kobject *k, struct kobject *t, const char *name)
+{
+}
 
 static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a)
 {
-- 
1.5.0.g53756

_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
[PATCH 5/5] driver core: Implement shadow directory support for device classes. [message #18085 is a reply to message #18084] Fri, 06 April 2007 17:14 Go to previous messageGo to next message
ebiederm is currently offline  ebiederm
Messages: 1354
Registered: February 2006
Senior Member
This patch enables shadowing on every class directory if struct class
has shadow_ops.

In addition device_del and device_rename were modified to use
sysfs_delete_link and sysfs_rename_link respectively to ensure when
these operations happen in the presence of shadow directories the
work properly.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 drivers/base/class.c   |   30 ++++++++++++++++++++++++++----
 drivers/base/core.c    |   20 +++++++++++---------
 include/linux/device.h |    2 ++
 3 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/drivers/base/class.c b/drivers/base/class.c
index 80bbb20..1ac2b0e 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -136,6 +136,17 @@ static void remove_class_attrs(struct class * cls)
 	}
 }
 
+static int class_setup_shadowing(struct class *cls)
+{
+	const struct shadow_dir_operations *shadow_ops;
+
+	shadow_ops = cls->shadow_ops;
+	if (!shadow_ops)
+		return 0;
+
+	return sysfs_enable_shadowing(&cls->subsys.kset.kobj, shadow_ops);
+}
+
 int class_register(struct class * cls)
 {
 	int error;
@@ -154,11 +165,22 @@ int class_register(struct class * cls)
 	subsys_set_kset(cls, class_subsys);
 
 	error = subsystem_register(&cls->subsys);
-	if (!error) {
-		error = add_class_attrs(class_get(cls));
-		class_put(cls);
-	}
+	if (error)
+		goto out;
+
+	error = class_setup_shadowing(cls);
+	if (error)
+		goto out_unregister;
+
+	error = add_class_attrs(cls);
+	if (error)
+		goto out_unregister;
+
+out:
 	return error;
+out_unregister:
+	subsystem_unregister(&cls->subsys);
+	goto out;
 }
 
 void class_unregister(struct class * cls)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 8650401..3d9c5ff 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -519,8 +519,14 @@ static struct kobject * get_device_parent(struct device *dev,
 			return kobj;
 
 		/* or create a new class-directory at the parent device */
-		return kobject_kset_add_dir(&dev->class->class_dirs,
+		kobj = kobject_kset_add_dir(&dev->class->class_dirs,
 					    parent_kobj, dev->class->name);
+
+		/* If we created a new class-directory setup shadowing */
+		if (kobj && dev->class->shadow_ops)
+			sysfs_enable_shadowing(kobj, dev->class->shadow_ops);
+
+		return kobj;
 	}
 
 	if (parent)
@@ -797,8 +803,8 @@ void device_del(struct device * dev)
 		/* If this is not a "fake" compatible device, remove the
 		 * symlink from the class to the device. */
 		if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
-			sysfs_remove_link(&dev->class->subsys.kset.kobj,
-					  dev->bus_id);
+			sysfs_delete_link(&dev->class->subsys.kset.kobj,
+					  &dev->kobj, dev->bus_id);
 		if (parent) {
 #ifdef CONFIG_SYSFS_DEPRECATED
 			char *class_name = make_class_name(dev->class->name,
@@ -1096,6 +1102,8 @@ int device_rename(struct device *dev, char *new_name)
 			goto out_free_old_class;
 		}
 		strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
+		sysfs_rename_link(&dev->class->subsys.kset.kobj, &dev->kobj,
+				  old_symlink_name, new_name);
 	}
 
 	strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
@@ -1113,12 +1121,6 @@ int device_rename(struct device *dev, char *new_name)
 	}
 #endif
 
-	if (dev->class) {
-		sysfs_remove_link(&dev->class->subsys.kset.kobj,
-				  old_symlink_name);
-		sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
-				  dev->bus_id);
-	}
 	put_device(dev);
 
 	kfree(new_class_name);
diff --git a/include/linux/device.h b/include/linux/device.h
index de0e73e..8326067 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -199,6 +199,8 @@ struct class {
 
 	int	(*suspend)(struct device *, pm_message_t state);
 	int	(*resume)(struct device *);
+
+	const struct shadow_dir_operations *shadow_ops;
 };
 
 extern int __must_check class_register(struct class *);
-- 
1.5.0.g53756

_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
Re: [PATCH 2/5] sysfs: Remove first pass at shadow directory support [message #18187 is a reply to message #18082] Thu, 12 April 2007 22:58 Go to previous messageGo to next message
Greg KH is currently offline  Greg KH
Messages: 27
Registered: February 2006
Junior Member
On Fri, Apr 06, 2007 at 10:48:42AM -0600, Eric W. Biederman wrote:
> 
> While shadow directories appear to be a good idea, the current scheme
> of controlling their creation and destruction outside of sysfs appears
> to be a locking and maintenance nightmare in the face of sysfs directories
> dynamically coming and going.  Which can now occur for directories containing
> network devices when CONFIG_SYSFS_DEPRECATED is not set.
> 
> This patch removes everything from the initial shadow directory support
> that allowed the shadow directory creation to be controlled at a higher
> level.  So except for a few bits of sysfs_rename_dir everything from
> commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 is now gone.

Can you rebase patches 2-5 on the latest -mm?  Tejun redid the whole
sysfs internals which pretty much means that this patch series doesn't
apply anymore :(

thanks,

greg k-h
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
patch kobject-comment-and-warning-fixes-to-kobject.c.patch added to gregkh-2.6 tree [message #18188 is a reply to message #18081] Thu, 12 April 2007 23:00 Go to previous messageGo to next message
gregkh is currently offline  gregkh
Messages: 14
Registered: April 2007
Junior Member
This is a note to let you know that I've just added the patch titled

     Subject: kobject: Comment and warning fixes to kobject.c

to my gregkh-2.6 tree.  Its filename is

     kobject-comment-and-warning-fixes-to-kobject.c.patch

This tree can be found at 
    http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/


>From ebiederm@xmission.com Fri Apr  6 09:47:44 2007
From: ebiederm@xmission.com (Eric W. Biederman)
Date: Fri, 06 Apr 2007 10:47:11 -0600
Subject: kobject: Comment and warning fixes to kobject.c
To: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Kay Sievers <kay.sievers@vrfy.org>, Linux Containers <containers@lists.osdl.org>
Message-ID: <m11wix8n74.fsf@ebiederm.dsl.xmission.com>


This dots some i's and crosses some t's after left over from when
kobject_kset_add_dir was built from kobject_add_dir. 

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Cc: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 lib/kobject.c |   13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -569,7 +569,7 @@ static struct kobj_type dir_ktype = {
 };
 
 /**
- *	kobject__kset_add_dir - add sub directory of object.
+ *	kobject_kset_add_dir - add sub directory of object.
  *	@kset:		kset the directory is belongs to.
  *	@parent:	object in which a directory is created.
  *	@name:	directory name.
@@ -595,8 +595,8 @@ struct kobject *kobject_kset_add_dir(str
 	kobject_set_name(k, name);
 	ret = kobject_register(k);
 	if (ret < 0) {
-		printk(KERN_WARNING "kobject_add_dir: "
-			"kobject_register error: %d\n", ret);
+		printk(KERN_WARNING "%s: kobject_register error: %d\n",
+			__func__, ret);
 		kobject_del(k);
 		return NULL;
 	}
@@ -604,6 +604,13 @@ struct kobject *kobject_kset_add_dir(str
 	return k;
 }
 
+/**
+ *	kobject_add_dir - add sub directory of object.
+ *	@parent:	object in which a directory is created.
+ *	@name:	directory name.
+ *
+ *	Add a plain directory object as child of given object.
+ */
 struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
 {
 	return kobject_kset_add_dir(NULL, parent, name);


Patches currently in gregkh-2.6 which might be from gregkh@suse.de are

_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
Re: [PATCH 2/5] sysfs: Remove first pass at shadow directory support [message #18222 is a reply to message #18187] Fri, 13 April 2007 17:23 Go to previous message
ebiederm is currently offline  ebiederm
Messages: 1354
Registered: February 2006
Senior Member
Greg KH <greg@kroah.com> writes:

> On Fri, Apr 06, 2007 at 10:48:42AM -0600, Eric W. Biederman wrote:
>> 
>> While shadow directories appear to be a good idea, the current scheme
>> of controlling their creation and destruction outside of sysfs appears
>> to be a locking and maintenance nightmare in the face of sysfs directories
>> dynamically coming and going.  Which can now occur for directories containing
>> network devices when CONFIG_SYSFS_DEPRECATED is not set.
>> 
>> This patch removes everything from the initial shadow directory support
>> that allowed the shadow directory creation to be controlled at a higher
>> level.  So except for a few bits of sysfs_rename_dir everything from
>> commit b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 is now gone.
>
> Can you rebase patches 2-5 on the latest -mm?  Tejun redid the whole
> sysfs internals which pretty much means that this patch series doesn't
> apply anymore :(

Groan...

I expect so.  I'm in the middle of figuring out how to make kthread_stop
successfully terminate interruptible sleeps, so I can convert the
last hold outs using kernel_thread to kthread.

Which means it will be a day or two before I can look at this, unless
I get lucky and it happens to be a trivial rebase.

Eric
_______________________________________________
Containers mailing list
Containers@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
Previous Topic: Licensing Userland utils
Next Topic: Re: [patch 0/8] unprivileged mount syscall
Goto Forum:
  


Current Time: Thu Sep 26 23:22:08 GMT 2024

Total time taken to generate the page: 0.04192 seconds