Merge to kernel-2.6.20-1.2949.fc6.vs2.2.0.1
[linux-2.6.git] / fs / sysfs / bin.c
index d455725..e8f540d 100644 (file)
@@ -1,11 +1,16 @@
 /*
  * bin.c - binary file operations for sysfs.
+ *
+ * Copyright (c) 2003 Patrick Mochel
+ * Copyright (c) 2003 Matthew Wilcox
+ * Copyright (c) 2004 Silicon Graphics, Inc.
  */
 
 #undef DEBUG
 
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/kernel.h>
 #include <linux/kobject.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 static int
 fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
 {
-       struct bin_attribute * attr = dentry->d_fsdata;
-       struct kobject * kobj = dentry->d_parent->d_fsdata;
+       struct bin_attribute * attr = to_bin_attr(dentry);
+       struct kobject * kobj = to_kobj(dentry->d_parent);
+
+       if (!attr->read)
+               return -EIO;
 
        return attr->read(kobj, buffer, off, count);
 }
@@ -27,7 +35,7 @@ static ssize_t
 read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
 {
        char *buffer = file->private_data;
-       struct dentry *dentry = file->f_dentry;
+       struct dentry *dentry = file->f_path.dentry;
        int size = dentry->d_inode->i_size;
        loff_t offs = *off;
        int ret;
@@ -60,8 +68,11 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
 static int
 flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
 {
-       struct bin_attribute *attr = dentry->d_fsdata;
-       struct kobject *kobj = dentry->d_parent->d_fsdata;
+       struct bin_attribute *attr = to_bin_attr(dentry);
+       struct kobject *kobj = to_kobj(dentry->d_parent);
+
+       if (!attr->write)
+               return -EIO;
 
        return attr->write(kobj, buffer, offset, count);
 }
@@ -70,7 +81,7 @@ static ssize_t write(struct file * file, const char __user * userbuf,
                     size_t count, loff_t * off)
 {
        char *buffer = file->private_data;
-       struct dentry *dentry = file->f_dentry;
+       struct dentry *dentry = file->f_path.dentry;
        int size = dentry->d_inode->i_size;
        loff_t offs = *off;
 
@@ -92,10 +103,22 @@ static ssize_t write(struct file * file, const char __user * userbuf,
        return count;
 }
 
+static int mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct dentry *dentry = file->f_path.dentry;
+       struct bin_attribute *attr = to_bin_attr(dentry);
+       struct kobject *kobj = to_kobj(dentry->d_parent);
+
+       if (!attr->mmap)
+               return -EINVAL;
+
+       return attr->mmap(kobj, attr, vma);
+}
+
 static int open(struct inode * inode, struct file * file)
 {
-       struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
-       struct bin_attribute * attr = file->f_dentry->d_fsdata;
+       struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
+       struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
        int error = -EINVAL;
 
        if (!kobj || !attr)
@@ -107,9 +130,9 @@ static int open(struct inode * inode, struct file * file)
                goto Done;
 
        error = -EACCES;
-       if ((file->f_mode & FMODE_WRITE) && !attr->write)
+       if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
                goto Error;
-       if ((file->f_mode & FMODE_READ) && !attr->read)
+       if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
                goto Error;
 
        error = -ENOMEM;
@@ -130,8 +153,8 @@ static int open(struct inode * inode, struct file * file)
 
 static int release(struct inode * inode, struct file * file)
 {
-       struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
-       struct bin_attribute * attr = file->f_dentry->d_fsdata;
+       struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent);
+       struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
        u8 * buffer = file->private_data;
 
        if (kobj) 
@@ -141,9 +164,10 @@ static int release(struct inode * inode, struct file * file)
        return 0;
 }
 
-static struct file_operations bin_fops = {
+const struct file_operations bin_fops = {
        .read           = read,
        .write          = write,
+       .mmap           = mmap,
        .llseek         = generic_file_llseek,
        .open           = open,
        .release        = release,
@@ -153,36 +177,13 @@ static struct file_operations bin_fops = {
  *     sysfs_create_bin_file - create binary file for object.
  *     @kobj:  object.
  *     @attr:  attribute descriptor.
- *
  */
 
 int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
 {
-       struct dentry * dentry;
-       struct dentry * parent;
-       int error = 0;
-
-       if (!kobj || !attr)
-               return -EINVAL;
+       BUG_ON(!kobj || !kobj->dentry || !attr);
 
-       parent = kobj->dentry;
-
-       down(&parent->d_inode->i_sem);
-       dentry = sysfs_get_dentry(parent,attr->attr.name);
-       if (!IS_ERR(dentry)) {
-               dentry->d_fsdata = (void *)attr;
-               error = sysfs_create(dentry,
-                                    (attr->attr.mode & S_IALLUGO) | S_IFREG,
-                                    NULL);
-               if (!error) {
-                       dentry->d_inode->i_size = attr->size;
-                       dentry->d_inode->i_fop = &bin_fops;
-               }
-               dput(dentry);
-       } else
-               error = PTR_ERR(dentry);
-       up(&parent->d_inode->i_sem);
-       return error;
+       return sysfs_add_file(kobj->dentry, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
 }
 
 
@@ -190,14 +191,17 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
  *     sysfs_remove_bin_file - remove binary file for object.
  *     @kobj:  object.
  *     @attr:  attribute descriptor.
- *
  */
 
-int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
+void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
 {
-       sysfs_hash_and_remove(kobj->dentry,attr->attr.name);
-       return 0;
+       if (sysfs_hash_and_remove(kobj->dentry, attr->attr.name) < 0) {
+               printk(KERN_ERR "%s: "
+                       "bad dentry or inode or no such file: \"%s\"\n",
+                       __FUNCTION__, attr->attr.name);
+               dump_stack();
+       }
 }
 
-EXPORT_SYMBOL(sysfs_create_bin_file);
-EXPORT_SYMBOL(sysfs_remove_bin_file);
+EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
+EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);