at v2.6.20-rc4 207 lines 4.6 kB view raw
1/* 2 * bin.c - binary file operations for sysfs. 3 * 4 * Copyright (c) 2003 Patrick Mochel 5 * Copyright (c) 2003 Matthew Wilcox 6 * Copyright (c) 2004 Silicon Graphics, Inc. 7 */ 8 9#undef DEBUG 10 11#include <linux/errno.h> 12#include <linux/fs.h> 13#include <linux/kernel.h> 14#include <linux/kobject.h> 15#include <linux/module.h> 16#include <linux/slab.h> 17 18#include <asm/uaccess.h> 19 20#include "sysfs.h" 21 22static int 23fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) 24{ 25 struct bin_attribute * attr = to_bin_attr(dentry); 26 struct kobject * kobj = to_kobj(dentry->d_parent); 27 28 if (!attr->read) 29 return -EIO; 30 31 return attr->read(kobj, buffer, off, count); 32} 33 34static ssize_t 35read(struct file * file, char __user * userbuf, size_t count, loff_t * off) 36{ 37 char *buffer = file->private_data; 38 struct dentry *dentry = file->f_path.dentry; 39 int size = dentry->d_inode->i_size; 40 loff_t offs = *off; 41 int ret; 42 43 if (count > PAGE_SIZE) 44 count = PAGE_SIZE; 45 46 if (size) { 47 if (offs > size) 48 return 0; 49 if (offs + count > size) 50 count = size - offs; 51 } 52 53 ret = fill_read(dentry, buffer, offs, count); 54 if (ret < 0) 55 return ret; 56 count = ret; 57 58 if (copy_to_user(userbuf, buffer, count)) 59 return -EFAULT; 60 61 pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count); 62 63 *off = offs + count; 64 65 return count; 66} 67 68static int 69flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) 70{ 71 struct bin_attribute *attr = to_bin_attr(dentry); 72 struct kobject *kobj = to_kobj(dentry->d_parent); 73 74 if (!attr->write) 75 return -EIO; 76 77 return attr->write(kobj, buffer, offset, count); 78} 79 80static ssize_t write(struct file * file, const char __user * userbuf, 81 size_t count, loff_t * off) 82{ 83 char *buffer = file->private_data; 84 struct dentry *dentry = file->f_path.dentry; 85 int size = dentry->d_inode->i_size; 86 loff_t offs = *off; 87 88 if (count > PAGE_SIZE) 89 count = PAGE_SIZE; 90 if (size) { 91 if (offs > size) 92 return 0; 93 if (offs + count > size) 94 count = size - offs; 95 } 96 97 if (copy_from_user(buffer, userbuf, count)) 98 return -EFAULT; 99 100 count = flush_write(dentry, buffer, offs, count); 101 if (count > 0) 102 *off = offs + count; 103 return count; 104} 105 106static int mmap(struct file *file, struct vm_area_struct *vma) 107{ 108 struct dentry *dentry = file->f_path.dentry; 109 struct bin_attribute *attr = to_bin_attr(dentry); 110 struct kobject *kobj = to_kobj(dentry->d_parent); 111 112 if (!attr->mmap) 113 return -EINVAL; 114 115 return attr->mmap(kobj, attr, vma); 116} 117 118static int open(struct inode * inode, struct file * file) 119{ 120 struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); 121 struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); 122 int error = -EINVAL; 123 124 if (!kobj || !attr) 125 goto Done; 126 127 /* Grab the module reference for this attribute if we have one */ 128 error = -ENODEV; 129 if (!try_module_get(attr->attr.owner)) 130 goto Done; 131 132 error = -EACCES; 133 if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) 134 goto Error; 135 if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) 136 goto Error; 137 138 error = -ENOMEM; 139 file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); 140 if (!file->private_data) 141 goto Error; 142 143 error = 0; 144 goto Done; 145 146 Error: 147 module_put(attr->attr.owner); 148 Done: 149 if (error && kobj) 150 kobject_put(kobj); 151 return error; 152} 153 154static int release(struct inode * inode, struct file * file) 155{ 156 struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent); 157 struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); 158 u8 * buffer = file->private_data; 159 160 if (kobj) 161 kobject_put(kobj); 162 module_put(attr->attr.owner); 163 kfree(buffer); 164 return 0; 165} 166 167const struct file_operations bin_fops = { 168 .read = read, 169 .write = write, 170 .mmap = mmap, 171 .llseek = generic_file_llseek, 172 .open = open, 173 .release = release, 174}; 175 176/** 177 * sysfs_create_bin_file - create binary file for object. 178 * @kobj: object. 179 * @attr: attribute descriptor. 180 */ 181 182int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) 183{ 184 BUG_ON(!kobj || !kobj->dentry || !attr); 185 186 return sysfs_add_file(kobj->dentry, &attr->attr, SYSFS_KOBJ_BIN_ATTR); 187} 188 189 190/** 191 * sysfs_remove_bin_file - remove binary file for object. 192 * @kobj: object. 193 * @attr: attribute descriptor. 194 */ 195 196void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) 197{ 198 if (sysfs_hash_and_remove(kobj->dentry, attr->attr.name) < 0) { 199 printk(KERN_ERR "%s: " 200 "bad dentry or inode or no such file: \"%s\"\n", 201 __FUNCTION__, attr->attr.name); 202 dump_stack(); 203 } 204} 205 206EXPORT_SYMBOL_GPL(sysfs_create_bin_file); 207EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);