What is the intended usage of DEVICE_INT_ATTR? - c

I would like to expose some settings of my device via sysfs. If I understand it right, a driver can have multiple devices, so there should be one instance of the settings variable per device. This should be easy enough using DEVICE_ATTR macro.
Checking the sources I noticed there is also DEVICE_INT_ATTR and other with different type. I wonder what is the intended usage, as they use device_show_int functions that get pointer to device, but don't actually use it:
ssize_t device_store_int(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct dev_ext_attribute *ea = to_ext_attr(attr);
int ret;
long new;
ret = kstrtol(buf, 0, &new);
if (ret)
return ret;
if (new > INT_MAX || new < INT_MIN)
return -EINVAL;
*(int *)(ea->var) = new;
/* Always return full write size even if we didn't consume all */
return size;
}
EXPORT_SYMBOL_GPL(device_store_int);
I searched kernel sources for those macros, and it seems that they work with a global variable. For example DEVICE_INT_ATTR is used in drivers/base/core.c for mca_cfg.tolerant:
static DEVICE_INT_ATTR(tolerant, 0644, mca_cfg.tolerant);
but the mca_cfg varaible is actually global, not tied to a device:
struct mca_config mca_cfg __read_mostly = {
.bootlog = -1,
/* ... */
.tolerant = 1,
.monarch_timeout = -1
};
which makes it look like a driver (not device) attribute.
I also checked commit that adds these macros but it did not help me much.

You correctly take that DEVICE_INT_ATTR and other macros from that family are for "global" attributes, which store and show methods doesn't use dev parameter.
If you want to define attribute, which can be bound to several devices, then you could write your own store and show methods which gets information about the value from dev.
E.g. by having device
struct my_device
{
struct device base;
int repetition;
};
you could expose its repetition field in the attribute using following show method:
// Shows value of 'repetition' field of my_device.
static ssize_t repetition_show(struct device *dev, struct device_attribute *attr, char *buf)
{
// Obtain pointer to the real device structure.
struct my_device* my_dev = container_of(dev, struct my_device, base);
return sprintf(buf, "%d\n", my_dev->repetition);
}
Structure of such attribute could be initialized using __ATTR macro:
static struct device_attribute repetition_attr =
__ATTR(repetition, S_IRUGO, repetition_show, NULL);
Making "generic" attributes
Assume your device struct contains many int fields, which you want to expose via attributes:
struct my_device
{
struct device base;
int repetition;
int counter;
int value;
};
In that case you could generalize attribute definition, so you don't need to create many show (and store) functions.
E.g. you could store offset of the exposed field in your attribute structure:
struct device_bounded_attr
{
struct device_attribute base_attr;
size_t field_offset;
};
// Initializer for struct device_bounded_attr
//
// - real_device_type - type of the actual device structure
// - device_member - member of type 'struct device' in the actual device structure
// - field_member - member in actual device structure which you want to expose as attribute.
#define BOUNDED_ATTR(name, mode, show, store, real_device_type, device_member, field_member) { \
.base_attr = __ATTR(name, mode, show, store), \
.field_offset = offsetof(real_device_type, field_member) - offsetof(real_device_type, device_member)
}
Using this field, you could rewrite show method as follows:
// Shows value of integer field, stored in device.
static ssize_t bounded_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
{
// Obtain pointer to the real attribute structure.
struct device_bounded_attr* bounded_attr = container_of(attr, struct device_bounded_attr, base_attr);
// Having offset of the field, calculate pointer to it
int field_ptr* = (int*)(((char*)dev) + bounded_attr->field_offset);
return sprintf(buf, "%d\n", *field_ptr);
}
So attributes can be declared as follows:
static struct device_bounded_attr repetition_attr =
BOUNDED_ATTR(repetition, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, repetition);
static struct device_bounded_attr counter_attr =
BOUNDED_ATTR(counter, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, counter);
static struct device_bounded_attr value_attr =
BOUNDED_ATTR(counter, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, value);

Related

Confused on creation of binary sysfs entry

