what should be a simple question about sysfs attributes ...

Robert P. J. Day rpjday at crashcourse.ca
Fri Jan 30 06:55:45 EST 2015


... 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
========================================================================



More information about the Kernelnewbies mailing list