staging: android: timed_output: fix sysfs file creation race

The sysfs file for the driver was being created _after_ the device was
announced to userspace, causing a race with any tools looking for sysfs
files.

Fix the race by using the default attribute group for the class.

Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Greg Kroah-Hartman 2013-08-24 10:27:29 -07:00
Родитель 76e1f486b2
Коммит 9d3ab80174
1 изменённых файлов: 10 добавлений и 17 удалений

Просмотреть файл

@ -28,7 +28,7 @@ static struct class *timed_output_class;
static atomic_t device_count; static atomic_t device_count;
static ssize_t enable_show(struct device *dev, struct device_attribute *attr, static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct timed_output_dev *tdev = dev_get_drvdata(dev); struct timed_output_dev *tdev = dev_get_drvdata(dev);
int remaining = tdev->get_time(tdev); int remaining = tdev->get_time(tdev);
@ -36,9 +36,8 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", remaining); return sprintf(buf, "%d\n", remaining);
} }
static ssize_t enable_store( static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
const char *buf, size_t size)
{ {
struct timed_output_dev *tdev = dev_get_drvdata(dev); struct timed_output_dev *tdev = dev_get_drvdata(dev);
int value; int value;
@ -50,8 +49,13 @@ static ssize_t enable_store(
return size; return size;
} }
static DEVICE_ATTR_RW(enable);
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); static struct attribute *timed_output_attrs[] = {
&dev_attr_enable.attr,
NULL,
};
ATTRIBUTE_GROUPS(timed_output);
static int create_timed_output_class(void) static int create_timed_output_class(void)
{ {
@ -60,6 +64,7 @@ static int create_timed_output_class(void)
if (IS_ERR(timed_output_class)) if (IS_ERR(timed_output_class))
return PTR_ERR(timed_output_class); return PTR_ERR(timed_output_class);
atomic_set(&device_count, 0); atomic_set(&device_count, 0);
timed_output_class->dev_groups = timed_output_groups;
} }
return 0; return 0;
@ -82,27 +87,15 @@ int timed_output_dev_register(struct timed_output_dev *tdev)
if (IS_ERR(tdev->dev)) if (IS_ERR(tdev->dev))
return PTR_ERR(tdev->dev); return PTR_ERR(tdev->dev);
ret = device_create_file(tdev->dev, &dev_attr_enable);
if (ret < 0)
goto err_create_file;
dev_set_drvdata(tdev->dev, tdev); dev_set_drvdata(tdev->dev, tdev);
tdev->state = 0; tdev->state = 0;
return 0; return 0;
err_create_file:
device_destroy(timed_output_class, MKDEV(0, tdev->index));
pr_err("failed to register driver %s\n",
tdev->name);
return ret;
} }
EXPORT_SYMBOL_GPL(timed_output_dev_register); EXPORT_SYMBOL_GPL(timed_output_dev_register);
void timed_output_dev_unregister(struct timed_output_dev *tdev) void timed_output_dev_unregister(struct timed_output_dev *tdev)
{ {
tdev->enable(tdev, 0); tdev->enable(tdev, 0);
device_remove_file(tdev->dev, &dev_attr_enable);
device_destroy(timed_output_class, MKDEV(0, tdev->index)); device_destroy(timed_output_class, MKDEV(0, tdev->index));
dev_set_drvdata(tdev->dev, NULL); dev_set_drvdata(tdev->dev, NULL);
} }