what should be a simple question about sysfs attributes ...
... but will take a while to set up. i want to write a short tutorial on kobjects, sysfs and attributes so i want to make absolutely sure i understand them (which is something i should understand anyway. :-) from sysfs.h and kobject.h, we have the definition of the generic kernel-wide "attribute" and "kobj_attribute" structures: struct attribute { const char *name; umode_t mode; #ifdef CONFIG_DEBUG_LOCK_ALLOC bool ignore_lockdep:1; struct lock_class_key *key; struct lock_class_key skey; #endif }; and struct kobj_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); }; so what the above shows is that a "kobj_attribute" contains an "attribute" and has, as its internal callback routines, functions that deal only with completely generic kobject and kobj_attribute pointers. so if i'm creating a number of attributes for some kobject i've created, and i'm associating show and store routines with each one, those show and store routines must have that prototype. for example, look at mm/ksm.c and how the attributes and callback routines are defined -- here's one: //////// static ssize_t full_scans_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%lu\n", ksm_scan.seqnr); } KSM_ATTR_RO(full_scans); static struct attribute *ksm_attrs[] = { &sleep_millisecs_attr.attr, &pages_to_scan_attr.attr, &run_attr.attr, &pages_shared_attr.attr, &pages_sharing_attr.attr, &pages_unshared_attr.attr, &pages_volatile_attr.attr, &full_scans_attr.attr, #ifdef CONFIG_NUMA &merge_across_nodes_attr.attr, #endif NULL, }; static struct attribute_group ksm_attr_group = { .attrs = ksm_attrs, .name = "ksm", }; //////// so the way i've always interpreted the above is that, when i finally register the attributes with the kernel, i am registering really just the underlying generic "attribute" structure and, when i try to access that attribute file, it automatically dereferences to the enclosing kobj_attribute structure to pick up the corresponding show() and store() routines associated with that attribute. so the first question is, is my understanding correct? if, in the above case, whenever i try to access one of the ksm attributes in /sys/kernel/mm/ksm, does the kernel take the reference to that *generic* attribute and automatically dereference/container_of() on it to get the enclosing kobj_attribute structure to pick up the corresponding show() and store() routines? asked a shorter way, is it assumed that a kobject attribute is *always* contained inside a kobj_attribute structure? and that the code in mm/ksm.c is an example of how to add individual show() and store() routines to such attributes? now here's part 2, and it's just a followup from the above. the second variation for attributes is what you see in cpufreq.c. rather than each attribute having its own callback routines, that code defines a prototype for cpufreq-*specific* show and store routines and a cpufreq-specific "freq_attr": struct freq_attr { struct attribute attr; ssize_t (*show)(struct cpufreq_policy *, char *); ssize_t (*store)(struct cpufreq_policy *, const char *, size_t count); }; *however* (and here's the thing i want to make sure i understand), when you register all of the cpufreq attribute files, each one still has to be interpreted as if it's part of a generic kobj_attribute structure with generic show() and store() routines, so what cpufreq does is define two generic show() and store() routines, and a couple helper macros that allow those two routines to then dereference to the appropriate cpufreq_policy and freq_attr pointers, then call the attribute-specific show() and store() routines: ////////// #define to_policy(k) container_of(k, struct cpufreq_policy, kobj) #define to_attr(a) container_of(a, struct freq_attr, attr) static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) { struct cpufreq_policy *policy = to_policy(kobj); struct freq_attr *fattr = to_attr(attr); ... snip ... } static ssize_t store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { struct cpufreq_policy *policy = to_policy(kobj); struct freq_attr *fattr = to_attr(attr); ... snip ... } ////////// and at the end of that file, the attributes are all registered with: static const struct sysfs_ops sysfs_ops = { .show = show, .store = store, }; static struct kobj_type ktype_cpufreq = { .sysfs_ops = &sysfs_ops, .default_attrs = default_attrs, .release = cpufreq_sysfs_release, }; which i interpret as saying that all of those attributes should be registered with the same single show() and store() routines (as opposed to ksm, which used different show() and store() routines for each attribute. in closing(?), as i understand it, when i access a kobject attribute file, it is assumed that that attribute is enclosed in a kobj_attribute structure, which contains the generic show() and store() routines, and i've seen two patterns for that: 1) in mm/ksm.c, each attribute is *directly* registered with callback routines with that prototype specific to that attribute, or 2) in cpufreq.c, all attributes are, in one operation, all registered with the *same* pair of generic callback functions, and those functions are then required to dereference the generic pointers to be able to call the appropriate callbacks for the given attribute. do i have this about right? rday -- ======================================================================== Robert P. J. Day Ottawa, Ontario, CANADA http://crashcourse.ca Twitter: http://twitter.com/rpjday LinkedIn: http://ca.linkedin.com/in/rpjday ========================================================================
hmmmmmmm ... i think i made a mess of that last question/explanation so let me think about it more. darn. rday -- ======================================================================== Robert P. J. Day Ottawa, Ontario, CANADA http://crashcourse.ca Twitter: http://twitter.com/rpjday LinkedIn: http://ca.linkedin.com/in/rpjday ========================================================================
i'll try this one more time, but much more concisely. so far, i've seen two different ways to create a kobject's attributes and register callback routines for them: the first general way i've seen is in mm/ksm.c, where each attribute is enclosed in a surrounding kobj_attribute structure, which also contains references to *generic* show() and store() routines: struct kobj_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); }; in mm/ksm.c file, each attribute is associated *directly* with a different show() and store() routine specific to that attribute. so my understanding is, when you try to access a ksm attribute file under /sys, the generic attribute object is *assumed* to be contained inside a kobj_attribute structure, so dereferencing to get to the show() and store() routine for that attribute is easy. is that correct? that is, the way ksm.c creates and registers attributes means that it is assumed "kobj_attribute" structures will be used as containers for generic attributes? the second way is in cpufreq.c, where the difference is that, rather than each attribute file being *directly* associated with its own pair of callback routines, a pair of *generic* show() and store() routines are defined: static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) static ssize_t store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) and the way the attributes are registered in *that* source file: static const struct sysfs_ops sysfs_ops = { .show = show, .store = store, }; static struct kobj_type ktype_cpufreq = { .sysfs_ops = &sysfs_ops, .default_attrs = default_attrs, .release = cpufreq_sysfs_release, }; means that, rather than dereferencing each generic attribute to an enclosing kobj_attribute, each attribute file reference is redirected to the *same* generic show() and store() callback associated with the ktype, at which point those two generic callbacks are responsible for dereferencing a generic attribute pointer to get to (in this case), the enclosing cpufreq-specific freq_attr structure. i *think* i got it right this time. comments? rday -- ======================================================================== Robert P. J. Day Ottawa, Ontario, CANADA http://crashcourse.ca Twitter: http://twitter.com/rpjday LinkedIn: http://ca.linkedin.com/in/rpjday ========================================================================
On Fri, Jan 30, 2015 at 04:30:02AM -0800, Robert P. J. Day wrote:
i'll try this one more time, but much more concisely. so far, i've seen two different ways to create a kobject's attributes and register callback routines for them:
the first general way i've seen is in mm/ksm.c, where each attribute is enclosed in a surrounding kobj_attribute structure, which also contains references to *generic* show() and store() routines:
struct kobj_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); };
in mm/ksm.c file, each attribute is associated *directly* with a different show() and store() routine specific to that attribute. so my understanding is, when you try to access a ksm attribute file under /sys, the generic attribute object is *assumed* to be contained inside a kobj_attribute structure, so dereferencing to get to the show() and store() routine for that attribute is easy.
is that correct? that is, the way ksm.c creates and registers attributes means that it is assumed "kobj_attribute" structures will be used as containers for generic attributes?
the second way is in cpufreq.c, where the difference is that, rather than each attribute file being *directly* associated with its own pair of callback routines, a pair of *generic* show() and store() routines are defined:
static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
static ssize_t store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)
and the way the attributes are registered in *that* source file:
static const struct sysfs_ops sysfs_ops = { .show = show, .store = store, };
static struct kobj_type ktype_cpufreq = { .sysfs_ops = &sysfs_ops, .default_attrs = default_attrs, .release = cpufreq_sysfs_release, };
means that, rather than dereferencing each generic attribute to an enclosing kobj_attribute, each attribute file reference is redirected to the *same* generic show() and store() callback associated with the ktype, at which point those two generic callbacks are responsible for dereferencing a generic attribute pointer to get to (in this case), the enclosing cpufreq-specific freq_attr structure.
i *think* i got it right this time. comments?
If I'm understanding correctly, this is describing the same thing. "Sometimes all that a developer wants is a way to create a simple directory in the sysfs hierarchy, and not have to mess with the whole complication of ksets, show and store functions, and other details. This is the one exception where a single kobject should be created." from: Documentation/kobject.txt
participants (2)
-
John de la Garza -
Robert P. J. Day