On kernel 4.0, when stepping through the kernel source for sysfs_create_bin_file, I notice it passes to sysfs_add_file(kobj->sd, &attr->attr, true); The &attr->attr being the struct attribute struct within the bin_attribute struct.
This makes sense until I visit sysfs_add_file_mode_ns, which is directly called from sysfs_add_file, and on line #277 sets temp variable stuct bin_attribute *battr = (void*)attr;
Isn't this pointing to a struct attribute at this point, how is it resolving this to the proper struct (due to the call to sysfs_add_file using &attr->attr on line #483)?
Code
int sysfs_create_bin_file(struct kobject *kobj,
const struct bin_attribute *attr)
{
BUG_ON(!kobj || !kobj->sd || !attr);
return sysfs_add_file(kobj->sd, &attr->attr, true);
}
int sysfs_add_file(struct kernfs_node *parent, const struct attribute *attr,
bool is_bin)
{
return sysfs_add_file_mode_ns(parent, attr, is_bin, attr->mode, NULL);
}
int sysfs_add_file_mode_ns(struct kernfs_node *parent,
const struct attribute *attr, bool is_bin,
umode_t mode, const void *ns)
{
struct lock_class_key *key = NULL;
const struct kernfs_ops *ops;
struct kernfs_node *kn;
loff_t size;
if (!is_bin) {
...
} else {
struct bin_attribute *battr = (void *)attr;
...
}
Line
stuct bin_attribute *battr = (void*)attr;
correctly obtains pointer to the bin_attribute structure from the pointer to its first field attr of type struct attribute.
Normally, Linux kernel developers tend to use container_of macro for obtaining pointer to the structure type knowing pointer to its field. More "canonical" way for the transformation above would be:
stuct bin_attribute *battr = container_of(attr, struct bin_attribute, attr);
(In this call the first attr argument refers to the pointer, and the third attr argument refers to the field's name).

Modern C++ pattern for ugly C struct allocation

I'm making an ioctl call from C++ into a driver I don't own/maintain, and I'm trying to sort out if there's a clean, "safe-ish" mechanism to deal with some of the ugly struct allocation required.
Slimmed down version of some structures involved
// IOCTL expects an instance of this structure "first"
typedef struct {
int param1;
int param2;
} s_ioctl_request;
//... followed by an instance of this. If attr_length
// is > sizeof(s_attr_header), more data is allowed to follow.
typedef struct {
uint32_t attr_length;
uint32_t attr_type;
} s_attr_header;
// Example that uses more data than just the header.
typedef struct {
s_attr_header hdr;
uint32_t attr_param;
} s_attr_type1;
// Another example.
typedef struct {
s_attr_header hdr;
uint32_t attr_param1;
uint32_t attr_param2;
} s_attr_type2;
The ioctl requires that s_ioctl_request be immediately followed by an s_attr_header, or other struct containing it, where attr_length is set to the size of the outer struct in bytes.
In C, to write a wrapper for the ioctl it would be done via something along these lines:
int do_ugly_ioctl(int fd, int p1, int p2, s_attr_header * attr)
{
int res;
// Allocate enough memory for both structures.
s_ioctl_request *req = malloc( sizeof(*req) + attr->hdr.attr_length );
// Copy the 2nd, (variable length) structure after the first.
memcpy( ((char*)req) + sizeof(*req), attr, attr->hdr.attr_length);
// Modify params as necessary
req->param1 = p1;
req->param2 = p2;
// Make the driver call, free mem, and return result.
res = ioctl(fd, SOME_IOCTL_ID, req);
free(req);
return res;
}
// Example invocation.
s_attr_type1 a1;
a1.hdr.attr_length = sizeof(a1);
a1.hdr.attr_type = 1;
do_ugly_ioctl(fd, 10, 20, &a1);
A couple options I'm thinking of, are:
Throw modern C++-isms out the window, and do exactly what I've shown above.
Allocate the storage with a std::vector, then do ugly casts with the resulting std::vector::data() pointer so at least I'm not doing new[] / delete[] or malloc / free.
Create a unique wrapper method for each s_attr_type* that uses its own "special" struct. This seems "safest", i.e. least likely for the user of the wrapper method to screw it up. And bonus points, allows pass-by-ref.
Method #3 example:
int do_ugly_ioctl(fd, int param1, int param2, s_attr_type2& attr){
struct RequestData {
s_ioctl_request ioreq;
s_attr_type2 attr;
};
RequestData r;
r.ioreq.param1 = param1;
r.ioreq.param2 = param2;
r.attr = attr;
r.attr.hdr.attr_length = sizeof(attr); // Might as well enforce this here.
ioctl(fd, SOME_IOCTL_ID, (void*) &r);
}
So I guess some questions here are:
Is it "worth it" to C++-ize a solution to this problem? (as opposed to relying on the more error-prone C impl).
If I go with method #3 or similar, is there anything that I can do with <type_traits> to make a template of this function and only accept structs with an s_attr_header as the first member?
Any other brilliant ideas?
Totally worth it, and your solution is quite nice.
You might want to declare your structures as packed (there are compiler extensions to achieve this) to avoid having extra padding when combining multiple structures.
You can also set the size of the structure within the constructor.
struct RequestData
{
RequestData() : ioreq{}, attr{}
{
attr.hdr.attr_length = sizeof(attr);
}
s_ioctl_request ioreq;
s_attr_type2 attr;
};
concerning your second question, you could split the assignment in two, it's not too nice but it's easy and if you pass something without a correct header, it will lead to a compiler error:
template<typename Attr>
int do_ugly_ioctl(fd, int param1, int param2, Attr& attr){
struct RequestData {
s_ioctl_request ioreq;
Attr attr;
};
RequestData r;
r.ioreq.param1 = param1;
r.ioreq.param2 = param2;
s_attr_header hdr = Attr.hdr; //this will lead to compilation error if the type is not what we expect
(void) hdr;
r.attr = attr;
r.attr.hdr.attr_length = sizeof(attr); // Might as well enforce this here.
ioctl(fd, SOME_IOCTL_ID, (void*) &r);
}

Linux driver with multiple device attributes linking to same function

I am writing a simple Linux driver with multiple device attributes. Now independently to which attribute you read or write, in the end you will read or write somewhere on the device's memory. Only the offset defining the exact position changes from one attribute to another. This is easier explained with a few lines of code:
/* General read function evoked by attributes */
static const ssize_t foo_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u32 offset;
if (attr->attr.name == "control")
offset = OFFSET_CTRL;
else if (attr->attr.name == "status")
offset = OFFSET_STATUS;
u32 data = ioread32(dev_mem + offset);
...
}
...
/* declaring attributes, all linking to the same function */
static DEVICE_ATTR(control, S_IWUGO | S_IRUGO, foo_show, foo_set);
static DEVICE_ATTR(status, S_IRUGO, foo_show, NULL);
Now as you may guess using attr->attr.name == foo is not really a nice way of doing it especially since I get the warning "comparison with string literal results in unspecified behavior" telling me to use strcmp. Do you know any better way to identify which attribute was responsible for the call?
The way this seems to be done in existing drivers is to compare to the global attribute directly.
static DEVICE_ATTR(control, S_IWUGO | S_IRUGO, foo_show, foo_set);
static DEVICE_ATTR(status, S_IRUGO, foo_show, NULL);
static const ssize_t foo_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
u32 offset;
if (attr == &dev_attr_control)
offset = OFFSET_CTRL;
else if (attr == &dev_attr_status)
offset = OFFSET_STATUS;
Attributes can identified only based on name. Since only two fields available in attribute by default. http://lxr.free-electrons.com/source/include/linux/sysfs.h#L29
kernel space implementation of strcmp() is available. So using it will works.
http://lxr.free-electrons.com/source/lib/string.c#L245

Debugging of a simple char driver failing on container_of when reading from device attribute

I am writing a simple char driver which accesses a PCI card. It is registered to sysfs with the help of a new class. Now I would like to access multiple parameters (i.e. version, status, control...) of the device in a convenient way. I thought of registering multiple attributes to the device (via device_create_file()).
To do so I create my own device structure foo_dev for which I allocate memory and store all device informations in it (i.e. struct device). Once the attribute gets called I wanted to recover my structure by using container_of() as shown in my code (stripped of return verification for readability):
static const ssize_t foo_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct foo_dev *foo_dev = container_of(dev, struct foo_dev,
dev);
mutex_lock(&mutex);
u32 data = ioread32(foo_dev->bar + 0x2020);
mutex_unlock(&mutex);
return sprintf(buf, "%d\n", data);
}
The problem: As soon as I write to the device, the kernel aborts with a Bad IO access at port 0x2020 (return inl(port)) coming from the ioread32() call. Having investigated further and printed other informations stored in foo_dev I see that the structure is completely empty - container_of() apparently does not reconstruct my original structure. For completeness here the device initialization in the probe() function:
...
foo_dev->dev = device_create(fooClass, NULL, foo_dev->devNbr,
foo_dev, DEVICE_NAME);
cdev_init(&foo_dev->cdev, &foo_fops);
rv = cdev_add(&foo_dev->cdev, foo_dev->devNbr, 1);
rv = pci_enable_device(dev);
...
device_create_file(foo_dev->dev, &dev_attr_bar);
...
What do I probably wrong? How can I investigate further on what I actually receive as struct dev in foo_show()?
container_of() does not work with an embedded pointer.
It works only for a structure that is directly embedded in another structure:
struct foo_dev {
...
struct device dev;
...
};
(You then have to use device_initialize().)
Having a closer look at device_create() one can see that the initialized device actually gets a pointer on its parent structure via dev_set_drvdata(). Instead of using container_of() in the attribute routine one can then recover the foodev structure with dev_get_drvdata(). The routine becomes:
static const ssize_t foo_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct foo_dev *foo_dev = dev_get_drvdata(dev);
mutex_lock(&mutex);
u32 data = ioread32(foo_dev->bar + 0x2020);
mutex_unlock(&mutex);
return sprintf(buf, "%d\n", data);
}

