Blame view

fs/sysfs/bin.c 10.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
6d66f5cd2   Tejun Heo   sysfs: add copyri...
2
   * fs/sysfs/bin.c - sysfs binary file implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
   *
   * Copyright (c) 2003 Patrick Mochel
   * Copyright (c) 2003 Matthew Wilcox
   * Copyright (c) 2004 Silicon Graphics, Inc.
6d66f5cd2   Tejun Heo   sysfs: add copyri...
7
8
9
10
11
12
   * Copyright (c) 2007 SUSE Linux Products GmbH
   * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
   *
   * This file is released under the GPLv2.
   *
   * Please see Documentation/filesystems/sysfs.txt for more information.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
   */
  
  #undef DEBUG
  
  #include <linux/errno.h>
  #include <linux/fs.h>
995982ca7   Randy.Dunlap   sysfs_remove_bin_...
19
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
  #include <linux/kobject.h>
  #include <linux/module.h>
  #include <linux/slab.h>
869512ab5   Dave Young   sysfs: cleanup se...
23
  #include <linux/mutex.h>
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
24
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
  
  #include <asm/uaccess.h>
  
  #include "sysfs.h"
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
29
30
31
32
33
34
35
36
  /*
   * There's one bin_buffer for each open file.
   *
   * filp->private_data points to bin_buffer and
   * sysfs_dirent->s_bin_attr.buffers points to a the bin_buffer s
   * sysfs_dirent->s_bin_attr.buffers is protected by sysfs_bin_lock
   */
  static DEFINE_MUTEX(sysfs_bin_lock);
