/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- dev_open
- dev_close
- dev_reclaim
- dev_read
- null_io
- dev_write
- dev_ioctl
- dev_stat
- dev_gettype
- dev_tryseek
- null_fsync
- dev_mmap
- dev_truncate
- dev_namefile
- null_creat
- null_mkdir
- null_symlink
- null_nameop
- null_link
- null_rename
- dev_lookup
- dev_lookparent
- dev_create_vnode
1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3 * The President and Fellows of Harvard College.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*
31 * Vnode operations for VFS devices.
32 *
33 * These hand off to the functions in the VFS device structure (see dev.h)
34 * but take care of a bunch of common tasks in a uniform fashion.
35 */
36 #include <types.h>
37 #include <kern/errno.h>
38 #include <kern/fcntl.h>
39 #include <stat.h>
40 #include <lib.h>
41 #include <uio.h>
42 #include <synch.h>
43 #include <vnode.h>
44 #include <device.h>
45
46 /*
47 * Called for each open().
48 *
49 * We reject O_APPEND.
50 */
51 static
52 int
53 dev_open(struct vnode *v, int flags)
54 {
55 struct device *d = v->vn_data;
56
57 if (flags & (O_CREAT | O_TRUNC | O_EXCL | O_APPEND)) {
58 return EINVAL;
59 }
60
61 return d->d_open(d, flags);
62 }
63
64 /*
65 * Called on the last close().
66 * Just pass through.
67 */
68 static
69 int
70 dev_close(struct vnode *v)
71 {
72 struct device *d = v->vn_data;
73 return d->d_close(d);
74 }
75
76 /*
77 * Called when the vnode refcount reaches zero.
78 * Do nothing; devices are permanent.
79 */
80 static
81 int
82 dev_reclaim(struct vnode *v)
83 {
84 (void)v;
85 /* nothing - device continues to exist even when not in use */
86 return 0;
87 }
88
89 /*
90 * Called for read. Hand off to d_io.
91 */
92 static
93 int
94 dev_read(struct vnode *v, struct uio *uio)
95 {
96 struct device *d = v->vn_data;
97 KASSERT(uio->uio_rw == UIO_READ);
98 return d->d_io(d, uio);
99 }
100
101 /*
102 * Used for several functions with the same type signature that are
103 * not meaningful on devices.
104 */
105 static
106 int
107 null_io(struct vnode *v, struct uio *uio)
108 {
109 (void)v;
110 (void)uio;
111 return EINVAL;
112 }
113
114 /*
115 * Called for write. Hand off to d_io.
116 */
117 static
118 int
119 dev_write(struct vnode *v, struct uio *uio)
120 {
121 struct device *d = v->vn_data;
122 KASSERT(uio->uio_rw == UIO_WRITE);
123 return d->d_io(d, uio);
124 }
125
126 /*
127 * Called for ioctl(). Just pass through.
128 */
129 static
130 int
131 dev_ioctl(struct vnode *v, int op, userptr_t data)
132 {
133 struct device *d = v->vn_data;
134 return d->d_ioctl(d, op, data);
135 }
136
137 /*
138 * Called for stat().
139 * Set the type and the size (block devices only).
140 * The link count for a device is always 1.
141 */
142 static
143 int
144 dev_stat(struct vnode *v, struct stat *statbuf)
145 {
146 struct device *d = v->vn_data;
147 int result;
148
149 bzero(statbuf, sizeof(struct stat));
150
151 if (d->d_blocks > 0) {
152 statbuf->st_size = d->d_blocks * d->d_blocksize;
153 statbuf->st_blksize = d->d_blocksize;
154 }
155 else {
156 statbuf->st_size = 0;
157 }
158
159 result = VOP_GETTYPE(v, &statbuf->st_mode);
160 if (result) {
161 return result;
162 }
163 /* Make up some plausible default permissions. */
164 statbuf->st_mode |= 0600;
165
166 statbuf->st_nlink = 1;
167 statbuf->st_blocks = d->d_blocks;
168
169 /* The device number this device sits on (in OS/161, it doesn't) */
170 statbuf->st_dev = 0;
171
172 /* The device number this device *is* */
173 statbuf->st_rdev = d->d_devnumber;
174
175 return 0;
176 }
177
178 /*
179 * Return the type. A device is a "block device" if it has a known
180 * length. A device that generates data in a stream is a "character
181 * device".
182 */
183 static
184 int
185 dev_gettype(struct vnode *v, mode_t *ret)
186 {
187 struct device *d = v->vn_data;
188 if (d->d_blocks > 0) {
189 *ret = S_IFBLK;
190 }
191 else {
192 *ret = S_IFCHR;
193 }
194 return 0;
195 }
196
197 /*
198 * Attempt a seek.
199 * For block devices, require block alignment.
200 * For character devices, prohibit seeking entirely.
201 */
202 static
203 int
204 dev_tryseek(struct vnode *v, off_t pos)
205 {
206 struct device *d = v->vn_data;
207 if (d->d_blocks > 0) {
208 if ((pos % d->d_blocksize)!=0) {
209 /* not block-aligned */
210 return EINVAL;
211 }
212 if (pos < 0) {
213 /*
214 * Nonsensical.
215 * (note: off_t must be signed for SEEK_CUR or
216 * SEEK_END seeks to work, so this case must
217 * be checked.)
218 */
219 return EINVAL;
220 }
221 if (pos / d->d_blocksize >= d->d_blocks) {
222 /* off the end */
223 return EINVAL;
224 }
225 }
226 else {
227 return ESPIPE;
228 }
229 return 0;
230 }
231
232 /*
233 * For fsync() - meaningless, do nothing.
234 */
235 static
236 int
237 null_fsync(struct vnode *v)
238 {
239 (void)v;
240 return 0;
241 }
242
243 /*
244 * For mmap. If you want this to do anything, you have to write it
245 * yourself. Some devices may not make sense to map. Others do.
246 */
247 static
248 int
249 dev_mmap(struct vnode *v /* add stuff as needed */)
250 {
251 (void)v;
252 return EUNIMP;
253 }
254
255 /*
256 * For ftruncate().
257 */
258 static
259 int
260 dev_truncate(struct vnode *v, off_t len)
261 {
262 struct device *d = v->vn_data;
263
264 /*
265 * Allow truncating to the object's own size, if it has one.
266 */
267 if (d->d_blocks > 0 && (off_t)(d->d_blocks*d->d_blocksize) == len) {
268 return 0;
269 }
270
271 return EINVAL;
272 }
273
274 /*
275 * For namefile (which implements "pwd")
276 *
277 * This should never be reached, as it's not possible to chdir to a
278 * device vnode.
279 */
280 static
281 int
282 dev_namefile(struct vnode *v, struct uio *uio)
283 {
284 /*
285 * The name of a device is always just "device:". The VFS
286 * layer puts in the device name for us, so we don't need to
287 * do anything further.
288 */
289
290 (void)v;
291 (void)uio;
292
293 return 0;
294 }
295
296 /*
297 * Operations that are completely meaningless on devices.
298 */
299
300 static
301 int
302 null_creat(struct vnode *v, const char *name, bool excl, mode_t mode,
303 struct vnode **result)
304 {
305 (void)v;
306 (void)name;
307 (void)excl;
308 (void)mode;
309 (void)result;
310 return ENOTDIR;
311 }
312
313 static
314 int
315 null_mkdir(struct vnode *v, const char *name, mode_t mode)
316 {
317 (void)v;
318 (void)name;
319 (void)mode;
320 return ENOTDIR;
321 }
322
323 static
324 int
325 null_symlink(struct vnode *v, const char *contents, const char *name)
326 {
327 (void)v;
328 (void)contents;
329 (void)name;
330 return ENOTDIR;
331 }
332
333 static
334 int
335 null_nameop(struct vnode *v, const char *name)
336 {
337 (void)v;
338 (void)name;
339 return ENOTDIR;
340 }
341
342 static
343 int
344 null_link(struct vnode *v, const char *name, struct vnode *file)
345 {
346 (void)v;
347 (void)name;
348 (void)file;
349 return ENOTDIR;
350 }
351
352 static
353 int
354 null_rename(struct vnode *v, const char *n1, struct vnode *v2, const char *n2)
355 {
356 (void)v;
357 (void)n1;
358 (void)v2;
359 (void)n2;
360 return ENOTDIR;
361 }
362
363
364 /*
365 * Name lookup.
366 *
367 * One interesting feature of device:name pathname syntax is that you
368 * can implement pathnames on arbitrary devices. For instance, if you
369 * had a graphics device that supported multiple resolutions (which we
370 * don't), you might arrange things so that you could open it with
371 * pathnames like "video:800x600/24bpp" in order to select the operating
372 * mode.
373 *
374 * However, we have no support for this in the base system.
375 */
376 static
377 int
378 dev_lookup(struct vnode *dir,
379 char *pathname, struct vnode **result)
380 {
381 /*
382 * If the path was "device:", we get "". For that, return self.
383 * Anything else is an error.
384 * Increment the ref count of the vnode before returning it.
385 */
386 if (strlen(pathname)>0) {
387 return ENOENT;
388 }
389 VOP_INCREF(dir);
390 *result = dir;
391 return 0;
392 }
393
394 static
395 int
396 dev_lookparent(struct vnode *dir,
397 char *pathname, struct vnode **result,
398 char *namebuf, size_t buflen)
399 {
400 /*
401 * This is always an error.
402 */
403 (void)dir;
404 (void)pathname;
405 (void)result;
406 (void)namebuf;
407 (void)buflen;
408
409 return ENOTDIR;
410 }
411
412 /*
413 * Function table for device vnodes.
414 */
415 static const struct vnode_ops dev_vnode_ops = {
416 VOP_MAGIC,
417
418 dev_open,
419 dev_close,
420 dev_reclaim,
421 dev_read,
422 null_io, /* readlink */
423 null_io, /* getdirentry */
424 dev_write,
425 dev_ioctl,
426 dev_stat,
427 dev_gettype,
428 dev_tryseek,
429 null_fsync,
430 dev_mmap,
431 dev_truncate,
432 dev_namefile,
433 null_creat,
434 null_symlink,
435 null_mkdir,
436 null_link,
437 null_nameop, /* remove */
438 null_nameop, /* rmdir */
439 null_rename,
440 dev_lookup,
441 dev_lookparent,
442 };
443
444 /*
445 * Function to create a vnode for a VFS device.
446 */
447 struct vnode *
448 dev_create_vnode(struct device *dev)
449 {
450 int result;
451 struct vnode *v;
452
453 v = kmalloc(sizeof(struct vnode));
454 if (v==NULL) {
455 return NULL;
456 }
457
458 result = VOP_INIT(v, &dev_vnode_ops, NULL, dev);
459 if (result != 0) {
460 panic("While creating vnode for device: VOP_INIT: %s\n",
461 strerror(result));
462 }
463
464 return v;
465 }