1 struct with 2 different definitions (or dynamic structs)

I'm implementing a little program in C which uses a shared library called "libhelper.so".
The "libhelper.so" defines a struct in it's h-file, but sadly depending on the target-system those definitions are different (libhelper.so is always provided by the system and not by myself):
System A:
struct theStruct {
int fd;
unsigned int flags;
struct config config; // only in System A
int foo; // in both systems
int bar; // only in System A
};
System B:
struct theStruct {
int fd;
unsigned int flags;
int foo; // in both systems
int foobar; // only in system B
};
In my program, I thought I just define that struct by myself like this:
struct theStruct {
int fd;
unsigned int flags;
struct config config; // only in System A
int foo; // in both systems
int foobar; // only in system B
int bar; // only in System A
};
As the result of a call to a function in "libhelper.so" I got an instance of "theStruct" and now I though I can just check if "theStructInstance->bar" or "theStructInstance->foobar" is filled with a valid value to detect which implementation has been used by the library.
But it seems that I get just values like 1...6 which looks like the position of the field in the struct.
Has anyone an idea how I can do this?
No, this won't work.
First of all, all the definitions of the structure must be the same, otherwise you get the infamous Undefined Behaviour.
Second, look at the memory layout. What should be the offset to bar from the beginning of the structure? The first and the third definitions don't agree on this (the fields are most likely to be located consecutively).
Maybe you can try a union?
struct theStruct {
int fd;
unsigned int flags;
struct config config;
int foo; // in both systems
union {
int bar; // only in System A
int foobar; // only in system B
};
};
If you choose this, you should use only bar on System A and only foobar on System B.
If the two systems are incompatible, and the actual type needed for bar is not available on System B (and vice versa), you can do with the following code:
struct theStruct {
int fd;
unsigned int flags;
struct config config;
int foo; // in both systems
#ifdef SYSTEM_A
int bar; // only in System A
#else
#ifdef SYSTEM_B
int foobar; // only in system B
#else
#pragma error(either SYSTEM_A or SYSTEM_B must be enabled)
#endif
#endif
};
This way you will be always working with either with code compiled for System A or for System B, so you'll need to have different executables (which seems to be unavoidable anyway if you are compiling for the systems so much different).
You'll need to wrap parts of your code accessing the fields into #ifdefs:
#ifdef SYSTEM_A
s.bar = 5;
#endif
-- otherwise you'll get compile errors on System B.
Another possible solution would be to write platform dependent code to handle each of the individual structs, and then load their data into a common struct. This would then allow you to deal with the same members of the struct, no matter the code path, rather than always referencing one of the two union members based on the system:
struct mystruct;
mystruct.member1 = theStruct.member1; //the common part of the struct
mystruct.member2 = theStruct.member2;
#ifdef platform1
mystruct.member3 = theStruct.p1member; //specific to platform1
mystruct.member4 = -1;
#else
mystruct.member3 = -1;
mystruct.member4 = theStruct.p2member; //specific to platform2
#endif
Here is an approach to think about.
A bit of background about the assumptions I am making first.
It sounds like you have some function libraryFunction () that returns a pointer to a struct theStruct. However the actual layout of the struct theStruct depends on the particular system on which your application is running. In this struct is some information that you need to access. You do not specify the calling arguments or signature of the library function and if the pointer to the struct theStruct is returned as a function value or a pointer to a pointer is part of the argument list. I will assume it is a function return value.
Create a struct you define for the information that you want. Create two files each of which has a function that takes a void pointer and a pointer to your new struct and then fills in your struct with the data you want from the library supplied struct. Each of these two files will be compiled with a particular system target specified (SystemA or SystemB) so that your conversion function will interpret the struct provided by the library function depending on the target system and fill in your struct with the data you want.
file 1 for System A
// copy of the struct used in System A which is in the library header file
// put here for reference only as should be in the header file
struct theStruct {
int fd;
unsigned int flags;
struct config config; // only in System A
int foo; // in both systems
int bar; // only in System A
};
// my struct that contains the data from struct theStruct that I want
// would be in a header file included into each of these files but here for reference
struct myConvertStruct {
int foo;
};
void convert2SystemA (void *structPtr, struct *myStruct)
{
myStruct->foo = ((struct theStruct *)structPtr)->foo;
}
file 2 for System B
// copy of the struct used in System B which is in the library header file
// put here for reference only as should be in the header file
struct theStruct {
int fd;
unsigned int flags;
int foo; // in both systems
int foobar; // only in system B
};
// my struct that contains the data from struct theStruct that I want
// would be in a header file included into each of these files but here for reference
struct myConvertStruct {
int foo;
};
void convert2SystemB (void *structPtr, struct *myStruct)
{
myStruct->foo = ((struct theStruct *)structPtr)->foo;
}
file 3 using the conversion functions
// my struct that contains the data from struct theStruct that I want
// would be in a header file included into each of these files but here for reference
struct myConvertStruct {
int foo;
};
{
struct myConvertStruct myStruct;
// some function body and now we come to the library call
if (mySystem == SystemA) {
void *pStruct = libraryFunction (......);
convert2SystemA (pStruct, &myStruct);
} else if (mySystem == SystemB) {
void *pStruct = libraryFunction (......);
convert2SystemB (pStruct, &myStruct);
} else {
// some error conditions
}
// now use the data that you have pulled as you want to use it
}
The reason why your proposal won't work is that the offset to the foo member is different for System A and System B. You say that you can only figure out what System you are using at runtime. So, when System B sets foo, it will likely end up setting something inside of config instead.
enum system { SystemUnknown, SystemA, SystemB };
struct theStructSystemA {
int fd;
unsigned int flags;
struct config config; // only in System A
int foo; // in both systems
int bar; // only in System A
};
struct theStructSystemB {
int fd;
unsigned int flags;
int foo;
int foobar;
};
struct myStruct {
union {
struct theStructSystemA a;
struct theStructSystemB b;
} u;
enum system sys;
};
struct myStruct s = { 0 };
Now, you can set bar to some invalid value: s.u.a.bar = -1, for example. Now, when you call into your library, you can check:
s.u.a.bar = -1;
some_libhelper_call((void *)&s);
if (s.u.a.bar != -1) s.sys = SystemA;
else s.sys = SystemB;
So now, after s.sys is known, you can switch to a different code path that deals entirely with a known system version.

Resources