diff options
Diffstat (limited to 'fs/sysfs')
-rw-r--r-- | fs/sysfs/dir.c | 10 | ||||
-rw-r--r-- | fs/sysfs/file.c | 78 | ||||
-rw-r--r-- | fs/sysfs/group.c | 26 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 88 |
4 files changed, 85 insertions, 117 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 337162935d2..4948d9bc405 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -440,7 +440,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) /** * sysfs_remove_one - remove sysfs_dirent from parent * @acxt: addrm context to use - * @sd: sysfs_dirent to be added + * @sd: sysfs_dirent to be removed * * Mark @sd removed and drop nlink of parent inode if @sd is a * directory. @sd is unlinked from the children list. @@ -678,8 +678,10 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); /* no such entry */ - if (!sd) + if (!sd) { + ret = ERR_PTR(-ENOENT); goto out_unlock; + } /* attach dentry and inode */ inode = sysfs_get_inode(sd); @@ -781,6 +783,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); + old_dentry = NULL; goto out; } @@ -848,6 +851,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) old_dentry = sysfs_get_dentry(sd); if (IS_ERR(old_dentry)) { error = PTR_ERR(old_dentry); + old_dentry = NULL; goto out; } old_parent = old_dentry->d_parent; @@ -855,6 +859,7 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) new_parent = sysfs_get_dentry(new_parent_sd); if (IS_ERR(new_parent)) { error = PTR_ERR(new_parent); + new_parent = NULL; goto out; } @@ -878,7 +883,6 @@ again: error = 0; d_add(new_dentry, NULL); d_move(old_dentry, new_dentry); - dput(new_dentry); /* Remove from old parent's list and insert into new parent's list. */ sysfs_unlink_sibling(sd); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 4045bdcc4b3..a271c87c447 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -20,43 +20,6 @@ #include "sysfs.h" -#define to_sattr(a) container_of(a,struct subsys_attribute, attr) - -/* - * Subsystem file operations. - * These operations allow subsystems to have files that can be - * read/written. - */ -static ssize_t -subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page) -{ - struct kset *kset = to_kset(kobj); - struct subsys_attribute * sattr = to_sattr(attr); - ssize_t ret = -EIO; - - if (sattr->show) - ret = sattr->show(kset, page); - return ret; -} - -static ssize_t -subsys_attr_store(struct kobject * kobj, struct attribute * attr, - const char * page, size_t count) -{ - struct kset *kset = to_kset(kobj); - struct subsys_attribute * sattr = to_sattr(attr); - ssize_t ret = -EIO; - - if (sattr->store) - ret = sattr->store(kset, page, count); - return ret; -} - -static struct sysfs_ops subsys_sysfs_ops = { - .show = subsys_attr_show, - .store = subsys_attr_store, -}; - /* * There's one sysfs_buffer for each open file and one * sysfs_open_dirent for each sysfs_dirent with one or more open @@ -66,7 +29,7 @@ static struct sysfs_ops subsys_sysfs_ops = { * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open * is protected by sysfs_open_dirent_lock. */ -static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(sysfs_open_dirent_lock); struct sysfs_open_dirent { atomic_t refcnt; @@ -354,31 +317,23 @@ static int sysfs_open_file(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; - struct sysfs_buffer * buffer; - struct sysfs_ops * ops = NULL; - int error; + struct sysfs_buffer *buffer; + struct sysfs_ops *ops; + int error = -EACCES; /* need attr_sd for attr and ops, its parent for kobj */ if (!sysfs_get_active_two(attr_sd)) return -ENODEV; - /* if the kobject has no ktype, then we assume that it is a subsystem - * itself, and use ops for it. - */ - if (kobj->kset && kobj->kset->ktype) - ops = kobj->kset->ktype->sysfs_ops; - else if (kobj->ktype) + /* every kobject with an attribute needs a ktype assigned */ + if (kobj->ktype && kobj->ktype->sysfs_ops) ops = kobj->ktype->sysfs_ops; - else - ops = &subsys_sysfs_ops; - - error = -EACCES; - - /* No sysfs operations, either from having no subsystem, - * or the subsystem have no operations. - */ - if (!ops) + else { + printk(KERN_ERR "missing sysfs attribute operations for " + "kobject: %s\n", kobject_name(kobj)); + WARN_ON(1); goto err_out; + } /* File needs write support. * The inode's perms must say it's ok, @@ -568,7 +523,11 @@ int sysfs_add_file_to_group(struct kobject *kobj, struct sysfs_dirent *dir_sd; int error; - dir_sd = sysfs_get_dirent(kobj->sd, group); + if (group) + dir_sd = sysfs_get_dirent(kobj->sd, group); + else + dir_sd = sysfs_get(kobj->sd); + if (!dir_sd) return -ENOENT; @@ -656,7 +615,10 @@ void sysfs_remove_file_from_group(struct kobject *kobj, { struct sysfs_dirent *dir_sd; - dir_sd = sysfs_get_dirent(kobj->sd, group); + if (group) + dir_sd = sysfs_get_dirent(kobj->sd, group); + else + dir_sd = sysfs_get(kobj->sd); if (dir_sd) { sysfs_hash_and_remove(dir_sd, attr->name); sysfs_put(dir_sd); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index d1972374655..0871c3dadce 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -16,25 +16,31 @@ #include "sysfs.h" -static void remove_files(struct sysfs_dirent *dir_sd, +static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, const struct attribute_group *grp) { struct attribute *const* attr; + int i; - for (attr = grp->attrs; *attr; attr++) - sysfs_hash_and_remove(dir_sd, (*attr)->name); + for (i = 0, attr = grp->attrs; *attr; i++, attr++) + if (!grp->is_visible || + grp->is_visible(kobj, *attr, i)) + sysfs_hash_and_remove(dir_sd, (*attr)->name); } -static int create_files(struct sysfs_dirent *dir_sd, +static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, const struct attribute_group *grp) { struct attribute *const* attr; - int error = 0; + int error = 0, i; - for (attr = grp->attrs; *attr && !error; attr++) - error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR); + for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) + if (!grp->is_visible || + grp->is_visible(kobj, *attr, i)) + error |= + sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR); if (error) - remove_files(dir_sd, grp); + remove_files(dir_sd, kobj, grp); return error; } @@ -54,7 +60,7 @@ int sysfs_create_group(struct kobject * kobj, } else sd = kobj->sd; sysfs_get(sd); - error = create_files(sd, grp); + error = create_files(sd, kobj, grp); if (error) { if (grp->name) sysfs_remove_subdir(sd); @@ -75,7 +81,7 @@ void sysfs_remove_group(struct kobject * kobj, } else sd = sysfs_get(dir_sd); - remove_files(sd, grp); + remove_files(sd, kobj, grp); if (grp->name) sysfs_remove_subdir(sd); diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 3eac20c63c4..5f66c446615 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -19,39 +19,6 @@ #include "sysfs.h" -static int object_depth(struct sysfs_dirent *sd) -{ - int depth = 0; - - for (; sd->s_parent; sd = sd->s_parent) - depth++; - - return depth; -} - -static int object_path_length(struct sysfs_dirent * sd) -{ - int length = 1; - - for (; sd->s_parent; sd = sd->s_parent) - length += strlen(sd->s_name) + 1; - - return length; -} - -static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length) -{ - --length; - for (; sd->s_parent; sd = sd->s_parent) { - int cur = strlen(sd->s_name); - - /* back up enough to print this bus id with '/' */ - length -= cur; - strncpy(buffer + length, sd->s_name, cur); - *(buffer + --length) = '/'; - } -} - /** * sysfs_create_link - create symlink between two objects. * @kobj: object whose directory we're creating the link in. @@ -112,7 +79,6 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char return error; } - /** * sysfs_remove_link - remove symlink in object's directory. * @kobj: object we're acting for. @@ -124,24 +90,54 @@ void sysfs_remove_link(struct kobject * kobj, const char * name) sysfs_hash_and_remove(kobj->sd, name); } -static int sysfs_get_target_path(struct sysfs_dirent * parent_sd, - struct sysfs_dirent * target_sd, char *path) +static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, + struct sysfs_dirent *target_sd, char *path) { - char * s; - int depth, size; + struct sysfs_dirent *base, *sd; + char *s = path; + int len = 0; + + /* go up to the root, stop at the base */ + base = parent_sd; + while (base->s_parent) { + sd = target_sd->s_parent; + while (sd->s_parent && base != sd) + sd = sd->s_parent; + + if (base == sd) + break; + + strcpy(s, "../"); + s += 3; + base = base->s_parent; + } + + /* determine end of target string for reverse fillup */ + sd = target_sd; + while (sd->s_parent && sd != base) { + len += strlen(sd->s_name) + 1; + sd = sd->s_parent; + } - depth = object_depth(parent_sd); - size = object_path_length(target_sd) + depth * 3 - 1; - if (size > PATH_MAX) + /* check limits */ + if (len < 2) + return -EINVAL; + len--; + if ((s - path) + len > PATH_MAX) return -ENAMETOOLONG; - pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size); + /* reverse fillup of target string from target to base */ + sd = target_sd; + while (sd->s_parent && sd != base) { + int slen = strlen(sd->s_name); - for (s = path; depth--; s += 3) - strcpy(s,"../"); + len -= slen; + strncpy(s + len, sd->s_name, slen); + if (len) + s[--len] = '/'; - fill_object_path(target_sd, path, size); - pr_debug("%s: path = '%s'\n", __FUNCTION__, path); + sd = sd->s_parent; + } return 0; } |