Commit 96028d74 authored by Andrew Morton's avatar Andrew Morton Committed by Greg Kroah-Hartman

[PATCH] Fix race in sysfs_read_file() and sysfs_write_file()

From: Simon Derr <Simon.Derr@bull.net>

- fixes the race between threads by adding a semaphore in sysfs_buffer

- allocates the buffer upon call to pread().  We still call again
  fill_read_buffer() if the file is "rewinded" to offset zero.

- fixes the comparison in flush_read_buffer().
Signed-off-by: default avatarSimon Derr <simon.derr@bull.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 2fcff040
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/dnotify.h> #include <linux/dnotify.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/semaphore.h>
#include "sysfs.h" #include "sysfs.h"
...@@ -53,6 +54,7 @@ struct sysfs_buffer { ...@@ -53,6 +54,7 @@ struct sysfs_buffer {
loff_t pos; loff_t pos;
char * page; char * page;
struct sysfs_ops * ops; struct sysfs_ops * ops;
struct semaphore sem;
}; };
...@@ -106,6 +108,9 @@ static int flush_read_buffer(struct sysfs_buffer * buffer, char __user * buf, ...@@ -106,6 +108,9 @@ static int flush_read_buffer(struct sysfs_buffer * buffer, char __user * buf,
{ {
int error; int error;
if (*ppos > buffer->count)
return 0;
if (count > (buffer->count - *ppos)) if (count > (buffer->count - *ppos))
count = buffer->count - *ppos; count = buffer->count - *ppos;
...@@ -140,13 +145,17 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) ...@@ -140,13 +145,17 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct sysfs_buffer * buffer = file->private_data; struct sysfs_buffer * buffer = file->private_data;
ssize_t retval = 0; ssize_t retval = 0;
if (!*ppos) { down(&buffer->sem);
if ((!*ppos) || (!buffer->page)) {
if ((retval = fill_read_buffer(file->f_dentry,buffer))) if ((retval = fill_read_buffer(file->f_dentry,buffer)))
return retval; goto out;
} }
pr_debug("%s: count = %d, ppos = %lld, buf = %s\n", pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
__FUNCTION__,count,*ppos,buffer->page); __FUNCTION__,count,*ppos,buffer->page);
return flush_read_buffer(buffer,buf,count,ppos); retval = flush_read_buffer(buffer,buf,count,ppos);
out:
up(&buffer->sem);
return retval;
} }
...@@ -220,11 +229,13 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t ...@@ -220,11 +229,13 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
{ {
struct sysfs_buffer * buffer = file->private_data; struct sysfs_buffer * buffer = file->private_data;
down(&buffer->sem);
count = fill_write_buffer(buffer,buf,count); count = fill_write_buffer(buffer,buf,count);
if (count > 0) if (count > 0)
count = flush_write_buffer(file->f_dentry,buffer,count); count = flush_write_buffer(file->f_dentry,buffer,count);
if (count > 0) if (count > 0)
*ppos += count; *ppos += count;
up(&buffer->sem);
return count; return count;
} }
...@@ -287,6 +298,7 @@ static int check_perm(struct inode * inode, struct file * file) ...@@ -287,6 +298,7 @@ static int check_perm(struct inode * inode, struct file * file)
buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL); buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);
if (buffer) { if (buffer) {
memset(buffer,0,sizeof(struct sysfs_buffer)); memset(buffer,0,sizeof(struct sysfs_buffer));
init_MUTEX(&buffer->sem);
buffer->ops = ops; buffer->ops = ops;
file->private_data = buffer; file->private_data = buffer;
} else } else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment