diff options
| author | Patrick Mochel <mochel@osdl.org> | 2002-10-29 09:26:38 -0800 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2002-10-29 09:26:38 -0800 |
| commit | 0862416ecefa629a52f3ee0907206e9633ca45c3 (patch) | |
| tree | 7d5c779987a53212a7d5ce1354b208779d412487 | |
| parent | d2f8eca7b0d7ef4503e40f809fb8d12e9d1d5389 (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.c | 90 | ||||
| -rw-r--r-- | include/linux/sysfs.h | 2 |
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); |
