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#include <asm/semaphore.h> 20 21#include "sysfs.h" 22 23static int 24fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) 25{ 26 struct bin_attribute * attr = to_bin_attr(dentry); 27 struct kobject * kobj = to_kobj(dentry->d_parent); 28 29 if (!attr->read) 30 return -EIO; 31 32 return attr->read(kobj, buffer, off, count); 33} 34 35static ssize_t 36read(struct file * file, char __user * userbuf, size_t count, loff_t * off) 37{ 38 char *buffer = file->private_data; 39 struct dentry *dentry = file->f_path.dentry; 40 int size = dentry->d_inode->i_size; 41 loff_t offs = *off; 42 int ret; 43 44 if (count > PAGE_SIZE) 45 count = PAGE_SIZE; 46 47 if (size) { 48 if (offs > size) 49 return 0; 50 if (offs + count > size) 51 count = size - offs; 52 } 53 54 ret = fill_read(dentry, buffer, offs, count); 55 if (ret < 0) 56 return ret; 57 count = ret; 58 59 if (copy_to_user(userbuf, buffer, count)) 60 return -EFAULT; 61 62 pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count); 63 64 *off = offs + count; 65 66 return count; 67} 68 69static int 70flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) 71{ 72 struct bin_attribute *attr = to_bin_attr(dentry); 73 struct kobject *kobj = to_kobj(dentry->d_parent); 74 75 if (!attr->write) 76 return -EIO; 77 78 return attr->write(kobj, buffer, offset, count); 79} 80 81static ssize_t write(struct file * file, const char __user * userbuf, 82 size_t count, loff_t * off) 83{ 84 char *buffer = file->private_data; 85 struct dentry *dentry = file->f_path.dentry; 86 int size = dentry->d_inode->i_size; 87 loff_t offs = *off; 88 89 if (count > PAGE_SIZE) 90 count = PAGE_SIZE; 91 if (size) { 92 if (offs > size) 93 return 0; 94 if (offs + count > size) 95 count = size - offs; 96 } 97 98 if (copy_from_user(buffer, userbuf, count)) 99 return -EFAULT; 100 101 count = flush_write(dentry, buffer, offs, count); 102 if (count > 0) 103 *off = offs + count; 104 return count; 105} 106 107static int mmap(struct file *file, struct vm_area_struct *vma) 108{ 109 struct dentry *dentry = file->f_path.dentry; 110 struct bin_attribute *attr = to_bin_attr(dentry); 111 struct kobject *kobj = to_kobj(dentry->d_parent); 112 113 if (!attr->mmap) 114 return -EINVAL; 115 116 return attr->mmap(kobj, attr, vma); 117} 118 119static int open(struct inode * inode, struct file * file) 120{ 121 struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); 122 struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); 123 int error = -EINVAL; 124 125 if (!kobj || !attr) 126 goto Done; 127 128 /* Grab the module reference for this attribute if we have one */ 129 error = -ENODEV; 130 if (!try_module_get(attr->attr.owner)) 131 goto Done; 132 133 error = -EACCES; 134 if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) 135 goto Error; 136 if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) 137 goto Error; 138 139 error = -ENOMEM; 140 file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); 141 if (!file->private_data) 142 goto Error; 143 144 error = 0; 145 goto Done; 146 147 Error: 148 module_put(attr->attr.owner); 149 Done: 150 if (error) 151 kobject_put(kobj); 152 return error; 153} 154 155static int release(struct inode * inode, struct file * file) 156{ 157 struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent); 158 struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); 159 u8 * buffer = file->private_data; 160 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); 208