at v2.6.28-rc2 279 lines 6.0 kB view raw
1/* 2 * fs/sysfs/bin.c - sysfs binary file implementation 3 * 4 * Copyright (c) 2003 Patrick Mochel 5 * Copyright (c) 2003 Matthew Wilcox 6 * Copyright (c) 2004 Silicon Graphics, Inc. 7 * Copyright (c) 2007 SUSE Linux Products GmbH 8 * Copyright (c) 2007 Tejun Heo <teheo@suse.de> 9 * 10 * This file is released under the GPLv2. 11 * 12 * Please see Documentation/filesystems/sysfs.txt for more information. 13 */ 14 15#undef DEBUG 16 17#include <linux/errno.h> 18#include <linux/fs.h> 19#include <linux/kernel.h> 20#include <linux/kobject.h> 21#include <linux/module.h> 22#include <linux/slab.h> 23#include <linux/mutex.h> 24 25#include <asm/uaccess.h> 26 27#include "sysfs.h" 28 29struct bin_buffer { 30 struct mutex mutex; 31 void *buffer; 32 int mmapped; 33}; 34 35static int 36fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count) 37{ 38 struct sysfs_dirent *attr_sd = dentry->d_fsdata; 39 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 40 struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; 41 int rc; 42 43 /* need attr_sd for attr, its parent for kobj */ 44 if (!sysfs_get_active_two(attr_sd)) 45 return -ENODEV; 46 47 rc = -EIO; 48 if (attr->read) 49 rc = attr->read(kobj, attr, buffer, off, count); 50 51 sysfs_put_active_two(attr_sd); 52 53 return rc; 54} 55 56static ssize_t 57read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off) 58{ 59 struct bin_buffer *bb = file->private_data; 60 struct dentry *dentry = file->f_path.dentry; 61 int size = dentry->d_inode->i_size; 62 loff_t offs = *off; 63 int count = min_t(size_t, bytes, PAGE_SIZE); 64 char *temp; 65 66 if (size) { 67 if (offs > size) 68 return 0; 69 if (offs + count > size) 70 count = size - offs; 71 } 72 73 temp = kmalloc(count, GFP_KERNEL); 74 if (!temp) 75 return -ENOMEM; 76 77 mutex_lock(&bb->mutex); 78 79 count = fill_read(dentry, bb->buffer, offs, count); 80 if (count < 0) { 81 mutex_unlock(&bb->mutex); 82 goto out_free; 83 } 84 85 memcpy(temp, bb->buffer, count); 86 87 mutex_unlock(&bb->mutex); 88 89 if (copy_to_user(userbuf, temp, count)) { 90 count = -EFAULT; 91 goto out_free; 92 } 93 94 pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count); 95 96 *off = offs + count; 97 98 out_free: 99 kfree(temp); 100 return count; 101} 102 103static int 104flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count) 105{ 106 struct sysfs_dirent *attr_sd = dentry->d_fsdata; 107 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 108 struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; 109 int rc; 110 111 /* need attr_sd for attr, its parent for kobj */ 112 if (!sysfs_get_active_two(attr_sd)) 113 return -ENODEV; 114 115 rc = -EIO; 116 if (attr->write) 117 rc = attr->write(kobj, attr, buffer, offset, count); 118 119 sysfs_put_active_two(attr_sd); 120 121 return rc; 122} 123 124static ssize_t write(struct file *file, const char __user *userbuf, 125 size_t bytes, loff_t *off) 126{ 127 struct bin_buffer *bb = file->private_data; 128 struct dentry *dentry = file->f_path.dentry; 129 int size = dentry->d_inode->i_size; 130 loff_t offs = *off; 131 int count = min_t(size_t, bytes, PAGE_SIZE); 132 char *temp; 133 134 if (size) { 135 if (offs > size) 136 return 0; 137 if (offs + count > size) 138 count = size - offs; 139 } 140 141 temp = kmalloc(count, GFP_KERNEL); 142 if (!temp) 143 return -ENOMEM; 144 145 if (copy_from_user(temp, userbuf, count)) { 146 count = -EFAULT; 147 goto out_free; 148 } 149 150 mutex_lock(&bb->mutex); 151 152 memcpy(bb->buffer, temp, count); 153 154 count = flush_write(dentry, bb->buffer, offs, count); 155 mutex_unlock(&bb->mutex); 156 157 if (count > 0) 158 *off = offs + count; 159 160out_free: 161 kfree(temp); 162 return count; 163} 164 165static int mmap(struct file *file, struct vm_area_struct *vma) 166{ 167 struct bin_buffer *bb = file->private_data; 168 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 169 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 170 struct kobject *kobj = attr_sd->s_parent->s_dir.kobj; 171 int rc; 172 173 mutex_lock(&bb->mutex); 174 175 /* need attr_sd for attr, its parent for kobj */ 176 if (!sysfs_get_active_two(attr_sd)) 177 return -ENODEV; 178 179 rc = -EINVAL; 180 if (attr->mmap) 181 rc = attr->mmap(kobj, attr, vma); 182 183 if (rc == 0 && !bb->mmapped) 184 bb->mmapped = 1; 185 else 186 sysfs_put_active_two(attr_sd); 187 188 mutex_unlock(&bb->mutex); 189 190 return rc; 191} 192 193static int open(struct inode * inode, struct file * file) 194{ 195 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 196 struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr; 197 struct bin_buffer *bb = NULL; 198 int error; 199 200 /* binary file operations requires both @sd and its parent */ 201 if (!sysfs_get_active_two(attr_sd)) 202 return -ENODEV; 203 204 error = -EACCES; 205 if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap)) 206 goto err_out; 207 if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap)) 208 goto err_out; 209 210 error = -ENOMEM; 211 bb = kzalloc(sizeof(*bb), GFP_KERNEL); 212 if (!bb) 213 goto err_out; 214 215 bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 216 if (!bb->buffer) 217 goto err_out; 218 219 mutex_init(&bb->mutex); 220 file->private_data = bb; 221 222 /* open succeeded, put active references */ 223 sysfs_put_active_two(attr_sd); 224 return 0; 225 226 err_out: 227 sysfs_put_active_two(attr_sd); 228 kfree(bb); 229 return error; 230} 231 232static int release(struct inode * inode, struct file * file) 233{ 234 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; 235 struct bin_buffer *bb = file->private_data; 236 237 if (bb->mmapped) 238 sysfs_put_active_two(attr_sd); 239 kfree(bb->buffer); 240 kfree(bb); 241 return 0; 242} 243 244const struct file_operations bin_fops = { 245 .read = read, 246 .write = write, 247 .mmap = mmap, 248 .llseek = generic_file_llseek, 249 .open = open, 250 .release = release, 251}; 252 253/** 254 * sysfs_create_bin_file - create binary file for object. 255 * @kobj: object. 256 * @attr: attribute descriptor. 257 */ 258 259int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr) 260{ 261 BUG_ON(!kobj || !kobj->sd || !attr); 262 263 return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR); 264} 265 266 267/** 268 * sysfs_remove_bin_file - remove binary file for object. 269 * @kobj: object. 270 * @attr: attribute descriptor. 271 */ 272 273void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr) 274{ 275 sysfs_hash_and_remove(kobj->sd, attr->attr.name); 276} 277 278EXPORT_SYMBOL_GPL(sysfs_create_bin_file); 279EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);