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