1 |
1275 |
phoenix |
/* devfs (Device FileSystem) driver.
|
2 |
|
|
|
3 |
|
|
Copyright (C) 1998-2002 Richard Gooch
|
4 |
|
|
|
5 |
|
|
This library is free software; you can redistribute it and/or
|
6 |
|
|
modify it under the terms of the GNU Library General Public
|
7 |
|
|
License as published by the Free Software Foundation; either
|
8 |
|
|
version 2 of the License, or (at your option) any later version.
|
9 |
|
|
|
10 |
|
|
This library is distributed in the hope that it will be useful,
|
11 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13 |
|
|
Library General Public License for more details.
|
14 |
|
|
|
15 |
|
|
You should have received a copy of the GNU Library General Public
|
16 |
|
|
License along with this library; if not, write to the Free
|
17 |
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
18 |
|
|
|
19 |
|
|
Richard Gooch may be reached by email at rgooch@atnf.csiro.au
|
20 |
|
|
The postal address is:
|
21 |
|
|
Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
|
22 |
|
|
|
23 |
|
|
ChangeLog
|
24 |
|
|
|
25 |
|
|
19980110 Richard Gooch <rgooch@atnf.csiro.au>
|
26 |
|
|
Original version.
|
27 |
|
|
v0.1
|
28 |
|
|
19980111 Richard Gooch <rgooch@atnf.csiro.au>
|
29 |
|
|
Created per-fs inode table rather than using inode->u.generic_ip
|
30 |
|
|
v0.2
|
31 |
|
|
19980111 Richard Gooch <rgooch@atnf.csiro.au>
|
32 |
|
|
Created .epoch inode which has a ctime of 0.
|
33 |
|
|
Fixed loss of named pipes when dentries lost.
|
34 |
|
|
Fixed loss of inode data when devfs_register() follows mknod().
|
35 |
|
|
v0.3
|
36 |
|
|
19980111 Richard Gooch <rgooch@atnf.csiro.au>
|
37 |
|
|
Fix for when compiling with CONFIG_KERNELD.
|
38 |
|
|
19980112 Richard Gooch <rgooch@atnf.csiro.au>
|
39 |
|
|
Fix for readdir() which sometimes didn't show entries.
|
40 |
|
|
Added <<tolerant>> option to <devfs_register>.
|
41 |
|
|
v0.4
|
42 |
|
|
19980113 Richard Gooch <rgooch@atnf.csiro.au>
|
43 |
|
|
Created <devfs_fill_file> function.
|
44 |
|
|
v0.5
|
45 |
|
|
19980115 Richard Gooch <rgooch@atnf.csiro.au>
|
46 |
|
|
Added subdirectory support. Major restructuring.
|
47 |
|
|
19980116 Richard Gooch <rgooch@atnf.csiro.au>
|
48 |
|
|
Fixed <find_by_dev> to not search major=0,minor=0.
|
49 |
|
|
Added symlink support.
|
50 |
|
|
v0.6
|
51 |
|
|
19980120 Richard Gooch <rgooch@atnf.csiro.au>
|
52 |
|
|
Created <devfs_mk_dir> function and support directory unregister
|
53 |
|
|
19980120 Richard Gooch <rgooch@atnf.csiro.au>
|
54 |
|
|
Auto-ownership uses real uid/gid rather than effective uid/gid.
|
55 |
|
|
v0.7
|
56 |
|
|
19980121 Richard Gooch <rgooch@atnf.csiro.au>
|
57 |
|
|
Supported creation of sockets.
|
58 |
|
|
v0.8
|
59 |
|
|
19980122 Richard Gooch <rgooch@atnf.csiro.au>
|
60 |
|
|
Added DEVFS_FL_HIDE_UNREG flag.
|
61 |
|
|
Interface change to <devfs_mk_symlink>.
|
62 |
|
|
Created <devfs_symlink> to support symlink(2).
|
63 |
|
|
v0.9
|
64 |
|
|
19980123 Richard Gooch <rgooch@atnf.csiro.au>
|
65 |
|
|
Added check to <devfs_fill_file> to check inode is in devfs.
|
66 |
|
|
Added optional traversal of symlinks.
|
67 |
|
|
v0.10
|
68 |
|
|
19980124 Richard Gooch <rgooch@atnf.csiro.au>
|
69 |
|
|
Created <devfs_get_flags> and <devfs_set_flags>.
|
70 |
|
|
v0.11
|
71 |
|
|
19980125 C. Scott Ananian <cananian@alumni.princeton.edu>
|
72 |
|
|
Created <devfs_find_handle>.
|
73 |
|
|
19980125 Richard Gooch <rgooch@atnf.csiro.au>
|
74 |
|
|
Allow removal of symlinks.
|
75 |
|
|
v0.12
|
76 |
|
|
19980125 Richard Gooch <rgooch@atnf.csiro.au>
|
77 |
|
|
Created <devfs_set_symlink_destination>.
|
78 |
|
|
19980126 Richard Gooch <rgooch@atnf.csiro.au>
|
79 |
|
|
Moved DEVFS_SUPER_MAGIC into header file.
|
80 |
|
|
Added DEVFS_FL_HIDE flag.
|
81 |
|
|
Created <devfs_get_maj_min>.
|
82 |
|
|
Created <devfs_get_handle_from_inode>.
|
83 |
|
|
Fixed minor bug in <find_by_dev>.
|
84 |
|
|
19980127 Richard Gooch <rgooch@atnf.csiro.au>
|
85 |
|
|
Changed interface to <find_by_dev>, <find_entry>,
|
86 |
|
|
<devfs_unregister>, <devfs_fill_file> and <devfs_find_handle>.
|
87 |
|
|
Fixed inode times when symlink created with symlink(2).
|
88 |
|
|
v0.13
|
89 |
|
|
19980129 C. Scott Ananian <cananian@alumni.princeton.edu>
|
90 |
|
|
Exported <devfs_set_symlink_destination>, <devfs_get_maj_min>
|
91 |
|
|
and <devfs_get_handle_from_inode>.
|
92 |
|
|
19980129 Richard Gooch <rgooch@atnf.csiro.au>
|
93 |
|
|
Created <devfs_unlink> to support unlink(2).
|
94 |
|
|
v0.14
|
95 |
|
|
19980129 Richard Gooch <rgooch@atnf.csiro.au>
|
96 |
|
|
Fixed kerneld support for entries in devfs subdirectories.
|
97 |
|
|
19980130 Richard Gooch <rgooch@atnf.csiro.au>
|
98 |
|
|
Bugfixes in <call_kerneld>.
|
99 |
|
|
v0.15
|
100 |
|
|
19980207 Richard Gooch <rgooch@atnf.csiro.au>
|
101 |
|
|
Call kerneld when looking up unregistered entries.
|
102 |
|
|
v0.16
|
103 |
|
|
19980326 Richard Gooch <rgooch@atnf.csiro.au>
|
104 |
|
|
Modified interface to <devfs_find_handle> for symlink traversal.
|
105 |
|
|
v0.17
|
106 |
|
|
19980331 Richard Gooch <rgooch@atnf.csiro.au>
|
107 |
|
|
Fixed persistence bug with device numbers for manually created
|
108 |
|
|
device files.
|
109 |
|
|
Fixed problem with recreating symlinks with different content.
|
110 |
|
|
v0.18
|
111 |
|
|
19980401 Richard Gooch <rgooch@atnf.csiro.au>
|
112 |
|
|
Changed to CONFIG_KMOD.
|
113 |
|
|
Hide entries which are manually unlinked.
|
114 |
|
|
Always invalidate devfs dentry cache when registering entries.
|
115 |
|
|
Created <devfs_rmdir> to support rmdir(2).
|
116 |
|
|
Ensure directories created by <devfs_mk_dir> are visible.
|
117 |
|
|
v0.19
|
118 |
|
|
19980402 Richard Gooch <rgooch@atnf.csiro.au>
|
119 |
|
|
Invalidate devfs dentry cache when making directories.
|
120 |
|
|
Invalidate devfs dentry cache when removing entries.
|
121 |
|
|
Fixed persistence bug with fifos.
|
122 |
|
|
v0.20
|
123 |
|
|
19980421 Richard Gooch <rgooch@atnf.csiro.au>
|
124 |
|
|
Print process command when debugging kerneld/kmod.
|
125 |
|
|
Added debugging for register/unregister/change operations.
|
126 |
|
|
19980422 Richard Gooch <rgooch@atnf.csiro.au>
|
127 |
|
|
Added "devfs=" boot options.
|
128 |
|
|
v0.21
|
129 |
|
|
19980426 Richard Gooch <rgooch@atnf.csiro.au>
|
130 |
|
|
No longer lock/unlock superblock in <devfs_put_super>.
|
131 |
|
|
Drop negative dentries when they are released.
|
132 |
|
|
Manage dcache more efficiently.
|
133 |
|
|
v0.22
|
134 |
|
|
19980427 Richard Gooch <rgooch@atnf.csiro.au>
|
135 |
|
|
Added DEVFS_FL_AUTO_DEVNUM flag.
|
136 |
|
|
v0.23
|
137 |
|
|
19980430 Richard Gooch <rgooch@atnf.csiro.au>
|
138 |
|
|
No longer set unnecessary methods.
|
139 |
|
|
v0.24
|
140 |
|
|
19980504 Richard Gooch <rgooch@atnf.csiro.au>
|
141 |
|
|
Added PID display to <call_kerneld> debugging message.
|
142 |
|
|
Added "after" debugging message to <call_kerneld>.
|
143 |
|
|
19980519 Richard Gooch <rgooch@atnf.csiro.au>
|
144 |
|
|
Added "diread" and "diwrite" boot options.
|
145 |
|
|
19980520 Richard Gooch <rgooch@atnf.csiro.au>
|
146 |
|
|
Fixed persistence problem with permissions.
|
147 |
|
|
v0.25
|
148 |
|
|
19980602 Richard Gooch <rgooch@atnf.csiro.au>
|
149 |
|
|
Support legacy device nodes.
|
150 |
|
|
Fixed bug where recreated inodes were hidden.
|
151 |
|
|
v0.26
|
152 |
|
|
19980602 Richard Gooch <rgooch@atnf.csiro.au>
|
153 |
|
|
Improved debugging in <get_vfs_inode>.
|
154 |
|
|
19980607 Richard Gooch <rgooch@atnf.csiro.au>
|
155 |
|
|
No longer free old dentries in <devfs_mk_dir>.
|
156 |
|
|
Free all dentries for a given entry when deleting inodes.
|
157 |
|
|
v0.27
|
158 |
|
|
19980627 Richard Gooch <rgooch@atnf.csiro.au>
|
159 |
|
|
Limit auto-device numbering to majors 128 to 239.
|
160 |
|
|
v0.28
|
161 |
|
|
19980629 Richard Gooch <rgooch@atnf.csiro.au>
|
162 |
|
|
Fixed inode times persistence problem.
|
163 |
|
|
v0.29
|
164 |
|
|
19980704 Richard Gooch <rgooch@atnf.csiro.au>
|
165 |
|
|
Fixed spelling in <devfs_readlink> debug.
|
166 |
|
|
Fixed bug in <devfs_setup> parsing "dilookup".
|
167 |
|
|
v0.30
|
168 |
|
|
19980705 Richard Gooch <rgooch@atnf.csiro.au>
|
169 |
|
|
Fixed devfs inode leak when manually recreating inodes.
|
170 |
|
|
Fixed permission persistence problem when recreating inodes.
|
171 |
|
|
v0.31
|
172 |
|
|
19980727 Richard Gooch <rgooch@atnf.csiro.au>
|
173 |
|
|
Removed harmless "unused variable" compiler warning.
|
174 |
|
|
Fixed modes for manually recreated device nodes.
|
175 |
|
|
v0.32
|
176 |
|
|
19980728 Richard Gooch <rgooch@atnf.csiro.au>
|
177 |
|
|
Added NULL devfs inode warning in <devfs_read_inode>.
|
178 |
|
|
Force all inode nlink values to 1.
|
179 |
|
|
v0.33
|
180 |
|
|
19980730 Richard Gooch <rgooch@atnf.csiro.au>
|
181 |
|
|
Added "dimknod" boot option.
|
182 |
|
|
Set inode nlink to 0 when freeing dentries.
|
183 |
|
|
Fixed modes for manually recreated symlinks.
|
184 |
|
|
v0.34
|
185 |
|
|
19980802 Richard Gooch <rgooch@atnf.csiro.au>
|
186 |
|
|
Fixed bugs in recreated directories and symlinks.
|
187 |
|
|
v0.35
|
188 |
|
|
19980806 Richard Gooch <rgooch@atnf.csiro.au>
|
189 |
|
|
Fixed bugs in recreated device nodes.
|
190 |
|
|
19980807 Richard Gooch <rgooch@atnf.csiro.au>
|
191 |
|
|
Fixed bug in currently unused <devfs_get_handle_from_inode>.
|
192 |
|
|
Defined new <devfs_handle_t> type.
|
193 |
|
|
Improved debugging when getting entries.
|
194 |
|
|
Fixed bug where directories could be emptied.
|
195 |
|
|
v0.36
|
196 |
|
|
19980809 Richard Gooch <rgooch@atnf.csiro.au>
|
197 |
|
|
Replaced dummy .epoch inode with .devfsd character device.
|
198 |
|
|
19980810 Richard Gooch <rgooch@atnf.csiro.au>
|
199 |
|
|
Implemented devfsd protocol revision 0.
|
200 |
|
|
v0.37
|
201 |
|
|
19980819 Richard Gooch <rgooch@atnf.csiro.au>
|
202 |
|
|
Added soothing message to warning in <devfs_d_iput>.
|
203 |
|
|
v0.38
|
204 |
|
|
19980829 Richard Gooch <rgooch@atnf.csiro.au>
|
205 |
|
|
Use GCC extensions for structure initialisations.
|
206 |
|
|
Implemented async open notification.
|
207 |
|
|
Incremented devfsd protocol revision to 1.
|
208 |
|
|
v0.39
|
209 |
|
|
19980908 Richard Gooch <rgooch@atnf.csiro.au>
|
210 |
|
|
Moved async open notification to end of <devfs_open>.
|
211 |
|
|
v0.40
|
212 |
|
|
19980910 Richard Gooch <rgooch@atnf.csiro.au>
|
213 |
|
|
Prepended "/dev/" to module load request.
|
214 |
|
|
Renamed <call_kerneld> to <call_kmod>.
|
215 |
|
|
v0.41
|
216 |
|
|
19980910 Richard Gooch <rgooch@atnf.csiro.au>
|
217 |
|
|
Fixed typo "AYSNC" -> "ASYNC".
|
218 |
|
|
v0.42
|
219 |
|
|
19980910 Richard Gooch <rgooch@atnf.csiro.au>
|
220 |
|
|
Added open flag for files.
|
221 |
|
|
v0.43
|
222 |
|
|
19980927 Richard Gooch <rgooch@atnf.csiro.au>
|
223 |
|
|
Set i_blocks=0 and i_blksize=1024 in <devfs_read_inode>.
|
224 |
|
|
v0.44
|
225 |
|
|
19981005 Richard Gooch <rgooch@atnf.csiro.au>
|
226 |
|
|
Added test for empty <<name>> in <devfs_find_handle>.
|
227 |
|
|
Renamed <generate_path> to <devfs_generate_path> and published.
|
228 |
|
|
v0.45
|
229 |
|
|
19981006 Richard Gooch <rgooch@atnf.csiro.au>
|
230 |
|
|
Created <devfs_get_fops>.
|
231 |
|
|
v0.46
|
232 |
|
|
19981007 Richard Gooch <rgooch@atnf.csiro.au>
|
233 |
|
|
Limit auto-device numbering to majors 144 to 239.
|
234 |
|
|
v0.47
|
235 |
|
|
19981010 Richard Gooch <rgooch@atnf.csiro.au>
|
236 |
|
|
Updated <devfs_follow_link> for VFS change in 2.1.125.
|
237 |
|
|
v0.48
|
238 |
|
|
19981022 Richard Gooch <rgooch@atnf.csiro.au>
|
239 |
|
|
Created DEVFS_ FL_COMPAT flag.
|
240 |
|
|
v0.49
|
241 |
|
|
19981023 Richard Gooch <rgooch@atnf.csiro.au>
|
242 |
|
|
Created "nocompat" boot option.
|
243 |
|
|
v0.50
|
244 |
|
|
19981025 Richard Gooch <rgooch@atnf.csiro.au>
|
245 |
|
|
Replaced "mount" boot option with "nomount".
|
246 |
|
|
v0.51
|
247 |
|
|
19981110 Richard Gooch <rgooch@atnf.csiro.au>
|
248 |
|
|
Created "only" boot option.
|
249 |
|
|
v0.52
|
250 |
|
|
19981112 Richard Gooch <rgooch@atnf.csiro.au>
|
251 |
|
|
Added DEVFS_FL_REMOVABLE flag.
|
252 |
|
|
v0.53
|
253 |
|
|
19981114 Richard Gooch <rgooch@atnf.csiro.au>
|
254 |
|
|
Only call <scan_dir_for_removable> on first call to
|
255 |
|
|
<devfs_readdir>.
|
256 |
|
|
v0.54
|
257 |
|
|
19981205 Richard Gooch <rgooch@atnf.csiro.au>
|
258 |
|
|
Updated <devfs_rmdir> for VFS change in 2.1.131.
|
259 |
|
|
v0.55
|
260 |
|
|
19981218 Richard Gooch <rgooch@atnf.csiro.au>
|
261 |
|
|
Created <devfs_mk_compat>.
|
262 |
|
|
19981220 Richard Gooch <rgooch@atnf.csiro.au>
|
263 |
|
|
Check for partitions on removable media in <devfs_lookup>.
|
264 |
|
|
v0.56
|
265 |
|
|
19990118 Richard Gooch <rgooch@atnf.csiro.au>
|
266 |
|
|
Added support for registering regular files.
|
267 |
|
|
Created <devfs_set_file_size>.
|
268 |
|
|
Update devfs inodes from entries if not changed through FS.
|
269 |
|
|
v0.57
|
270 |
|
|
19990124 Richard Gooch <rgooch@atnf.csiro.au>
|
271 |
|
|
Fixed <devfs_fill_file> to only initialise temporary inodes.
|
272 |
|
|
Trap for NULL fops in <devfs_register>.
|
273 |
|
|
Return -ENODEV in <devfs_fill_file> for non-driver inodes.
|
274 |
|
|
v0.58
|
275 |
|
|
19990126 Richard Gooch <rgooch@atnf.csiro.au>
|
276 |
|
|
Switched from PATH_MAX to DEVFS_PATHLEN.
|
277 |
|
|
v0.59
|
278 |
|
|
19990127 Richard Gooch <rgooch@atnf.csiro.au>
|
279 |
|
|
Created "nottycompat" boot option.
|
280 |
|
|
v0.60
|
281 |
|
|
19990318 Richard Gooch <rgooch@atnf.csiro.au>
|
282 |
|
|
Fixed <devfsd_read> to not overrun event buffer.
|
283 |
|
|
v0.61
|
284 |
|
|
19990329 Richard Gooch <rgooch@atnf.csiro.au>
|
285 |
|
|
Created <devfs_auto_unregister>.
|
286 |
|
|
v0.62
|
287 |
|
|
19990330 Richard Gooch <rgooch@atnf.csiro.au>
|
288 |
|
|
Don't return unregistred entries in <devfs_find_handle>.
|
289 |
|
|
Panic in <devfs_unregister> if entry unregistered.
|
290 |
|
|
19990401 Richard Gooch <rgooch@atnf.csiro.au>
|
291 |
|
|
Don't panic in <devfs_auto_unregister> for duplicates.
|
292 |
|
|
v0.63
|
293 |
|
|
19990402 Richard Gooch <rgooch@atnf.csiro.au>
|
294 |
|
|
Don't unregister already unregistered entries in <unregister>.
|
295 |
|
|
v0.64
|
296 |
|
|
19990510 Richard Gooch <rgooch@atnf.csiro.au>
|
297 |
|
|
Disable warning messages when unable to read partition table for
|
298 |
|
|
removable media.
|
299 |
|
|
v0.65
|
300 |
|
|
19990512 Richard Gooch <rgooch@atnf.csiro.au>
|
301 |
|
|
Updated <devfs_lookup> for VFS change in 2.3.1-pre1.
|
302 |
|
|
Created "oops-on-panic" boot option.
|
303 |
|
|
Improved debugging in <devfs_register> and <devfs_unregister>.
|
304 |
|
|
v0.66
|
305 |
|
|
19990519 Richard Gooch <rgooch@atnf.csiro.au>
|
306 |
|
|
Added documentation for some functions.
|
307 |
|
|
19990525 Richard Gooch <rgooch@atnf.csiro.au>
|
308 |
|
|
Removed "oops-on-panic" boot option: now always Oops.
|
309 |
|
|
v0.67
|
310 |
|
|
19990531 Richard Gooch <rgooch@atnf.csiro.au>
|
311 |
|
|
Improved debugging in <devfs_register>.
|
312 |
|
|
v0.68
|
313 |
|
|
19990604 Richard Gooch <rgooch@atnf.csiro.au>
|
314 |
|
|
Added "diunlink" and "nokmod" boot options.
|
315 |
|
|
Removed superfluous warning message in <devfs_d_iput>.
|
316 |
|
|
v0.69
|
317 |
|
|
19990611 Richard Gooch <rgooch@atnf.csiro.au>
|
318 |
|
|
Took account of change to <d_alloc_root>.
|
319 |
|
|
v0.70
|
320 |
|
|
19990614 Richard Gooch <rgooch@atnf.csiro.au>
|
321 |
|
|
Created separate event queue for each mounted devfs.
|
322 |
|
|
Removed <devfs_invalidate_dcache>.
|
323 |
|
|
Created new ioctl()s.
|
324 |
|
|
Incremented devfsd protocol revision to 3.
|
325 |
|
|
Fixed bug when re-creating directories: contents were lost.
|
326 |
|
|
Block access to inodes until devfsd updates permissions.
|
327 |
|
|
19990615 Richard Gooch <rgooch@atnf.csiro.au>
|
328 |
|
|
Support 2.2.x kernels.
|
329 |
|
|
v0.71
|
330 |
|
|
19990623 Richard Gooch <rgooch@atnf.csiro.au>
|
331 |
|
|
Switched to sending process uid/gid to devfsd.
|
332 |
|
|
Renamed <call_kmod> to <try_modload>.
|
333 |
|
|
Added DEVFSD_NOTIFY_LOOKUP event.
|
334 |
|
|
19990624 Richard Gooch <rgooch@atnf.csiro.au>
|
335 |
|
|
Added DEVFSD_NOTIFY_CHANGE event.
|
336 |
|
|
Incremented devfsd protocol revision to 4.
|
337 |
|
|
v0.72
|
338 |
|
|
19990713 Richard Gooch <rgooch@atnf.csiro.au>
|
339 |
|
|
Return EISDIR rather than EINVAL for read(2) on directories.
|
340 |
|
|
v0.73
|
341 |
|
|
19990809 Richard Gooch <rgooch@atnf.csiro.au>
|
342 |
|
|
Changed <devfs_setup> to new __init scheme.
|
343 |
|
|
v0.74
|
344 |
|
|
19990901 Richard Gooch <rgooch@atnf.csiro.au>
|
345 |
|
|
Changed remaining function declarations to new __init scheme.
|
346 |
|
|
v0.75
|
347 |
|
|
19991013 Richard Gooch <rgooch@atnf.csiro.au>
|
348 |
|
|
Created <devfs_get_info>, <devfs_set_info>,
|
349 |
|
|
<devfs_get_first_child> and <devfs_get_next_sibling>.
|
350 |
|
|
Added <<dir>> parameter to <devfs_register>, <devfs_mk_compat>,
|
351 |
|
|
<devfs_mk_dir> and <devfs_find_handle>.
|
352 |
|
|
Work sponsored by SGI.
|
353 |
|
|
v0.76
|
354 |
|
|
19991017 Richard Gooch <rgooch@atnf.csiro.au>
|
355 |
|
|
Allow multiple unregistrations.
|
356 |
|
|
Work sponsored by SGI.
|
357 |
|
|
v0.77
|
358 |
|
|
19991026 Richard Gooch <rgooch@atnf.csiro.au>
|
359 |
|
|
Added major and minor number to devfsd protocol.
|
360 |
|
|
Incremented devfsd protocol revision to 5.
|
361 |
|
|
Work sponsored by SGI.
|
362 |
|
|
v0.78
|
363 |
|
|
19991030 Richard Gooch <rgooch@atnf.csiro.au>
|
364 |
|
|
Support info pointer for all devfs entry types.
|
365 |
|
|
Added <<info>> parameter to <devfs_mk_dir> and
|
366 |
|
|
<devfs_mk_symlink>.
|
367 |
|
|
Work sponsored by SGI.
|
368 |
|
|
v0.79
|
369 |
|
|
19991031 Richard Gooch <rgooch@atnf.csiro.au>
|
370 |
|
|
Support "../" when searching devfs namespace.
|
371 |
|
|
Work sponsored by SGI.
|
372 |
|
|
v0.80
|
373 |
|
|
19991101 Richard Gooch <rgooch@atnf.csiro.au>
|
374 |
|
|
Created <devfs_get_unregister_slave>.
|
375 |
|
|
Work sponsored by SGI.
|
376 |
|
|
v0.81
|
377 |
|
|
19991103 Richard Gooch <rgooch@atnf.csiro.au>
|
378 |
|
|
Exported <devfs_get_parent>.
|
379 |
|
|
Work sponsored by SGI.
|
380 |
|
|
v0.82
|
381 |
|
|
19991104 Richard Gooch <rgooch@atnf.csiro.au>
|
382 |
|
|
Removed unused <devfs_set_symlink_destination>.
|
383 |
|
|
19991105 Richard Gooch <rgooch@atnf.csiro.au>
|
384 |
|
|
Do not hide entries from devfsd or children.
|
385 |
|
|
Removed DEVFS_ FL_TTY_COMPAT flag.
|
386 |
|
|
Removed "nottycompat" boot option.
|
387 |
|
|
Removed <devfs_mk_compat>.
|
388 |
|
|
Work sponsored by SGI.
|
389 |
|
|
v0.83
|
390 |
|
|
19991107 Richard Gooch <rgooch@atnf.csiro.au>
|
391 |
|
|
Added DEVFS_FL_WAIT flag.
|
392 |
|
|
Work sponsored by SGI.
|
393 |
|
|
v0.84
|
394 |
|
|
19991107 Richard Gooch <rgooch@atnf.csiro.au>
|
395 |
|
|
Support new "disc" naming scheme in <get_removable_partition>.
|
396 |
|
|
Allow NULL fops in <devfs_register>.
|
397 |
|
|
Work sponsored by SGI.
|
398 |
|
|
v0.85
|
399 |
|
|
19991110 Richard Gooch <rgooch@atnf.csiro.au>
|
400 |
|
|
Fall back to major table if NULL fops given to <devfs_register>.
|
401 |
|
|
Work sponsored by SGI.
|
402 |
|
|
v0.86
|
403 |
|
|
19991204 Richard Gooch <rgooch@atnf.csiro.au>
|
404 |
|
|
Support fifos when unregistering.
|
405 |
|
|
Work sponsored by SGI.
|
406 |
|
|
v0.87
|
407 |
|
|
19991209 Richard Gooch <rgooch@atnf.csiro.au>
|
408 |
|
|
Removed obsolete DEVFS_ FL_COMPAT and DEVFS_ FL_TOLERANT flags.
|
409 |
|
|
Work sponsored by SGI.
|
410 |
|
|
v0.88
|
411 |
|
|
19991214 Richard Gooch <rgooch@atnf.csiro.au>
|
412 |
|
|
Removed kmod support.
|
413 |
|
|
Work sponsored by SGI.
|
414 |
|
|
v0.89
|
415 |
|
|
19991216 Richard Gooch <rgooch@atnf.csiro.au>
|
416 |
|
|
Improved debugging in <get_vfs_inode>.
|
417 |
|
|
Ensure dentries created by devfsd will be cleaned up.
|
418 |
|
|
Work sponsored by SGI.
|
419 |
|
|
v0.90
|
420 |
|
|
19991223 Richard Gooch <rgooch@atnf.csiro.au>
|
421 |
|
|
Created <devfs_get_name>.
|
422 |
|
|
Work sponsored by SGI.
|
423 |
|
|
v0.91
|
424 |
|
|
20000203 Richard Gooch <rgooch@atnf.csiro.au>
|
425 |
|
|
Ported to kernel 2.3.42.
|
426 |
|
|
Removed <devfs_fill_file>.
|
427 |
|
|
Work sponsored by SGI.
|
428 |
|
|
v0.92
|
429 |
|
|
20000306 Richard Gooch <rgooch@atnf.csiro.au>
|
430 |
|
|
Added DEVFS_ FL_NO_PERSISTENCE flag.
|
431 |
|
|
Removed unnecessary call to <update_devfs_inode_from_entry> in
|
432 |
|
|
<devfs_readdir>.
|
433 |
|
|
Work sponsored by SGI.
|
434 |
|
|
v0.93
|
435 |
|
|
20000413 Richard Gooch <rgooch@atnf.csiro.au>
|
436 |
|
|
Set inode->i_size to correct size for symlinks.
|
437 |
|
|
20000414 Richard Gooch <rgooch@atnf.csiro.au>
|
438 |
|
|
Only give lookup() method to directories to comply with new VFS
|
439 |
|
|
assumptions.
|
440 |
|
|
Work sponsored by SGI.
|
441 |
|
|
20000415 Richard Gooch <rgooch@atnf.csiro.au>
|
442 |
|
|
Remove unnecessary tests in symlink methods.
|
443 |
|
|
Don't kill existing block ops in <devfs_read_inode>.
|
444 |
|
|
Work sponsored by SGI.
|
445 |
|
|
v0.94
|
446 |
|
|
20000424 Richard Gooch <rgooch@atnf.csiro.au>
|
447 |
|
|
Don't create missing directories in <devfs_find_handle>.
|
448 |
|
|
Work sponsored by SGI.
|
449 |
|
|
v0.95
|
450 |
|
|
20000430 Richard Gooch <rgooch@atnf.csiro.au>
|
451 |
|
|
Added CONFIG_DEVFS_MOUNT.
|
452 |
|
|
Work sponsored by SGI.
|
453 |
|
|
v0.96
|
454 |
|
|
20000608 Richard Gooch <rgooch@atnf.csiro.au>
|
455 |
|
|
Disabled multi-mount capability (use VFS bindings instead).
|
456 |
|
|
Work sponsored by SGI.
|
457 |
|
|
v0.97
|
458 |
|
|
20000610 Richard Gooch <rgooch@atnf.csiro.au>
|
459 |
|
|
Switched to FS_SINGLE to disable multi-mounts.
|
460 |
|
|
20000612 Richard Gooch <rgooch@atnf.csiro.au>
|
461 |
|
|
Removed module support.
|
462 |
|
|
Removed multi-mount code.
|
463 |
|
|
Removed compatibility macros: VFS has changed too much.
|
464 |
|
|
Work sponsored by SGI.
|
465 |
|
|
v0.98
|
466 |
|
|
20000614 Richard Gooch <rgooch@atnf.csiro.au>
|
467 |
|
|
Merged devfs inode into devfs entry.
|
468 |
|
|
Work sponsored by SGI.
|
469 |
|
|
v0.99
|
470 |
|
|
20000619 Richard Gooch <rgooch@atnf.csiro.au>
|
471 |
|
|
Removed dead code in <devfs_register> which used to call
|
472 |
|
|
<free_dentries>.
|
473 |
|
|
Work sponsored by SGI.
|
474 |
|
|
v0.100
|
475 |
|
|
20000621 Richard Gooch <rgooch@atnf.csiro.au>
|
476 |
|
|
Changed interface to <devfs_register>.
|
477 |
|
|
Work sponsored by SGI.
|
478 |
|
|
v0.101
|
479 |
|
|
20000622 Richard Gooch <rgooch@atnf.csiro.au>
|
480 |
|
|
Simplified interface to <devfs_mk_symlink> and <devfs_mk_dir>.
|
481 |
|
|
Simplified interface to <devfs_find_handle>.
|
482 |
|
|
Work sponsored by SGI.
|
483 |
|
|
v0.102
|
484 |
|
|
20010519 Richard Gooch <rgooch@atnf.csiro.au>
|
485 |
|
|
Ensure <devfs_generate_path> terminates string for root entry.
|
486 |
|
|
Exported <devfs_get_name> to modules.
|
487 |
|
|
20010520 Richard Gooch <rgooch@atnf.csiro.au>
|
488 |
|
|
Make <devfs_mk_symlink> send events to devfsd.
|
489 |
|
|
Cleaned up option processing in <devfs_setup>.
|
490 |
|
|
20010521 Richard Gooch <rgooch@atnf.csiro.au>
|
491 |
|
|
Fixed bugs in handling symlinks: could leak or cause Oops.
|
492 |
|
|
20010522 Richard Gooch <rgooch@atnf.csiro.au>
|
493 |
|
|
Cleaned up directory handling by separating fops.
|
494 |
|
|
v0.103
|
495 |
|
|
20010601 Richard Gooch <rgooch@atnf.csiro.au>
|
496 |
|
|
Fixed handling of inverted options in <devfs_setup>.
|
497 |
|
|
v0.104
|
498 |
|
|
20010604 Richard Gooch <rgooch@atnf.csiro.au>
|
499 |
|
|
Adjusted <try_modload> to account for <devfs_generate_path> fix.
|
500 |
|
|
v0.105
|
501 |
|
|
20010617 Richard Gooch <rgooch@atnf.csiro.au>
|
502 |
|
|
Answered question posed by Al Viro and removed his comments.
|
503 |
|
|
Moved setting of registered flag after other fields are changed.
|
504 |
|
|
Fixed race between <devfsd_close> and <devfsd_notify_one>.
|
505 |
|
|
Global VFS changes added bogus BKL to <devfsd_close>: removed.
|
506 |
|
|
Widened locking in <devfs_readlink> and <devfs_follow_link>.
|
507 |
|
|
Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc.
|
508 |
|
|
Simplified locking in <devfsd_ioctl> and fixed memory leak.
|
509 |
|
|
v0.106
|
510 |
|
|
20010709 Richard Gooch <rgooch@atnf.csiro.au>
|
511 |
|
|
Removed broken devnum allocation and use <devfs_alloc_devnum>.
|
512 |
|
|
Fixed old devnum leak by calling new <devfs_dealloc_devnum>.
|
513 |
|
|
v0.107
|
514 |
|
|
20010712 Richard Gooch <rgooch@atnf.csiro.au>
|
515 |
|
|
Fixed bug in <devfs_setup> which could hang boot process.
|
516 |
|
|
v0.108
|
517 |
|
|
20010730 Richard Gooch <rgooch@atnf.csiro.au>
|
518 |
|
|
Added DEVFSD_NOTIFY_DELETE event.
|
519 |
|
|
20010801 Richard Gooch <rgooch@atnf.csiro.au>
|
520 |
|
|
Removed #include <asm/segment.h>.
|
521 |
|
|
v0.109
|
522 |
|
|
20010807 Richard Gooch <rgooch@atnf.csiro.au>
|
523 |
|
|
Fixed inode table races by removing it and using
|
524 |
|
|
inode->u.generic_ip instead.
|
525 |
|
|
Moved <devfs_read_inode> into <get_vfs_inode>.
|
526 |
|
|
Moved <devfs_write_inode> into <devfs_notify_change>.
|
527 |
|
|
v0.110
|
528 |
|
|
20010808 Richard Gooch <rgooch@atnf.csiro.au>
|
529 |
|
|
Fixed race in <devfs_do_symlink> for uni-processor.
|
530 |
|
|
v0.111
|
531 |
|
|
20010818 Richard Gooch <rgooch@atnf.csiro.au>
|
532 |
|
|
Removed remnant of multi-mount support in <devfs_mknod>.
|
533 |
|
|
Removed unused DEVFS_FL_SHOW_UNREG flag.
|
534 |
|
|
v0.112
|
535 |
|
|
20010820 Richard Gooch <rgooch@atnf.csiro.au>
|
536 |
|
|
Removed nlink field from struct devfs_inode.
|
537 |
|
|
v0.113
|
538 |
|
|
20010823 Richard Gooch <rgooch@atnf.csiro.au>
|
539 |
|
|
Replaced BKL with global rwsem to protect symlink data (quick
|
540 |
|
|
and dirty hack).
|
541 |
|
|
v0.114
|
542 |
|
|
20010827 Richard Gooch <rgooch@atnf.csiro.au>
|
543 |
|
|
Replaced global rwsem for symlink with per-link refcount.
|
544 |
|
|
v0.115
|
545 |
|
|
20010919 Richard Gooch <rgooch@atnf.csiro.au>
|
546 |
|
|
Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode>.
|
547 |
|
|
v0.116
|
548 |
|
|
20011008 Richard Gooch <rgooch@atnf.csiro.au>
|
549 |
|
|
Fixed overrun in <devfs_link> by removing function (not needed).
|
550 |
|
|
20011009 Richard Gooch <rgooch@atnf.csiro.au>
|
551 |
|
|
Fixed buffer underrun in <try_modload>.
|
552 |
|
|
20011029 Richard Gooch <rgooch@atnf.csiro.au>
|
553 |
|
|
Fixed race in <devfsd_ioctl> when setting event mask.
|
554 |
|
|
20011114 Richard Gooch <rgooch@atnf.csiro.au>
|
555 |
|
|
First release of new locking code.
|
556 |
|
|
v1.0
|
557 |
|
|
20011117 Richard Gooch <rgooch@atnf.csiro.au>
|
558 |
|
|
Discard temporary buffer, now use "%s" for dentry names.
|
559 |
|
|
20011118 Richard Gooch <rgooch@atnf.csiro.au>
|
560 |
|
|
Don't generate path in <try_modload>: use fake entry instead.
|
561 |
|
|
Use "existing" directory in <_devfs_make_parent_for_leaf>.
|
562 |
|
|
20011122 Richard Gooch <rgooch@atnf.csiro.au>
|
563 |
|
|
Use slab cache rather than fixed buffer for devfsd events.
|
564 |
|
|
v1.1
|
565 |
|
|
20011125 Richard Gooch <rgooch@atnf.csiro.au>
|
566 |
|
|
Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>.
|
567 |
|
|
20011127 Richard Gooch <rgooch@atnf.csiro.au>
|
568 |
|
|
Fixed locking bug in <devfs_d_revalidate_wait> due to typo.
|
569 |
|
|
Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from
|
570 |
|
|
devfsd or children.
|
571 |
|
|
v1.2
|
572 |
|
|
20011202 Richard Gooch <rgooch@atnf.csiro.au>
|
573 |
|
|
Fixed bug in <devfsd_read>: was dereferencing freed pointer.
|
574 |
|
|
v1.3
|
575 |
|
|
20011203 Richard Gooch <rgooch@atnf.csiro.au>
|
576 |
|
|
Fixed bug in <devfsd_close>: was dereferencing freed pointer.
|
577 |
|
|
Added process group check for devfsd privileges.
|
578 |
|
|
v1.4
|
579 |
|
|
20011204 Richard Gooch <rgooch@atnf.csiro.au>
|
580 |
|
|
Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>.
|
581 |
|
|
v1.5
|
582 |
|
|
20011211 Richard Gooch <rgooch@atnf.csiro.au>
|
583 |
|
|
Return old entry in <devfs_mk_dir> for 2.4.x kernels.
|
584 |
|
|
20011212 Richard Gooch <rgooch@atnf.csiro.au>
|
585 |
|
|
Increment refcount on module in <check_disc_changed>.
|
586 |
|
|
20011215 Richard Gooch <rgooch@atnf.csiro.au>
|
587 |
|
|
Created <devfs_get_handle> and exported <devfs_put>.
|
588 |
|
|
Increment refcount on module in <devfs_get_ops>.
|
589 |
|
|
Created <devfs_put_ops>.
|
590 |
|
|
v1.6
|
591 |
|
|
20011216 Richard Gooch <rgooch@atnf.csiro.au>
|
592 |
|
|
Added poisoning to <devfs_put>.
|
593 |
|
|
Improved debugging messages.
|
594 |
|
|
v1.7
|
595 |
|
|
20011221 Richard Gooch <rgooch@atnf.csiro.au>
|
596 |
|
|
Corrected (made useful) debugging message in <unregister>.
|
597 |
|
|
Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs>
|
598 |
|
|
20011224 Richard Gooch <rgooch@atnf.csiro.au>
|
599 |
|
|
Added magic number to guard against scribbling drivers.
|
600 |
|
|
20011226 Richard Gooch <rgooch@atnf.csiro.au>
|
601 |
|
|
Only return old entry in <devfs_mk_dir> if a directory.
|
602 |
|
|
Defined macros for error and debug messages.
|
603 |
|
|
v1.8
|
604 |
|
|
20020113 Richard Gooch <rgooch@atnf.csiro.au>
|
605 |
|
|
Fixed (rare, old) race in <devfs_lookup>.
|
606 |
|
|
v1.9
|
607 |
|
|
20020120 Richard Gooch <rgooch@atnf.csiro.au>
|
608 |
|
|
Fixed deadlock bug in <devfs_d_revalidate_wait>.
|
609 |
|
|
Tag VFS deletable in <devfs_mk_symlink> if handle ignored.
|
610 |
|
|
v1.10
|
611 |
|
|
20020129 Richard Gooch <rgooch@atnf.csiro.au>
|
612 |
|
|
Added KERN_* to remaining messages.
|
613 |
|
|
Cleaned up declaration of <stat_read>.
|
614 |
|
|
v1.11
|
615 |
|
|
20020219 Richard Gooch <rgooch@atnf.csiro.au>
|
616 |
|
|
Changed <devfs_rmdir> to allow later additions if not yet empty.
|
617 |
|
|
v1.12
|
618 |
|
|
20020514 Richard Gooch <rgooch@atnf.csiro.au>
|
619 |
|
|
Added BKL to <devfs_open> because drivers still need it.
|
620 |
|
|
Protected <scan_dir_for_removable> and <get_removable_partition>
|
621 |
|
|
from changing directory contents.
|
622 |
|
|
v1.12a
|
623 |
|
|
20020721 Richard Gooch <rgooch@atnf.csiro.au>
|
624 |
|
|
Switched to ISO C structure field initialisers.
|
625 |
|
|
Switch to set_current_state() and move before add_wait_queue().
|
626 |
|
|
20020722 Richard Gooch <rgooch@atnf.csiro.au>
|
627 |
|
|
Fixed devfs entry leak in <devfs_readdir> when *readdir fails.
|
628 |
|
|
v1.12b
|
629 |
|
|
20020818 Richard Gooch <rgooch@atnf.csiro.au>
|
630 |
|
|
Fixed module unload race in <devfs_open>.
|
631 |
|
|
v1.12c
|
632 |
|
|
*/
|
633 |
|
|
#include <linux/types.h>
|
634 |
|
|
#include <linux/errno.h>
|
635 |
|
|
#include <linux/sched.h>
|
636 |
|
|
#include <linux/tty.h>
|
637 |
|
|
#include <linux/timer.h>
|
638 |
|
|
#include <linux/config.h>
|
639 |
|
|
#include <linux/kernel.h>
|
640 |
|
|
#include <linux/wait.h>
|
641 |
|
|
#include <linux/string.h>
|
642 |
|
|
#include <linux/slab.h>
|
643 |
|
|
#include <linux/ioport.h>
|
644 |
|
|
#include <linux/delay.h>
|
645 |
|
|
#include <linux/ctype.h>
|
646 |
|
|
#include <linux/mm.h>
|
647 |
|
|
#include <linux/module.h>
|
648 |
|
|
#include <linux/init.h>
|
649 |
|
|
#include <linux/devfs_fs.h>
|
650 |
|
|
#include <linux/devfs_fs_kernel.h>
|
651 |
|
|
#include <linux/smp_lock.h>
|
652 |
|
|
#include <linux/smp.h>
|
653 |
|
|
#include <linux/version.h>
|
654 |
|
|
#include <linux/rwsem.h>
|
655 |
|
|
|
656 |
|
|
#include <asm/uaccess.h>
|
657 |
|
|
#include <asm/io.h>
|
658 |
|
|
#include <asm/processor.h>
|
659 |
|
|
#include <asm/system.h>
|
660 |
|
|
#include <asm/pgtable.h>
|
661 |
|
|
#include <asm/bitops.h>
|
662 |
|
|
#include <asm/atomic.h>
|
663 |
|
|
|
664 |
|
|
#define DEVFS_VERSION "1.12c (20020818)"
|
665 |
|
|
|
666 |
|
|
#define DEVFS_NAME "devfs"
|
667 |
|
|
|
668 |
|
|
#define FIRST_INODE 1
|
669 |
|
|
|
670 |
|
|
#define STRING_LENGTH 256
|
671 |
|
|
#define FAKE_BLOCK_SIZE 1024
|
672 |
|
|
#define POISON_PTR ( *(void **) poison_array )
|
673 |
|
|
#define MAGIC_VALUE 0x327db823
|
674 |
|
|
|
675 |
|
|
#ifndef TRUE
|
676 |
|
|
# define TRUE 1
|
677 |
|
|
# define FALSE 0
|
678 |
|
|
#endif
|
679 |
|
|
|
680 |
|
|
#define MODE_DIR (S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO)
|
681 |
|
|
|
682 |
|
|
#define IS_HIDDEN(de) ( (de)->hide && !is_devfsd_or_child(fs_info) )
|
683 |
|
|
|
684 |
|
|
#define DEBUG_NONE 0x0000000
|
685 |
|
|
#define DEBUG_MODULE_LOAD 0x0000001
|
686 |
|
|
#define DEBUG_REGISTER 0x0000002
|
687 |
|
|
#define DEBUG_UNREGISTER 0x0000004
|
688 |
|
|
#define DEBUG_FREE 0x0000008
|
689 |
|
|
#define DEBUG_SET_FLAGS 0x0000010
|
690 |
|
|
#define DEBUG_S_READ 0x0000100 /* Break */
|
691 |
|
|
#define DEBUG_I_LOOKUP 0x0001000 /* Break */
|
692 |
|
|
#define DEBUG_I_CREATE 0x0002000
|
693 |
|
|
#define DEBUG_I_GET 0x0004000
|
694 |
|
|
#define DEBUG_I_CHANGE 0x0008000
|
695 |
|
|
#define DEBUG_I_UNLINK 0x0010000
|
696 |
|
|
#define DEBUG_I_RLINK 0x0020000
|
697 |
|
|
#define DEBUG_I_FLINK 0x0040000
|
698 |
|
|
#define DEBUG_I_MKNOD 0x0080000
|
699 |
|
|
#define DEBUG_F_READDIR 0x0100000 /* Break */
|
700 |
|
|
#define DEBUG_D_DELETE 0x1000000 /* Break */
|
701 |
|
|
#define DEBUG_D_RELEASE 0x2000000
|
702 |
|
|
#define DEBUG_D_IPUT 0x4000000
|
703 |
|
|
#define DEBUG_ALL 0xfffffff
|
704 |
|
|
#define DEBUG_DISABLED DEBUG_NONE
|
705 |
|
|
|
706 |
|
|
#define OPTION_NONE 0x00
|
707 |
|
|
#define OPTION_MOUNT 0x01
|
708 |
|
|
#define OPTION_ONLY 0x02
|
709 |
|
|
|
710 |
|
|
#define PRINTK(format, args...) \
|
711 |
|
|
{printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);}
|
712 |
|
|
|
713 |
|
|
#define OOPS(format, args...) \
|
714 |
|
|
{printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \
|
715 |
|
|
printk ("Forcing Oops\n"); \
|
716 |
|
|
BUG();}
|
717 |
|
|
|
718 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
719 |
|
|
# define VERIFY_ENTRY(de) \
|
720 |
|
|
{if ((de) && (de)->magic_number != MAGIC_VALUE) \
|
721 |
|
|
OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);}
|
722 |
|
|
# define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic)
|
723 |
|
|
# define DPRINTK(flag, format, args...) \
|
724 |
|
|
{if (devfs_debug & flag) \
|
725 |
|
|
printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);}
|
726 |
|
|
#else
|
727 |
|
|
# define VERIFY_ENTRY(de)
|
728 |
|
|
# define WRITE_ENTRY_MAGIC(de,magic)
|
729 |
|
|
# define DPRINTK(flag, format, args...)
|
730 |
|
|
#endif
|
731 |
|
|
|
732 |
|
|
|
733 |
|
|
struct directory_type
|
734 |
|
|
{
|
735 |
|
|
rwlock_t lock; /* Lock for searching(R)/updating(W) */
|
736 |
|
|
struct devfs_entry *first;
|
737 |
|
|
struct devfs_entry *last;
|
738 |
|
|
unsigned short num_removable; /* Lock for writing but not reading */
|
739 |
|
|
unsigned char no_more_additions:1;
|
740 |
|
|
};
|
741 |
|
|
|
742 |
|
|
struct file_type
|
743 |
|
|
{
|
744 |
|
|
unsigned long size;
|
745 |
|
|
};
|
746 |
|
|
|
747 |
|
|
struct device_type
|
748 |
|
|
{
|
749 |
|
|
unsigned short major;
|
750 |
|
|
unsigned short minor;
|
751 |
|
|
};
|
752 |
|
|
|
753 |
|
|
struct fcb_type /* File, char, block type */
|
754 |
|
|
{
|
755 |
|
|
void *ops;
|
756 |
|
|
union
|
757 |
|
|
{
|
758 |
|
|
struct file_type file;
|
759 |
|
|
struct device_type device;
|
760 |
|
|
}
|
761 |
|
|
u;
|
762 |
|
|
unsigned char auto_owner:1;
|
763 |
|
|
unsigned char aopen_notify:1;
|
764 |
|
|
unsigned char removable:1; /* Belongs in device_type, but save space */
|
765 |
|
|
unsigned char open:1; /* Not entirely correct */
|
766 |
|
|
unsigned char autogen:1; /* Belongs in device_type, but save space */
|
767 |
|
|
};
|
768 |
|
|
|
769 |
|
|
struct symlink_type
|
770 |
|
|
{
|
771 |
|
|
unsigned int length; /* Not including the NULL-termimator */
|
772 |
|
|
char *linkname; /* This is NULL-terminated */
|
773 |
|
|
};
|
774 |
|
|
|
775 |
|
|
struct devfs_inode /* This structure is for "persistent" inode storage */
|
776 |
|
|
{
|
777 |
|
|
struct dentry *dentry;
|
778 |
|
|
time_t atime;
|
779 |
|
|
time_t mtime;
|
780 |
|
|
time_t ctime;
|
781 |
|
|
unsigned int ino; /* Inode number as seen in the VFS */
|
782 |
|
|
uid_t uid;
|
783 |
|
|
gid_t gid;
|
784 |
|
|
};
|
785 |
|
|
|
786 |
|
|
struct devfs_entry
|
787 |
|
|
{
|
788 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
789 |
|
|
unsigned int magic_number;
|
790 |
|
|
#endif
|
791 |
|
|
void *info;
|
792 |
|
|
atomic_t refcount; /* When this drops to zero, it's unused */
|
793 |
|
|
union
|
794 |
|
|
{
|
795 |
|
|
struct directory_type dir;
|
796 |
|
|
struct fcb_type fcb;
|
797 |
|
|
struct symlink_type symlink;
|
798 |
|
|
const char *name; /* Only used for (mode == 0) */
|
799 |
|
|
}
|
800 |
|
|
u;
|
801 |
|
|
struct devfs_entry *prev; /* Previous entry in the parent directory */
|
802 |
|
|
struct devfs_entry *next; /* Next entry in the parent directory */
|
803 |
|
|
struct devfs_entry *parent; /* The parent directory */
|
804 |
|
|
struct devfs_entry *slave; /* Another entry to unregister */
|
805 |
|
|
struct devfs_inode inode;
|
806 |
|
|
umode_t mode;
|
807 |
|
|
unsigned short namelen; /* I think 64k+ filenames are a way off... */
|
808 |
|
|
unsigned char hide:1;
|
809 |
|
|
unsigned char vfs_deletable:1;/* Whether the VFS may delete the entry */
|
810 |
|
|
char name[1]; /* This is just a dummy: the allocated array
|
811 |
|
|
is bigger. This is NULL-terminated */
|
812 |
|
|
};
|
813 |
|
|
|
814 |
|
|
/* The root of the device tree */
|
815 |
|
|
static struct devfs_entry *root_entry;
|
816 |
|
|
|
817 |
|
|
struct devfsd_buf_entry
|
818 |
|
|
{
|
819 |
|
|
struct devfs_entry *de; /* The name is generated with this */
|
820 |
|
|
unsigned short type; /* The type of event */
|
821 |
|
|
umode_t mode;
|
822 |
|
|
uid_t uid;
|
823 |
|
|
gid_t gid;
|
824 |
|
|
struct devfsd_buf_entry *next;
|
825 |
|
|
};
|
826 |
|
|
|
827 |
|
|
struct fs_info /* This structure is for the mounted devfs */
|
828 |
|
|
{
|
829 |
|
|
struct super_block *sb;
|
830 |
|
|
spinlock_t devfsd_buffer_lock; /* Lock when inserting/deleting events */
|
831 |
|
|
struct devfsd_buf_entry *devfsd_first_event;
|
832 |
|
|
struct devfsd_buf_entry *devfsd_last_event;
|
833 |
|
|
volatile int devfsd_sleeping;
|
834 |
|
|
volatile struct task_struct *devfsd_task;
|
835 |
|
|
volatile pid_t devfsd_pgrp;
|
836 |
|
|
volatile struct file *devfsd_file;
|
837 |
|
|
struct devfsd_notify_struct *devfsd_info;
|
838 |
|
|
volatile unsigned long devfsd_event_mask;
|
839 |
|
|
atomic_t devfsd_overrun_count;
|
840 |
|
|
wait_queue_head_t devfsd_wait_queue; /* Wake devfsd on input */
|
841 |
|
|
wait_queue_head_t revalidate_wait_queue; /* Wake when devfsd sleeps */
|
842 |
|
|
};
|
843 |
|
|
|
844 |
|
|
static struct fs_info fs_info = {devfsd_buffer_lock: SPIN_LOCK_UNLOCKED};
|
845 |
|
|
static kmem_cache_t *devfsd_buf_cache;
|
846 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
847 |
|
|
static unsigned int devfs_debug_init __initdata = DEBUG_NONE;
|
848 |
|
|
static unsigned int devfs_debug = DEBUG_NONE;
|
849 |
|
|
static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;
|
850 |
|
|
static unsigned int stat_num_entries;
|
851 |
|
|
static unsigned int stat_num_bytes;
|
852 |
|
|
#endif
|
853 |
|
|
static unsigned char poison_array[8] =
|
854 |
|
|
{0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a};
|
855 |
|
|
|
856 |
|
|
#ifdef CONFIG_DEVFS_MOUNT
|
857 |
|
|
static unsigned int boot_options = OPTION_MOUNT;
|
858 |
|
|
#else
|
859 |
|
|
static unsigned int boot_options = OPTION_NONE;
|
860 |
|
|
#endif
|
861 |
|
|
|
862 |
|
|
/* Forward function declarations */
|
863 |
|
|
static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir,
|
864 |
|
|
const char *name, int namelen,
|
865 |
|
|
int traverse_symlink);
|
866 |
|
|
static ssize_t devfsd_read (struct file *file, char *buf, size_t len,
|
867 |
|
|
loff_t *ppos);
|
868 |
|
|
static int devfsd_ioctl (struct inode *inode, struct file *file,
|
869 |
|
|
unsigned int cmd, unsigned long arg);
|
870 |
|
|
static int devfsd_close (struct inode *inode, struct file *file);
|
871 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
872 |
|
|
static ssize_t stat_read (struct file *file, char *buf, size_t len,
|
873 |
|
|
loff_t *ppos);
|
874 |
|
|
static struct file_operations stat_fops =
|
875 |
|
|
{
|
876 |
|
|
.read = stat_read,
|
877 |
|
|
};
|
878 |
|
|
#endif
|
879 |
|
|
|
880 |
|
|
|
881 |
|
|
/* Devfs daemon file operations */
|
882 |
|
|
static struct file_operations devfsd_fops =
|
883 |
|
|
{
|
884 |
|
|
.read = devfsd_read,
|
885 |
|
|
.ioctl = devfsd_ioctl,
|
886 |
|
|
.release = devfsd_close,
|
887 |
|
|
};
|
888 |
|
|
|
889 |
|
|
|
890 |
|
|
/* Support functions follow */
|
891 |
|
|
|
892 |
|
|
|
893 |
|
|
/**
|
894 |
|
|
* devfs_get - Get a reference to a devfs entry.
|
895 |
|
|
* @de: The devfs entry.
|
896 |
|
|
*/
|
897 |
|
|
|
898 |
|
|
static struct devfs_entry *devfs_get (struct devfs_entry *de)
|
899 |
|
|
{
|
900 |
|
|
VERIFY_ENTRY (de);
|
901 |
|
|
if (de) atomic_inc (&de->refcount);
|
902 |
|
|
return de;
|
903 |
|
|
} /* End Function devfs_get */
|
904 |
|
|
|
905 |
|
|
/**
|
906 |
|
|
* devfs_put - Put (release) a reference to a devfs entry.
|
907 |
|
|
* @de: The handle to the devfs entry.
|
908 |
|
|
*/
|
909 |
|
|
|
910 |
|
|
void devfs_put (devfs_handle_t de)
|
911 |
|
|
{
|
912 |
|
|
if (!de) return;
|
913 |
|
|
VERIFY_ENTRY (de);
|
914 |
|
|
if (de->info == POISON_PTR) OOPS ("(%p): poisoned pointer\n", de);
|
915 |
|
|
if ( !atomic_dec_and_test (&de->refcount) ) return;
|
916 |
|
|
if (de == root_entry) OOPS ("(%p): root entry being freed\n", de);
|
917 |
|
|
DPRINTK (DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n",
|
918 |
|
|
de->name, de, de->parent,
|
919 |
|
|
de->parent ? de->parent->name : "no parent");
|
920 |
|
|
if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname);
|
921 |
|
|
if ( ( S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.autogen )
|
922 |
|
|
{
|
923 |
|
|
devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR :
|
924 |
|
|
DEVFS_SPECIAL_BLK,
|
925 |
|
|
mk_kdev (de->u.fcb.u.device.major,
|
926 |
|
|
de->u.fcb.u.device.minor) );
|
927 |
|
|
}
|
928 |
|
|
WRITE_ENTRY_MAGIC (de, 0);
|
929 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
930 |
|
|
spin_lock (&stat_lock);
|
931 |
|
|
--stat_num_entries;
|
932 |
|
|
stat_num_bytes -= sizeof *de + de->namelen;
|
933 |
|
|
if ( S_ISLNK (de->mode) ) stat_num_bytes -= de->u.symlink.length + 1;
|
934 |
|
|
spin_unlock (&stat_lock);
|
935 |
|
|
#endif
|
936 |
|
|
de->info = POISON_PTR;
|
937 |
|
|
kfree (de);
|
938 |
|
|
} /* End Function devfs_put */
|
939 |
|
|
|
940 |
|
|
/**
|
941 |
|
|
* _devfs_search_dir - Search for a devfs entry in a directory.
|
942 |
|
|
* @dir: The directory to search.
|
943 |
|
|
* @name: The name of the entry to search for.
|
944 |
|
|
* @namelen: The number of characters in @name.
|
945 |
|
|
*
|
946 |
|
|
* Search for a devfs entry in a directory and returns a pointer to the entry
|
947 |
|
|
* on success, else %NULL. The directory must be locked already.
|
948 |
|
|
* An implicit devfs_get() is performed on the returned entry.
|
949 |
|
|
*/
|
950 |
|
|
|
951 |
|
|
static struct devfs_entry *_devfs_search_dir (struct devfs_entry *dir,
|
952 |
|
|
const char *name,
|
953 |
|
|
unsigned int namelen)
|
954 |
|
|
{
|
955 |
|
|
struct devfs_entry *curr;
|
956 |
|
|
|
957 |
|
|
if ( !S_ISDIR (dir->mode) )
|
958 |
|
|
{
|
959 |
|
|
PRINTK ("(%s): not a directory\n", dir->name);
|
960 |
|
|
return NULL;
|
961 |
|
|
}
|
962 |
|
|
for (curr = dir->u.dir.first; curr != NULL; curr = curr->next)
|
963 |
|
|
{
|
964 |
|
|
if (curr->namelen != namelen) continue;
|
965 |
|
|
if (memcmp (curr->name, name, namelen) == 0) break;
|
966 |
|
|
/* Not found: try the next one */
|
967 |
|
|
}
|
968 |
|
|
return devfs_get (curr);
|
969 |
|
|
} /* End Function _devfs_search_dir */
|
970 |
|
|
|
971 |
|
|
|
972 |
|
|
/**
|
973 |
|
|
* _devfs_alloc_entry - Allocate a devfs entry.
|
974 |
|
|
* @name: The name of the entry.
|
975 |
|
|
* @namelen: The number of characters in @name.
|
976 |
|
|
*
|
977 |
|
|
* Allocate a devfs entry and returns a pointer to the entry on success, else
|
978 |
|
|
* %NULL.
|
979 |
|
|
*/
|
980 |
|
|
|
981 |
|
|
static struct devfs_entry *_devfs_alloc_entry (const char *name,
|
982 |
|
|
unsigned int namelen,
|
983 |
|
|
umode_t mode)
|
984 |
|
|
{
|
985 |
|
|
struct devfs_entry *new;
|
986 |
|
|
static unsigned long inode_counter = FIRST_INODE;
|
987 |
|
|
static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED;
|
988 |
|
|
|
989 |
|
|
if ( name && (namelen < 1) ) namelen = strlen (name);
|
990 |
|
|
if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL )
|
991 |
|
|
return NULL;
|
992 |
|
|
memset (new, 0, sizeof *new + namelen); /* Will set '\0' on name */
|
993 |
|
|
new->mode = mode;
|
994 |
|
|
if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock);
|
995 |
|
|
atomic_set (&new->refcount, 1);
|
996 |
|
|
spin_lock (&counter_lock);
|
997 |
|
|
new->inode.ino = inode_counter++;
|
998 |
|
|
spin_unlock (&counter_lock);
|
999 |
|
|
if (name) memcpy (new->name, name, namelen);
|
1000 |
|
|
new->namelen = namelen;
|
1001 |
|
|
WRITE_ENTRY_MAGIC (new, MAGIC_VALUE);
|
1002 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
1003 |
|
|
spin_lock (&stat_lock);
|
1004 |
|
|
++stat_num_entries;
|
1005 |
|
|
stat_num_bytes += sizeof *new + namelen;
|
1006 |
|
|
spin_unlock (&stat_lock);
|
1007 |
|
|
#endif
|
1008 |
|
|
return new;
|
1009 |
|
|
} /* End Function _devfs_alloc_entry */
|
1010 |
|
|
|
1011 |
|
|
|
1012 |
|
|
/**
|
1013 |
|
|
* _devfs_append_entry - Append a devfs entry to a directory's child list.
|
1014 |
|
|
* @dir: The directory to add to.
|
1015 |
|
|
* @de: The devfs entry to append.
|
1016 |
|
|
* @removable: If TRUE, increment the count of removable devices for %dir.
|
1017 |
|
|
* @old_de: If an existing entry exists, it will be written here. This may
|
1018 |
|
|
* be %NULL. An implicit devfs_get() is performed on this entry.
|
1019 |
|
|
*
|
1020 |
|
|
* Append a devfs entry to a directory's list of children, checking first to
|
1021 |
|
|
* see if an entry of the same name exists. The directory will be locked.
|
1022 |
|
|
* The value 0 is returned on success, else a negative error code.
|
1023 |
|
|
* On failure, an implicit devfs_put() is performed on %de.
|
1024 |
|
|
*/
|
1025 |
|
|
|
1026 |
|
|
static int _devfs_append_entry (devfs_handle_t dir, devfs_handle_t de,
|
1027 |
|
|
int removable, devfs_handle_t *old_de)
|
1028 |
|
|
{
|
1029 |
|
|
int retval;
|
1030 |
|
|
|
1031 |
|
|
if (old_de) *old_de = NULL;
|
1032 |
|
|
if ( !S_ISDIR (dir->mode) )
|
1033 |
|
|
{
|
1034 |
|
|
PRINTK ("(%s): dir: \"%s\" is not a directory\n", de->name, dir->name);
|
1035 |
|
|
devfs_put (de);
|
1036 |
|
|
return -ENOTDIR;
|
1037 |
|
|
}
|
1038 |
|
|
write_lock (&dir->u.dir.lock);
|
1039 |
|
|
if (dir->u.dir.no_more_additions) retval = -ENOENT;
|
1040 |
|
|
else
|
1041 |
|
|
{
|
1042 |
|
|
struct devfs_entry *old;
|
1043 |
|
|
|
1044 |
|
|
old = _devfs_search_dir (dir, de->name, de->namelen);
|
1045 |
|
|
if (old_de) *old_de = old;
|
1046 |
|
|
else devfs_put (old);
|
1047 |
|
|
if (old == NULL)
|
1048 |
|
|
{
|
1049 |
|
|
de->parent = dir;
|
1050 |
|
|
de->prev = dir->u.dir.last;
|
1051 |
|
|
/* Append to the directory's list of children */
|
1052 |
|
|
if (dir->u.dir.first == NULL) dir->u.dir.first = de;
|
1053 |
|
|
else dir->u.dir.last->next = de;
|
1054 |
|
|
dir->u.dir.last = de;
|
1055 |
|
|
if (removable) ++dir->u.dir.num_removable;
|
1056 |
|
|
retval = 0;
|
1057 |
|
|
}
|
1058 |
|
|
else retval = -EEXIST;
|
1059 |
|
|
}
|
1060 |
|
|
write_unlock (&dir->u.dir.lock);
|
1061 |
|
|
if (retval) devfs_put (de);
|
1062 |
|
|
return retval;
|
1063 |
|
|
} /* End Function _devfs_append_entry */
|
1064 |
|
|
|
1065 |
|
|
|
1066 |
|
|
/**
|
1067 |
|
|
* _devfs_get_root_entry - Get the root devfs entry.
|
1068 |
|
|
*
|
1069 |
|
|
* Returns the root devfs entry on success, else %NULL.
|
1070 |
|
|
*/
|
1071 |
|
|
|
1072 |
|
|
static struct devfs_entry *_devfs_get_root_entry (void)
|
1073 |
|
|
{
|
1074 |
|
|
kdev_t devnum;
|
1075 |
|
|
struct devfs_entry *new;
|
1076 |
|
|
static spinlock_t root_lock = SPIN_LOCK_UNLOCKED;
|
1077 |
|
|
|
1078 |
|
|
/* Always ensure the root is created */
|
1079 |
|
|
if (root_entry) return root_entry;
|
1080 |
|
|
if ( ( new = _devfs_alloc_entry (NULL, 0,MODE_DIR) ) == NULL ) return NULL;
|
1081 |
|
|
spin_lock (&root_lock);
|
1082 |
|
|
if (root_entry)
|
1083 |
|
|
{
|
1084 |
|
|
spin_unlock (&root_lock);
|
1085 |
|
|
devfs_put (new);
|
1086 |
|
|
return (root_entry);
|
1087 |
|
|
}
|
1088 |
|
|
root_entry = new;
|
1089 |
|
|
spin_unlock (&root_lock);
|
1090 |
|
|
/* And create the entry for ".devfsd" */
|
1091 |
|
|
if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) )
|
1092 |
|
|
== NULL ) return NULL;
|
1093 |
|
|
devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
|
1094 |
|
|
new->u.fcb.u.device.major = major (devnum);
|
1095 |
|
|
new->u.fcb.u.device.minor = minor (devnum);
|
1096 |
|
|
new->u.fcb.ops = &devfsd_fops;
|
1097 |
|
|
_devfs_append_entry (root_entry, new, FALSE, NULL);
|
1098 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
1099 |
|
|
if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) )
|
1100 |
|
|
== NULL ) return NULL;
|
1101 |
|
|
devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR);
|
1102 |
|
|
new->u.fcb.u.device.major = major (devnum);
|
1103 |
|
|
new->u.fcb.u.device.minor = minor (devnum);
|
1104 |
|
|
new->u.fcb.ops = &stat_fops;
|
1105 |
|
|
_devfs_append_entry (root_entry, new, FALSE, NULL);
|
1106 |
|
|
#endif
|
1107 |
|
|
return root_entry;
|
1108 |
|
|
} /* End Function _devfs_get_root_entry */
|
1109 |
|
|
|
1110 |
|
|
|
1111 |
|
|
/**
|
1112 |
|
|
* _devfs_descend - Descend down a tree using the next component name.
|
1113 |
|
|
* @dir: The directory to search.
|
1114 |
|
|
* @name: The component name to search for.
|
1115 |
|
|
* @namelen: The length of %name.
|
1116 |
|
|
* @next_pos: The position of the next '/' or '\0' is written here.
|
1117 |
|
|
*
|
1118 |
|
|
* Descend into a directory, searching for a component. This function forms
|
1119 |
|
|
* the core of a tree-walking algorithm. The directory will be locked.
|
1120 |
|
|
* The devfs entry corresponding to the component is returned. If there is
|
1121 |
|
|
* no matching entry, %NULL is returned.
|
1122 |
|
|
* An implicit devfs_get() is performed on the returned entry.
|
1123 |
|
|
*/
|
1124 |
|
|
|
1125 |
|
|
static struct devfs_entry *_devfs_descend (struct devfs_entry *dir,
|
1126 |
|
|
const char *name, int namelen,
|
1127 |
|
|
int *next_pos)
|
1128 |
|
|
{
|
1129 |
|
|
const char *stop, *ptr;
|
1130 |
|
|
struct devfs_entry *entry;
|
1131 |
|
|
|
1132 |
|
|
if ( (namelen >= 3) && (strncmp (name, "../", 3) == 0) )
|
1133 |
|
|
{ /* Special-case going to parent directory */
|
1134 |
|
|
*next_pos = 3;
|
1135 |
|
|
return devfs_get (dir->parent);
|
1136 |
|
|
}
|
1137 |
|
|
stop = name + namelen;
|
1138 |
|
|
/* Search for a possible '/' */
|
1139 |
|
|
for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr);
|
1140 |
|
|
*next_pos = ptr - name;
|
1141 |
|
|
read_lock (&dir->u.dir.lock);
|
1142 |
|
|
entry = _devfs_search_dir (dir, name, *next_pos);
|
1143 |
|
|
read_unlock (&dir->u.dir.lock);
|
1144 |
|
|
return entry;
|
1145 |
|
|
} /* End Function _devfs_descend */
|
1146 |
|
|
|
1147 |
|
|
|
1148 |
|
|
static devfs_handle_t _devfs_make_parent_for_leaf (struct devfs_entry *dir,
|
1149 |
|
|
const char *name,
|
1150 |
|
|
int namelen, int *leaf_pos)
|
1151 |
|
|
{
|
1152 |
|
|
int next_pos = 0;
|
1153 |
|
|
|
1154 |
|
|
if (dir == NULL) dir = _devfs_get_root_entry ();
|
1155 |
|
|
if (dir == NULL) return NULL;
|
1156 |
|
|
devfs_get (dir);
|
1157 |
|
|
/* Search for possible trailing component and ignore it */
|
1158 |
|
|
for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen);
|
1159 |
|
|
*leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0;
|
1160 |
|
|
for (; namelen > 0; name += next_pos, namelen -= next_pos)
|
1161 |
|
|
{
|
1162 |
|
|
struct devfs_entry *de, *old;
|
1163 |
|
|
|
1164 |
|
|
if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL )
|
1165 |
|
|
{
|
1166 |
|
|
de = _devfs_alloc_entry (name, next_pos, MODE_DIR);
|
1167 |
|
|
devfs_get (de);
|
1168 |
|
|
if ( !de || _devfs_append_entry (dir, de, FALSE, &old) )
|
1169 |
|
|
{
|
1170 |
|
|
devfs_put (de);
|
1171 |
|
|
if ( !old || !S_ISDIR (old->mode) )
|
1172 |
|
|
{
|
1173 |
|
|
devfs_put (old);
|
1174 |
|
|
devfs_put (dir);
|
1175 |
|
|
return NULL;
|
1176 |
|
|
}
|
1177 |
|
|
de = old; /* Use the existing directory */
|
1178 |
|
|
}
|
1179 |
|
|
}
|
1180 |
|
|
if (de == dir->parent)
|
1181 |
|
|
{
|
1182 |
|
|
devfs_put (dir);
|
1183 |
|
|
devfs_put (de);
|
1184 |
|
|
return NULL;
|
1185 |
|
|
}
|
1186 |
|
|
devfs_put (dir);
|
1187 |
|
|
dir = de;
|
1188 |
|
|
if (name[next_pos] == '/') ++next_pos;
|
1189 |
|
|
}
|
1190 |
|
|
return dir;
|
1191 |
|
|
} /* End Function _devfs_make_parent_for_leaf */
|
1192 |
|
|
|
1193 |
|
|
|
1194 |
|
|
static devfs_handle_t _devfs_prepare_leaf (devfs_handle_t *dir,
|
1195 |
|
|
const char *name, umode_t mode)
|
1196 |
|
|
{
|
1197 |
|
|
int namelen, leaf_pos;
|
1198 |
|
|
struct devfs_entry *de;
|
1199 |
|
|
|
1200 |
|
|
namelen = strlen (name);
|
1201 |
|
|
if ( ( *dir = _devfs_make_parent_for_leaf (*dir, name, namelen,
|
1202 |
|
|
&leaf_pos) ) == NULL )
|
1203 |
|
|
{
|
1204 |
|
|
PRINTK ("(%s): could not create parent path\n", name);
|
1205 |
|
|
return NULL;
|
1206 |
|
|
}
|
1207 |
|
|
if ( ( de = _devfs_alloc_entry (name + leaf_pos, namelen - leaf_pos,mode) )
|
1208 |
|
|
== NULL )
|
1209 |
|
|
{
|
1210 |
|
|
PRINTK ("(%s): could not allocate entry\n", name);
|
1211 |
|
|
devfs_put (*dir);
|
1212 |
|
|
return NULL;
|
1213 |
|
|
}
|
1214 |
|
|
return de;
|
1215 |
|
|
} /* End Function _devfs_prepare_leaf */
|
1216 |
|
|
|
1217 |
|
|
|
1218 |
|
|
static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir,
|
1219 |
|
|
const char *name, int namelen,
|
1220 |
|
|
int traverse_symlink)
|
1221 |
|
|
{
|
1222 |
|
|
int next_pos = 0;
|
1223 |
|
|
|
1224 |
|
|
if (dir == NULL) dir = _devfs_get_root_entry ();
|
1225 |
|
|
if (dir == NULL) return NULL;
|
1226 |
|
|
devfs_get (dir);
|
1227 |
|
|
for (; namelen > 0; name += next_pos, namelen -= next_pos)
|
1228 |
|
|
{
|
1229 |
|
|
struct devfs_entry *de, *link;
|
1230 |
|
|
|
1231 |
|
|
if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL )
|
1232 |
|
|
{
|
1233 |
|
|
devfs_put (dir);
|
1234 |
|
|
return NULL;
|
1235 |
|
|
}
|
1236 |
|
|
if (S_ISLNK (de->mode) && traverse_symlink)
|
1237 |
|
|
{ /* Need to follow the link: this is a stack chomper */
|
1238 |
|
|
link = _devfs_walk_path (dir, de->u.symlink.linkname,
|
1239 |
|
|
de->u.symlink.length, TRUE);
|
1240 |
|
|
devfs_put (de);
|
1241 |
|
|
if (!link)
|
1242 |
|
|
{
|
1243 |
|
|
devfs_put (dir);
|
1244 |
|
|
return NULL;
|
1245 |
|
|
}
|
1246 |
|
|
de = link;
|
1247 |
|
|
}
|
1248 |
|
|
devfs_put (dir);
|
1249 |
|
|
dir = de;
|
1250 |
|
|
if (name[next_pos] == '/') ++next_pos;
|
1251 |
|
|
}
|
1252 |
|
|
return dir;
|
1253 |
|
|
} /* End Function _devfs_walk_path */
|
1254 |
|
|
|
1255 |
|
|
|
1256 |
|
|
/**
|
1257 |
|
|
* _devfs_find_by_dev - Find a devfs entry in a directory.
|
1258 |
|
|
* @dir: The directory where to search
|
1259 |
|
|
* @major: The major number to search for.
|
1260 |
|
|
* @minor: The minor number to search for.
|
1261 |
|
|
* @type: The type of special file to search for. This may be either
|
1262 |
|
|
* %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
|
1263 |
|
|
*
|
1264 |
|
|
* Returns the devfs_entry pointer on success, else %NULL. An implicit
|
1265 |
|
|
* devfs_get() is performed.
|
1266 |
|
|
*/
|
1267 |
|
|
|
1268 |
|
|
static struct devfs_entry *_devfs_find_by_dev (struct devfs_entry *dir,
|
1269 |
|
|
unsigned int major,
|
1270 |
|
|
unsigned int minor, char type)
|
1271 |
|
|
{
|
1272 |
|
|
struct devfs_entry *entry, *de;
|
1273 |
|
|
|
1274 |
|
|
devfs_get (dir);
|
1275 |
|
|
if (dir == NULL) return NULL;
|
1276 |
|
|
if ( !S_ISDIR (dir->mode) )
|
1277 |
|
|
{
|
1278 |
|
|
PRINTK ("(%p): not a directory\n", dir);
|
1279 |
|
|
devfs_put (dir);
|
1280 |
|
|
return NULL;
|
1281 |
|
|
}
|
1282 |
|
|
/* First search files in this directory */
|
1283 |
|
|
read_lock (&dir->u.dir.lock);
|
1284 |
|
|
for (entry = dir->u.dir.first; entry != NULL; entry = entry->next)
|
1285 |
|
|
{
|
1286 |
|
|
if ( !S_ISCHR (entry->mode) && !S_ISBLK (entry->mode) ) continue;
|
1287 |
|
|
if ( S_ISCHR (entry->mode) && (type != DEVFS_SPECIAL_CHR) ) continue;
|
1288 |
|
|
if ( S_ISBLK (entry->mode) && (type != DEVFS_SPECIAL_BLK) ) continue;
|
1289 |
|
|
if ( (entry->u.fcb.u.device.major == major) &&
|
1290 |
|
|
(entry->u.fcb.u.device.minor == minor) )
|
1291 |
|
|
{
|
1292 |
|
|
devfs_get (entry);
|
1293 |
|
|
read_unlock (&dir->u.dir.lock);
|
1294 |
|
|
devfs_put (dir);
|
1295 |
|
|
return entry;
|
1296 |
|
|
}
|
1297 |
|
|
/* Not found: try the next one */
|
1298 |
|
|
}
|
1299 |
|
|
/* Now recursively search the subdirectories: this is a stack chomper */
|
1300 |
|
|
for (entry = dir->u.dir.first; entry != NULL; entry = entry->next)
|
1301 |
|
|
{
|
1302 |
|
|
if ( !S_ISDIR (entry->mode) ) continue;
|
1303 |
|
|
de = _devfs_find_by_dev (entry, major, minor, type);
|
1304 |
|
|
if (de)
|
1305 |
|
|
{
|
1306 |
|
|
read_unlock (&dir->u.dir.lock);
|
1307 |
|
|
devfs_put (dir);
|
1308 |
|
|
return de;
|
1309 |
|
|
}
|
1310 |
|
|
}
|
1311 |
|
|
read_unlock (&dir->u.dir.lock);
|
1312 |
|
|
devfs_put (dir);
|
1313 |
|
|
return NULL;
|
1314 |
|
|
} /* End Function _devfs_find_by_dev */
|
1315 |
|
|
|
1316 |
|
|
|
1317 |
|
|
/**
|
1318 |
|
|
* _devfs_find_entry - Find a devfs entry.
|
1319 |
|
|
* @dir: The handle to the parent devfs directory entry. If this is %NULL the
|
1320 |
|
|
* name is relative to the root of the devfs.
|
1321 |
|
|
* @name: The name of the entry. This may be %NULL.
|
1322 |
|
|
* @major: The major number. This is used if lookup by @name fails.
|
1323 |
|
|
* @minor: The minor number. This is used if lookup by @name fails.
|
1324 |
|
|
* NOTE: If @major and @minor are both 0, searching by major and minor
|
1325 |
|
|
* numbers is disabled.
|
1326 |
|
|
* @type: The type of special file to search for. This may be either
|
1327 |
|
|
* %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
|
1328 |
|
|
* @traverse_symlink: If %TRUE then symbolic links are traversed.
|
1329 |
|
|
*
|
1330 |
|
|
* Returns the devfs_entry pointer on success, else %NULL. An implicit
|
1331 |
|
|
* devfs_get() is performed.
|
1332 |
|
|
*/
|
1333 |
|
|
|
1334 |
|
|
static struct devfs_entry *_devfs_find_entry (devfs_handle_t dir,
|
1335 |
|
|
const char *name,
|
1336 |
|
|
unsigned int major,
|
1337 |
|
|
unsigned int minor,
|
1338 |
|
|
char type, int traverse_symlink)
|
1339 |
|
|
{
|
1340 |
|
|
struct devfs_entry *entry;
|
1341 |
|
|
|
1342 |
|
|
if (name != NULL)
|
1343 |
|
|
{
|
1344 |
|
|
unsigned int namelen = strlen (name);
|
1345 |
|
|
|
1346 |
|
|
if (name[0] == '/')
|
1347 |
|
|
{
|
1348 |
|
|
/* Skip leading pathname component */
|
1349 |
|
|
if (namelen < 2)
|
1350 |
|
|
{
|
1351 |
|
|
PRINTK ("(%s): too short\n", name);
|
1352 |
|
|
return NULL;
|
1353 |
|
|
}
|
1354 |
|
|
for (++name, --namelen; (*name != '/') && (namelen > 0);
|
1355 |
|
|
++name, --namelen);
|
1356 |
|
|
if (namelen < 2)
|
1357 |
|
|
{
|
1358 |
|
|
PRINTK ("(%s): too short\n", name);
|
1359 |
|
|
return NULL;
|
1360 |
|
|
}
|
1361 |
|
|
++name;
|
1362 |
|
|
--namelen;
|
1363 |
|
|
}
|
1364 |
|
|
entry = _devfs_walk_path (dir, name, namelen, traverse_symlink);
|
1365 |
|
|
if (entry != NULL) return entry;
|
1366 |
|
|
}
|
1367 |
|
|
/* Have to search by major and minor: slow */
|
1368 |
|
|
if ( (major == 0) && (minor == 0) ) return NULL;
|
1369 |
|
|
return _devfs_find_by_dev (root_entry, major, minor, type);
|
1370 |
|
|
} /* End Function _devfs_find_entry */
|
1371 |
|
|
|
1372 |
|
|
static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode)
|
1373 |
|
|
{
|
1374 |
|
|
if (inode == NULL) return NULL;
|
1375 |
|
|
VERIFY_ENTRY ( (struct devfs_entry *) inode->u.generic_ip );
|
1376 |
|
|
return inode->u.generic_ip;
|
1377 |
|
|
} /* End Function get_devfs_entry_from_vfs_inode */
|
1378 |
|
|
|
1379 |
|
|
|
1380 |
|
|
/**
|
1381 |
|
|
* free_dentry - Free the dentry for a device entry and invalidate inode.
|
1382 |
|
|
* @de: The entry.
|
1383 |
|
|
*
|
1384 |
|
|
* This must only be called after the entry has been unhooked from it's
|
1385 |
|
|
* parent directory.
|
1386 |
|
|
*/
|
1387 |
|
|
|
1388 |
|
|
static void free_dentry (struct devfs_entry *de)
|
1389 |
|
|
{
|
1390 |
|
|
struct dentry *dentry = de->inode.dentry;
|
1391 |
|
|
|
1392 |
|
|
if (!dentry) return;
|
1393 |
|
|
spin_lock (&dcache_lock);
|
1394 |
|
|
dget_locked (dentry);
|
1395 |
|
|
spin_unlock (&dcache_lock);
|
1396 |
|
|
/* Forcefully remove the inode */
|
1397 |
|
|
if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0;
|
1398 |
|
|
d_drop (dentry);
|
1399 |
|
|
dput (dentry);
|
1400 |
|
|
} /* End Function free_dentry */
|
1401 |
|
|
|
1402 |
|
|
|
1403 |
|
|
/**
|
1404 |
|
|
* is_devfsd_or_child - Test if the current process is devfsd or one of its children.
|
1405 |
|
|
* @fs_info: The filesystem information.
|
1406 |
|
|
*
|
1407 |
|
|
* Returns %TRUE if devfsd or child, else %FALSE.
|
1408 |
|
|
*/
|
1409 |
|
|
|
1410 |
|
|
static int is_devfsd_or_child (struct fs_info *fs_info)
|
1411 |
|
|
{
|
1412 |
|
|
struct task_struct *p;
|
1413 |
|
|
|
1414 |
|
|
if (current == fs_info->devfsd_task) return (TRUE);
|
1415 |
|
|
if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
|
1416 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)
|
1417 |
|
|
for (p = current->p_opptr; p != &init_task; p = p->p_opptr)
|
1418 |
|
|
{
|
1419 |
|
|
if (p == fs_info->devfsd_task) return (TRUE);
|
1420 |
|
|
}
|
1421 |
|
|
#endif
|
1422 |
|
|
return (FALSE);
|
1423 |
|
|
} /* End Function is_devfsd_or_child */
|
1424 |
|
|
|
1425 |
|
|
|
1426 |
|
|
/**
|
1427 |
|
|
* devfsd_queue_empty - Test if devfsd has work pending in its event queue.
|
1428 |
|
|
* @fs_info: The filesystem information.
|
1429 |
|
|
*
|
1430 |
|
|
* Returns %TRUE if the queue is empty, else %FALSE.
|
1431 |
|
|
*/
|
1432 |
|
|
|
1433 |
|
|
static inline int devfsd_queue_empty (struct fs_info *fs_info)
|
1434 |
|
|
{
|
1435 |
|
|
return (fs_info->devfsd_last_event) ? FALSE : TRUE;
|
1436 |
|
|
} /* End Function devfsd_queue_empty */
|
1437 |
|
|
|
1438 |
|
|
|
1439 |
|
|
/**
|
1440 |
|
|
* wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue.
|
1441 |
|
|
* @fs_info: The filesystem information.
|
1442 |
|
|
*
|
1443 |
|
|
* Returns %TRUE if no more waiting will be required, else %FALSE.
|
1444 |
|
|
*/
|
1445 |
|
|
|
1446 |
|
|
static int wait_for_devfsd_finished (struct fs_info *fs_info)
|
1447 |
|
|
{
|
1448 |
|
|
DECLARE_WAITQUEUE (wait, current);
|
1449 |
|
|
|
1450 |
|
|
if (fs_info->devfsd_task == NULL) return (TRUE);
|
1451 |
|
|
if (devfsd_queue_empty (fs_info) && fs_info->devfsd_sleeping) return TRUE;
|
1452 |
|
|
if ( is_devfsd_or_child (fs_info) ) return (FALSE);
|
1453 |
|
|
set_current_state (TASK_UNINTERRUPTIBLE);
|
1454 |
|
|
add_wait_queue (&fs_info->revalidate_wait_queue, &wait);
|
1455 |
|
|
if (!devfsd_queue_empty (fs_info) || !fs_info->devfsd_sleeping)
|
1456 |
|
|
if (fs_info->devfsd_task) schedule ();
|
1457 |
|
|
remove_wait_queue (&fs_info->revalidate_wait_queue, &wait);
|
1458 |
|
|
__set_current_state (TASK_RUNNING);
|
1459 |
|
|
return (TRUE);
|
1460 |
|
|
} /* End Function wait_for_devfsd_finished */
|
1461 |
|
|
|
1462 |
|
|
|
1463 |
|
|
/**
|
1464 |
|
|
* devfsd_notify_de - Notify the devfsd daemon of a change.
|
1465 |
|
|
* @de: The devfs entry that has changed. This and all parent entries will
|
1466 |
|
|
* have their reference counts incremented if the event was queued.
|
1467 |
|
|
* @type: The type of change.
|
1468 |
|
|
* @mode: The mode of the entry.
|
1469 |
|
|
* @uid: The user ID.
|
1470 |
|
|
* @gid: The group ID.
|
1471 |
|
|
* @fs_info: The filesystem info.
|
1472 |
|
|
*
|
1473 |
|
|
* Returns %TRUE if an event was queued and devfsd woken up, else %FALSE.
|
1474 |
|
|
*/
|
1475 |
|
|
|
1476 |
|
|
static int devfsd_notify_de (struct devfs_entry *de,
|
1477 |
|
|
unsigned short type, umode_t mode,
|
1478 |
|
|
uid_t uid, gid_t gid, struct fs_info *fs_info,
|
1479 |
|
|
int atomic)
|
1480 |
|
|
{
|
1481 |
|
|
struct devfsd_buf_entry *entry;
|
1482 |
|
|
struct devfs_entry *curr;
|
1483 |
|
|
|
1484 |
|
|
if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE);
|
1485 |
|
|
if ( ( entry = kmem_cache_alloc (devfsd_buf_cache,
|
1486 |
|
|
atomic ? SLAB_ATOMIC : SLAB_KERNEL) )
|
1487 |
|
|
== NULL )
|
1488 |
|
|
{
|
1489 |
|
|
atomic_inc (&fs_info->devfsd_overrun_count);
|
1490 |
|
|
return (FALSE);
|
1491 |
|
|
}
|
1492 |
|
|
for (curr = de; curr != NULL; curr = curr->parent) devfs_get (curr);
|
1493 |
|
|
entry->de = de;
|
1494 |
|
|
entry->type = type;
|
1495 |
|
|
entry->mode = mode;
|
1496 |
|
|
entry->uid = uid;
|
1497 |
|
|
entry->gid = gid;
|
1498 |
|
|
entry->next = NULL;
|
1499 |
|
|
spin_lock (&fs_info->devfsd_buffer_lock);
|
1500 |
|
|
if (!fs_info->devfsd_first_event) fs_info->devfsd_first_event = entry;
|
1501 |
|
|
if (fs_info->devfsd_last_event) fs_info->devfsd_last_event->next = entry;
|
1502 |
|
|
fs_info->devfsd_last_event = entry;
|
1503 |
|
|
spin_unlock (&fs_info->devfsd_buffer_lock);
|
1504 |
|
|
wake_up_interruptible (&fs_info->devfsd_wait_queue);
|
1505 |
|
|
return (TRUE);
|
1506 |
|
|
} /* End Function devfsd_notify_de */
|
1507 |
|
|
|
1508 |
|
|
|
1509 |
|
|
/**
|
1510 |
|
|
* devfsd_notify - Notify the devfsd daemon of a change.
|
1511 |
|
|
* @de: The devfs entry that has changed.
|
1512 |
|
|
* @type: The type of change event.
|
1513 |
|
|
* @wait: If TRUE, the function waits for the daemon to finish processing
|
1514 |
|
|
* the event.
|
1515 |
|
|
*/
|
1516 |
|
|
|
1517 |
|
|
static void devfsd_notify (struct devfs_entry *de,unsigned short type,int wait)
|
1518 |
|
|
{
|
1519 |
|
|
if (devfsd_notify_de (de, type, de->mode, current->euid,
|
1520 |
|
|
current->egid, &fs_info, 0) && wait)
|
1521 |
|
|
wait_for_devfsd_finished (&fs_info);
|
1522 |
|
|
} /* End Function devfsd_notify */
|
1523 |
|
|
|
1524 |
|
|
|
1525 |
|
|
/**
|
1526 |
|
|
* devfs_register - Register a device entry.
|
1527 |
|
|
* @dir: The handle to the parent devfs directory entry. If this is %NULL the
|
1528 |
|
|
* new name is relative to the root of the devfs.
|
1529 |
|
|
* @name: The name of the entry.
|
1530 |
|
|
* @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
|
1531 |
|
|
* @major: The major number. Not needed for regular files.
|
1532 |
|
|
* @minor: The minor number. Not needed for regular files.
|
1533 |
|
|
* @mode: The default file mode.
|
1534 |
|
|
* @ops: The &file_operations or &block_device_operations structure.
|
1535 |
|
|
* This must not be externally deallocated.
|
1536 |
|
|
* @info: An arbitrary pointer which will be written to the @private_data
|
1537 |
|
|
* field of the &file structure passed to the device driver. You can set
|
1538 |
|
|
* this to whatever you like, and change it once the file is opened (the next
|
1539 |
|
|
* file opened will not see this change).
|
1540 |
|
|
*
|
1541 |
|
|
* Returns a handle which may later be used in a call to devfs_unregister().
|
1542 |
|
|
* On failure %NULL is returned.
|
1543 |
|
|
*/
|
1544 |
|
|
|
1545 |
|
|
devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
|
1546 |
|
|
unsigned int flags,
|
1547 |
|
|
unsigned int major, unsigned int minor,
|
1548 |
|
|
umode_t mode, void *ops, void *info)
|
1549 |
|
|
{
|
1550 |
|
|
char devtype = S_ISCHR (mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK;
|
1551 |
|
|
int err;
|
1552 |
|
|
kdev_t devnum = NODEV;
|
1553 |
|
|
struct devfs_entry *de;
|
1554 |
|
|
|
1555 |
|
|
if (name == NULL)
|
1556 |
|
|
{
|
1557 |
|
|
PRINTK ("(): NULL name pointer\n");
|
1558 |
|
|
return NULL;
|
1559 |
|
|
}
|
1560 |
|
|
if (ops == NULL)
|
1561 |
|
|
{
|
1562 |
|
|
if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major);
|
1563 |
|
|
if (ops == NULL)
|
1564 |
|
|
{
|
1565 |
|
|
PRINTK ("(%s): NULL ops pointer\n", name);
|
1566 |
|
|
return NULL;
|
1567 |
|
|
}
|
1568 |
|
|
PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops);
|
1569 |
|
|
}
|
1570 |
|
|
if ( S_ISDIR (mode) )
|
1571 |
|
|
{
|
1572 |
|
|
PRINTK ("(%s): creating directories is not allowed\n", name);
|
1573 |
|
|
return NULL;
|
1574 |
|
|
}
|
1575 |
|
|
if ( S_ISLNK (mode) )
|
1576 |
|
|
{
|
1577 |
|
|
PRINTK ("(%s): creating symlinks is not allowed\n", name);
|
1578 |
|
|
return NULL;
|
1579 |
|
|
}
|
1580 |
|
|
if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) &&
|
1581 |
|
|
(flags & DEVFS_FL_AUTO_DEVNUM) )
|
1582 |
|
|
{
|
1583 |
|
|
if ( kdev_none ( devnum = devfs_alloc_devnum (devtype) ) )
|
1584 |
|
|
{
|
1585 |
|
|
PRINTK ("(%s): exhausted %s device numbers\n",
|
1586 |
|
|
name, S_ISCHR (mode) ? "char" : "block");
|
1587 |
|
|
return NULL;
|
1588 |
|
|
}
|
1589 |
|
|
major = major (devnum);
|
1590 |
|
|
minor = minor (devnum);
|
1591 |
|
|
}
|
1592 |
|
|
if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
|
1593 |
|
|
{
|
1594 |
|
|
PRINTK ("(%s): could not prepare leaf\n", name);
|
1595 |
|
|
if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
|
1596 |
|
|
return NULL;
|
1597 |
|
|
}
|
1598 |
|
|
if ( S_ISCHR (mode) || S_ISBLK (mode) )
|
1599 |
|
|
{
|
1600 |
|
|
de->u.fcb.u.device.major = major;
|
1601 |
|
|
de->u.fcb.u.device.minor = minor;
|
1602 |
|
|
de->u.fcb.autogen = kdev_none (devnum) ? FALSE : TRUE;
|
1603 |
|
|
}
|
1604 |
|
|
else if ( !S_ISREG (mode) )
|
1605 |
|
|
{
|
1606 |
|
|
PRINTK ("(%s): illegal mode: %x\n", name, mode);
|
1607 |
|
|
devfs_put (de);
|
1608 |
|
|
devfs_put (dir);
|
1609 |
|
|
return (NULL);
|
1610 |
|
|
}
|
1611 |
|
|
de->info = info;
|
1612 |
|
|
if (flags & DEVFS_FL_CURRENT_OWNER)
|
1613 |
|
|
{
|
1614 |
|
|
de->inode.uid = current->uid;
|
1615 |
|
|
de->inode.gid = current->gid;
|
1616 |
|
|
}
|
1617 |
|
|
else
|
1618 |
|
|
{
|
1619 |
|
|
de->inode.uid = 0;
|
1620 |
|
|
de->inode.gid = 0;
|
1621 |
|
|
}
|
1622 |
|
|
de->u.fcb.ops = ops;
|
1623 |
|
|
de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
|
1624 |
|
|
de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE;
|
1625 |
|
|
de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
|
1626 |
|
|
if (flags & DEVFS_FL_REMOVABLE) de->u.fcb.removable = TRUE;
|
1627 |
|
|
if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) )
|
1628 |
|
|
!= 0 )
|
1629 |
|
|
{
|
1630 |
|
|
PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
|
1631 |
|
|
devfs_put (dir);
|
1632 |
|
|
if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
|
1633 |
|
|
return NULL;
|
1634 |
|
|
}
|
1635 |
|
|
DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\" pp: %p\n",
|
1636 |
|
|
name, de, dir, dir->name, dir->parent);
|
1637 |
|
|
devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
|
1638 |
|
|
devfs_put (dir);
|
1639 |
|
|
return de;
|
1640 |
|
|
} /* End Function devfs_register */
|
1641 |
|
|
|
1642 |
|
|
|
1643 |
|
|
/**
|
1644 |
|
|
* _devfs_unhook - Unhook a device entry from its parents list
|
1645 |
|
|
* @de: The entry to unhook.
|
1646 |
|
|
*
|
1647 |
|
|
* Returns %TRUE if the entry was unhooked, else %FALSE if it was
|
1648 |
|
|
* previously unhooked.
|
1649 |
|
|
* The caller must have a write lock on the parent directory.
|
1650 |
|
|
*/
|
1651 |
|
|
|
1652 |
|
|
static int _devfs_unhook (struct devfs_entry *de)
|
1653 |
|
|
{
|
1654 |
|
|
struct devfs_entry *parent;
|
1655 |
|
|
|
1656 |
|
|
if ( !de || (de->prev == de) ) return FALSE;
|
1657 |
|
|
parent = de->parent;
|
1658 |
|
|
if (de->prev == NULL) parent->u.dir.first = de->next;
|
1659 |
|
|
else de->prev->next = de->next;
|
1660 |
|
|
if (de->next == NULL) parent->u.dir.last = de->prev;
|
1661 |
|
|
else de->next->prev = de->prev;
|
1662 |
|
|
de->prev = de; /* Indicate we're unhooked */
|
1663 |
|
|
de->next = NULL; /* Force early termination for <devfs_readdir> */
|
1664 |
|
|
if ( ( S_ISREG (de->mode) || S_ISCHR (de->mode) || S_ISBLK (de->mode) ) &&
|
1665 |
|
|
de->u.fcb.removable )
|
1666 |
|
|
--parent->u.dir.num_removable;
|
1667 |
|
|
return TRUE;
|
1668 |
|
|
} /* End Function _devfs_unhook */
|
1669 |
|
|
|
1670 |
|
|
|
1671 |
|
|
/**
|
1672 |
|
|
* _devfs_unregister - Unregister a device entry from it's parent.
|
1673 |
|
|
* @dir: The parent directory.
|
1674 |
|
|
* @de: The entry to unregister.
|
1675 |
|
|
*
|
1676 |
|
|
* The caller must have a write lock on the parent directory, which is
|
1677 |
|
|
* unlocked by this function.
|
1678 |
|
|
*/
|
1679 |
|
|
|
1680 |
|
|
static void _devfs_unregister (struct devfs_entry *dir, struct devfs_entry *de)
|
1681 |
|
|
{
|
1682 |
|
|
int unhooked = _devfs_unhook (de);
|
1683 |
|
|
|
1684 |
|
|
write_unlock (&dir->u.dir.lock);
|
1685 |
|
|
if (!unhooked) return;
|
1686 |
|
|
devfs_get (dir);
|
1687 |
|
|
devfs_unregister (de->slave); /* Let it handle the locking */
|
1688 |
|
|
devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0);
|
1689 |
|
|
free_dentry (de);
|
1690 |
|
|
devfs_put (dir);
|
1691 |
|
|
if ( !S_ISDIR (de->mode) ) return;
|
1692 |
|
|
while (TRUE) /* Recursively unregister: this is a stack chomper */
|
1693 |
|
|
{
|
1694 |
|
|
struct devfs_entry *child;
|
1695 |
|
|
|
1696 |
|
|
write_lock (&de->u.dir.lock);
|
1697 |
|
|
de->u.dir.no_more_additions = TRUE;
|
1698 |
|
|
child = de->u.dir.first;
|
1699 |
|
|
VERIFY_ENTRY (child);
|
1700 |
|
|
_devfs_unregister (de, child);
|
1701 |
|
|
if (!child) break;
|
1702 |
|
|
DPRINTK (DEBUG_UNREGISTER, "(%s): child: %p refcount: %d\n",
|
1703 |
|
|
child->name, child, atomic_read (&child->refcount) );
|
1704 |
|
|
devfs_put (child);
|
1705 |
|
|
}
|
1706 |
|
|
} /* End Function _devfs_unregister */
|
1707 |
|
|
|
1708 |
|
|
|
1709 |
|
|
/**
|
1710 |
|
|
* devfs_unregister - Unregister a device entry.
|
1711 |
|
|
* @de: A handle previously created by devfs_register() or returned from
|
1712 |
|
|
* devfs_get_handle(). If this is %NULL the routine does nothing.
|
1713 |
|
|
*/
|
1714 |
|
|
|
1715 |
|
|
void devfs_unregister (devfs_handle_t de)
|
1716 |
|
|
{
|
1717 |
|
|
VERIFY_ENTRY (de);
|
1718 |
|
|
if ( (de == NULL) || (de->parent == NULL) ) return;
|
1719 |
|
|
DPRINTK (DEBUG_UNREGISTER, "(%s): de: %p refcount: %d\n",
|
1720 |
|
|
de->name, de, atomic_read (&de->refcount) );
|
1721 |
|
|
write_lock (&de->parent->u.dir.lock);
|
1722 |
|
|
_devfs_unregister (de->parent, de);
|
1723 |
|
|
devfs_put (de);
|
1724 |
|
|
} /* End Function devfs_unregister */
|
1725 |
|
|
|
1726 |
|
|
static int devfs_do_symlink (devfs_handle_t dir, const char *name,
|
1727 |
|
|
unsigned int flags, const char *link,
|
1728 |
|
|
devfs_handle_t *handle, void *info)
|
1729 |
|
|
{
|
1730 |
|
|
int err;
|
1731 |
|
|
unsigned int linklength;
|
1732 |
|
|
char *newlink;
|
1733 |
|
|
struct devfs_entry *de;
|
1734 |
|
|
|
1735 |
|
|
if (handle != NULL) *handle = NULL;
|
1736 |
|
|
if (name == NULL)
|
1737 |
|
|
{
|
1738 |
|
|
PRINTK ("(): NULL name pointer\n");
|
1739 |
|
|
return -EINVAL;
|
1740 |
|
|
}
|
1741 |
|
|
if (link == NULL)
|
1742 |
|
|
{
|
1743 |
|
|
PRINTK ("(%s): NULL link pointer\n", name);
|
1744 |
|
|
return -EINVAL;
|
1745 |
|
|
}
|
1746 |
|
|
linklength = strlen (link);
|
1747 |
|
|
if ( ( newlink = kmalloc (linklength + 1, GFP_KERNEL) ) == NULL )
|
1748 |
|
|
return -ENOMEM;
|
1749 |
|
|
memcpy (newlink, link, linklength);
|
1750 |
|
|
newlink[linklength] = '\0';
|
1751 |
|
|
if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) )
|
1752 |
|
|
== NULL )
|
1753 |
|
|
{
|
1754 |
|
|
PRINTK ("(%s): could not prepare leaf\n", name);
|
1755 |
|
|
kfree (newlink);
|
1756 |
|
|
return -ENOTDIR;
|
1757 |
|
|
}
|
1758 |
|
|
de->info = info;
|
1759 |
|
|
de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
|
1760 |
|
|
de->u.symlink.linkname = newlink;
|
1761 |
|
|
de->u.symlink.length = linklength;
|
1762 |
|
|
if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 )
|
1763 |
|
|
{
|
1764 |
|
|
PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
|
1765 |
|
|
devfs_put (dir);
|
1766 |
|
|
return err;
|
1767 |
|
|
}
|
1768 |
|
|
devfs_put (dir);
|
1769 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
1770 |
|
|
spin_lock (&stat_lock);
|
1771 |
|
|
stat_num_bytes += linklength + 1;
|
1772 |
|
|
spin_unlock (&stat_lock);
|
1773 |
|
|
#endif
|
1774 |
|
|
if (handle != NULL) *handle = de;
|
1775 |
|
|
return 0;
|
1776 |
|
|
} /* End Function devfs_do_symlink */
|
1777 |
|
|
|
1778 |
|
|
|
1779 |
|
|
/**
|
1780 |
|
|
* devfs_mk_symlink Create a symbolic link in the devfs namespace.
|
1781 |
|
|
* @dir: The handle to the parent devfs directory entry. If this is %NULL the
|
1782 |
|
|
* new name is relative to the root of the devfs.
|
1783 |
|
|
* @name: The name of the entry.
|
1784 |
|
|
* @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
|
1785 |
|
|
* @link: The destination name.
|
1786 |
|
|
* @handle: The handle to the symlink entry is written here. This may be %NULL.
|
1787 |
|
|
* @info: An arbitrary pointer which will be associated with the entry.
|
1788 |
|
|
*
|
1789 |
|
|
* Returns 0 on success, else a negative error code is returned.
|
1790 |
|
|
*/
|
1791 |
|
|
|
1792 |
|
|
int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags,
|
1793 |
|
|
const char *link, devfs_handle_t *handle, void *info)
|
1794 |
|
|
{
|
1795 |
|
|
int err;
|
1796 |
|
|
devfs_handle_t de;
|
1797 |
|
|
|
1798 |
|
|
if (handle != NULL) *handle = NULL;
|
1799 |
|
|
DPRINTK (DEBUG_REGISTER, "(%s)\n", name);
|
1800 |
|
|
err = devfs_do_symlink (dir, name, flags, link, &de, info);
|
1801 |
|
|
if (err) return err;
|
1802 |
|
|
if (handle == NULL) de->vfs_deletable = TRUE;
|
1803 |
|
|
else *handle = de;
|
1804 |
|
|
devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
|
1805 |
|
|
return 0;
|
1806 |
|
|
} /* End Function devfs_mk_symlink */
|
1807 |
|
|
|
1808 |
|
|
|
1809 |
|
|
/**
|
1810 |
|
|
* devfs_mk_dir - Create a directory in the devfs namespace.
|
1811 |
|
|
* @dir: The handle to the parent devfs directory entry. If this is %NULL the
|
1812 |
|
|
* new name is relative to the root of the devfs.
|
1813 |
|
|
* @name: The name of the entry.
|
1814 |
|
|
* @info: An arbitrary pointer which will be associated with the entry.
|
1815 |
|
|
*
|
1816 |
|
|
* Use of this function is optional. The devfs_register() function
|
1817 |
|
|
* will automatically create intermediate directories as needed. This function
|
1818 |
|
|
* is provided for efficiency reasons, as it provides a handle to a directory.
|
1819 |
|
|
* Returns a handle which may later be used in a call to devfs_unregister().
|
1820 |
|
|
* On failure %NULL is returned.
|
1821 |
|
|
*/
|
1822 |
|
|
|
1823 |
|
|
devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info)
|
1824 |
|
|
{
|
1825 |
|
|
int err;
|
1826 |
|
|
struct devfs_entry *de, *old;
|
1827 |
|
|
|
1828 |
|
|
if (name == NULL)
|
1829 |
|
|
{
|
1830 |
|
|
PRINTK ("(): NULL name pointer\n");
|
1831 |
|
|
return NULL;
|
1832 |
|
|
}
|
1833 |
|
|
if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL )
|
1834 |
|
|
{
|
1835 |
|
|
PRINTK ("(%s): could not prepare leaf\n", name);
|
1836 |
|
|
return NULL;
|
1837 |
|
|
}
|
1838 |
|
|
de->info = info;
|
1839 |
|
|
if ( ( err = _devfs_append_entry (dir, de, FALSE, &old) ) != 0 )
|
1840 |
|
|
{
|
1841 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)
|
1842 |
|
|
if ( old && S_ISDIR (old->mode) )
|
1843 |
|
|
{
|
1844 |
|
|
PRINTK ("(%s): using old entry in dir: %p \"%s\"\n",
|
1845 |
|
|
name, dir, dir->name);
|
1846 |
|
|
old->vfs_deletable = FALSE;
|
1847 |
|
|
devfs_put (dir);
|
1848 |
|
|
return old;
|
1849 |
|
|
}
|
1850 |
|
|
#endif
|
1851 |
|
|
PRINTK ("(%s): could not append to dir: %p \"%s\", err: %d\n",
|
1852 |
|
|
name, dir, dir->name, err);
|
1853 |
|
|
devfs_put (old);
|
1854 |
|
|
devfs_put (dir);
|
1855 |
|
|
return NULL;
|
1856 |
|
|
}
|
1857 |
|
|
DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"\n",
|
1858 |
|
|
name, de, dir, dir->name);
|
1859 |
|
|
devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, 0);
|
1860 |
|
|
devfs_put (dir);
|
1861 |
|
|
return de;
|
1862 |
|
|
} /* End Function devfs_mk_dir */
|
1863 |
|
|
|
1864 |
|
|
|
1865 |
|
|
/**
|
1866 |
|
|
* devfs_get_handle - Find the handle of a devfs entry.
|
1867 |
|
|
* @dir: The handle to the parent devfs directory entry. If this is %NULL the
|
1868 |
|
|
* name is relative to the root of the devfs.
|
1869 |
|
|
* @name: The name of the entry.
|
1870 |
|
|
* @major: The major number. This is used if @name is %NULL.
|
1871 |
|
|
* @minor: The minor number. This is used if @name is %NULL.
|
1872 |
|
|
* @type: The type of special file to search for. This may be either
|
1873 |
|
|
* %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK.
|
1874 |
|
|
* @traverse_symlinks: If %TRUE then symlink entries in the devfs namespace are
|
1875 |
|
|
* traversed. Symlinks pointing out of the devfs namespace will cause a
|
1876 |
|
|
* failure. Symlink traversal consumes stack space.
|
1877 |
|
|
*
|
1878 |
|
|
* Returns a handle which may later be used in a call to
|
1879 |
|
|
* devfs_unregister(), devfs_get_flags(), or devfs_set_flags(). A
|
1880 |
|
|
* subsequent devfs_put() is required to decrement the refcount.
|
1881 |
|
|
* On failure %NULL is returned.
|
1882 |
|
|
*/
|
1883 |
|
|
|
1884 |
|
|
devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name,
|
1885 |
|
|
unsigned int major, unsigned int minor,
|
1886 |
|
|
char type, int traverse_symlinks)
|
1887 |
|
|
{
|
1888 |
|
|
if ( (name != NULL) && (name[0] == '\0') ) name = NULL;
|
1889 |
|
|
return _devfs_find_entry (dir, name, major, minor, type,traverse_symlinks);
|
1890 |
|
|
} /* End Function devfs_get_handle */
|
1891 |
|
|
|
1892 |
|
|
|
1893 |
|
|
/* Compatibility function. Will be removed in sometime in 2.5 */
|
1894 |
|
|
|
1895 |
|
|
devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name,
|
1896 |
|
|
unsigned int major, unsigned int minor,
|
1897 |
|
|
char type, int traverse_symlinks)
|
1898 |
|
|
{
|
1899 |
|
|
devfs_handle_t de;
|
1900 |
|
|
|
1901 |
|
|
de = devfs_get_handle (dir, name, major, minor, type, traverse_symlinks);
|
1902 |
|
|
devfs_put (de);
|
1903 |
|
|
return de;
|
1904 |
|
|
} /* End Function devfs_find_handle */
|
1905 |
|
|
|
1906 |
|
|
|
1907 |
|
|
/**
|
1908 |
|
|
* devfs_get_flags - Get the flags for a devfs entry.
|
1909 |
|
|
* @de: The handle to the device entry.
|
1910 |
|
|
* @flags: The flags are written here.
|
1911 |
|
|
*
|
1912 |
|
|
* Returns 0 on success, else a negative error code.
|
1913 |
|
|
*/
|
1914 |
|
|
|
1915 |
|
|
int devfs_get_flags (devfs_handle_t de, unsigned int *flags)
|
1916 |
|
|
{
|
1917 |
|
|
unsigned int fl = 0;
|
1918 |
|
|
|
1919 |
|
|
if (de == NULL) return -EINVAL;
|
1920 |
|
|
VERIFY_ENTRY (de);
|
1921 |
|
|
if (de->hide) fl |= DEVFS_FL_HIDE;
|
1922 |
|
|
if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
|
1923 |
|
|
{
|
1924 |
|
|
if (de->u.fcb.auto_owner) fl |= DEVFS_FL_AUTO_OWNER;
|
1925 |
|
|
if (de->u.fcb.aopen_notify) fl |= DEVFS_FL_AOPEN_NOTIFY;
|
1926 |
|
|
if (de->u.fcb.removable) fl |= DEVFS_FL_REMOVABLE;
|
1927 |
|
|
}
|
1928 |
|
|
*flags = fl;
|
1929 |
|
|
return 0;
|
1930 |
|
|
} /* End Function devfs_get_flags */
|
1931 |
|
|
|
1932 |
|
|
|
1933 |
|
|
/*
|
1934 |
|
|
* devfs_set_flags - Set the flags for a devfs entry.
|
1935 |
|
|
* @de: The handle to the device entry.
|
1936 |
|
|
* @flags: The flags to set. Unset flags are cleared.
|
1937 |
|
|
*
|
1938 |
|
|
* Returns 0 on success, else a negative error code.
|
1939 |
|
|
*/
|
1940 |
|
|
|
1941 |
|
|
int devfs_set_flags (devfs_handle_t de, unsigned int flags)
|
1942 |
|
|
{
|
1943 |
|
|
if (de == NULL) return -EINVAL;
|
1944 |
|
|
VERIFY_ENTRY (de);
|
1945 |
|
|
DPRINTK (DEBUG_SET_FLAGS, "(%s): flags: %x\n", de->name, flags);
|
1946 |
|
|
de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
|
1947 |
|
|
if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
|
1948 |
|
|
{
|
1949 |
|
|
de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
|
1950 |
|
|
de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE:FALSE;
|
1951 |
|
|
}
|
1952 |
|
|
return 0;
|
1953 |
|
|
} /* End Function devfs_set_flags */
|
1954 |
|
|
|
1955 |
|
|
|
1956 |
|
|
/**
|
1957 |
|
|
* devfs_get_maj_min - Get the major and minor numbers for a devfs entry.
|
1958 |
|
|
* @de: The handle to the device entry.
|
1959 |
|
|
* @major: The major number is written here. This may be %NULL.
|
1960 |
|
|
* @minor: The minor number is written here. This may be %NULL.
|
1961 |
|
|
*
|
1962 |
|
|
* Returns 0 on success, else a negative error code.
|
1963 |
|
|
*/
|
1964 |
|
|
|
1965 |
|
|
int devfs_get_maj_min (devfs_handle_t de, unsigned int *major,
|
1966 |
|
|
unsigned int *minor)
|
1967 |
|
|
{
|
1968 |
|
|
if (de == NULL) return -EINVAL;
|
1969 |
|
|
VERIFY_ENTRY (de);
|
1970 |
|
|
if ( S_ISDIR (de->mode) ) return -EISDIR;
|
1971 |
|
|
if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) ) return -EINVAL;
|
1972 |
|
|
if (major != NULL) *major = de->u.fcb.u.device.major;
|
1973 |
|
|
if (minor != NULL) *minor = de->u.fcb.u.device.minor;
|
1974 |
|
|
return 0;
|
1975 |
|
|
} /* End Function devfs_get_maj_min */
|
1976 |
|
|
|
1977 |
|
|
|
1978 |
|
|
/**
|
1979 |
|
|
* devfs_get_handle_from_inode - Get the devfs handle for a VFS inode.
|
1980 |
|
|
* @inode: The VFS inode.
|
1981 |
|
|
*
|
1982 |
|
|
* Returns the devfs handle on success, else %NULL.
|
1983 |
|
|
*/
|
1984 |
|
|
|
1985 |
|
|
devfs_handle_t devfs_get_handle_from_inode (struct inode *inode)
|
1986 |
|
|
{
|
1987 |
|
|
if (!inode || !inode->i_sb) return NULL;
|
1988 |
|
|
if (inode->i_sb->s_magic != DEVFS_SUPER_MAGIC) return NULL;
|
1989 |
|
|
return get_devfs_entry_from_vfs_inode (inode);
|
1990 |
|
|
} /* End Function devfs_get_handle_from_inode */
|
1991 |
|
|
|
1992 |
|
|
|
1993 |
|
|
/**
|
1994 |
|
|
* devfs_generate_path - Generate a pathname for an entry, relative to the devfs root.
|
1995 |
|
|
* @de: The devfs entry.
|
1996 |
|
|
* @path: The buffer to write the pathname to. The pathname and '\0'
|
1997 |
|
|
* terminator will be written at the end of the buffer.
|
1998 |
|
|
* @buflen: The length of the buffer.
|
1999 |
|
|
*
|
2000 |
|
|
* Returns the offset in the buffer where the pathname starts on success,
|
2001 |
|
|
* else a negative error code.
|
2002 |
|
|
*/
|
2003 |
|
|
|
2004 |
|
|
int devfs_generate_path (devfs_handle_t de, char *path, int buflen)
|
2005 |
|
|
{
|
2006 |
|
|
int pos;
|
2007 |
|
|
#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name )
|
2008 |
|
|
|
2009 |
|
|
if (de == NULL) return -EINVAL;
|
2010 |
|
|
VERIFY_ENTRY (de);
|
2011 |
|
|
if (de->namelen >= buflen) return -ENAMETOOLONG; /* Must be first */
|
2012 |
|
|
path[buflen - 1] = '\0';
|
2013 |
|
|
if (de->parent == NULL) return buflen - 1; /* Don't prepend root */
|
2014 |
|
|
pos = buflen - de->namelen - 1;
|
2015 |
|
|
memcpy (path + pos, NAMEOF (de), de->namelen);
|
2016 |
|
|
for (de = de->parent; de->parent != NULL; de = de->parent)
|
2017 |
|
|
{
|
2018 |
|
|
if (pos - de->namelen - 1 < 0) return -ENAMETOOLONG;
|
2019 |
|
|
path[--pos] = '/';
|
2020 |
|
|
pos -= de->namelen;
|
2021 |
|
|
memcpy (path + pos, NAMEOF (de), de->namelen);
|
2022 |
|
|
}
|
2023 |
|
|
return pos;
|
2024 |
|
|
} /* End Function devfs_generate_path */
|
2025 |
|
|
|
2026 |
|
|
|
2027 |
|
|
/**
|
2028 |
|
|
* devfs_get_ops - Get the device operations for a devfs entry.
|
2029 |
|
|
* @de: The handle to the device entry.
|
2030 |
|
|
*
|
2031 |
|
|
* Returns a pointer to the device operations on success, else NULL.
|
2032 |
|
|
* The use count for the module owning the operations will be incremented.
|
2033 |
|
|
*/
|
2034 |
|
|
|
2035 |
|
|
void *devfs_get_ops (devfs_handle_t de)
|
2036 |
|
|
{
|
2037 |
|
|
struct module *owner;
|
2038 |
|
|
|
2039 |
|
|
if (de == NULL) return NULL;
|
2040 |
|
|
VERIFY_ENTRY (de);
|
2041 |
|
|
if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
|
2042 |
|
|
return NULL;
|
2043 |
|
|
if (de->u.fcb.ops == NULL) return NULL;
|
2044 |
|
|
read_lock (&de->parent->u.dir.lock); /* Prevent module from unloading */
|
2045 |
|
|
if (de->next == de) owner = NULL; /* Ops pointer is already stale */
|
2046 |
|
|
else if ( S_ISCHR (de->mode) || S_ISREG (de->mode) )
|
2047 |
|
|
owner = ( (struct file_operations *) de->u.fcb.ops )->owner;
|
2048 |
|
|
else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner;
|
2049 |
|
|
if ( (de->next == de) || !try_inc_mod_count (owner) )
|
2050 |
|
|
{ /* Entry is already unhooked or module is unloading */
|
2051 |
|
|
read_unlock (&de->parent->u.dir.lock);
|
2052 |
|
|
return NULL;
|
2053 |
|
|
}
|
2054 |
|
|
read_unlock (&de->parent->u.dir.lock); /* Module can continue unloading*/
|
2055 |
|
|
return de->u.fcb.ops;
|
2056 |
|
|
} /* End Function devfs_get_ops */
|
2057 |
|
|
|
2058 |
|
|
|
2059 |
|
|
/**
|
2060 |
|
|
* devfs_put_ops - Put the device operations for a devfs entry.
|
2061 |
|
|
* @de: The handle to the device entry.
|
2062 |
|
|
*
|
2063 |
|
|
* The use count for the module owning the operations will be decremented.
|
2064 |
|
|
*/
|
2065 |
|
|
|
2066 |
|
|
void devfs_put_ops (devfs_handle_t de)
|
2067 |
|
|
{
|
2068 |
|
|
struct module *owner;
|
2069 |
|
|
|
2070 |
|
|
if (de == NULL) return;
|
2071 |
|
|
VERIFY_ENTRY (de);
|
2072 |
|
|
if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
|
2073 |
|
|
return;
|
2074 |
|
|
if (de->u.fcb.ops == NULL) return;
|
2075 |
|
|
if ( S_ISCHR (de->mode) || S_ISREG (de->mode) )
|
2076 |
|
|
owner = ( (struct file_operations *) de->u.fcb.ops )->owner;
|
2077 |
|
|
else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner;
|
2078 |
|
|
if (owner) __MOD_DEC_USE_COUNT (owner);
|
2079 |
|
|
} /* End Function devfs_put_ops */
|
2080 |
|
|
|
2081 |
|
|
|
2082 |
|
|
/**
|
2083 |
|
|
* devfs_set_file_size - Set the file size for a devfs regular file.
|
2084 |
|
|
* @de: The handle to the device entry.
|
2085 |
|
|
* @size: The new file size.
|
2086 |
|
|
*
|
2087 |
|
|
* Returns 0 on success, else a negative error code.
|
2088 |
|
|
*/
|
2089 |
|
|
|
2090 |
|
|
int devfs_set_file_size (devfs_handle_t de, unsigned long size)
|
2091 |
|
|
{
|
2092 |
|
|
if (de == NULL) return -EINVAL;
|
2093 |
|
|
VERIFY_ENTRY (de);
|
2094 |
|
|
if ( !S_ISREG (de->mode) ) return -EINVAL;
|
2095 |
|
|
if (de->u.fcb.u.file.size == size) return 0;
|
2096 |
|
|
de->u.fcb.u.file.size = size;
|
2097 |
|
|
if (de->inode.dentry == NULL) return 0;
|
2098 |
|
|
if (de->inode.dentry->d_inode == NULL) return 0;
|
2099 |
|
|
de->inode.dentry->d_inode->i_size = size;
|
2100 |
|
|
return 0;
|
2101 |
|
|
} /* End Function devfs_set_file_size */
|
2102 |
|
|
|
2103 |
|
|
|
2104 |
|
|
/**
|
2105 |
|
|
* devfs_get_info - Get the info pointer written to private_data of @de upon open.
|
2106 |
|
|
* @de: The handle to the device entry.
|
2107 |
|
|
*
|
2108 |
|
|
* Returns the info pointer.
|
2109 |
|
|
*/
|
2110 |
|
|
void *devfs_get_info (devfs_handle_t de)
|
2111 |
|
|
{
|
2112 |
|
|
if (de == NULL) return NULL;
|
2113 |
|
|
VERIFY_ENTRY (de);
|
2114 |
|
|
return de->info;
|
2115 |
|
|
} /* End Function devfs_get_info */
|
2116 |
|
|
|
2117 |
|
|
|
2118 |
|
|
/**
|
2119 |
|
|
* devfs_set_info - Set the info pointer written to private_data upon open.
|
2120 |
|
|
* @de: The handle to the device entry.
|
2121 |
|
|
* @info: pointer to the data
|
2122 |
|
|
*
|
2123 |
|
|
* Returns 0 on success, else a negative error code.
|
2124 |
|
|
*/
|
2125 |
|
|
int devfs_set_info (devfs_handle_t de, void *info)
|
2126 |
|
|
{
|
2127 |
|
|
if (de == NULL) return -EINVAL;
|
2128 |
|
|
VERIFY_ENTRY (de);
|
2129 |
|
|
de->info = info;
|
2130 |
|
|
return 0;
|
2131 |
|
|
} /* End Function devfs_set_info */
|
2132 |
|
|
|
2133 |
|
|
|
2134 |
|
|
/**
|
2135 |
|
|
* devfs_get_parent - Get the parent device entry.
|
2136 |
|
|
* @de: The handle to the device entry.
|
2137 |
|
|
*
|
2138 |
|
|
* Returns the parent device entry if it exists, else %NULL.
|
2139 |
|
|
*/
|
2140 |
|
|
devfs_handle_t devfs_get_parent (devfs_handle_t de)
|
2141 |
|
|
{
|
2142 |
|
|
if (de == NULL) return NULL;
|
2143 |
|
|
VERIFY_ENTRY (de);
|
2144 |
|
|
return de->parent;
|
2145 |
|
|
} /* End Function devfs_get_parent */
|
2146 |
|
|
|
2147 |
|
|
|
2148 |
|
|
/**
|
2149 |
|
|
* devfs_get_first_child - Get the first leaf node in a directory.
|
2150 |
|
|
* @de: The handle to the device entry.
|
2151 |
|
|
*
|
2152 |
|
|
* Returns the leaf node device entry if it exists, else %NULL.
|
2153 |
|
|
*/
|
2154 |
|
|
|
2155 |
|
|
devfs_handle_t devfs_get_first_child (devfs_handle_t de)
|
2156 |
|
|
{
|
2157 |
|
|
if (de == NULL) return NULL;
|
2158 |
|
|
VERIFY_ENTRY (de);
|
2159 |
|
|
if ( !S_ISDIR (de->mode) ) return NULL;
|
2160 |
|
|
return de->u.dir.first;
|
2161 |
|
|
} /* End Function devfs_get_first_child */
|
2162 |
|
|
|
2163 |
|
|
|
2164 |
|
|
/**
|
2165 |
|
|
* devfs_get_next_sibling - Get the next sibling leaf node. for a device entry.
|
2166 |
|
|
* @de: The handle to the device entry.
|
2167 |
|
|
*
|
2168 |
|
|
* Returns the leaf node device entry if it exists, else %NULL.
|
2169 |
|
|
*/
|
2170 |
|
|
|
2171 |
|
|
devfs_handle_t devfs_get_next_sibling (devfs_handle_t de)
|
2172 |
|
|
{
|
2173 |
|
|
if (de == NULL) return NULL;
|
2174 |
|
|
VERIFY_ENTRY (de);
|
2175 |
|
|
return de->next;
|
2176 |
|
|
} /* End Function devfs_get_next_sibling */
|
2177 |
|
|
|
2178 |
|
|
|
2179 |
|
|
/**
|
2180 |
|
|
* devfs_auto_unregister - Configure a devfs entry to be automatically unregistered.
|
2181 |
|
|
* @master: The master devfs entry. Only one slave may be registered.
|
2182 |
|
|
* @slave: The devfs entry which will be automatically unregistered when the
|
2183 |
|
|
* master entry is unregistered. It is illegal to call devfs_unregister()
|
2184 |
|
|
* on this entry.
|
2185 |
|
|
*/
|
2186 |
|
|
|
2187 |
|
|
void devfs_auto_unregister (devfs_handle_t master, devfs_handle_t slave)
|
2188 |
|
|
{
|
2189 |
|
|
if (master == NULL) return;
|
2190 |
|
|
VERIFY_ENTRY (master);
|
2191 |
|
|
VERIFY_ENTRY (slave);
|
2192 |
|
|
if (master->slave != NULL)
|
2193 |
|
|
{
|
2194 |
|
|
/* Because of the dumbness of the layers above, ignore duplicates */
|
2195 |
|
|
if (master->slave == slave) return;
|
2196 |
|
|
PRINTK ("(%s): only one slave allowed\n", master->name);
|
2197 |
|
|
OOPS ("(): old slave: \"%s\" new slave: \"%s\"\n",
|
2198 |
|
|
master->slave->name, slave->name);
|
2199 |
|
|
}
|
2200 |
|
|
master->slave = slave;
|
2201 |
|
|
} /* End Function devfs_auto_unregister */
|
2202 |
|
|
|
2203 |
|
|
|
2204 |
|
|
/**
|
2205 |
|
|
* devfs_get_unregister_slave - Get the slave entry which will be automatically unregistered.
|
2206 |
|
|
* @master: The master devfs entry.
|
2207 |
|
|
*
|
2208 |
|
|
* Returns the slave which will be unregistered when @master is unregistered.
|
2209 |
|
|
*/
|
2210 |
|
|
|
2211 |
|
|
devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master)
|
2212 |
|
|
{
|
2213 |
|
|
if (master == NULL) return NULL;
|
2214 |
|
|
VERIFY_ENTRY (master);
|
2215 |
|
|
return master->slave;
|
2216 |
|
|
} /* End Function devfs_get_unregister_slave */
|
2217 |
|
|
|
2218 |
|
|
|
2219 |
|
|
/**
|
2220 |
|
|
* devfs_get_name - Get the name for a device entry in its parent directory.
|
2221 |
|
|
* @de: The handle to the device entry.
|
2222 |
|
|
* @namelen: The length of the name is written here. This may be %NULL.
|
2223 |
|
|
*
|
2224 |
|
|
* Returns the name on success, else %NULL.
|
2225 |
|
|
*/
|
2226 |
|
|
|
2227 |
|
|
const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen)
|
2228 |
|
|
{
|
2229 |
|
|
if (de == NULL) return NULL;
|
2230 |
|
|
VERIFY_ENTRY (de);
|
2231 |
|
|
if (namelen != NULL) *namelen = de->namelen;
|
2232 |
|
|
return de->name;
|
2233 |
|
|
} /* End Function devfs_get_name */
|
2234 |
|
|
|
2235 |
|
|
|
2236 |
|
|
/**
|
2237 |
|
|
* devfs_register_chrdev - Optionally register a conventional character driver.
|
2238 |
|
|
* @major: The major number for the driver.
|
2239 |
|
|
* @name: The name of the driver (as seen in /proc/devices).
|
2240 |
|
|
* @fops: The &file_operations structure pointer.
|
2241 |
|
|
*
|
2242 |
|
|
* This function will register a character driver provided the "devfs=only"
|
2243 |
|
|
* option was not provided at boot time.
|
2244 |
|
|
* Returns 0 on success, else a negative error code on failure.
|
2245 |
|
|
*/
|
2246 |
|
|
|
2247 |
|
|
int devfs_register_chrdev (unsigned int major, const char *name,
|
2248 |
|
|
struct file_operations *fops)
|
2249 |
|
|
{
|
2250 |
|
|
if (boot_options & OPTION_ONLY) return 0;
|
2251 |
|
|
return register_chrdev (major, name, fops);
|
2252 |
|
|
} /* End Function devfs_register_chrdev */
|
2253 |
|
|
|
2254 |
|
|
|
2255 |
|
|
/**
|
2256 |
|
|
* devfs_register_blkdev - Optionally register a conventional block driver.
|
2257 |
|
|
* @major: The major number for the driver.
|
2258 |
|
|
* @name: The name of the driver (as seen in /proc/devices).
|
2259 |
|
|
* @bdops: The &block_device_operations structure pointer.
|
2260 |
|
|
*
|
2261 |
|
|
* This function will register a block driver provided the "devfs=only"
|
2262 |
|
|
* option was not provided at boot time.
|
2263 |
|
|
* Returns 0 on success, else a negative error code on failure.
|
2264 |
|
|
*/
|
2265 |
|
|
|
2266 |
|
|
int devfs_register_blkdev (unsigned int major, const char *name,
|
2267 |
|
|
struct block_device_operations *bdops)
|
2268 |
|
|
{
|
2269 |
|
|
if (boot_options & OPTION_ONLY) return 0;
|
2270 |
|
|
return register_blkdev (major, name, bdops);
|
2271 |
|
|
} /* End Function devfs_register_blkdev */
|
2272 |
|
|
|
2273 |
|
|
|
2274 |
|
|
/**
|
2275 |
|
|
* devfs_unregister_chrdev - Optionally unregister a conventional character driver.
|
2276 |
|
|
* @major: The major number for the driver.
|
2277 |
|
|
* @name: The name of the driver (as seen in /proc/devices).
|
2278 |
|
|
*
|
2279 |
|
|
* This function will unregister a character driver provided the "devfs=only"
|
2280 |
|
|
* option was not provided at boot time.
|
2281 |
|
|
* Returns 0 on success, else a negative error code on failure.
|
2282 |
|
|
*/
|
2283 |
|
|
|
2284 |
|
|
int devfs_unregister_chrdev (unsigned int major, const char *name)
|
2285 |
|
|
{
|
2286 |
|
|
if (boot_options & OPTION_ONLY) return 0;
|
2287 |
|
|
return unregister_chrdev (major, name);
|
2288 |
|
|
} /* End Function devfs_unregister_chrdev */
|
2289 |
|
|
|
2290 |
|
|
|
2291 |
|
|
/**
|
2292 |
|
|
* devfs_unregister_blkdev - Optionally unregister a conventional block driver.
|
2293 |
|
|
* @major: The major number for the driver.
|
2294 |
|
|
* @name: The name of the driver (as seen in /proc/devices).
|
2295 |
|
|
*
|
2296 |
|
|
* This function will unregister a block driver provided the "devfs=only"
|
2297 |
|
|
* option was not provided at boot time.
|
2298 |
|
|
* Returns 0 on success, else a negative error code on failure.
|
2299 |
|
|
*/
|
2300 |
|
|
|
2301 |
|
|
int devfs_unregister_blkdev (unsigned int major, const char *name)
|
2302 |
|
|
{
|
2303 |
|
|
if (boot_options & OPTION_ONLY) return 0;
|
2304 |
|
|
return unregister_blkdev (major, name);
|
2305 |
|
|
} /* End Function devfs_unregister_blkdev */
|
2306 |
|
|
|
2307 |
|
|
/**
|
2308 |
|
|
* devfs_setup - Process kernel boot options.
|
2309 |
|
|
* @str: The boot options after the "devfs=".
|
2310 |
|
|
*/
|
2311 |
|
|
|
2312 |
|
|
static int __init devfs_setup (char *str)
|
2313 |
|
|
{
|
2314 |
|
|
static struct
|
2315 |
|
|
{
|
2316 |
|
|
char *name;
|
2317 |
|
|
unsigned int mask;
|
2318 |
|
|
unsigned int *opt;
|
2319 |
|
|
} devfs_options_tab[] __initdata =
|
2320 |
|
|
{
|
2321 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
2322 |
|
|
{"dall", DEBUG_ALL, &devfs_debug_init},
|
2323 |
|
|
{"dmod", DEBUG_MODULE_LOAD, &devfs_debug_init},
|
2324 |
|
|
{"dreg", DEBUG_REGISTER, &devfs_debug_init},
|
2325 |
|
|
{"dunreg", DEBUG_UNREGISTER, &devfs_debug_init},
|
2326 |
|
|
{"dfree", DEBUG_FREE, &devfs_debug_init},
|
2327 |
|
|
{"diget", DEBUG_I_GET, &devfs_debug_init},
|
2328 |
|
|
{"dchange", DEBUG_SET_FLAGS, &devfs_debug_init},
|
2329 |
|
|
{"dsread", DEBUG_S_READ, &devfs_debug_init},
|
2330 |
|
|
{"dichange", DEBUG_I_CHANGE, &devfs_debug_init},
|
2331 |
|
|
{"dimknod", DEBUG_I_MKNOD, &devfs_debug_init},
|
2332 |
|
|
{"dilookup", DEBUG_I_LOOKUP, &devfs_debug_init},
|
2333 |
|
|
{"diunlink", DEBUG_I_UNLINK, &devfs_debug_init},
|
2334 |
|
|
#endif /* CONFIG_DEVFS_DEBUG */
|
2335 |
|
|
{"only", OPTION_ONLY, &boot_options},
|
2336 |
|
|
{"mount", OPTION_MOUNT, &boot_options},
|
2337 |
|
|
{NULL, 0, NULL}
|
2338 |
|
|
};
|
2339 |
|
|
|
2340 |
|
|
while ( (*str != '\0') && !isspace (*str) )
|
2341 |
|
|
{
|
2342 |
|
|
int i, found = 0, invert = 0;
|
2343 |
|
|
|
2344 |
|
|
if (strncmp (str, "no", 2) == 0)
|
2345 |
|
|
{
|
2346 |
|
|
invert = 1;
|
2347 |
|
|
str += 2;
|
2348 |
|
|
}
|
2349 |
|
|
for (i = 0; devfs_options_tab[i].name != NULL; i++)
|
2350 |
|
|
{
|
2351 |
|
|
int len = strlen (devfs_options_tab[i].name);
|
2352 |
|
|
|
2353 |
|
|
if (strncmp (str, devfs_options_tab[i].name, len) == 0)
|
2354 |
|
|
{
|
2355 |
|
|
if (invert)
|
2356 |
|
|
*devfs_options_tab[i].opt &= ~devfs_options_tab[i].mask;
|
2357 |
|
|
else
|
2358 |
|
|
*devfs_options_tab[i].opt |= devfs_options_tab[i].mask;
|
2359 |
|
|
str += len;
|
2360 |
|
|
found = 1;
|
2361 |
|
|
break;
|
2362 |
|
|
}
|
2363 |
|
|
}
|
2364 |
|
|
if (!found) return 0; /* No match */
|
2365 |
|
|
if (*str != ',') return 0; /* No more options */
|
2366 |
|
|
++str;
|
2367 |
|
|
}
|
2368 |
|
|
return 1;
|
2369 |
|
|
} /* End Function devfs_setup */
|
2370 |
|
|
|
2371 |
|
|
__setup("devfs=", devfs_setup);
|
2372 |
|
|
|
2373 |
|
|
EXPORT_SYMBOL(devfs_put);
|
2374 |
|
|
EXPORT_SYMBOL(devfs_register);
|
2375 |
|
|
EXPORT_SYMBOL(devfs_unregister);
|
2376 |
|
|
EXPORT_SYMBOL(devfs_mk_symlink);
|
2377 |
|
|
EXPORT_SYMBOL(devfs_mk_dir);
|
2378 |
|
|
EXPORT_SYMBOL(devfs_get_handle);
|
2379 |
|
|
EXPORT_SYMBOL(devfs_find_handle);
|
2380 |
|
|
EXPORT_SYMBOL(devfs_get_flags);
|
2381 |
|
|
EXPORT_SYMBOL(devfs_set_flags);
|
2382 |
|
|
EXPORT_SYMBOL(devfs_get_maj_min);
|
2383 |
|
|
EXPORT_SYMBOL(devfs_get_handle_from_inode);
|
2384 |
|
|
EXPORT_SYMBOL(devfs_generate_path);
|
2385 |
|
|
EXPORT_SYMBOL(devfs_get_ops);
|
2386 |
|
|
EXPORT_SYMBOL(devfs_set_file_size);
|
2387 |
|
|
EXPORT_SYMBOL(devfs_get_info);
|
2388 |
|
|
EXPORT_SYMBOL(devfs_set_info);
|
2389 |
|
|
EXPORT_SYMBOL(devfs_get_parent);
|
2390 |
|
|
EXPORT_SYMBOL(devfs_get_first_child);
|
2391 |
|
|
EXPORT_SYMBOL(devfs_get_next_sibling);
|
2392 |
|
|
EXPORT_SYMBOL(devfs_auto_unregister);
|
2393 |
|
|
EXPORT_SYMBOL(devfs_get_unregister_slave);
|
2394 |
|
|
EXPORT_SYMBOL(devfs_get_name);
|
2395 |
|
|
EXPORT_SYMBOL(devfs_register_chrdev);
|
2396 |
|
|
EXPORT_SYMBOL(devfs_register_blkdev);
|
2397 |
|
|
EXPORT_SYMBOL(devfs_unregister_chrdev);
|
2398 |
|
|
EXPORT_SYMBOL(devfs_unregister_blkdev);
|
2399 |
|
|
|
2400 |
|
|
|
2401 |
|
|
/**
|
2402 |
|
|
* try_modload - Notify devfsd of an inode lookup by a non-devfsd process.
|
2403 |
|
|
* @parent: The parent devfs entry.
|
2404 |
|
|
* @fs_info: The filesystem info.
|
2405 |
|
|
* @name: The device name.
|
2406 |
|
|
* @namelen: The number of characters in @name.
|
2407 |
|
|
* @buf: A working area that will be used. This must not go out of scope
|
2408 |
|
|
* until devfsd is idle again.
|
2409 |
|
|
*
|
2410 |
|
|
* Returns 0 on success (event was queued), else a negative error code.
|
2411 |
|
|
*/
|
2412 |
|
|
|
2413 |
|
|
static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
|
2414 |
|
|
const char *name, unsigned namelen,
|
2415 |
|
|
struct devfs_entry *buf)
|
2416 |
|
|
{
|
2417 |
|
|
if ( !( fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP) ) )
|
2418 |
|
|
return -ENOENT;
|
2419 |
|
|
if ( is_devfsd_or_child (fs_info) ) return -ENOENT;
|
2420 |
|
|
memset (buf, 0, sizeof *buf);
|
2421 |
|
|
atomic_set (&buf->refcount, 1);
|
2422 |
|
|
buf->parent = parent;
|
2423 |
|
|
buf->namelen = namelen;
|
2424 |
|
|
buf->u.name = name;
|
2425 |
|
|
WRITE_ENTRY_MAGIC (buf, MAGIC_VALUE);
|
2426 |
|
|
if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0,
|
2427 |
|
|
current->euid, current->egid, fs_info, 0) )
|
2428 |
|
|
return -ENOENT;
|
2429 |
|
|
/* Possible success: event has been queued */
|
2430 |
|
|
return 0;
|
2431 |
|
|
} /* End Function try_modload */
|
2432 |
|
|
|
2433 |
|
|
|
2434 |
|
|
/**
|
2435 |
|
|
* check_disc_changed - Check if a removable disc was changed.
|
2436 |
|
|
* @de: The device.
|
2437 |
|
|
*
|
2438 |
|
|
* Returns 1 if the media was changed, else 0.
|
2439 |
|
|
*
|
2440 |
|
|
* This function may block, and may indirectly cause the parent directory
|
2441 |
|
|
* contents to be changed due to partition re-reading.
|
2442 |
|
|
*/
|
2443 |
|
|
|
2444 |
|
|
static int check_disc_changed (struct devfs_entry *de)
|
2445 |
|
|
{
|
2446 |
|
|
int tmp;
|
2447 |
|
|
int retval = 0;
|
2448 |
|
|
kdev_t dev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
|
2449 |
|
|
struct block_device_operations *bdops;
|
2450 |
|
|
extern int warn_no_part;
|
2451 |
|
|
|
2452 |
|
|
if ( !S_ISBLK (de->mode) ) return 0;
|
2453 |
|
|
bdops = devfs_get_ops (de);
|
2454 |
|
|
if (!bdops) return 0;
|
2455 |
|
|
if (bdops->check_media_change == NULL) goto out;
|
2456 |
|
|
if ( !bdops->check_media_change (dev) ) goto out;
|
2457 |
|
|
retval = 1;
|
2458 |
|
|
printk (KERN_DEBUG "VFS: Disk change detected on device %s\n",
|
2459 |
|
|
kdevname (dev) );
|
2460 |
|
|
if ( invalidate_device (dev, 0) )
|
2461 |
|
|
printk (KERN_WARNING "VFS: busy inodes on changed media..\n");
|
2462 |
|
|
/* Ugly hack to disable messages about unable to read partition table */
|
2463 |
|
|
tmp = warn_no_part;
|
2464 |
|
|
warn_no_part = 0;
|
2465 |
|
|
if (bdops->revalidate) bdops->revalidate (dev);
|
2466 |
|
|
warn_no_part = tmp;
|
2467 |
|
|
out:
|
2468 |
|
|
devfs_put_ops (de);
|
2469 |
|
|
return retval;
|
2470 |
|
|
} /* End Function check_disc_changed */
|
2471 |
|
|
|
2472 |
|
|
|
2473 |
|
|
/**
|
2474 |
|
|
* scan_dir_for_removable - Scan a directory for removable media devices and check media.
|
2475 |
|
|
* @dir: The directory.
|
2476 |
|
|
*
|
2477 |
|
|
* This function may block, and may indirectly cause the directory
|
2478 |
|
|
* contents to be changed due to partition re-reading. The directory will
|
2479 |
|
|
* be locked for reading.
|
2480 |
|
|
*/
|
2481 |
|
|
|
2482 |
|
|
static void scan_dir_for_removable (struct devfs_entry *dir)
|
2483 |
|
|
{
|
2484 |
|
|
struct devfs_entry *de;
|
2485 |
|
|
|
2486 |
|
|
read_lock (&dir->u.dir.lock);
|
2487 |
|
|
if (dir->u.dir.num_removable < 1) de = NULL;
|
2488 |
|
|
else
|
2489 |
|
|
{
|
2490 |
|
|
for (de = dir->u.dir.first; de != NULL; de = de->next)
|
2491 |
|
|
{
|
2492 |
|
|
if (S_ISBLK (de->mode) && de->u.fcb.removable) break;
|
2493 |
|
|
}
|
2494 |
|
|
devfs_get (de);
|
2495 |
|
|
}
|
2496 |
|
|
read_unlock (&dir->u.dir.lock);
|
2497 |
|
|
if (de) check_disc_changed (de);
|
2498 |
|
|
devfs_put (de);
|
2499 |
|
|
} /* End Function scan_dir_for_removable */
|
2500 |
|
|
|
2501 |
|
|
/**
|
2502 |
|
|
* get_removable_partition - Get removable media partition.
|
2503 |
|
|
* @dir: The parent directory.
|
2504 |
|
|
* @name: The name of the entry.
|
2505 |
|
|
* @namelen: The number of characters in <<name>>.
|
2506 |
|
|
*
|
2507 |
|
|
* Returns 1 if the media was changed, else 0.
|
2508 |
|
|
*
|
2509 |
|
|
* This function may block, and may indirectly cause the directory
|
2510 |
|
|
* contents to be changed due to partition re-reading. The directory must
|
2511 |
|
|
* be locked for reading upon entry, and will be unlocked upon exit.
|
2512 |
|
|
*/
|
2513 |
|
|
|
2514 |
|
|
static int get_removable_partition (struct devfs_entry *dir, const char *name,
|
2515 |
|
|
unsigned int namelen)
|
2516 |
|
|
{
|
2517 |
|
|
int retval;
|
2518 |
|
|
struct devfs_entry *de;
|
2519 |
|
|
|
2520 |
|
|
if (dir->u.dir.num_removable < 1)
|
2521 |
|
|
{
|
2522 |
|
|
read_unlock (&dir->u.dir.lock);
|
2523 |
|
|
return 0;
|
2524 |
|
|
}
|
2525 |
|
|
for (de = dir->u.dir.first; de != NULL; de = de->next)
|
2526 |
|
|
{
|
2527 |
|
|
if (!S_ISBLK (de->mode) || !de->u.fcb.removable) continue;
|
2528 |
|
|
if (strcmp (de->name, "disc") == 0) break;
|
2529 |
|
|
/* Support for names where the partition is appended to the disc name
|
2530 |
|
|
*/
|
2531 |
|
|
if (de->namelen >= namelen) continue;
|
2532 |
|
|
if (strncmp (de->name, name, de->namelen) == 0) break;
|
2533 |
|
|
}
|
2534 |
|
|
devfs_get (de);
|
2535 |
|
|
read_unlock (&dir->u.dir.lock);
|
2536 |
|
|
retval = de ? check_disc_changed (de) : 0;
|
2537 |
|
|
devfs_put (de);
|
2538 |
|
|
return retval;
|
2539 |
|
|
} /* End Function get_removable_partition */
|
2540 |
|
|
|
2541 |
|
|
|
2542 |
|
|
/* Superblock operations follow */
|
2543 |
|
|
|
2544 |
|
|
static struct inode_operations devfs_iops;
|
2545 |
|
|
static struct inode_operations devfs_dir_iops;
|
2546 |
|
|
static struct file_operations devfs_fops;
|
2547 |
|
|
static struct file_operations devfs_dir_fops;
|
2548 |
|
|
static struct inode_operations devfs_symlink_iops;
|
2549 |
|
|
|
2550 |
|
|
static int devfs_notify_change (struct dentry *dentry, struct iattr *iattr)
|
2551 |
|
|
{
|
2552 |
|
|
int retval;
|
2553 |
|
|
struct devfs_entry *de;
|
2554 |
|
|
struct inode *inode = dentry->d_inode;
|
2555 |
|
|
struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
|
2556 |
|
|
|
2557 |
|
|
de = get_devfs_entry_from_vfs_inode (inode);
|
2558 |
|
|
if (de == NULL) return -ENODEV;
|
2559 |
|
|
retval = inode_change_ok (inode, iattr);
|
2560 |
|
|
if (retval != 0) return retval;
|
2561 |
|
|
retval = inode_setattr (inode, iattr);
|
2562 |
|
|
if (retval != 0) return retval;
|
2563 |
|
|
DPRINTK (DEBUG_I_CHANGE, "(%d): VFS inode: %p devfs_entry: %p\n",
|
2564 |
|
|
(int) inode->i_ino, inode, de);
|
2565 |
|
|
DPRINTK (DEBUG_I_CHANGE, "(): mode: 0%o uid: %d gid: %d\n",
|
2566 |
|
|
(int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid);
|
2567 |
|
|
/* Inode is not on hash chains, thus must save permissions here rather
|
2568 |
|
|
than in a write_inode() method */
|
2569 |
|
|
if ( ( !S_ISREG (inode->i_mode) && !S_ISCHR (inode->i_mode) &&
|
2570 |
|
|
!S_ISBLK (inode->i_mode) ) || !de->u.fcb.auto_owner )
|
2571 |
|
|
{
|
2572 |
|
|
de->mode = inode->i_mode;
|
2573 |
|
|
de->inode.uid = inode->i_uid;
|
2574 |
|
|
de->inode.gid = inode->i_gid;
|
2575 |
|
|
}
|
2576 |
|
|
de->inode.atime = inode->i_atime;
|
2577 |
|
|
de->inode.mtime = inode->i_mtime;
|
2578 |
|
|
de->inode.ctime = inode->i_ctime;
|
2579 |
|
|
if ( ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) &&
|
2580 |
|
|
!is_devfsd_or_child (fs_info) )
|
2581 |
|
|
devfsd_notify_de (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,
|
2582 |
|
|
inode->i_uid, inode->i_gid, fs_info, 0);
|
2583 |
|
|
return 0;
|
2584 |
|
|
} /* End Function devfs_notify_change */
|
2585 |
|
|
|
2586 |
|
|
static int devfs_statfs (struct super_block *sb, struct statfs *buf)
|
2587 |
|
|
{
|
2588 |
|
|
buf->f_type = DEVFS_SUPER_MAGIC;
|
2589 |
|
|
buf->f_bsize = FAKE_BLOCK_SIZE;
|
2590 |
|
|
buf->f_bfree = 0;
|
2591 |
|
|
buf->f_bavail = 0;
|
2592 |
|
|
buf->f_ffree = 0;
|
2593 |
|
|
buf->f_namelen = NAME_MAX;
|
2594 |
|
|
return 0;
|
2595 |
|
|
} /* End Function devfs_statfs */
|
2596 |
|
|
|
2597 |
|
|
static void devfs_clear_inode (struct inode *inode)
|
2598 |
|
|
{
|
2599 |
|
|
if ( S_ISBLK (inode->i_mode) ) bdput (inode->i_bdev);
|
2600 |
|
|
} /* End Function devfs_clear_inode */
|
2601 |
|
|
|
2602 |
|
|
static struct super_operations devfs_sops =
|
2603 |
|
|
{
|
2604 |
|
|
.put_inode = force_delete,
|
2605 |
|
|
.clear_inode = devfs_clear_inode,
|
2606 |
|
|
.statfs = devfs_statfs,
|
2607 |
|
|
};
|
2608 |
|
|
|
2609 |
|
|
|
2610 |
|
|
/**
|
2611 |
|
|
* _devfs_get_vfs_inode - Get a VFS inode.
|
2612 |
|
|
* @sb: The super block.
|
2613 |
|
|
* @de: The devfs inode.
|
2614 |
|
|
* @dentry: The dentry to register with the devfs inode.
|
2615 |
|
|
*
|
2616 |
|
|
* Returns the inode on success, else %NULL. An implicit devfs_get() is
|
2617 |
|
|
* performed if the inode is created.
|
2618 |
|
|
*/
|
2619 |
|
|
|
2620 |
|
|
static struct inode *_devfs_get_vfs_inode (struct super_block *sb,
|
2621 |
|
|
struct devfs_entry *de,
|
2622 |
|
|
struct dentry *dentry)
|
2623 |
|
|
{
|
2624 |
|
|
int is_fcb = FALSE;
|
2625 |
|
|
struct inode *inode;
|
2626 |
|
|
|
2627 |
|
|
if (de->prev == de) return NULL; /* Quick check to see if unhooked */
|
2628 |
|
|
if ( ( inode = new_inode (sb) ) == NULL )
|
2629 |
|
|
{
|
2630 |
|
|
PRINTK ("(%s): new_inode() failed, de: %p\n", de->name, de);
|
2631 |
|
|
return NULL;
|
2632 |
|
|
}
|
2633 |
|
|
if (de->parent)
|
2634 |
|
|
{
|
2635 |
|
|
read_lock (&de->parent->u.dir.lock);
|
2636 |
|
|
if (de->prev != de) de->inode.dentry = dentry; /* Not unhooked */
|
2637 |
|
|
read_unlock (&de->parent->u.dir.lock);
|
2638 |
|
|
}
|
2639 |
|
|
else de->inode.dentry = dentry; /* Root: no locking needed */
|
2640 |
|
|
if (de->inode.dentry != dentry)
|
2641 |
|
|
{ /* Must have been unhooked */
|
2642 |
|
|
iput (inode);
|
2643 |
|
|
return NULL;
|
2644 |
|
|
}
|
2645 |
|
|
inode->u.generic_ip = devfs_get (de);
|
2646 |
|
|
inode->i_ino = de->inode.ino;
|
2647 |
|
|
DPRINTK (DEBUG_I_GET, "(%d): VFS inode: %p devfs_entry: %p\n",
|
2648 |
|
|
(int) inode->i_ino, inode, de);
|
2649 |
|
|
inode->i_blocks = 0;
|
2650 |
|
|
inode->i_blksize = FAKE_BLOCK_SIZE;
|
2651 |
|
|
inode->i_op = &devfs_iops;
|
2652 |
|
|
inode->i_fop = &devfs_fops;
|
2653 |
|
|
inode->i_rdev = NODEV;
|
2654 |
|
|
if ( S_ISCHR (de->mode) )
|
2655 |
|
|
{
|
2656 |
|
|
inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
|
2657 |
|
|
de->u.fcb.u.device.minor);
|
2658 |
|
|
inode->i_cdev = cdget ( kdev_t_to_nr (inode->i_rdev) );
|
2659 |
|
|
is_fcb = TRUE;
|
2660 |
|
|
}
|
2661 |
|
|
else if ( S_ISBLK (de->mode) )
|
2662 |
|
|
{
|
2663 |
|
|
inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
|
2664 |
|
|
de->u.fcb.u.device.minor);
|
2665 |
|
|
if (bd_acquire (inode) == 0)
|
2666 |
|
|
{
|
2667 |
|
|
if (!inode->i_bdev->bd_op && de->u.fcb.ops)
|
2668 |
|
|
inode->i_bdev->bd_op = de->u.fcb.ops;
|
2669 |
|
|
}
|
2670 |
|
|
else PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino);
|
2671 |
|
|
is_fcb = TRUE;
|
2672 |
|
|
}
|
2673 |
|
|
else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops;
|
2674 |
|
|
else if ( S_ISREG (de->mode) )
|
2675 |
|
|
{
|
2676 |
|
|
inode->i_size = de->u.fcb.u.file.size;
|
2677 |
|
|
is_fcb = TRUE;
|
2678 |
|
|
}
|
2679 |
|
|
else if ( S_ISDIR (de->mode) )
|
2680 |
|
|
{
|
2681 |
|
|
inode->i_op = &devfs_dir_iops;
|
2682 |
|
|
inode->i_fop = &devfs_dir_fops;
|
2683 |
|
|
}
|
2684 |
|
|
else if ( S_ISLNK (de->mode) )
|
2685 |
|
|
{
|
2686 |
|
|
inode->i_op = &devfs_symlink_iops;
|
2687 |
|
|
inode->i_size = de->u.symlink.length;
|
2688 |
|
|
}
|
2689 |
|
|
if (is_fcb && de->u.fcb.auto_owner)
|
2690 |
|
|
inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
|
2691 |
|
|
else inode->i_mode = de->mode;
|
2692 |
|
|
inode->i_uid = de->inode.uid;
|
2693 |
|
|
inode->i_gid = de->inode.gid;
|
2694 |
|
|
inode->i_atime = de->inode.atime;
|
2695 |
|
|
inode->i_mtime = de->inode.mtime;
|
2696 |
|
|
inode->i_ctime = de->inode.ctime;
|
2697 |
|
|
DPRINTK (DEBUG_I_GET, "(): mode: 0%o uid: %d gid: %d\n",
|
2698 |
|
|
(int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid);
|
2699 |
|
|
return inode;
|
2700 |
|
|
} /* End Function _devfs_get_vfs_inode */
|
2701 |
|
|
|
2702 |
|
|
|
2703 |
|
|
/* File operations for device entries follow */
|
2704 |
|
|
|
2705 |
|
|
static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir)
|
2706 |
|
|
{
|
2707 |
|
|
int err, count;
|
2708 |
|
|
int stored = 0;
|
2709 |
|
|
struct fs_info *fs_info;
|
2710 |
|
|
struct devfs_entry *parent, *de, *next = NULL;
|
2711 |
|
|
struct inode *inode = file->f_dentry->d_inode;
|
2712 |
|
|
|
2713 |
|
|
fs_info = inode->i_sb->u.generic_sbp;
|
2714 |
|
|
parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode);
|
2715 |
|
|
if ( (long) file->f_pos < 0 ) return -EINVAL;
|
2716 |
|
|
DPRINTK (DEBUG_F_READDIR, "(%s): fs_info: %p pos: %ld\n",
|
2717 |
|
|
parent->name, fs_info, (long) file->f_pos);
|
2718 |
|
|
switch ( (long) file->f_pos )
|
2719 |
|
|
{
|
2720 |
|
|
case 0:
|
2721 |
|
|
scan_dir_for_removable (parent);
|
2722 |
|
|
err = (*filldir) (dirent, "..", 2, file->f_pos,
|
2723 |
|
|
file->f_dentry->d_parent->d_inode->i_ino, DT_DIR);
|
2724 |
|
|
if (err == -EINVAL) break;
|
2725 |
|
|
if (err < 0) return err;
|
2726 |
|
|
file->f_pos++;
|
2727 |
|
|
++stored;
|
2728 |
|
|
/* Fall through */
|
2729 |
|
|
case 1:
|
2730 |
|
|
err = (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino, DT_DIR);
|
2731 |
|
|
if (err == -EINVAL) break;
|
2732 |
|
|
if (err < 0) return err;
|
2733 |
|
|
file->f_pos++;
|
2734 |
|
|
++stored;
|
2735 |
|
|
/* Fall through */
|
2736 |
|
|
default:
|
2737 |
|
|
/* Skip entries */
|
2738 |
|
|
count = file->f_pos - 2;
|
2739 |
|
|
read_lock (&parent->u.dir.lock);
|
2740 |
|
|
for (de = parent->u.dir.first; de && (count > 0); de = de->next)
|
2741 |
|
|
if ( !IS_HIDDEN (de) ) --count;
|
2742 |
|
|
devfs_get (de);
|
2743 |
|
|
read_unlock (&parent->u.dir.lock);
|
2744 |
|
|
/* Now add all remaining entries */
|
2745 |
|
|
while (de)
|
2746 |
|
|
{
|
2747 |
|
|
if ( IS_HIDDEN (de) ) err = 0;
|
2748 |
|
|
else
|
2749 |
|
|
{
|
2750 |
|
|
err = (*filldir) (dirent, de->name, de->namelen,
|
2751 |
|
|
file->f_pos, de->inode.ino, de->mode >> 12);
|
2752 |
|
|
if (err < 0) devfs_put (de);
|
2753 |
|
|
else
|
2754 |
|
|
{
|
2755 |
|
|
file->f_pos++;
|
2756 |
|
|
++stored;
|
2757 |
|
|
}
|
2758 |
|
|
}
|
2759 |
|
|
if (err == -EINVAL) break;
|
2760 |
|
|
if (err < 0) return err;
|
2761 |
|
|
read_lock (&parent->u.dir.lock);
|
2762 |
|
|
next = devfs_get (de->next);
|
2763 |
|
|
read_unlock (&parent->u.dir.lock);
|
2764 |
|
|
devfs_put (de);
|
2765 |
|
|
de = next;
|
2766 |
|
|
}
|
2767 |
|
|
break;
|
2768 |
|
|
}
|
2769 |
|
|
return stored;
|
2770 |
|
|
} /* End Function devfs_readdir */
|
2771 |
|
|
|
2772 |
|
|
static int devfs_open (struct inode *inode, struct file *file)
|
2773 |
|
|
{
|
2774 |
|
|
int err;
|
2775 |
|
|
struct fcb_type *df;
|
2776 |
|
|
struct devfs_entry *de;
|
2777 |
|
|
struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
|
2778 |
|
|
void *ops;
|
2779 |
|
|
|
2780 |
|
|
de = get_devfs_entry_from_vfs_inode (inode);
|
2781 |
|
|
if (de == NULL) return -ENODEV;
|
2782 |
|
|
if ( S_ISDIR (de->mode) ) return 0;
|
2783 |
|
|
df = &de->u.fcb;
|
2784 |
|
|
file->private_data = de->info;
|
2785 |
|
|
ops = devfs_get_ops (de); /* Now have module refcount */
|
2786 |
|
|
if ( S_ISBLK (inode->i_mode) )
|
2787 |
|
|
{
|
2788 |
|
|
file->f_op = &def_blk_fops;
|
2789 |
|
|
if (ops) inode->i_bdev->bd_op = ops;
|
2790 |
|
|
err = def_blk_fops.open (inode, file); /* This bumps module refcount */
|
2791 |
|
|
devfs_put_ops (de); /* So drop my refcount */
|
2792 |
|
|
}
|
2793 |
|
|
else
|
2794 |
|
|
{
|
2795 |
|
|
file->f_op = ops;
|
2796 |
|
|
if (file->f_op)
|
2797 |
|
|
{
|
2798 |
|
|
lock_kernel ();
|
2799 |
|
|
err = file->f_op->open ? (*file->f_op->open) (inode, file) : 0;
|
2800 |
|
|
unlock_kernel ();
|
2801 |
|
|
}
|
2802 |
|
|
else
|
2803 |
|
|
{ /* Fallback to legacy scheme (I don't have a module refcount) */
|
2804 |
|
|
if ( S_ISCHR (inode->i_mode) ) err = chrdev_open (inode, file);
|
2805 |
|
|
else err = -ENODEV;
|
2806 |
|
|
}
|
2807 |
|
|
}
|
2808 |
|
|
if (err < 0) return err;
|
2809 |
|
|
/* Open was successful */
|
2810 |
|
|
if (df->open) return 0;
|
2811 |
|
|
df->open = TRUE; /* This is the first open */
|
2812 |
|
|
if (df->auto_owner)
|
2813 |
|
|
{
|
2814 |
|
|
/* Change the ownership/protection to what driver specified */
|
2815 |
|
|
inode->i_mode = de->mode;
|
2816 |
|
|
inode->i_uid = current->euid;
|
2817 |
|
|
inode->i_gid = current->egid;
|
2818 |
|
|
}
|
2819 |
|
|
if ( df->aopen_notify && !is_devfsd_or_child (fs_info) )
|
2820 |
|
|
devfsd_notify_de (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode,
|
2821 |
|
|
current->euid, current->egid, fs_info, 0);
|
2822 |
|
|
return 0;
|
2823 |
|
|
} /* End Function devfs_open */
|
2824 |
|
|
|
2825 |
|
|
static struct file_operations devfs_fops =
|
2826 |
|
|
{
|
2827 |
|
|
.open = devfs_open,
|
2828 |
|
|
};
|
2829 |
|
|
|
2830 |
|
|
static struct file_operations devfs_dir_fops =
|
2831 |
|
|
{
|
2832 |
|
|
.read = generic_read_dir,
|
2833 |
|
|
.readdir = devfs_readdir,
|
2834 |
|
|
.open = devfs_open,
|
2835 |
|
|
};
|
2836 |
|
|
|
2837 |
|
|
|
2838 |
|
|
/* Dentry operations for device entries follow */
|
2839 |
|
|
|
2840 |
|
|
|
2841 |
|
|
/**
|
2842 |
|
|
* devfs_d_release - Callback for when a dentry is freed.
|
2843 |
|
|
* @dentry: The dentry.
|
2844 |
|
|
*/
|
2845 |
|
|
|
2846 |
|
|
static void devfs_d_release (struct dentry *dentry)
|
2847 |
|
|
{
|
2848 |
|
|
DPRINTK (DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode);
|
2849 |
|
|
} /* End Function devfs_d_release */
|
2850 |
|
|
|
2851 |
|
|
/**
|
2852 |
|
|
* devfs_d_iput - Callback for when a dentry loses its inode.
|
2853 |
|
|
* @dentry: The dentry.
|
2854 |
|
|
* @inode: The inode.
|
2855 |
|
|
*/
|
2856 |
|
|
|
2857 |
|
|
static void devfs_d_iput (struct dentry *dentry, struct inode *inode)
|
2858 |
|
|
{
|
2859 |
|
|
struct devfs_entry *de;
|
2860 |
|
|
|
2861 |
|
|
de = get_devfs_entry_from_vfs_inode (inode);
|
2862 |
|
|
DPRINTK (DEBUG_D_IPUT,"(%s): dentry: %p inode: %p de: %p de->dentry: %p\n",
|
2863 |
|
|
de->name, dentry, inode, de, de->inode.dentry);
|
2864 |
|
|
if ( de->inode.dentry && (de->inode.dentry != dentry) )
|
2865 |
|
|
OOPS ("(%s): de: %p dentry: %p de->dentry: %p\n",
|
2866 |
|
|
de->name, de, dentry, de->inode.dentry);
|
2867 |
|
|
de->inode.dentry = NULL;
|
2868 |
|
|
iput (inode);
|
2869 |
|
|
devfs_put (de);
|
2870 |
|
|
} /* End Function devfs_d_iput */
|
2871 |
|
|
|
2872 |
|
|
static int devfs_d_delete (struct dentry *dentry);
|
2873 |
|
|
|
2874 |
|
|
static struct dentry_operations devfs_dops =
|
2875 |
|
|
{
|
2876 |
|
|
.d_delete = devfs_d_delete,
|
2877 |
|
|
.d_release = devfs_d_release,
|
2878 |
|
|
.d_iput = devfs_d_iput,
|
2879 |
|
|
};
|
2880 |
|
|
|
2881 |
|
|
static int devfs_d_revalidate_wait (struct dentry *dentry, int flags);
|
2882 |
|
|
|
2883 |
|
|
static struct dentry_operations devfs_wait_dops =
|
2884 |
|
|
{
|
2885 |
|
|
.d_delete = devfs_d_delete,
|
2886 |
|
|
.d_release = devfs_d_release,
|
2887 |
|
|
.d_iput = devfs_d_iput,
|
2888 |
|
|
.d_revalidate = devfs_d_revalidate_wait,
|
2889 |
|
|
};
|
2890 |
|
|
|
2891 |
|
|
/**
|
2892 |
|
|
* devfs_d_delete - Callback for when all files for a dentry are closed.
|
2893 |
|
|
* @dentry: The dentry.
|
2894 |
|
|
*/
|
2895 |
|
|
|
2896 |
|
|
static int devfs_d_delete (struct dentry *dentry)
|
2897 |
|
|
{
|
2898 |
|
|
struct inode *inode = dentry->d_inode;
|
2899 |
|
|
struct devfs_entry *de;
|
2900 |
|
|
struct fs_info *fs_info;
|
2901 |
|
|
|
2902 |
|
|
if (dentry->d_op == &devfs_wait_dops) dentry->d_op = &devfs_dops;
|
2903 |
|
|
/* Unhash dentry if negative (has no inode) */
|
2904 |
|
|
if (inode == NULL)
|
2905 |
|
|
{
|
2906 |
|
|
DPRINTK (DEBUG_D_DELETE, "(%p): dropping negative dentry\n", dentry);
|
2907 |
|
|
return 1;
|
2908 |
|
|
}
|
2909 |
|
|
fs_info = inode->i_sb->u.generic_sbp;
|
2910 |
|
|
de = get_devfs_entry_from_vfs_inode (inode);
|
2911 |
|
|
DPRINTK (DEBUG_D_DELETE, "(%p): inode: %p devfs_entry: %p\n",
|
2912 |
|
|
dentry, inode, de);
|
2913 |
|
|
if (de == NULL) return 0;
|
2914 |
|
|
if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
|
2915 |
|
|
return 0;
|
2916 |
|
|
if (!de->u.fcb.open) return 0;
|
2917 |
|
|
de->u.fcb.open = FALSE;
|
2918 |
|
|
if (de->u.fcb.aopen_notify)
|
2919 |
|
|
devfsd_notify_de (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
|
2920 |
|
|
current->euid, current->egid, fs_info, 1);
|
2921 |
|
|
if (!de->u.fcb.auto_owner) return 0;
|
2922 |
|
|
/* Change the ownership/protection back */
|
2923 |
|
|
inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
|
2924 |
|
|
inode->i_uid = de->inode.uid;
|
2925 |
|
|
inode->i_gid = de->inode.gid;
|
2926 |
|
|
return 0;
|
2927 |
|
|
} /* End Function devfs_d_delete */
|
2928 |
|
|
|
2929 |
|
|
struct devfs_lookup_struct
|
2930 |
|
|
{
|
2931 |
|
|
devfs_handle_t de;
|
2932 |
|
|
wait_queue_head_t wait_queue;
|
2933 |
|
|
};
|
2934 |
|
|
|
2935 |
|
|
static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
|
2936 |
|
|
{
|
2937 |
|
|
struct inode *dir = dentry->d_parent->d_inode;
|
2938 |
|
|
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
|
2939 |
|
|
devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
|
2940 |
|
|
struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
|
2941 |
|
|
DECLARE_WAITQUEUE (wait, current);
|
2942 |
|
|
|
2943 |
|
|
if ( is_devfsd_or_child (fs_info) )
|
2944 |
|
|
{
|
2945 |
|
|
devfs_handle_t de = lookup_info->de;
|
2946 |
|
|
struct inode *inode;
|
2947 |
|
|
|
2948 |
|
|
DPRINTK (DEBUG_I_LOOKUP,
|
2949 |
|
|
"(%s): dentry: %p inode: %p de: %p by: \"%s\"\n",
|
2950 |
|
|
dentry->d_name.name, dentry, dentry->d_inode, de,
|
2951 |
|
|
current->comm);
|
2952 |
|
|
if (dentry->d_inode) return 1;
|
2953 |
|
|
if (de == NULL)
|
2954 |
|
|
{
|
2955 |
|
|
read_lock (&parent->u.dir.lock);
|
2956 |
|
|
de = _devfs_search_dir (parent, dentry->d_name.name,
|
2957 |
|
|
dentry->d_name.len);
|
2958 |
|
|
read_unlock (&parent->u.dir.lock);
|
2959 |
|
|
if (de == NULL) return 1;
|
2960 |
|
|
lookup_info->de = de;
|
2961 |
|
|
}
|
2962 |
|
|
/* Create an inode, now that the driver information is available */
|
2963 |
|
|
inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
|
2964 |
|
|
if (!inode) return 1;
|
2965 |
|
|
DPRINTK (DEBUG_I_LOOKUP,
|
2966 |
|
|
"(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
|
2967 |
|
|
de->name, de->inode.ino, inode, de, current->comm);
|
2968 |
|
|
d_instantiate (dentry, inode);
|
2969 |
|
|
return 1;
|
2970 |
|
|
}
|
2971 |
|
|
if (lookup_info == NULL) return 1; /* Early termination */
|
2972 |
|
|
read_lock (&parent->u.dir.lock);
|
2973 |
|
|
if (dentry->d_fsdata)
|
2974 |
|
|
{
|
2975 |
|
|
set_current_state (TASK_UNINTERRUPTIBLE);
|
2976 |
|
|
add_wait_queue (&lookup_info->wait_queue, &wait);
|
2977 |
|
|
read_unlock (&parent->u.dir.lock);
|
2978 |
|
|
schedule ();
|
2979 |
|
|
}
|
2980 |
|
|
else read_unlock (&parent->u.dir.lock);
|
2981 |
|
|
return 1;
|
2982 |
|
|
} /* End Function devfs_d_revalidate_wait */
|
2983 |
|
|
|
2984 |
|
|
|
2985 |
|
|
/* Inode operations for device entries follow */
|
2986 |
|
|
|
2987 |
|
|
static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
|
2988 |
|
|
{
|
2989 |
|
|
struct devfs_entry tmp; /* Must stay in scope until devfsd idle again */
|
2990 |
|
|
struct devfs_lookup_struct lookup_info;
|
2991 |
|
|
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
|
2992 |
|
|
struct devfs_entry *parent, *de;
|
2993 |
|
|
struct inode *inode;
|
2994 |
|
|
struct dentry *retval = NULL;
|
2995 |
|
|
|
2996 |
|
|
/* Set up the dentry operations before anything else, to ensure cleaning
|
2997 |
|
|
up on any error */
|
2998 |
|
|
dentry->d_op = &devfs_dops;
|
2999 |
|
|
/* First try to get the devfs entry for this directory */
|
3000 |
|
|
parent = get_devfs_entry_from_vfs_inode (dir);
|
3001 |
|
|
DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n",
|
3002 |
|
|
dentry->d_name.name, dentry, parent, current->comm);
|
3003 |
|
|
if (parent == NULL) return ERR_PTR (-ENOENT);
|
3004 |
|
|
read_lock (&parent->u.dir.lock);
|
3005 |
|
|
de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
|
3006 |
|
|
if (de) read_unlock (&parent->u.dir.lock);
|
3007 |
|
|
else
|
3008 |
|
|
{ /* Try re-reading the partition (media may have changed) */
|
3009 |
|
|
if ( get_removable_partition (parent, dentry->d_name.name,
|
3010 |
|
|
dentry->d_name.len) ) /* Unlocks */
|
3011 |
|
|
{ /* Media did change */
|
3012 |
|
|
read_lock (&parent->u.dir.lock);
|
3013 |
|
|
de = _devfs_search_dir (parent, dentry->d_name.name,
|
3014 |
|
|
dentry->d_name.len);
|
3015 |
|
|
read_unlock (&parent->u.dir.lock);
|
3016 |
|
|
}
|
3017 |
|
|
}
|
3018 |
|
|
lookup_info.de = de;
|
3019 |
|
|
init_waitqueue_head (&lookup_info.wait_queue);
|
3020 |
|
|
dentry->d_fsdata = &lookup_info;
|
3021 |
|
|
if (de == NULL)
|
3022 |
|
|
{ /* Try with devfsd. For any kind of failure, leave a negative dentry
|
3023 |
|
|
so someone else can deal with it (in the case where the sysadmin
|
3024 |
|
|
does a mknod()). It's important to do this before hashing the
|
3025 |
|
|
dentry, so that the devfsd queue is filled before revalidates
|
3026 |
|
|
can start */
|
3027 |
|
|
if (try_modload (parent, fs_info,
|
3028 |
|
|
dentry->d_name.name, dentry->d_name.len, &tmp) < 0)
|
3029 |
|
|
{ /* Lookup event was not queued to devfsd */
|
3030 |
|
|
d_add (dentry, NULL);
|
3031 |
|
|
return NULL;
|
3032 |
|
|
}
|
3033 |
|
|
}
|
3034 |
|
|
dentry->d_op = &devfs_wait_dops;
|
3035 |
|
|
d_add (dentry, NULL); /* Open the floodgates */
|
3036 |
|
|
/* Unlock directory semaphore, which will release any waiters. They
|
3037 |
|
|
will get the hashed dentry, and may be forced to wait for
|
3038 |
|
|
revalidation */
|
3039 |
|
|
up (&dir->i_sem);
|
3040 |
|
|
wait_for_devfsd_finished (fs_info); /* If I'm not devfsd, must wait */
|
3041 |
|
|
down (&dir->i_sem); /* Grab it again because them's the rules */
|
3042 |
|
|
de = lookup_info.de;
|
3043 |
|
|
/* If someone else has been so kind as to make the inode, we go home
|
3044 |
|
|
early */
|
3045 |
|
|
if (dentry->d_inode) goto out;
|
3046 |
|
|
if (de == NULL)
|
3047 |
|
|
{
|
3048 |
|
|
read_lock (&parent->u.dir.lock);
|
3049 |
|
|
de = _devfs_search_dir (parent, dentry->d_name.name,
|
3050 |
|
|
dentry->d_name.len);
|
3051 |
|
|
read_unlock (&parent->u.dir.lock);
|
3052 |
|
|
if (de == NULL) goto out;
|
3053 |
|
|
/* OK, there's an entry now, but no VFS inode yet */
|
3054 |
|
|
}
|
3055 |
|
|
/* Create an inode, now that the driver information is available */
|
3056 |
|
|
inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry);
|
3057 |
|
|
if (!inode)
|
3058 |
|
|
{
|
3059 |
|
|
retval = ERR_PTR (-ENOMEM);
|
3060 |
|
|
goto out;
|
3061 |
|
|
}
|
3062 |
|
|
DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n",
|
3063 |
|
|
de->name, de->inode.ino, inode, de, current->comm);
|
3064 |
|
|
d_instantiate (dentry, inode);
|
3065 |
|
|
out:
|
3066 |
|
|
dentry->d_op = &devfs_dops;
|
3067 |
|
|
dentry->d_fsdata = NULL;
|
3068 |
|
|
write_lock (&parent->u.dir.lock);
|
3069 |
|
|
wake_up (&lookup_info.wait_queue);
|
3070 |
|
|
write_unlock (&parent->u.dir.lock);
|
3071 |
|
|
devfs_put (de);
|
3072 |
|
|
return retval;
|
3073 |
|
|
} /* End Function devfs_lookup */
|
3074 |
|
|
|
3075 |
|
|
static int devfs_unlink (struct inode *dir, struct dentry *dentry)
|
3076 |
|
|
{
|
3077 |
|
|
int unhooked;
|
3078 |
|
|
struct devfs_entry *de;
|
3079 |
|
|
struct inode *inode = dentry->d_inode;
|
3080 |
|
|
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
|
3081 |
|
|
|
3082 |
|
|
de = get_devfs_entry_from_vfs_inode (inode);
|
3083 |
|
|
DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
|
3084 |
|
|
if (de == NULL) return -ENOENT;
|
3085 |
|
|
if (!de->vfs_deletable) return -EPERM;
|
3086 |
|
|
write_lock (&de->parent->u.dir.lock);
|
3087 |
|
|
unhooked = _devfs_unhook (de);
|
3088 |
|
|
write_unlock (&de->parent->u.dir.lock);
|
3089 |
|
|
if (!unhooked) return -ENOENT;
|
3090 |
|
|
if ( !is_devfsd_or_child (fs_info) )
|
3091 |
|
|
devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
|
3092 |
|
|
inode->i_uid, inode->i_gid, fs_info, 0);
|
3093 |
|
|
free_dentry (de);
|
3094 |
|
|
devfs_put (de);
|
3095 |
|
|
return 0;
|
3096 |
|
|
} /* End Function devfs_unlink */
|
3097 |
|
|
|
3098 |
|
|
static int devfs_symlink (struct inode *dir, struct dentry *dentry,
|
3099 |
|
|
const char *symname)
|
3100 |
|
|
{
|
3101 |
|
|
int err;
|
3102 |
|
|
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
|
3103 |
|
|
struct devfs_entry *parent, *de;
|
3104 |
|
|
struct inode *inode;
|
3105 |
|
|
|
3106 |
|
|
/* First try to get the devfs entry for this directory */
|
3107 |
|
|
parent = get_devfs_entry_from_vfs_inode (dir);
|
3108 |
|
|
if (parent == NULL) return -ENOENT;
|
3109 |
|
|
err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE,
|
3110 |
|
|
symname, &de, NULL);
|
3111 |
|
|
DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n",
|
3112 |
|
|
dentry->d_name.name, err);
|
3113 |
|
|
if (err < 0) return err;
|
3114 |
|
|
de->vfs_deletable = TRUE;
|
3115 |
|
|
de->inode.uid = current->euid;
|
3116 |
|
|
de->inode.gid = current->egid;
|
3117 |
|
|
de->inode.atime = CURRENT_TIME;
|
3118 |
|
|
de->inode.mtime = CURRENT_TIME;
|
3119 |
|
|
de->inode.ctime = CURRENT_TIME;
|
3120 |
|
|
if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
|
3121 |
|
|
return -ENOMEM;
|
3122 |
|
|
DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n",
|
3123 |
|
|
dentry->d_name.name, de->inode.ino, inode, dentry);
|
3124 |
|
|
d_instantiate (dentry, inode);
|
3125 |
|
|
if ( !is_devfsd_or_child (fs_info) )
|
3126 |
|
|
devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
|
3127 |
|
|
inode->i_uid, inode->i_gid, fs_info, 0);
|
3128 |
|
|
return 0;
|
3129 |
|
|
} /* End Function devfs_symlink */
|
3130 |
|
|
|
3131 |
|
|
static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
|
3132 |
|
|
{
|
3133 |
|
|
int err;
|
3134 |
|
|
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
|
3135 |
|
|
struct devfs_entry *parent, *de;
|
3136 |
|
|
struct inode *inode;
|
3137 |
|
|
|
3138 |
|
|
mode = (mode & ~S_IFMT) | S_IFDIR; /* VFS doesn't pass S_IFMT part */
|
3139 |
|
|
parent = get_devfs_entry_from_vfs_inode (dir);
|
3140 |
|
|
if (parent == NULL) return -ENOENT;
|
3141 |
|
|
de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
|
3142 |
|
|
if (!de) return -ENOMEM;
|
3143 |
|
|
de->vfs_deletable = TRUE;
|
3144 |
|
|
if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
|
3145 |
|
|
return err;
|
3146 |
|
|
de->inode.uid = current->euid;
|
3147 |
|
|
de->inode.gid = current->egid;
|
3148 |
|
|
de->inode.atime = CURRENT_TIME;
|
3149 |
|
|
de->inode.mtime = CURRENT_TIME;
|
3150 |
|
|
de->inode.ctime = CURRENT_TIME;
|
3151 |
|
|
if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
|
3152 |
|
|
return -ENOMEM;
|
3153 |
|
|
DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n",
|
3154 |
|
|
dentry->d_name.name, de->inode.ino, inode, dentry);
|
3155 |
|
|
d_instantiate (dentry, inode);
|
3156 |
|
|
if ( !is_devfsd_or_child (fs_info) )
|
3157 |
|
|
devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
|
3158 |
|
|
inode->i_uid, inode->i_gid, fs_info, 0);
|
3159 |
|
|
return 0;
|
3160 |
|
|
} /* End Function devfs_mkdir */
|
3161 |
|
|
|
3162 |
|
|
static int devfs_rmdir (struct inode *dir, struct dentry *dentry)
|
3163 |
|
|
{
|
3164 |
|
|
int err = 0;
|
3165 |
|
|
struct devfs_entry *de;
|
3166 |
|
|
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
|
3167 |
|
|
struct inode *inode = dentry->d_inode;
|
3168 |
|
|
|
3169 |
|
|
if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL;
|
3170 |
|
|
de = get_devfs_entry_from_vfs_inode (inode);
|
3171 |
|
|
if (de == NULL) return -ENOENT;
|
3172 |
|
|
if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
|
3173 |
|
|
if (!de->vfs_deletable) return -EPERM;
|
3174 |
|
|
/* First ensure the directory is empty and will stay that way */
|
3175 |
|
|
write_lock (&de->u.dir.lock);
|
3176 |
|
|
if (de->u.dir.first) err = -ENOTEMPTY;
|
3177 |
|
|
else de->u.dir.no_more_additions = TRUE;
|
3178 |
|
|
write_unlock (&de->u.dir.lock);
|
3179 |
|
|
if (err) return err;
|
3180 |
|
|
/* Now unhook the directory from it's parent */
|
3181 |
|
|
write_lock (&de->parent->u.dir.lock);
|
3182 |
|
|
if ( !_devfs_unhook (de) ) err = -ENOENT;
|
3183 |
|
|
write_unlock (&de->parent->u.dir.lock);
|
3184 |
|
|
if (err) return err;
|
3185 |
|
|
if ( !is_devfsd_or_child (fs_info) )
|
3186 |
|
|
devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
|
3187 |
|
|
inode->i_uid, inode->i_gid, fs_info, 0);
|
3188 |
|
|
free_dentry (de);
|
3189 |
|
|
devfs_put (de);
|
3190 |
|
|
return 0;
|
3191 |
|
|
} /* End Function devfs_rmdir */
|
3192 |
|
|
|
3193 |
|
|
static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode,
|
3194 |
|
|
int rdev)
|
3195 |
|
|
{
|
3196 |
|
|
int err;
|
3197 |
|
|
struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
|
3198 |
|
|
struct devfs_entry *parent, *de;
|
3199 |
|
|
struct inode *inode;
|
3200 |
|
|
|
3201 |
|
|
DPRINTK (DEBUG_I_MKNOD, "(%s): mode: 0%o dev: %d\n",
|
3202 |
|
|
dentry->d_name.name, mode, rdev);
|
3203 |
|
|
parent = get_devfs_entry_from_vfs_inode (dir);
|
3204 |
|
|
if (parent == NULL) return -ENOENT;
|
3205 |
|
|
de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode);
|
3206 |
|
|
if (!de) return -ENOMEM;
|
3207 |
|
|
de->vfs_deletable = TRUE;
|
3208 |
|
|
if ( S_ISBLK (mode) || S_ISCHR (mode) )
|
3209 |
|
|
{
|
3210 |
|
|
de->u.fcb.u.device.major = MAJOR (rdev);
|
3211 |
|
|
de->u.fcb.u.device.minor = MINOR (rdev);
|
3212 |
|
|
}
|
3213 |
|
|
if ( ( err = _devfs_append_entry (parent, de, FALSE, NULL) ) != 0 )
|
3214 |
|
|
return err;
|
3215 |
|
|
de->inode.uid = current->euid;
|
3216 |
|
|
de->inode.gid = current->egid;
|
3217 |
|
|
de->inode.atime = CURRENT_TIME;
|
3218 |
|
|
de->inode.mtime = CURRENT_TIME;
|
3219 |
|
|
de->inode.ctime = CURRENT_TIME;
|
3220 |
|
|
if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL )
|
3221 |
|
|
return -ENOMEM;
|
3222 |
|
|
DPRINTK (DEBUG_I_MKNOD, ": new VFS inode(%u): %p dentry: %p\n",
|
3223 |
|
|
de->inode.ino, inode, dentry);
|
3224 |
|
|
d_instantiate (dentry, inode);
|
3225 |
|
|
if ( !is_devfsd_or_child (fs_info) )
|
3226 |
|
|
devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode,
|
3227 |
|
|
inode->i_uid, inode->i_gid, fs_info, 0);
|
3228 |
|
|
return 0;
|
3229 |
|
|
} /* End Function devfs_mknod */
|
3230 |
|
|
|
3231 |
|
|
static int devfs_readlink (struct dentry *dentry, char *buffer, int buflen)
|
3232 |
|
|
{
|
3233 |
|
|
int err;
|
3234 |
|
|
struct devfs_entry *de;
|
3235 |
|
|
|
3236 |
|
|
de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
|
3237 |
|
|
if (!de) return -ENODEV;
|
3238 |
|
|
err = vfs_readlink (dentry, buffer, buflen, de->u.symlink.linkname);
|
3239 |
|
|
return err;
|
3240 |
|
|
} /* End Function devfs_readlink */
|
3241 |
|
|
|
3242 |
|
|
static int devfs_follow_link (struct dentry *dentry, struct nameidata *nd)
|
3243 |
|
|
{
|
3244 |
|
|
int err;
|
3245 |
|
|
struct devfs_entry *de;
|
3246 |
|
|
|
3247 |
|
|
de = get_devfs_entry_from_vfs_inode (dentry->d_inode);
|
3248 |
|
|
if (!de) return -ENODEV;
|
3249 |
|
|
err = vfs_follow_link (nd, de->u.symlink.linkname);
|
3250 |
|
|
return err;
|
3251 |
|
|
} /* End Function devfs_follow_link */
|
3252 |
|
|
|
3253 |
|
|
static struct inode_operations devfs_iops =
|
3254 |
|
|
{
|
3255 |
|
|
.setattr = devfs_notify_change,
|
3256 |
|
|
};
|
3257 |
|
|
|
3258 |
|
|
static struct inode_operations devfs_dir_iops =
|
3259 |
|
|
{
|
3260 |
|
|
.lookup = devfs_lookup,
|
3261 |
|
|
.unlink = devfs_unlink,
|
3262 |
|
|
.symlink = devfs_symlink,
|
3263 |
|
|
.mkdir = devfs_mkdir,
|
3264 |
|
|
.rmdir = devfs_rmdir,
|
3265 |
|
|
.mknod = devfs_mknod,
|
3266 |
|
|
.setattr = devfs_notify_change,
|
3267 |
|
|
};
|
3268 |
|
|
|
3269 |
|
|
static struct inode_operations devfs_symlink_iops =
|
3270 |
|
|
{
|
3271 |
|
|
.readlink = devfs_readlink,
|
3272 |
|
|
.follow_link = devfs_follow_link,
|
3273 |
|
|
.setattr = devfs_notify_change,
|
3274 |
|
|
};
|
3275 |
|
|
|
3276 |
|
|
static struct super_block *devfs_read_super (struct super_block *sb,
|
3277 |
|
|
void *data, int silent)
|
3278 |
|
|
{
|
3279 |
|
|
struct inode *root_inode = NULL;
|
3280 |
|
|
|
3281 |
|
|
if (_devfs_get_root_entry () == NULL) goto out_no_root;
|
3282 |
|
|
atomic_set (&fs_info.devfsd_overrun_count, 0);
|
3283 |
|
|
init_waitqueue_head (&fs_info.devfsd_wait_queue);
|
3284 |
|
|
init_waitqueue_head (&fs_info.revalidate_wait_queue);
|
3285 |
|
|
fs_info.sb = sb;
|
3286 |
|
|
sb->u.generic_sbp = &fs_info;
|
3287 |
|
|
sb->s_blocksize = 1024;
|
3288 |
|
|
sb->s_blocksize_bits = 10;
|
3289 |
|
|
sb->s_magic = DEVFS_SUPER_MAGIC;
|
3290 |
|
|
sb->s_op = &devfs_sops;
|
3291 |
|
|
if ( ( root_inode = _devfs_get_vfs_inode (sb, root_entry, NULL) ) == NULL )
|
3292 |
|
|
goto out_no_root;
|
3293 |
|
|
sb->s_root = d_alloc_root (root_inode);
|
3294 |
|
|
if (!sb->s_root) goto out_no_root;
|
3295 |
|
|
DPRINTK (DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->u.generic_sbp);
|
3296 |
|
|
return sb;
|
3297 |
|
|
|
3298 |
|
|
out_no_root:
|
3299 |
|
|
PRINTK ("(): get root inode failed\n");
|
3300 |
|
|
if (root_inode) iput (root_inode);
|
3301 |
|
|
return NULL;
|
3302 |
|
|
} /* End Function devfs_read_super */
|
3303 |
|
|
|
3304 |
|
|
|
3305 |
|
|
static DECLARE_FSTYPE (devfs_fs_type, DEVFS_NAME, devfs_read_super, FS_SINGLE);
|
3306 |
|
|
|
3307 |
|
|
|
3308 |
|
|
/* File operations for devfsd follow */
|
3309 |
|
|
|
3310 |
|
|
static ssize_t devfsd_read (struct file *file, char *buf, size_t len,
|
3311 |
|
|
loff_t *ppos)
|
3312 |
|
|
{
|
3313 |
|
|
int done = FALSE;
|
3314 |
|
|
int ival;
|
3315 |
|
|
loff_t pos, devname_offset, tlen, rpos;
|
3316 |
|
|
devfs_handle_t de;
|
3317 |
|
|
struct devfsd_buf_entry *entry;
|
3318 |
|
|
struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->u.generic_sbp;
|
3319 |
|
|
struct devfsd_notify_struct *info = fs_info->devfsd_info;
|
3320 |
|
|
DECLARE_WAITQUEUE (wait, current);
|
3321 |
|
|
|
3322 |
|
|
/* Can't seek (pread) on this device */
|
3323 |
|
|
if (ppos != &file->f_pos) return -ESPIPE;
|
3324 |
|
|
/* Verify the task has grabbed the queue */
|
3325 |
|
|
if (fs_info->devfsd_task != current) return -EPERM;
|
3326 |
|
|
info->major = 0;
|
3327 |
|
|
info->minor = 0;
|
3328 |
|
|
/* Block for a new entry */
|
3329 |
|
|
set_current_state (TASK_INTERRUPTIBLE);
|
3330 |
|
|
add_wait_queue (&fs_info->devfsd_wait_queue, &wait);
|
3331 |
|
|
while ( devfsd_queue_empty (fs_info) )
|
3332 |
|
|
{
|
3333 |
|
|
fs_info->devfsd_sleeping = TRUE;
|
3334 |
|
|
wake_up (&fs_info->revalidate_wait_queue);
|
3335 |
|
|
schedule ();
|
3336 |
|
|
fs_info->devfsd_sleeping = FALSE;
|
3337 |
|
|
if ( signal_pending (current) )
|
3338 |
|
|
{
|
3339 |
|
|
remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
|
3340 |
|
|
__set_current_state (TASK_RUNNING);
|
3341 |
|
|
return -EINTR;
|
3342 |
|
|
}
|
3343 |
|
|
set_current_state (TASK_INTERRUPTIBLE);
|
3344 |
|
|
}
|
3345 |
|
|
remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
|
3346 |
|
|
__set_current_state (TASK_RUNNING);
|
3347 |
|
|
/* Now play with the data */
|
3348 |
|
|
ival = atomic_read (&fs_info->devfsd_overrun_count);
|
3349 |
|
|
info->overrun_count = ival;
|
3350 |
|
|
entry = fs_info->devfsd_first_event;
|
3351 |
|
|
info->type = entry->type;
|
3352 |
|
|
info->mode = entry->mode;
|
3353 |
|
|
info->uid = entry->uid;
|
3354 |
|
|
info->gid = entry->gid;
|
3355 |
|
|
de = entry->de;
|
3356 |
|
|
if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) )
|
3357 |
|
|
{
|
3358 |
|
|
info->major = de->u.fcb.u.device.major;
|
3359 |
|
|
info->minor = de->u.fcb.u.device.minor;
|
3360 |
|
|
}
|
3361 |
|
|
pos = devfs_generate_path (de, info->devname, DEVFS_PATHLEN);
|
3362 |
|
|
if (pos < 0) return pos;
|
3363 |
|
|
info->namelen = DEVFS_PATHLEN - pos - 1;
|
3364 |
|
|
if (info->mode == 0) info->mode = de->mode;
|
3365 |
|
|
devname_offset = info->devname - (char *) info;
|
3366 |
|
|
rpos = *ppos;
|
3367 |
|
|
if (rpos < devname_offset)
|
3368 |
|
|
{
|
3369 |
|
|
/* Copy parts of the header */
|
3370 |
|
|
tlen = devname_offset - rpos;
|
3371 |
|
|
if (tlen > len) tlen = len;
|
3372 |
|
|
if ( copy_to_user (buf, (char *) info + rpos, tlen) )
|
3373 |
|
|
{
|
3374 |
|
|
return -EFAULT;
|
3375 |
|
|
}
|
3376 |
|
|
rpos += tlen;
|
3377 |
|
|
buf += tlen;
|
3378 |
|
|
len -= tlen;
|
3379 |
|
|
}
|
3380 |
|
|
if ( (rpos >= devname_offset) && (len > 0) )
|
3381 |
|
|
{
|
3382 |
|
|
/* Copy the name */
|
3383 |
|
|
tlen = info->namelen + 1;
|
3384 |
|
|
if (tlen > len) tlen = len;
|
3385 |
|
|
else done = TRUE;
|
3386 |
|
|
if ( copy_to_user (buf, info->devname + pos + rpos - devname_offset,
|
3387 |
|
|
tlen) )
|
3388 |
|
|
{
|
3389 |
|
|
return -EFAULT;
|
3390 |
|
|
}
|
3391 |
|
|
rpos += tlen;
|
3392 |
|
|
}
|
3393 |
|
|
tlen = rpos - *ppos;
|
3394 |
|
|
if (done)
|
3395 |
|
|
{
|
3396 |
|
|
devfs_handle_t parent;
|
3397 |
|
|
|
3398 |
|
|
spin_lock (&fs_info->devfsd_buffer_lock);
|
3399 |
|
|
fs_info->devfsd_first_event = entry->next;
|
3400 |
|
|
if (entry->next == NULL) fs_info->devfsd_last_event = NULL;
|
3401 |
|
|
spin_unlock (&fs_info->devfsd_buffer_lock);
|
3402 |
|
|
for (; de != NULL; de = parent)
|
3403 |
|
|
{
|
3404 |
|
|
parent = de->parent;
|
3405 |
|
|
devfs_put (de);
|
3406 |
|
|
}
|
3407 |
|
|
kmem_cache_free (devfsd_buf_cache, entry);
|
3408 |
|
|
if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count);
|
3409 |
|
|
*ppos = 0;
|
3410 |
|
|
}
|
3411 |
|
|
else *ppos = rpos;
|
3412 |
|
|
return tlen;
|
3413 |
|
|
} /* End Function devfsd_read */
|
3414 |
|
|
|
3415 |
|
|
static int devfsd_ioctl (struct inode *inode, struct file *file,
|
3416 |
|
|
unsigned int cmd, unsigned long arg)
|
3417 |
|
|
{
|
3418 |
|
|
int ival;
|
3419 |
|
|
struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
|
3420 |
|
|
|
3421 |
|
|
switch (cmd)
|
3422 |
|
|
{
|
3423 |
|
|
case DEVFSDIOC_GET_PROTO_REV:
|
3424 |
|
|
ival = DEVFSD_PROTOCOL_REVISION_KERNEL;
|
3425 |
|
|
if ( copy_to_user ( (void *)arg, &ival, sizeof ival ) ) return -EFAULT;
|
3426 |
|
|
break;
|
3427 |
|
|
case DEVFSDIOC_SET_EVENT_MASK:
|
3428 |
|
|
/* Ensure only one reader has access to the queue. This scheme will
|
3429 |
|
|
work even if the global kernel lock were to be removed, because it
|
3430 |
|
|
doesn't matter who gets in first, as long as only one gets it */
|
3431 |
|
|
if (fs_info->devfsd_task == NULL)
|
3432 |
|
|
{
|
3433 |
|
|
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
|
3434 |
|
|
|
3435 |
|
|
if ( !spin_trylock (&lock) ) return -EBUSY;
|
3436 |
|
|
if (fs_info->devfsd_task != NULL)
|
3437 |
|
|
{ /* We lost the race... */
|
3438 |
|
|
spin_unlock (&lock);
|
3439 |
|
|
return -EBUSY;
|
3440 |
|
|
}
|
3441 |
|
|
fs_info->devfsd_task = current;
|
3442 |
|
|
spin_unlock (&lock);
|
3443 |
|
|
fs_info->devfsd_pgrp = (current->pgrp == current->pid) ?
|
3444 |
|
|
current->pgrp : 0;
|
3445 |
|
|
fs_info->devfsd_file = file;
|
3446 |
|
|
fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info,
|
3447 |
|
|
GFP_KERNEL);
|
3448 |
|
|
if (!fs_info->devfsd_info)
|
3449 |
|
|
{
|
3450 |
|
|
devfsd_close (inode, file);
|
3451 |
|
|
return -ENOMEM;
|
3452 |
|
|
}
|
3453 |
|
|
}
|
3454 |
|
|
else if (fs_info->devfsd_task != current) return -EBUSY;
|
3455 |
|
|
fs_info->devfsd_event_mask = arg; /* Let the masses come forth */
|
3456 |
|
|
break;
|
3457 |
|
|
case DEVFSDIOC_RELEASE_EVENT_QUEUE:
|
3458 |
|
|
if (fs_info->devfsd_file != file) return -EPERM;
|
3459 |
|
|
return devfsd_close (inode, file);
|
3460 |
|
|
/*break;*/
|
3461 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
3462 |
|
|
case DEVFSDIOC_SET_DEBUG_MASK:
|
3463 |
|
|
if ( copy_from_user (&ival, (void *) arg, sizeof ival) )return -EFAULT;
|
3464 |
|
|
devfs_debug = ival;
|
3465 |
|
|
break;
|
3466 |
|
|
#endif
|
3467 |
|
|
default:
|
3468 |
|
|
return -ENOIOCTLCMD;
|
3469 |
|
|
}
|
3470 |
|
|
return 0;
|
3471 |
|
|
} /* End Function devfsd_ioctl */
|
3472 |
|
|
|
3473 |
|
|
static int devfsd_close (struct inode *inode, struct file *file)
|
3474 |
|
|
{
|
3475 |
|
|
struct devfsd_buf_entry *entry, *next;
|
3476 |
|
|
struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
|
3477 |
|
|
|
3478 |
|
|
if (fs_info->devfsd_file != file) return 0;
|
3479 |
|
|
fs_info->devfsd_event_mask = 0;
|
3480 |
|
|
fs_info->devfsd_file = NULL;
|
3481 |
|
|
spin_lock (&fs_info->devfsd_buffer_lock);
|
3482 |
|
|
entry = fs_info->devfsd_first_event;
|
3483 |
|
|
fs_info->devfsd_first_event = NULL;
|
3484 |
|
|
fs_info->devfsd_last_event = NULL;
|
3485 |
|
|
if (fs_info->devfsd_info)
|
3486 |
|
|
{
|
3487 |
|
|
kfree (fs_info->devfsd_info);
|
3488 |
|
|
fs_info->devfsd_info = NULL;
|
3489 |
|
|
}
|
3490 |
|
|
spin_unlock (&fs_info->devfsd_buffer_lock);
|
3491 |
|
|
fs_info->devfsd_pgrp = 0;
|
3492 |
|
|
fs_info->devfsd_task = NULL;
|
3493 |
|
|
wake_up (&fs_info->revalidate_wait_queue);
|
3494 |
|
|
for (; entry; entry = next)
|
3495 |
|
|
{
|
3496 |
|
|
next = entry->next;
|
3497 |
|
|
kmem_cache_free (devfsd_buf_cache, entry);
|
3498 |
|
|
}
|
3499 |
|
|
return 0;
|
3500 |
|
|
} /* End Function devfsd_close */
|
3501 |
|
|
|
3502 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
3503 |
|
|
static ssize_t stat_read (struct file *file, char *buf, size_t len,
|
3504 |
|
|
loff_t *ppos)
|
3505 |
|
|
{
|
3506 |
|
|
ssize_t num;
|
3507 |
|
|
char txt[80];
|
3508 |
|
|
|
3509 |
|
|
num = sprintf (txt, "Number of entries: %u number of bytes: %u\n",
|
3510 |
|
|
stat_num_entries, stat_num_bytes) + 1;
|
3511 |
|
|
/* Can't seek (pread) on this device */
|
3512 |
|
|
if (ppos != &file->f_pos) return -ESPIPE;
|
3513 |
|
|
if (*ppos >= num) return 0;
|
3514 |
|
|
if (*ppos + len > num) len = num - *ppos;
|
3515 |
|
|
if ( copy_to_user (buf, txt + *ppos, len) ) return -EFAULT;
|
3516 |
|
|
*ppos += len;
|
3517 |
|
|
return len;
|
3518 |
|
|
} /* End Function stat_read */
|
3519 |
|
|
#endif
|
3520 |
|
|
|
3521 |
|
|
|
3522 |
|
|
static int __init init_devfs_fs (void)
|
3523 |
|
|
{
|
3524 |
|
|
int err;
|
3525 |
|
|
|
3526 |
|
|
printk (KERN_INFO "%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n",
|
3527 |
|
|
DEVFS_NAME, DEVFS_VERSION);
|
3528 |
|
|
devfsd_buf_cache = kmem_cache_create ("devfsd_event",
|
3529 |
|
|
sizeof (struct devfsd_buf_entry),
|
3530 |
|
|
0, 0, NULL, NULL);
|
3531 |
|
|
if (!devfsd_buf_cache) OOPS ("(): unable to allocate event slab\n");
|
3532 |
|
|
#ifdef CONFIG_DEVFS_DEBUG
|
3533 |
|
|
devfs_debug = devfs_debug_init;
|
3534 |
|
|
printk (KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug);
|
3535 |
|
|
#endif
|
3536 |
|
|
printk (KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options);
|
3537 |
|
|
err = register_filesystem (&devfs_fs_type);
|
3538 |
|
|
if (!err)
|
3539 |
|
|
{
|
3540 |
|
|
struct vfsmount *devfs_mnt = kern_mount (&devfs_fs_type);
|
3541 |
|
|
err = PTR_ERR (devfs_mnt);
|
3542 |
|
|
if ( !IS_ERR (devfs_mnt) ) err = 0;
|
3543 |
|
|
}
|
3544 |
|
|
return err;
|
3545 |
|
|
} /* End Function init_devfs_fs */
|
3546 |
|
|
|
3547 |
|
|
void __init mount_devfs_fs (void)
|
3548 |
|
|
{
|
3549 |
|
|
int err;
|
3550 |
|
|
|
3551 |
|
|
if ( !(boot_options & OPTION_MOUNT) ) return;
|
3552 |
|
|
err = do_mount ("none", "/dev", "devfs", 0, NULL);
|
3553 |
|
|
if (err == 0) printk (KERN_INFO "Mounted devfs on /dev\n");
|
3554 |
|
|
else PRINTK ("(): unable to mount devfs, err: %d\n", err);
|
3555 |
|
|
} /* End Function mount_devfs_fs */
|
3556 |
|
|
|
3557 |
|
|
module_init(init_devfs_fs)
|