summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@osdl.org>2002-10-29 09:26:38 -0800
committerPatrick Mochel <mochel@osdl.org>2002-10-29 09:26:38 -0800
commit0862416ecefa629a52f3ee0907206e9633ca45c3 (patch)
tree7d5c779987a53212a7d5ce1354b208779d412487
parentd2f8eca7b0d7ef4503e40f809fb8d12e9d1d5389 (diff)
sysfs: make symlinks easier.
It's now int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name) So, the caller doesn't have to determine the path of the target nor the depth of the object we're creating the symlink for; it's all taken care of.
-rw-r--r--fs/sysfs/inode.c90
-rw-r--r--include/linux/sysfs.h2
2 files changed, 71 insertions, 21 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 804f3655dc73..a82726460fca 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -457,34 +457,84 @@ int sysfs_create_file(struct kobject * kobj, struct attribute * attr)
}
+static int object_depth(struct kobject * kobj)
+{
+ struct kobject * p = kobj;
+ int depth = 0;
+ do { depth++; } while ((p = p->parent));
+ return depth;
+}
+
+static int object_path_length(struct kobject * kobj)
+{
+ struct kobject * p = kobj;
+ int length = 1;
+ do {
+ length += strlen(p->name) + 1;
+ p = p->parent;
+ } while (p);
+ return length;
+}
+
+static void fill_object_path(struct kobject * kobj, char * buffer, int length)
+{
+ struct kobject * p;
+
+ --length;
+ for (p = kobj; p; p = p->parent) {
+ int cur = strlen(p->name);
+
+ /* back up enough to print this bus id with '/' */
+ length -= cur;
+ strncpy(buffer + length,p->name,cur);
+ *(buffer + --length) = '/';
+ }
+}
+
/**
- * sysfs_create_symlink - make a symlink
- * @kobj: object who's directory we're creating in.
- * @name: name of the symlink.
- * @target: path we're pointing to.
+ * sysfs_create_link - create symlink between two objects.
+ * @kobj: object whose directory we're creating the link in.
+ * @target: object we're pointing to.
+ * @name: name of the symlink.
*/
-
-int sysfs_create_link(struct kobject * kobj, char * name, char * target)
+int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name)
{
- struct dentry * dentry;
- int error;
+ struct dentry * dentry = kobj->dir.dentry;
+ struct dentry * d;
+ int error = 0;
+ int size;
+ int depth;
+ char * path;
+ char * s;
+
+ depth = object_depth(kobj);
+ size = object_path_length(target) + depth * 3 - 1;
+ if (size > PATH_MAX)
+ return -ENAMETOOLONG;
+ pr_debug("%s: depth = %d, size = %d\n",__FUNCTION__,depth,size);
+
+ path = kmalloc(size,GFP_KERNEL);
+ if (!path)
+ return -ENOMEM;
+ memset(path,0,size);
- if (kobj) {
- struct dentry * parent = kobj->dir.dentry;
+ for (s = path; depth--; s += 3)
+ strcpy(s,"../");
- down(&parent->d_inode->i_sem);
- dentry = get_dentry(parent,name);
- if (!IS_ERR(dentry))
- error = sysfs_symlink(parent->d_inode,dentry,target);
- else
- error = PTR_ERR(dentry);
- up(&parent->d_inode->i_sem);
- } else
- error = -EINVAL;
+ fill_object_path(target,path,size);
+ pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
+
+ down(&dentry->d_inode->i_sem);
+ d = get_dentry(dentry,name);
+ if (!IS_ERR(d))
+ error = sysfs_symlink(dentry->d_inode,d,path);
+ else
+ error = PTR_ERR(d);
+ up(&dentry->d_inode->i_sem);
+ kfree(path);
return error;
}
-
static void hash_and_remove(struct dentry * dir, const char * name)
{
struct dentry * victim;
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index fe82dff179ce..066a9ccc0fb4 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -41,7 +41,7 @@ extern void
sysfs_remove_file(struct kobject *, struct attribute *);
extern int
-sysfs_create_link(struct kobject * kobj, char * name, char * target);
+sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name);
extern void
sysfs_remove_link(struct kobject *, char * name);