Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/vfs/device.c
2092 views
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
}
466
467