Re: RFC-patch - make sysfs_create_group skip members with attr.mode == 0

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Alexey Dobriyan wrote:
On Thu, Aug 17, 2006 at 04:50:25PM -0600, Jim Cromie wrote:
Currently, code in hwmon/*.c uses sysfs_create_group less than it could.

Please, provide sample patch which will use this feature. And I personally
don't understand the reasoning: can i2c code use sysfs_create_group()
with elements of struct attribute_group::attrs array ifdeffed?

A contributing reason is that many individual attr-files are created
conditionally,
depending upon both underlying hardware, driver configuration, etc.

--- try1/fs/sysfs/group.c	2006-06-17 19:49:35.000000000 -0600
+++ try2/fs/sysfs/group.c	2006-08-17 10:06:26.000000000 -0600
@@ -32,7 +33,8 @@ static int create_files(struct dentry *
	int error = 0;

	for (attr = grp->attrs; *attr && !error; attr++) {
-		error = sysfs_add_file(dir, *attr, SYSFS_KOBJ_ATTR);
+		if ((*attr)->mode)
+			error = sysfs_add_file(dir, *attr, SYSFS_KOBJ_ATTR);
	}


Hi Alexy,

Heres my motivation for the above patch, in 2 parts.

hwmon/pc87360 supports 5 kinds of sensors -
voltages, temps, thermistors, fans, pwm-fan-controllers.
Formerly, all attr-files were created by individual calls
to device_create_file().

patch 1 declares 4 separate groups (fans & pwm are together),
and creates the attr-files by calling sysfs_create_group()
for each.
This patch doesnt require the proposed patch, but sets it up..



diff -ruNp -X dontdiff -X exclude-diffs ../linux-2.6.18-rc4-mm1-sk/drivers/hwmon/pc87360.c sys-grp/drivers/hwmon/pc87360.c
--- ../linux-2.6.18-rc4-mm1-sk/drivers/hwmon/pc87360.c	2006-08-14 21:19:24.000000000 -0600
+++ sys-grp/drivers/hwmon/pc87360.c	2006-08-15 22:46:16.000000000 -0600
@@ -327,6 +327,12 @@ static struct sensor_device_attribute fa
	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2),
};

+#define FAN_UNIT_ATTRS(X)	\
+	&fan_input[X].dev_attr.attr,	\
+	&fan_status[X].dev_attr.attr,	\
+	&fan_div[X].dev_attr.attr,	\
+	&fan_min[X].dev_attr.attr
+
static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -359,6 +365,19 @@ static struct sensor_device_attribute pw
	SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
};

+static struct attribute * pc8736x_fan_attr_array[] = {
+	FAN_UNIT_ATTRS(0),
+	FAN_UNIT_ATTRS(1),
+	FAN_UNIT_ATTRS(2),
+	&pwm[0].dev_attr.attr,
+	&pwm[1].dev_attr.attr,
+	&pwm[2].dev_attr.attr,
+	NULL
+};
+static const struct attribute_group pc8736x_fan_group = {
+	.attrs = pc8736x_fan_attr_array,
+};
+
static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -471,6 +490,61 @@ static struct sensor_device_attribute in
	SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
};

+#define VIN_UNIT_ATTRS(X) \
+	&in_input[X].dev_attr.attr,	\
+	&in_status[X].dev_attr.attr,	\
+	&in_min[X].dev_attr.attr,	\
+	&in_max[X].dev_attr.attr
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pc87360_data *data = i2c_get_clientdata(client);
+	data->vrm = simple_strtoul(buf, NULL, 10);
+	return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct pc87360_data *data = pc87360_update_device(dev);
+	return sprintf(buf, "%u\n", data->in_alarms);
+}
+static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+
+static struct attribute *pc8736x_vin_attr_array[] = {
+	VIN_UNIT_ATTRS(0),
+	VIN_UNIT_ATTRS(1),
+	VIN_UNIT_ATTRS(2),
+	VIN_UNIT_ATTRS(3),
+	VIN_UNIT_ATTRS(4),
+	VIN_UNIT_ATTRS(5),
+	VIN_UNIT_ATTRS(6),
+	VIN_UNIT_ATTRS(7),
+	VIN_UNIT_ATTRS(8),
+	VIN_UNIT_ATTRS(9),
+	VIN_UNIT_ATTRS(10),
+	&dev_attr_cpu0_vid.attr,
+	&dev_attr_vrm.attr,
+	&dev_attr_alarms_in.attr,
+	NULL
+};
+static const struct attribute_group pc8736x_vin_group = {
+	.attrs = pc8736x_vin_attr_array,
+};
+
static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -589,33 +663,22 @@ static struct sensor_device_attribute th
		    show_therm_crit, set_therm_crit, 2+11),
};

-static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct pc87360_data *data = pc87360_update_device(dev);
-	return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
-}
-static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
-
-static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct pc87360_data *data = pc87360_update_device(dev);
-	return sprintf(buf, "%u\n", data->vrm);
-}
-static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
-	data->vrm = simple_strtoul(buf, NULL, 10);
-	return count;
-}
-static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
-
-static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct pc87360_data *data = pc87360_update_device(dev);
-	return sprintf(buf, "%u\n", data->in_alarms);
-}
-static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+#define THERM_UNIT_ATTRS(X) \
+	&therm_input[X].dev_attr.attr,	\
+	&therm_status[X].dev_attr.attr,	\
+	&therm_min[X].dev_attr.attr,	\
+	&therm_max[X].dev_attr.attr,	\
+	&therm_crit[X].dev_attr.attr
+
+static struct attribute * pc8736x_therm_attr_array[] = {
+	THERM_UNIT_ATTRS(0),
+	THERM_UNIT_ATTRS(1),
+	THERM_UNIT_ATTRS(2),
+	NULL
+};
+static const struct attribute_group pc8736x_therm_group = {
+	.attrs = pc8736x_therm_attr_array,
+};

static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
@@ -735,6 +798,25 @@ static ssize_t show_temp_alarms(struct d
}
static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);

+#define TEMP_UNIT_ATTRS(X) \
+	&temp_input[X].dev_attr.attr,	\
+	&temp_status[X].dev_attr.attr,	\
+	&temp_min[X].dev_attr.attr,	\
+	&temp_max[X].dev_attr.attr,	\
+	&temp_crit[X].dev_attr.attr
+
+static struct attribute * pc8736x_temp_attr_array[] = {
+	TEMP_UNIT_ATTRS(0),
+	TEMP_UNIT_ATTRS(1),
+	TEMP_UNIT_ATTRS(2),
+	/* include the few miscellaneous atts here */
+	&dev_attr_alarms_temp.attr,
+	NULL
+};
+static const struct attribute_group pc8736x_temp_group = {
+	.attrs = pc8736x_temp_attr_array,
+};
+
/*
 * Device detection, registration and update
 */
