Messages in this thread Patch in this message | | | From | Dmitry Torokhov <> | Subject | Re: [PATCH 0/5] I8K driver facelift | Date | Thu, 17 Mar 2005 01:40:48 -0500 |
| |
On Wednesday 16 March 2005 16:38, Frank Sorenson wrote: > Okay, I replaced the sysfs_ops with ops of my own, and now all the show > and store functions also accept the name of the attribute as a parameter. > This lets the functions know what attribute is being accessed, and allows > us to create attributes that share show and store functions, so things > don't need to be defined at compile time (I feel slightly evil!).
Hrm, can we be a little more explicit and not poke in the sysfs guts right in the driver? What do you think about the patch below athat implements "attribute arrays"? And I am attaching cumulative i8k patch using these arrays so they can be tested.
I am CC-ing Greg to see what he thinks about it.
-- Dmitry
===================================================================
sysfs: add support for attribure arrays so it is possible to create a (variable) number of similar attributes all sharing the same show and store handlers:
../<attr_name>/0 ../<attr_name>/1 ... ../<attr_name>/<n>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
fs/sysfs/Makefile | 2 fs/sysfs/array.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/sysfs.h | 20 +++++ 3 files changed, 187 insertions(+), 2 deletions(-)
Index: dtor/fs/sysfs/array.c =================================================================== --- /dev/null +++ dtor/fs/sysfs/array.c @@ -0,0 +1,167 @@ +/* + * fs/sysfs/array.c - Operations for adding/removing arrays of attributes. + * + * Copyright (c) 2005 Dmitry Torokhov <dtor@mail.ru> + * + * This file is released under the GPL v2. + * + */ + +#include <linux/kobject.h> +#include <linux/module.h> +#include <linux/dcache.h> +#include <linux/err.h> +#include "sysfs.h" + +struct attr_element { + struct attribute attr; + unsigned int idx; + char name[4]; +}; +#define to_attr_element(e) container_of(e, struct attr_element, attr) + +struct array_object { + const struct attribute_array *array; + unsigned int n_elements; + struct kobject kobj; + struct attr_element elements[0]; +}; +#define to_array_object(obj) container_of(obj, struct array_object, kobj) + +static ssize_t +attr_array_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct attr_element *element = to_attr_element(attr); + struct array_object *obj = to_array_object(kobj); + ssize_t ret = 0; + + if (obj->array->show) { + struct kobject *parent = kobject_get(kobj->parent); + ret = obj->array->show(parent, element->idx, buf); + kobject_put(parent); + } + + return ret; +} + +static ssize_t +attr_array_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct attr_element *element = to_attr_element(attr); + struct array_object *obj = to_array_object(kobj); + ssize_t ret = 0; + + if (obj->array->store) { + struct kobject *parent = kobject_get(kobj->parent); + ret = obj->array->store(parent, element->idx, buf, count); + kobject_put(parent); + } + + return ret; +} + +static struct sysfs_ops attr_array_sysfs_ops = { + .show = attr_array_show, + .store = attr_array_store, +}; + + +static void attr_array_release(struct kobject *kobj) +{ + kfree(to_array_object(kobj)); +} + +static struct kobj_type ktype_attr_array = { + .release = attr_array_release, + .sysfs_ops = &attr_array_sysfs_ops, +}; + + +static int create_array_element(struct array_object *obj, + unsigned int idx) +{ + struct attr_element *element = &obj->elements[idx]; + + snprintf(element->name, sizeof(element->name), "%d", idx); + element->idx = idx; + element->attr = obj->array->attr; + element->attr.name = element->name; + + return sysfs_create_file(&obj->kobj, &element->attr); +} + +static inline void remove_array_element(struct array_object *obj, + unsigned int idx) +{ + sysfs_remove_file(&obj->kobj, &obj->elements[idx].attr); +} + +int sysfs_create_array(struct kobject *kobj, + const struct attribute_array *array, + unsigned int n_elements) +{ + struct array_object *obj; + size_t size; + unsigned int i; + int error; + + BUG_ON(!kobj || !kobj->dentry); + BUG_ON(!array->attr.name); + + size = sizeof(struct array_object) + + sizeof(struct attr_element) * n_elements; + + obj = kmalloc(size, GFP_KERNEL); + if (!obj) + return -ENOMEM; + + memset(obj, 0, size); + obj->array = array; + obj->n_elements = n_elements; + + obj->kobj.ktype = &ktype_attr_array; + obj->kobj.parent = kobj; + kobject_set_name(&obj->kobj, array->attr.name); + + error = kobject_register(&obj->kobj); + if (error) + goto fail; + + for (i = 0; i < n_elements; i++) { + error = create_array_element(obj, i); + if (error) { + while (--i) + remove_array_element(obj, i); + goto fail; + } + } + + return 0; + + fail: + kfree(obj); + return error; +} + +void sysfs_remove_array(struct kobject *kobj, + const struct attribute_array *array) +{ + struct array_object *obj; + struct dentry *dir; + unsigned int i; + + dir = sysfs_get_dentry(kobj->dentry, array->attr.name); + + if (dir) { + obj = to_array_object(to_kobj(dir)); + for (i = 0; i < obj->n_elements; i++) + remove_array_element(obj, i); + kobject_unregister(&obj->kobj); + } + + dput(dir); +} + +EXPORT_SYMBOL_GPL(sysfs_create_array); +EXPORT_SYMBOL_GPL(sysfs_remove_array); Index: dtor/include/linux/sysfs.h =================================================================== --- dtor.orig/include/linux/sysfs.h +++ dtor/include/linux/sysfs.h @@ -26,7 +26,12 @@ struct attribute_group { struct attribute ** attrs; }; +struct attribute_array { + struct attribute attr; + ssize_t (*show)(struct kobject *, unsigned int index, char *); + ssize_t (*store)(struct kobject *, unsigned int index, const char *, size_t); +}; /** * Use these macros to make defining attributes easier. See include/linux/device.h @@ -102,7 +107,7 @@ sysfs_update_file(struct kobject *, cons extern void sysfs_remove_file(struct kobject *, const struct attribute *); -extern int +extern int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name); extern void @@ -114,6 +119,9 @@ int sysfs_remove_bin_file(struct kobject int sysfs_create_group(struct kobject *, const struct attribute_group *); void sysfs_remove_group(struct kobject *, const struct attribute_group *); +int sysfs_create_array(struct kobject *, const struct attribute_array *, unsigned int); +void sysfs_remove_array(struct kobject *, const struct attribute_array *); + #else /* CONFIG_SYSFS */ static inline int sysfs_create_dir(struct kobject * k) @@ -177,6 +185,16 @@ static inline void sysfs_remove_group(st ; } +static inline int sysfs_create_array(struct kobject * k, const struct attribute_array *a, unsigned int n) +{ + return 0; +} + +static inline void sysfs_remove_array(struct kobject * k, const struct attribute_array * a) +{ + ; +} + #endif /* CONFIG_SYSFS */ #endif /* _SYSFS_H_ */ Index: dtor/fs/sysfs/Makefile =================================================================== --- dtor.orig/fs/sysfs/Makefile +++ dtor/fs/sysfs/Makefile @@ -3,4 +3,4 @@ # obj-y := inode.o file.o dir.o symlink.o mount.o bin.o \ - group.o + group.o array.o | |