summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@osdl.org>2003-05-14 23:14:02 -0700
committerPatrick Mochel <mochel@osdl.org>2003-05-14 23:14:02 -0700
commit8a9af19ff3b8c8a5884656c2679f7984fd49db63 (patch)
treead12aba937bec72b9b262108b90c972cdbd09c18 /fs
parent77b3055a2a25b7ba9f5718651e7e89e5952d4912 (diff)
parent4352430976a0b40351483cd8d3a2091dde8d9582 (diff)
Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core
Diffstat (limited to 'fs')
-rw-r--r--fs/sysfs/bin.c173
1 files changed, 60 insertions, 113 deletions
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index cb72a8906379..f9981f822206 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -2,170 +2,118 @@
* bin.c - binary file operations for sysfs.
*/
+#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/module.h>
#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/slab.h>
#include <asm/uaccess.h>
#include "sysfs.h"
-static struct file_operations bin_fops;
-
-static int fill_read(struct file * file, struct sysfs_bin_buffer * buffer)
+static int
+fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
{
- struct bin_attribute * attr = file->f_dentry->d_fsdata;
- struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+ struct bin_attribute * attr = dentry->d_fsdata;
+ struct kobject * kobj = dentry->d_parent->d_fsdata;
- if (!buffer->data)
- attr->read(kobj,buffer);
- return buffer->size ? 0 : -ENOENT;
-}
-
-static int flush_read(struct file * file, char * userbuf,
- struct sysfs_bin_buffer * buffer)
-{
- return copy_to_user(userbuf,buffer->data + buffer->offset,buffer->count) ?
- -EFAULT : 0;
+ return attr->read(kobj, buffer, off, count);
}
static ssize_t
read(struct file * file, char * userbuf, size_t count, loff_t * off)
{
- struct sysfs_bin_buffer * buffer = file->private_data;
+ char *buffer = file->private_data;
+ struct dentry *dentry = file->f_dentry;
+ int size = dentry->d_inode->i_size;
+ loff_t offs = *off;
int ret;
- ret = fill_read(file,buffer);
- if (ret)
- goto Done;
+ if (offs > size)
+ return 0;
+ if (offs + count > size)
+ count = size - offs;
- buffer->offset = *off;
+ ret = fill_read(dentry, buffer, offs, count);
+ if (ret < 0)
+ goto Done;
+ count = ret;
- if (count > (buffer->size - *off))
- count = buffer->size - *off;
+ ret = -EFAULT;
+ if (copy_to_user(userbuf, buffer + offs, count) != 0)
+ goto Done;
- buffer->count = count;
+ *off = offs + count;
+ ret = count;
- ret = flush_read(file,userbuf,buffer);
- if (!ret) {
- *off += count;
- ret = count;
- }
Done:
- if (buffer && buffer->data) {
- kfree(buffer->data);
- buffer->data = NULL;
- }
return ret;
}
-int alloc_buf_data(struct sysfs_bin_buffer * buffer)
+static int
+flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
{
- buffer->data = kmalloc(buffer->count,GFP_KERNEL);
- if (buffer->data) {
- memset(buffer->data,0,buffer->count);
- return 0;
- } else
- return -ENOMEM;
-}
+ struct bin_attribute *attr = dentry->d_fsdata;
+ struct kobject *kobj = dentry->d_parent->d_fsdata;
-static int fill_write(struct file * file, const char * userbuf,
- struct sysfs_bin_buffer * buffer)
-{
- return copy_from_user(buffer->data,userbuf,buffer->count) ?
- -EFAULT : 0;
-}
-
-static int flush_write(struct file * file, const char * userbuf,
- struct sysfs_bin_buffer * buffer)
-{
- struct bin_attribute * attr = file->f_dentry->d_fsdata;
- struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
-
- return attr->write(kobj,buffer);
+ return attr->write(kobj, buffer, offset, count);
}
static ssize_t write(struct file * file, const char * userbuf,
size_t count, loff_t * off)
{
- struct sysfs_bin_buffer * buffer = file->private_data;
+ char *buffer = file->private_data;
+ struct dentry *dentry = file->f_dentry;
+ int size = dentry->d_inode->i_size;
+ loff_t offs = *off;
int ret;
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
- buffer->count = count;
-
- ret = alloc_buf_data(buffer);
- if (ret)
- goto Done;
+ if (offs > size)
+ return 0;
+ if (offs + count > size)
+ count = size - offs;
- ret = fill_write(file,userbuf,buffer);
- if (ret)
+ ret = -EFAULT;
+ if (copy_from_user(buffer + offs, userbuf, count))
goto Done;
- ret = flush_write(file,userbuf,buffer);
- if (ret > 0)
- *off += count;
+ count = flush_write(dentry, buffer, offs, count);
+ if (count > 0)
+ *off = offs + count;
+ ret = 0;
Done:
- if (buffer->data) {
- kfree(buffer->data);
- buffer->data = NULL;
- }
return ret;
}
-static int check_perm(struct inode * inode, struct file * file)
+static int open(struct inode * inode, struct file * file)
{
struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
struct bin_attribute * attr = file->f_dentry->d_fsdata;
- struct sysfs_bin_buffer * buffer;
- int error = 0;
+ int error = -EINVAL;
if (!kobj || !attr)
- goto Einval;
-
- /* File needs write support.
- * The inode's perms must say it's ok,
- * and we must have a store method.
- */
- if (file->f_mode & FMODE_WRITE) {
- if (!(inode->i_mode & S_IWUGO) || !attr->write)
- goto Eaccess;
- }
-
- /* File needs read support.
- * The inode's perms must say it's ok, and we there
- * must be a show method for it.
- */
- if (file->f_mode & FMODE_READ) {
- if (!(inode->i_mode & S_IRUGO) || !attr->read)
- goto Eaccess;
- }
-
- buffer = kmalloc(sizeof(struct sysfs_bin_buffer),GFP_KERNEL);
- if (buffer) {
- memset(buffer,0,sizeof(struct sysfs_bin_buffer));
- file->private_data = buffer;
- } else
- error = -ENOMEM;
- goto Done;
+ goto Done;
- Einval:
- error = -EINVAL;
- goto Done;
- Eaccess:
error = -EACCES;
+ if ((file->f_mode & FMODE_WRITE) && !attr->write)
+ goto Done;
+ if ((file->f_mode & FMODE_READ) && !attr->read)
+ goto Done;
+
+ error = -ENOMEM;
+ file->private_data = kmalloc(attr->size, GFP_KERNEL);
+ if (!file->private_data)
+ goto Done;
+
+ error = 0;
+
Done:
if (error && kobj)
kobject_put(kobj);
return error;
}
-static int open(struct inode * inode, struct file * file)
-{
- return check_perm(inode,file);
-}
-
static int release(struct inode * inode, struct file * file)
{
struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
@@ -173,8 +121,7 @@ static int release(struct inode * inode, struct file * file)
if (kobj)
kobject_put(kobj);
- if (buffer)
- kfree(buffer);
+ kfree(buffer);
return 0;
}