@@ -935,67 +1017,46 @@ static int pc87360_detect(struct i2c_ada
		pc87360_init_client(client, use_thermistors);
	}

-	/* Register sysfs hooks */
-	data->class_dev = hwmon_device_register(&client->dev);
-	if (IS_ERR(data->class_dev)) {
-		err = PTR_ERR(data->class_dev);
+	/* Register sysfs groups */
+
+ if (data->innr && + sysfs_create_group(&client->dev.kobj,
+			       &pc8736x_vin_group))
		goto ERROR3;
-	}

-	if (data->innr) {
-		for (i = 0; i < 11; i++) {
-			device_create_file(dev, &in_input[i].dev_attr);
-			device_create_file(dev, &in_min[i].dev_attr);
-			device_create_file(dev, &in_max[i].dev_attr);
-			device_create_file(dev, &in_status[i].dev_attr);
-		}
-		device_create_file(dev, &dev_attr_cpu0_vid);
-		device_create_file(dev, &dev_attr_vrm);
-		device_create_file(dev, &dev_attr_alarms_in);
-	}
+	if (data->tempnr &&
+ sysfs_create_group(&client->dev.kobj, + &pc8736x_temp_group))
+		goto ERROR3;

-	if (data->tempnr) {
-		for (i = 0; i < data->tempnr; i++) {
-			device_create_file(dev, &temp_input[i].dev_attr);
-			device_create_file(dev, &temp_min[i].dev_attr);
-			device_create_file(dev, &temp_max[i].dev_attr);
-			device_create_file(dev, &temp_crit[i].dev_attr);
-			device_create_file(dev, &temp_status[i].dev_attr);
-		}
-		device_create_file(dev, &dev_attr_alarms_temp);
-	}
+	if (data->innr == 14 &&
+ sysfs_create_group(&client->dev.kobj, + &pc8736x_therm_group))
+		goto ERROR3;

