sysfs: kill unnecessary attribute->owner
[linux-2.6-block.git] / fs / sysfs / bin.c
CommitLineData
1da177e4
LT
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>
995982ca 13#include <linux/kernel.h>
1da177e4
LT
14#include <linux/kobject.h>
15#include <linux/module.h>
16#include <linux/slab.h>
17
18#include <asm/uaccess.h>
94bebf4d 19#include <asm/semaphore.h>
1da177e4
LT
20
21#include "sysfs.h"
22
eb361653
TH
23struct bin_buffer {
24 struct mutex mutex;
25 void *buffer;
0ab66088 26 int mmapped;
eb361653
TH
27};
28
1da177e4
LT
29static int
30fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
31{
3e519038
TH
32 struct sysfs_dirent *attr_sd = dentry->d_fsdata;
33 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
0ab66088
TH
34 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
35 int rc;
36
37 /* need attr_sd for attr, its parent for kobj */
38 if (!sysfs_get_active_two(attr_sd))
39 return -ENODEV;
1da177e4 40
0ab66088
TH
41 rc = -EIO;
42 if (attr->read)
43 rc = attr->read(kobj, buffer, off, count);
1da177e4 44
0ab66088
TH
45 sysfs_put_active_two(attr_sd);
46
47 return rc;
1da177e4
LT
48}
49
50static ssize_t
93e3cd82 51read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
1da177e4 52{
eb361653 53 struct bin_buffer *bb = file->private_data;
f427f5d5 54 struct dentry *dentry = file->f_path.dentry;
1da177e4
LT
55 int size = dentry->d_inode->i_size;
56 loff_t offs = *off;
93e3cd82 57 int count = min_t(size_t, bytes, PAGE_SIZE);
1da177e4
LT
58
59 if (size) {
60 if (offs > size)
61 return 0;
62 if (offs + count > size)
63 count = size - offs;
64 }
65
eb361653
TH
66 mutex_lock(&bb->mutex);
67
68 count = fill_read(dentry, bb->buffer, offs, count);
93e3cd82 69 if (count < 0)
eb361653 70 goto out_unlock;
1da177e4 71
eb361653
TH
72 if (copy_to_user(userbuf, bb->buffer, count)) {
73 count = -EFAULT;
74 goto out_unlock;
75 }
1da177e4 76
93e3cd82 77 pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
1da177e4
LT
78
79 *off = offs + count;
80
eb361653
TH
81 out_unlock:
82 mutex_unlock(&bb->mutex);
1da177e4
LT
83 return count;
84}
85
86static int
87flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
88{
3e519038
TH
89 struct sysfs_dirent *attr_sd = dentry->d_fsdata;
90 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
0ab66088
TH
91 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
92 int rc;
93
94 /* need attr_sd for attr, its parent for kobj */
95 if (!sysfs_get_active_two(attr_sd))
96 return -ENODEV;
1da177e4 97
0ab66088
TH
98 rc = -EIO;
99 if (attr->write)
100 rc = attr->write(kobj, buffer, offset, count);
1da177e4 101
0ab66088
TH
102 sysfs_put_active_two(attr_sd);
103
104 return rc;
1da177e4
LT
105}
106
93e3cd82
TH
107static ssize_t write(struct file *file, const char __user *userbuf,
108 size_t bytes, loff_t *off)
1da177e4 109{
eb361653 110 struct bin_buffer *bb = file->private_data;
f427f5d5 111 struct dentry *dentry = file->f_path.dentry;
1da177e4
LT
112 int size = dentry->d_inode->i_size;
113 loff_t offs = *off;
93e3cd82 114 int count = min_t(size_t, bytes, PAGE_SIZE);
1da177e4 115
1da177e4
LT
116 if (size) {
117 if (offs > size)
118 return 0;
119 if (offs + count > size)
120 count = size - offs;
121 }
122
eb361653
TH
123 mutex_lock(&bb->mutex);
124
125 if (copy_from_user(bb->buffer, userbuf, count)) {
126 count = -EFAULT;
127 goto out_unlock;
128 }
1da177e4 129
eb361653 130 count = flush_write(dentry, bb->buffer, offs, count);
1da177e4
LT
131 if (count > 0)
132 *off = offs + count;
eb361653
TH
133
134 out_unlock:
135 mutex_unlock(&bb->mutex);
1da177e4
LT
136 return count;
137}
138
139static int mmap(struct file *file, struct vm_area_struct *vma)
140{
eb361653 141 struct bin_buffer *bb = file->private_data;
3e519038
TH
142 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
143 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
0ab66088 144 struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
eb361653 145 int rc;
1da177e4 146
eb361653 147 mutex_lock(&bb->mutex);
0ab66088
TH
148
149 /* need attr_sd for attr, its parent for kobj */
150 if (!sysfs_get_active_two(attr_sd))
151 return -ENODEV;
152
153 rc = -EINVAL;
154 if (attr->mmap)
155 rc = attr->mmap(kobj, attr, vma);
156
157 if (rc == 0 && !bb->mmapped)
158 bb->mmapped = 1;
159 else
160 sysfs_put_active_two(attr_sd);
161
eb361653
TH
162 mutex_unlock(&bb->mutex);
163
164 return rc;
1da177e4
LT
165}
166
167static int open(struct inode * inode, struct file * file)
168{
3e519038
TH
169 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
170 struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
eb361653 171 struct bin_buffer *bb = NULL;
0ab66088 172 int error;
1da177e4 173
0ab66088
TH
174 /* need attr_sd for attr */
175 if (!sysfs_get_active(attr_sd))
176 return -ENODEV;
1da177e4 177
1da177e4
LT
178 error = -EACCES;
179 if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
7b595756 180 goto err_out;
1da177e4 181 if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
7b595756 182 goto err_out;
1da177e4
LT
183
184 error = -ENOMEM;
eb361653
TH
185 bb = kzalloc(sizeof(*bb), GFP_KERNEL);
186 if (!bb)
7b595756 187 goto err_out;
1da177e4 188
eb361653
TH
189 bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
190 if (!bb->buffer)
7b595756 191 goto err_out;
eb361653
TH
192
193 mutex_init(&bb->mutex);
194 file->private_data = bb;
195
0ab66088
TH
196 /* open succeeded, put active reference and pin attr_sd */
197 sysfs_put_active(attr_sd);
198 sysfs_get(attr_sd);
199 return 0;
1da177e4 200
7b595756 201 err_out:
0ab66088
TH
202 sysfs_put_active(attr_sd);
203 kfree(bb);
1da177e4
LT
204 return error;
205}
206
207static int release(struct inode * inode, struct file * file)
208{
3e519038 209 struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
eb361653 210 struct bin_buffer *bb = file->private_data;
1da177e4 211
0ab66088
TH
212 if (bb->mmapped)
213 sysfs_put_active_two(attr_sd);
214 sysfs_put(attr_sd);
eb361653
TH
215 kfree(bb->buffer);
216 kfree(bb);
1da177e4
LT
217 return 0;
218}
219
4b6f5d20 220const struct file_operations bin_fops = {
1da177e4
LT
221 .read = read,
222 .write = write,
223 .mmap = mmap,
224 .llseek = generic_file_llseek,
225 .open = open,
226 .release = release,
227};
228
229/**
230 * sysfs_create_bin_file - create binary file for object.
231 * @kobj: object.
232 * @attr: attribute descriptor.
1da177e4
LT
233 */
234
235int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
236{
237 BUG_ON(!kobj || !kobj->dentry || !attr);
238
239 return sysfs_add_file(kobj->dentry, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
240}
241
242
243/**
244 * sysfs_remove_bin_file - remove binary file for object.
245 * @kobj: object.
246 * @attr: attribute descriptor.
1da177e4
LT
247 */
248
995982ca 249void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
1da177e4 250{
995982ca
RD
251 if (sysfs_hash_and_remove(kobj->dentry, attr->attr.name) < 0) {
252 printk(KERN_ERR "%s: "
253 "bad dentry or inode or no such file: \"%s\"\n",
254 __FUNCTION__, attr->attr.name);
255 dump_stack();
256 }
1da177e4
LT
257}
258
259EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
260EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);