eb3616535   Tejun Heo   sysfs: implement ...
37
  struct bin_buffer {
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
38
39
40
  	struct mutex			mutex;
  	void				*buffer;
  	int				mmapped;
f0f37e2f7   Alexey Dobriyan   const: mark struc...
41
  	const struct vm_operations_struct *vm_ops;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
42
43
  	struct file			*file;
  	struct hlist_node		list;
eb3616535   Tejun Heo   sysfs: implement ...
44
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  static int
2c3c8bea6   Chris Wright   sysfs: add struct...
46
  fill_read(struct file *file, char *buffer, loff_t off, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  {
2c3c8bea6   Chris Wright   sysfs: add struct...
48
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
b1fc3d614   Tejun Heo   sysfs: make s_ele...
49
50
  	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
  	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
0ab66088c   Tejun Heo   sysfs: implement ...
51
52
53
  	int rc;
  
  	/* need attr_sd for attr, its parent for kobj */
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
54
  	if (!sysfs_get_active(attr_sd))
0ab66088c   Tejun Heo   sysfs: implement ...
55
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

0ab66088c   Tejun Heo   sysfs: implement ...
57
58
  	rc = -EIO;
  	if (attr->read)
2c3c8bea6   Chris Wright   sysfs: add struct...
59
  		rc = attr->read(file, kobj, attr, buffer, off, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
61
  	sysfs_put_active(attr_sd);
0ab66088c   Tejun Heo   sysfs: implement ...
62
63
  
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
  }
  
  static ssize_t
93e3cd827   Tejun Heo   sysfs: fix error ...
67
  read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  {
eb3616535   Tejun Heo   sysfs: implement ...
69
  	struct bin_buffer *bb = file->private_data;
2c3c8bea6   Chris Wright   sysfs: add struct...
70
  	int size = file->f_path.dentry->d_inode->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  	loff_t offs = *off;
93e3cd827   Tejun Heo   sysfs: fix error ...
72
  	int count = min_t(size_t, bytes, PAGE_SIZE);
b31ca3f5d   Nick Piggin   sysfs: fix deadlock
73
  	char *temp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74

4503efd08   Greg Kroah-Hartman   sysfs: fix proble...
75
76
  	if (!bytes)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
80
81
82
  	if (size) {
  		if (offs > size)
  			return 0;
  		if (offs + count > size)
  			count = size - offs;
  	}
b31ca3f5d   Nick Piggin   sysfs: fix deadlock
83
84
85
  	temp = kmalloc(count, GFP_KERNEL);
  	if (!temp)
  		return -ENOMEM;
eb3616535   Tejun Heo   sysfs: implement ...
86
  	mutex_lock(&bb->mutex);
2c3c8bea6   Chris Wright   sysfs: add struct...
87
  	count = fill_read(file, bb->buffer, offs, count);
b31ca3f5d   Nick Piggin   sysfs: fix deadlock
88
89
90
91
  	if (count < 0) {
  		mutex_unlock(&bb->mutex);
  		goto out_free;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

b31ca3f5d   Nick Piggin   sysfs: fix deadlock
93
94
95
96
97
  	memcpy(temp, bb->buffer, count);
  
  	mutex_unlock(&bb->mutex);
  
  	if (copy_to_user(userbuf, temp, count)) {
eb3616535   Tejun Heo   sysfs: implement ...
98
  		count = -EFAULT;
b31ca3f5d   Nick Piggin   sysfs: fix deadlock
99
  		goto out_free;
eb3616535   Tejun Heo   sysfs: implement ...
100
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101

93e3cd827   Tejun Heo   sysfs: fix error ...
102
103
  	pr_debug("offs = %lld, *off = %lld, count = %d
  ", offs, *off, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
  
  	*off = offs + count;
b31ca3f5d   Nick Piggin   sysfs: fix deadlock
106
107
   out_free:
  	kfree(temp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
  	return count;
  }
  
  static int
2c3c8bea6   Chris Wright   sysfs: add struct...
112
  flush_write(struct file *file, char *buffer, loff_t offset, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  {
2c3c8bea6   Chris Wright   sysfs: add struct...
114
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
b1fc3d614   Tejun Heo   sysfs: make s_ele...
115
116
  	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
  	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
0ab66088c   Tejun Heo   sysfs: implement ...
117
118
119
  	int rc;
  
  	/* need attr_sd for attr, its parent for kobj */
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
120
  	if (!sysfs_get_active(attr_sd))
0ab66088c   Tejun Heo   sysfs: implement ...
121
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122

0ab66088c   Tejun Heo   sysfs: implement ...
123
124
  	rc = -EIO;
  	if (attr->write)
2c3c8bea6   Chris Wright   sysfs: add struct...
125
  		rc = attr->write(file, kobj, attr, buffer, offset, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
127
  	sysfs_put_active(attr_sd);
0ab66088c   Tejun Heo   sysfs: implement ...
128
129
  
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  }
93e3cd827   Tejun Heo   sysfs: fix error ...
131
132
  static ssize_t write(struct file *file, const char __user *userbuf,
  		     size_t bytes, loff_t *off)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  {
eb3616535   Tejun Heo   sysfs: implement ...
134
  	struct bin_buffer *bb = file->private_data;
2c3c8bea6   Chris Wright   sysfs: add struct...
135
  	int size = file->f_path.dentry->d_inode->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	loff_t offs = *off;
93e3cd827   Tejun Heo   sysfs: fix error ...
137
  	int count = min_t(size_t, bytes, PAGE_SIZE);
b31ca3f5d   Nick Piggin   sysfs: fix deadlock
138
  	char *temp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139

4503efd08   Greg Kroah-Hartman   sysfs: fix proble...
140
141
  	if (!bytes)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
147
  	if (size) {
  		if (offs > size)
  			return 0;
  		if (offs + count > size)
  			count = size - offs;
  	}
1c8542c7b   Li Zefan   sysfs: use memdup...
148
149
150
  	temp = memdup_user(userbuf, count);
  	if (IS_ERR(temp))
  		return PTR_ERR(temp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151

b31ca3f5d   Nick Piggin   sysfs: fix deadlock
152
153
154
  	mutex_lock(&bb->mutex);
  
  	memcpy(bb->buffer, temp, count);
2c3c8bea6   Chris Wright   sysfs: add struct...
155
  	count = flush_write(file, bb->buffer, offs, count);
b31ca3f5d   Nick Piggin   sysfs: fix deadlock
156
  	mutex_unlock(&bb->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
  	if (count > 0)
  		*off = offs + count;
eb3616535   Tejun Heo   sysfs: implement ...
159

d5ce5b40b   Catalin Marinas   Free the memory a...
160
  	kfree(temp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
  	return count;
  }
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
163
164
165
166
167
  static void bin_vma_open(struct vm_area_struct *vma)
  {
  	struct file *file = vma->vm_file;
  	struct bin_buffer *bb = file->private_data;
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
38f49a513   Eric W. Biederman   sysfs: only acces...
168
  	if (!bb->vm_ops)
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
169
  		return;
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
170
  	if (!sysfs_get_active(attr_sd))
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
171
  		return;
38f49a513   Eric W. Biederman   sysfs: only acces...
172
173
  	if (bb->vm_ops->open)
  		bb->vm_ops->open(vma);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
174

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
175
  	sysfs_put_active(attr_sd);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
176
  }
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
177
178
179
180
181
182
  static int bin_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
  {
  	struct file *file = vma->vm_file;
  	struct bin_buffer *bb = file->private_data;
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  	int ret;
38f49a513   Eric W. Biederman   sysfs: only acces...
183
  	if (!bb->vm_ops)
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
184
  		return VM_FAULT_SIGBUS;
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
185
  	if (!sysfs_get_active(attr_sd))
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
186
  		return VM_FAULT_SIGBUS;
38f49a513   Eric W. Biederman   sysfs: only acces...
187
188
189
  	ret = VM_FAULT_SIGBUS;
  	if (bb->vm_ops->fault)
  		ret = bb->vm_ops->fault(vma, vmf);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
190

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
191
  	sysfs_put_active(attr_sd);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
192
193
  	return ret;
  }
851a039cc   Hugh Dickins   mm: page_mkwrite ...
194
  static int bin_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
195
196
197
198
199
  {
  	struct file *file = vma->vm_file;
  	struct bin_buffer *bb = file->private_data;
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  	int ret;
095160aee   Hugh Dickins   sysfs: fix some b...
200
  	if (!bb->vm_ops)
851a039cc   Hugh Dickins   mm: page_mkwrite ...
201
  		return VM_FAULT_SIGBUS;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
202

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
203
  	if (!sysfs_get_active(attr_sd))
851a039cc   Hugh Dickins   mm: page_mkwrite ...
204
  		return VM_FAULT_SIGBUS;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
205

38f49a513   Eric W. Biederman   sysfs: only acces...
206
207
208
  	ret = 0;
  	if (bb->vm_ops->page_mkwrite)
  		ret = bb->vm_ops->page_mkwrite(vma, vmf);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
209

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
210
  	sysfs_put_active(attr_sd);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
211
212
213
214
215
216
217
218
219
220
  	return ret;
  }
  
  static int bin_access(struct vm_area_struct *vma, unsigned long addr,
  		  void *buf, int len, int write)
  {
  	struct file *file = vma->vm_file;
  	struct bin_buffer *bb = file->private_data;
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  	int ret;
38f49a513   Eric W. Biederman   sysfs: only acces...
221
  	if (!bb->vm_ops)
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
222
  		return -EINVAL;
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
223
  	if (!sysfs_get_active(attr_sd))
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
224
  		return -EINVAL;
38f49a513   Eric W. Biederman   sysfs: only acces...
225
226
227
  	ret = -EINVAL;
  	if (bb->vm_ops->access)
  		ret = bb->vm_ops->access(vma, addr, buf, len, write);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
228

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
229
  	sysfs_put_active(attr_sd);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
230
231
  	return ret;
  }
095160aee   Hugh Dickins   sysfs: fix some b...
232
233
234
235
236
237
238
  #ifdef CONFIG_NUMA
  static int bin_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
  {
  	struct file *file = vma->vm_file;
  	struct bin_buffer *bb = file->private_data;
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  	int ret;
38f49a513   Eric W. Biederman   sysfs: only acces...
239
  	if (!bb->vm_ops)
095160aee   Hugh Dickins   sysfs: fix some b...
240
  		return 0;
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
241
  	if (!sysfs_get_active(attr_sd))
095160aee   Hugh Dickins   sysfs: fix some b...
242
  		return -EINVAL;
38f49a513   Eric W. Biederman   sysfs: only acces...
243
244
245
  	ret = 0;
  	if (bb->vm_ops->set_policy)
  		ret = bb->vm_ops->set_policy(vma, new);
095160aee   Hugh Dickins   sysfs: fix some b...
246

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
247
  	sysfs_put_active(attr_sd);
095160aee   Hugh Dickins   sysfs: fix some b...
248
249
250
251
252
253
254
255
256
257
  	return ret;
  }
  
  static struct mempolicy *bin_get_policy(struct vm_area_struct *vma,
  					unsigned long addr)
  {
  	struct file *file = vma->vm_file;
  	struct bin_buffer *bb = file->private_data;
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  	struct mempolicy *pol;
38f49a513   Eric W. Biederman   sysfs: only acces...
258
  	if (!bb->vm_ops)
095160aee   Hugh Dickins   sysfs: fix some b...
259
  		return vma->vm_policy;
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
260
  	if (!sysfs_get_active(attr_sd))
095160aee   Hugh Dickins   sysfs: fix some b...
261
  		return vma->vm_policy;
38f49a513   Eric W. Biederman   sysfs: only acces...
262
263
264
  	pol = vma->vm_policy;
  	if (bb->vm_ops->get_policy)
  		pol = bb->vm_ops->get_policy(vma, addr);
095160aee   Hugh Dickins   sysfs: fix some b...
265

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
266
  	sysfs_put_active(attr_sd);
095160aee   Hugh Dickins   sysfs: fix some b...
267
268
269
270
271
272
273
274
275
276
  	return pol;
  }
  
  static int bin_migrate(struct vm_area_struct *vma, const nodemask_t *from,
  			const nodemask_t *to, unsigned long flags)
  {
  	struct file *file = vma->vm_file;
  	struct bin_buffer *bb = file->private_data;
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
  	int ret;
38f49a513   Eric W. Biederman   sysfs: only acces...
277
  	if (!bb->vm_ops)
095160aee   Hugh Dickins   sysfs: fix some b...
278
  		return 0;
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
279
  	if (!sysfs_get_active(attr_sd))
095160aee   Hugh Dickins   sysfs: fix some b...
280
  		return 0;
38f49a513   Eric W. Biederman   sysfs: only acces...
281
282
283
  	ret = 0;
  	if (bb->vm_ops->migrate)
  		ret = bb->vm_ops->migrate(vma, from, to, flags);
095160aee   Hugh Dickins   sysfs: fix some b...
284

e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
285
  	sysfs_put_active(attr_sd);
095160aee   Hugh Dickins   sysfs: fix some b...
286
287
288
  	return ret;
  }
  #endif
f0f37e2f7   Alexey Dobriyan   const: mark struc...
289
  static const struct vm_operations_struct bin_vm_ops = {
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
290
  	.open		= bin_vma_open,
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
291
292
293
  	.fault		= bin_fault,
  	.page_mkwrite	= bin_page_mkwrite,
  	.access		= bin_access,
095160aee   Hugh Dickins   sysfs: fix some b...
294
295
296
297
298
  #ifdef CONFIG_NUMA
  	.set_policy	= bin_set_policy,
  	.get_policy	= bin_get_policy,
  	.migrate	= bin_migrate,
  #endif
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
299
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  static int mmap(struct file *file, struct vm_area_struct *vma)
  {
eb3616535   Tejun Heo   sysfs: implement ...
302
  	struct bin_buffer *bb = file->private_data;
3e5190380   Tejun Heo   sysfs: make sysfs...
303
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
b1fc3d614   Tejun Heo   sysfs: make s_ele...
304
305
  	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
  	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
eb3616535   Tejun Heo   sysfs: implement ...
306
  	int rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307

eb3616535   Tejun Heo   sysfs: implement ...
308
  	mutex_lock(&bb->mutex);
0ab66088c   Tejun Heo   sysfs: implement ...
309
310
  
  	/* need attr_sd for attr, its parent for kobj */
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
311
  	rc = -ENODEV;
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
312
  	if (!sysfs_get_active(attr_sd))
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
313
  		goto out_unlock;
0ab66088c   Tejun Heo   sysfs: implement ...
314
315
  
  	rc = -EINVAL;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
316
317
  	if (!attr->mmap)
  		goto out_put;
0ab66088c   Tejun Heo   sysfs: implement ...
318

2c3c8bea6   Chris Wright   sysfs: add struct...
319
  	rc = attr->mmap(file, kobj, attr, vma);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
320
321
  	if (rc)
  		goto out_put;
0ab66088c   Tejun Heo   sysfs: implement ...
322

095160aee   Hugh Dickins   sysfs: fix some b...
323
324
325
326
327
328
  	/*
  	 * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup()
  	 * to satisfy versions of X which crash if the mmap fails: that
  	 * substitutes a new vm_file, and we don't then want bin_vm_ops.
  	 */
  	if (vma->vm_file != file)
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
329
  		goto out_put;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
330
  	rc = -EINVAL;
095160aee   Hugh Dickins   sysfs: fix some b...
331
  	if (bb->mmapped && bb->vm_ops != vma->vm_ops)
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
332
  		goto out_put;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
333

a6849fa1f   Eric W. Biederman   sysfs: Fail bin f...
334
335
336
337
338
339
340
  	/*
  	 * It is not possible to successfully wrap close.
  	 * So error if someone is trying to use close.
  	 */
  	rc = -EINVAL;
  	if (vma->vm_ops && vma->vm_ops->close)
  		goto out_put;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
341
342
  	rc = 0;
  	bb->mmapped = 1;
095160aee   Hugh Dickins   sysfs: fix some b...
343
344
  	bb->vm_ops = vma->vm_ops;
  	vma->vm_ops = &bin_vm_ops;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
345
  out_put:
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
346
  	sysfs_put_active(attr_sd);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
347
  out_unlock:
eb3616535   Tejun Heo   sysfs: implement ...
348
349
350
  	mutex_unlock(&bb->mutex);
  
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
  }
  
  static int open(struct inode * inode, struct file * file)
  {
3e5190380   Tejun Heo   sysfs: make sysfs...
355
  	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
b1fc3d614   Tejun Heo   sysfs: make s_ele...
356
  	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
eb3616535   Tejun Heo   sysfs: implement ...
357
  	struct bin_buffer *bb = NULL;
0ab66088c   Tejun Heo   sysfs: implement ...
358
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359

078ce6409   Tejun Heo   sysfs: make bin a...
360
  	/* binary file operations requires both @sd and its parent */
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
361
  	if (!sysfs_get_active(attr_sd))
0ab66088c   Tejun Heo   sysfs: implement ...
362
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
  	error = -EACCES;
  	if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
7b595756e   Tejun Heo   sysfs: kill unnec...
366
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  	if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
7b595756e   Tejun Heo   sysfs: kill unnec...
368
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
370
  
  	error = -ENOMEM;
eb3616535   Tejun Heo   sysfs: implement ...
371
372
  	bb = kzalloc(sizeof(*bb), GFP_KERNEL);
  	if (!bb)
7b595756e   Tejun Heo   sysfs: kill unnec...
373
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374

eb3616535   Tejun Heo   sysfs: implement ...
375
376
  	bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
  	if (!bb->buffer)
7b595756e   Tejun Heo   sysfs: kill unnec...
377
  		goto err_out;
eb3616535   Tejun Heo   sysfs: implement ...
378
379
  
  	mutex_init(&bb->mutex);
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
380
  	bb->file = file;
eb3616535   Tejun Heo   sysfs: implement ...
381
  	file->private_data = bb;
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
382
383
384
  	mutex_lock(&sysfs_bin_lock);
  	hlist_add_head(&bb->list, &attr_sd->s_bin_attr.buffers);
  	mutex_unlock(&sysfs_bin_lock);
078ce6409   Tejun Heo   sysfs: make bin a...
385
  	/* open succeeded, put active references */
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
386
  	sysfs_put_active(attr_sd);
0ab66088c   Tejun Heo   sysfs: implement ...
387
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388

7b595756e   Tejun Heo   sysfs: kill unnec...
389
   err_out:
e72ceb8cc   Eric W. Biederman   sysfs: Remove sys...
390
  	sysfs_put_active(attr_sd);
0ab66088c   Tejun Heo   sysfs: implement ...
391
  	kfree(bb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
  	return error;
  }
  
  static int release(struct inode * inode, struct file * file)
  {
eb3616535   Tejun Heo   sysfs: implement ...
397
  	struct bin_buffer *bb = file->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398

e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
399
400
401
  	mutex_lock(&sysfs_bin_lock);
  	hlist_del(&bb->list);
  	mutex_unlock(&sysfs_bin_lock);
eb3616535   Tejun Heo   sysfs: implement ...
402
403
  	kfree(bb->buffer);
  	kfree(bb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  	return 0;
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
406
  const struct file_operations bin_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
411
412
413
  	.read		= read,
  	.write		= write,
  	.mmap		= mmap,
  	.llseek		= generic_file_llseek,
  	.open		= open,
  	.release	= release,
  };
e0edd3c65   Eric W. Biederman   sysfs: don't bloc...
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
  
  void unmap_bin_file(struct sysfs_dirent *attr_sd)
  {
  	struct bin_buffer *bb;
  	struct hlist_node *tmp;
  
  	if (sysfs_type(attr_sd) != SYSFS_KOBJ_BIN_ATTR)
  		return;
  
  	mutex_lock(&sysfs_bin_lock);
  
  	hlist_for_each_entry(bb, tmp, &attr_sd->s_bin_attr.buffers, list) {
  		struct inode *inode = bb->file->f_path.dentry->d_inode;
  
  		unmap_mapping_range(inode->i_mapping, 0, 0, 1);
  	}
  
  	mutex_unlock(&sysfs_bin_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
  /**
   *	sysfs_create_bin_file - create binary file for object.
   *	@kobj:	object.
   *	@attr:	attribute descriptor.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
   */
66ecb92be   Phil Carmody   Driver core: bin_...
438
439
  int sysfs_create_bin_file(struct kobject *kobj,
  			  const struct bin_attribute *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  {
608e266a2   Tejun Heo   sysfs: make kobj ...
441
  	BUG_ON(!kobj || !kobj->sd || !attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442

608e266a2   Tejun Heo   sysfs: make kobj ...
443
  	return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
446
447
448
449
450
  }
  
  
  /**
   *	sysfs_remove_bin_file - remove binary file for object.
   *	@kobj:	object.
   *	@attr:	attribute descriptor.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
   */
66ecb92be   Phil Carmody   Driver core: bin_...
452
453
  void sysfs_remove_bin_file(struct kobject *kobj,
  			   const struct bin_attribute *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  {
3ff195b01   Eric W. Biederman   sysfs: Implement ...
455
  	sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
458
459
  }
  
  EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
  EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);