How do I initialize the attribute group correctly for a platform driver?
The problem arose from assigning the attr_groups
structure here:
static struct platform_driver platform = {
.remove = my_remove,
.probe = my_probe,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.groups = attr_groups, /* WRONGO: should not be assigned here. */
.of_match_table = of_match,
},
};
By doing it in struct class
instead, everything works as expected:
static int __init cz_tdm_init(void)
{
int ret;
pr_info("MODNAME=%s", KBUILD_MODNAME);
/* Dynamically allocate a major number and a
* range of DEV_MINOR_NUMBER_COUNT (1) minor numbers. */
if ((ret = alloc_chrdev_region(&first, 0, DEV_MINOR_NUMBER_COUNT, DRIVER_NAME)) < 0) {
ret = -ENODEV;
goto exit;
}
/* Add the char device to the system. */
cdev_init(&cdev, &fops);
if ((ret = cdev_add(&cdev, first, DEV_MINOR_NUMBER_COUNT)) < 0) {
ret = -ENODEV;
goto exit;
}
resources.cdev = 1;
/* Create a class entry in sysfs */
if ((class = class_create(THIS_MODULE, "coveloz")) == NULL) {
pr_err("Couldn't create 'struct class' structure.");
ret = -ENODEV;
goto exit;
}
class->dev_groups = attr_groups; /* RIGHTO */
/* Create the /dev/ file system entry */
/* return value ignored: there's a 'struct class' to 'struct device' mapping */
if (device_create(class, NULL, first, NULL, DRIVER_NAME) == NULL) {
pr_err("Couldn't create entry in '/dev/' file system.");
ret = -ENODEV;
goto exit;
}
How to attach file operations to sysfs attribute in platform driver?
It boils down to next:
- reuse existing kobject from
struct device
(from yourstruct platform_device
) forsysfs_create_group()
(instead of creating your ownkobject
) - use
DEVICE_ATTR()
to declarestruct device_attribute
instead of regular__ATTR()
, which createsstruct kobj_attribute
.
Here is how I created sysfs attributes for my platform driver.
Create structure you'll be using as private data in
show()
/store()
operations for your sysfs attribute (file). For example:struct mydrv {
struct device *dev;
long myparam;
};Allocate this structure in your driver's
probe()
:static int mydrv_probe(struct platform_device *pdev)
{
struct mydrv *mydrv;
mydrv = devm_kzalloc(&pdev->dev, sizeof(*mydrv), GFP_KERNEL);
mydrv->dev = &pdev->dev;
platform_set_drvdata(pdev, mydrv);
...
}Create
show()
/store()
functions:static ssize_t mydrv_myparam_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mydrv *mydrv = dev_get_drvdata(dev);
int len;
len = sprintf(buf, "%d\n", mydrv->myparam);
if (len <= 0)
dev_err(dev, "mydrv: Invalid sprintf len: %d\n", len);
return len;
}
static ssize_t mydrv_myparam_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mydrv *mydrv = dev_get_drvdata(dev);
kstrtol(buf, 10, &mydrv->myparam);
return count;
}Create device attribute for those functions (right after those functions):
static DEVICE_ATTR(myparam, S_IRUGO | S_IWUSR, mydrv_myparam_show,
mydrv_myparam_store);Declare attributes table (listing in fact sysfs files for you driver):
static struct attribute *mydrv_attrs[] = {
&dev_attr_myparam.attr,
NULL
};Declare attribute group (specifying in fact sysfs directory for your driver):
static struct attribute_group mydrv_group = {
.name = "mydrv",
.attrs = mydrv_attrs,
};
static struct attribute_group *mydrv_groups[] = {
&mydrv_group,
NULL
}which can be actually replaced with one line:
ATTRIBUTE_GROUPS(mydrv);
Create sysfs directory and files in your driver's
probe()
function:static int mydrv_probe(struct platform_device *pdev)
{
int ret;
...
ret = sysfs_create_group(&pdev->dev.kobj, &mydrv_group);
if (ret) {
dev_err(&pdev->dev, "sysfs creation failed\n");
return ret;
}
...
}Remove your sysfs files in your driver's
remove()
function:static int mydrv_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &mydrv_group);
...
}
Race condition note
As @FranzForstmayr correctly pointed out, there may be race condition when adding sysfs files with sysfs_create_group()
in mydrv_probe()
. That's because user-space can be already notified that those files exist before mydrv_probe()
called (where those files are actually being created by sysfs_create_group()
function). This issue covered in details in "How to Create a sysfs File Correctly" article by Greg Kroah-Hartman.
So in our case of platform_device
, instead of calling sysfs_create_group()
(and its counterpart sysfs_remove_group()
), you can use default attribute group. To do so, you need to assign corresponding .groups
field of your struct device
to your attribute groups variable:
static int mydrv_probe(struct platform_device *pdev)
{
...
pdev->dev.groups = mydrv_groups;
...
}
DISCLAIMER: I didn't test this code, though it should work, because of this code.
See [1,2,3] links for more insights on mentioned race condition.
For more examples, run next command in kernel source directory:
$ git grep -l --all-match -e platform_device -e attribute -e '\.groups =' -- drivers/
Also you can search by "default attribute" in commit messages:
$ git log --no-merges --oneline --grep="default attribute" -- drivers/
Some commits I found this way: [4,5,6,7].
References
[1] My attributes are way too racy, what should I do?
[2] PATCH: sysfs: add devm_sysfs_create_group() and friends
[3] [GIT PATCH] Driver core patches for 3.11-rc2
[4] commit 1
[5] commit 2
[6] commit 3
[7] commit 4
How do I properly initialize a late variable
If you got a LateInitializationError
before, it's not that "[result()
] doesn't recognize the value I initialized in calcBMI()
", it's that you called result()
before you called calcBMI()
.
Giving _bmi
an initial value avoids the LateInitializationError
, but you still have the same fundamental problem: you're reading _bmi
before you call calcBMI()
to assign it the value you actually want.
In particular, you have:
return ResultsPage(result: calc.result(), bMI: calc.calcBMI(), interpretation: calc.interpretation());
Dart evaluates function arguments in left-to-right order, so you'll call calc.result()
first, then calc.calcBMI()
, and then calc.interpretation()
. Changing the order should fix your problem:
return ResultsPage(
bMI: calc.calcBMI(),
result: calc.result(),
interpretation: calc.interpretation(),
);
However, relying on argument evaluation order would be poor style. It would not be obvious to readers (including your future self) that argument order matters. It would be much better to explicitly order operations that are order-dependent:
var bmi = calc.calcBMI();
return ResultsPage(
result: calc.result(),
bMI: bmi,
interpretation: calc.interpretation(),
);
Note that this has nothing to do with _bmi
being late
. Declaring _bmi
as late
provides no purpose in your code as currently written, and you could just remove it. But you also should consider rewriting your code to make CalculatorBrain
less dependent on consumers calling its methods in a particular order. Some possibilities:
Compute _bmi
dynamically
You could make _bmi
a getter that computes the correct value for weight
/height
on every access:
class CalculatorBrain {
CalculatorBrain({required this.weight, required this.height});
int weight;
int height;
double get _bmi => weight / pow(height / 100, 2);
String calcBMI() => _bmi.toStringAsFixed(1);
String result() {
final _bmi = this._bmi;
if(_bmi >= 25) {
return 'overweight';
} else if(_bmi > 18.5) {
return 'normal';
} else {
return 'underweight';
}
}
...
Compute _bmi
exactly once
If you make weight
/height
final
, then you can compute _bmi
once and be done:
class CalculatorBrain {
CalculatorBrain({required this.weight, required this.height});
final int weight;
final int height;
// `late` computes `_bmi` lazily, which is necessary because it depends on
// `weight` and `height`.
late final double _bmi = weight / pow(height / 100, 2);
...
Update _bmi
automatically if weight
or height
changes
If you weight
/height
must be mutable, then you could create setters so that _bmi
is always updated automatically:
class CalculatorBrain {
CalculatorBrain({required int weight, required int height})
: _weight = weight,
_height = height {
_updateBmi();
}
late double _bmi;
int _weight;
int get weight => _weight;
set weight(int value) {
_weight = value;
_updateBmi();
}
int _height;
int get height => _height;
set height(int value) {
_height = value;
_updateBmi();
}
void _updateBmi() {
_bmi => weight / pow(height / 100, 2);
}
...
Is this call to `device_show_int()` a Linux kernel bug?
You're confusing device_attribute
and driver_attribute
. The function drv_attr_show()
works on a struct driver_attribute
, which is defined as:
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *driver, char *buf);
ssize_t (*store)(struct device_driver *driver, const char *buf,
size_t count);
};
So no bug here.
Lateinit variable is not initialized in TestNG's @BeforeSuite
TestNG will create a new instance of BaseTest class for you per each test.
If you want to share your driver - make it static. Example:
abstract class BaseTest {
companion object {
lateinit var driver: AppiumDriver<MobileElement>
}
}
Spring boot doesn't load data to initialize database using data.sql
Try adding this line in application.properties:
spring.sql.init.mode=always
Or for Spring Boot before 2.5:
spring.datasource.initialization-mode=always
MySQL JDBC Driver 5.1.33 - Time Zone Issue
Apparently, to get version 5.1.33 of MySQL JDBC driver to work with UTC time zone, one has to specify the serverTimezone
explicitly in the connection string.
jdbc:mysql://localhost/db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
Property '...' has no initializer and is not definitely assigned in the constructor
I think you are using the latest version of TypeScript. Please see the section "Strict Class Initialization" in the link
.
There are two ways to fix this:
A. If you are using VSCode you need to change the TS version that the editor use.
B. Just initialize the array when you declare it
makes: any[] = [];
or inside the constructor:
constructor(private makeService: MakeService) {
// Initialization inside the constructor
this.makes = [];
}
Correct approach to validate attributes of an instance of class
You can use Python properties to cleanly apply rules to each field separately, and enforce them even when client code tries to change the field:
class Spam(object):
def __init__(self, description, value):
self.description = description
self.value = value
@property
def description(self):
return self._description
@description.setter
def description(self, d):
if not d: raise Exception("description cannot be empty")
self._description = d
@property
def value(self):
return self._value
@value.setter
def value(self, v):
if not (v > 0): raise Exception("value must be greater than zero")
self._value = v
An exception will be thrown on any attempt to violate the rules, even in the __init__
function, in which case object construction will fail.
UPDATE: Sometime between 2010 and now, I learned about operator.attrgetter
:
import operator
class Spam(object):
def __init__(self, description, value):
self.description = description
self.value = value
description = property(operator.attrgetter('_description'))
@description.setter
def description(self, d):
if not d: raise Exception("description cannot be empty")
self._description = d
value = property(operator.attrgetter('_value'))
@value.setter
def value(self, v):
if not (v > 0): raise Exception("value must be greater than zero")
self._value = v
Related Topics
Sending Sigint from Keyboard to Piped Commands in Bash
Read File Without Disk Caching in Linux
Sed Error:Bad Option in Substitution Expression
Too Many Open Files Error While Running Awk Command
What Do the Suffixes "+" and "-" After the Job Id of Background Jobs Mean
Rsync --Exclude Not Excluding Specific Files
Extract Text Between Two Strings Repeatedly Using Sed or Awk
How to Manage Log Verbosity Inside a Shell Script
Restoring Stdout and Stderr to Default Value
Which Is the Best Way to Make Config Changes in Conf Files in Ansible
How to Join Multiple PDF Pages to a Single Page