-	if (data->innr == 14) {
-		for (i = 0; i < 3; i++) {
-			device_create_file(dev, &therm_input[i].dev_attr);
-			device_create_file(dev, &therm_min[i].dev_attr);
-			device_create_file(dev, &therm_max[i].dev_attr);
-			device_create_file(dev, &therm_crit[i].dev_attr);
-			device_create_file(dev, &therm_status[i].dev_attr);
-		}
-	}
+	if (data->fannr &&
+	    sysfs_create_group(&client->dev.kobj,
+			       &pc8736x_fan_group))
+		goto ERROR3;

-	for (i = 0; i < data->fannr; i++) {
-		if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
-			device_create_file(dev, &fan_input[i].dev_attr);
-			device_create_file(dev, &fan_min[i].dev_attr);
-			device_create_file(dev, &fan_div[i].dev_attr);
-			device_create_file(dev, &fan_status[i].dev_attr);
-		}
-		if (FAN_CONFIG_CONTROL(data->fan_conf, i))
-			device_create_file(dev, &pwm[i].dev_attr);
+	data->class_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->class_dev)) {
+		err = PTR_ERR(data->class_dev);
+		goto ERROR3;
	}
-
	return 0;

ERROR3:
+	sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
+	sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
+	sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
+	sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
+
	i2c_detach_client(client);
ERROR2:
-	for (i = 0; i < 3; i++) {
-		if (data->address[i]) {
+	for (i = 0; i < 3; i++)
+		if (data->address[i])
			release_region(data->address[i], PC87360_EXTENT);
-		}
-	}
ERROR1:
	kfree(data);
	return err;
@@ -1008,16 +1069,19 @@ static int pc87360_detach_client(struct
	hwmon_device_unregister(data->class_dev);

+	sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
+	sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
+	sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
+	sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
+
	if ((i = i2c_detach_client(client)))
		return i;

-	for (i = 0; i < 3; i++) {
-		if (data->address[i]) {
+	for (i = 0; i < 3; i++)
+		if (data->address[i])
			release_region(data->address[i], PC87360_EXTENT);
-		}
-	}
-	kfree(data);

+	kfree(data);
	return 0;
}


So, now we have 4 working groups (with a few problems)

However, the driver supports several different chips,
which have varying numbers of voltage & temp measurement circuits.

Prior to this patch, the way to get 3 sets of voltage-device-attrs
was to call device_create_file for the 1st 3, but not for 4..N.
If you'd declared (at compile time) a group of voltage-attrs, the corresponding attr-files would be created en-masse.

With this patch, atts 4..N can be disabled at runtime,
by setting mode = 0.  Afterwards, when sysfs_group_create
is called, it creates attr-files *only* for those whose
mode != 0.  IOW - no attr-files for non-existent hardware.
Normally, mode is set usefully, and attr-files
are created as normal.


IE, like this:


diff -ruNp -X dontdiff -X exclude-diffs sys-grp/drivers/hwmon/pc87360.c grp2/drivers/hwmon/pc87360.c
--- sys-grp/drivers/hwmon/pc87360.c	2006-08-16 07:53:00.000000000 -0600
+++ grp2/drivers/hwmon/pc87360.c	2006-08-17 11:54:59.000000000 -0600
@@ -1020,7 +1020,32 @@ static int pc87360_detect(struct i2c_ada
		pc87360_init_client(client, use_thermistors);
	}

-	/* Register sysfs groups */
+	/* disable group members which arent supported by the
+	   available hardware.  For efficiency, we handle all-or-none
+	   groups separately below, and more variant groups here
+	 */
+
+#	define disable_attr(X) 	(X).dev_attr.attr.mode = 0
+
+	for (i = 0; i < ARRAY_SIZE(fan_input); i++) {
+		if (!FAN_CONFIG_MONITOR(data->fan_conf, i)) {
+			disable_attr(fan_input[i]);
+			disable_attr(fan_min[i]);
+			disable_attr(fan_div[i]);
+			disable_attr(fan_status[i]);
+		}
+		if (FAN_CONFIG_CONTROL(data->fan_conf, i))
+			disable_attr(pwm[i]);
+	}
+	for (i = data->tempnr; i &&  i < ARRAY_SIZE(temp_input); i++) {
+		disable_attr(temp_input[i]);
+		disable_attr(temp_min[i]);
+		disable_attr(temp_max[i]);
+		disable_attr(temp_crit[i]);
+		disable_attr(temp_status[i]);
+	}
+
+	/* Register sysfs groups for available hardware */

if (data->innr && sysfs_create_group(&client->dev.kobj,



I hope that clarifies (and sufficiently justifies) ..

thanks





-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux