1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
#include <errno.h>
#include <fs/stat.h>
#include <fs/vfs.h>
#include <fs/vnode.h>
#include <util/debug.h>
static long special_file_stat(vnode_t *file, stat_t *ss);
static ssize_t chardev_file_read(vnode_t *file, size_t pos, void *buf,
size_t count);
static ssize_t chardev_file_write(vnode_t *file, size_t pos, const void *buf,
size_t count);
static long chardev_file_mmap(vnode_t *file, mobj_t **ret);
static long chardev_file_fill_pframe(vnode_t *file, pframe_t *pf);
static long chardev_file_flush_pframe(vnode_t *file, pframe_t *pf);
static vnode_ops_t chardev_spec_vops = {
.read = chardev_file_read,
.write = chardev_file_write,
.mmap = chardev_file_mmap,
.mknod = NULL,
.lookup = NULL,
.link = NULL,
.unlink = NULL,
.mkdir = NULL,
.rmdir = NULL,
.readdir = NULL,
.stat = special_file_stat,
.get_pframe = NULL,
.fill_pframe = chardev_file_fill_pframe,
.flush_pframe = chardev_file_flush_pframe,
};
static ssize_t blockdev_file_read(vnode_t *file, size_t pos, void *buf,
size_t count);
static ssize_t blockdev_file_write(vnode_t *file, size_t pos, const void *buf,
size_t count);
static long blockdev_file_mmap(vnode_t *file, mobj_t **ret);
static long blockdev_file_fill_pframe(vnode_t *file, pframe_t *pf);
static long blockdev_file_flush_pframe(vnode_t *file, pframe_t *pf);
static vnode_ops_t blockdev_spec_vops = {
.read = blockdev_file_read,
.write = blockdev_file_write,
.mmap = blockdev_file_mmap,
.mknod = NULL,
.lookup = NULL,
.link = NULL,
.unlink = NULL,
.mkdir = NULL,
.rmdir = NULL,
.readdir = NULL,
.stat = special_file_stat,
.get_pframe = NULL,
.fill_pframe = blockdev_file_fill_pframe,
.flush_pframe = blockdev_file_flush_pframe,
};
void init_special_vnode(vnode_t *vn)
{
if (S_ISCHR(vn->vn_mode))
{
vn->vn_ops = &chardev_spec_vops;
vn->vn_dev.chardev = chardev_lookup(vn->vn_devid);
}
else
{
KASSERT(S_ISBLK(vn->vn_mode));
vn->vn_ops = &blockdev_spec_vops;
vn->vn_dev.blockdev = blockdev_lookup(vn->vn_devid);
}
}
static long special_file_stat(vnode_t *file, stat_t *ss)
{
KASSERT(file->vn_fs->fs_root->vn_ops->stat != NULL);
// call the containing file system's stat routine
return file->vn_fs->fs_root->vn_ops->stat(file, ss);
}
/*
* Make a read by deferring to the underlying chardev and its read operation.
*
* Returns what the chardev's read returned.
*
* Hint: Watch out! chardev_file_read and chardev_file_write are indirectly
* called in do_read and do_write, respectively, as the read/write ops for
* chardev-type vnodes. This means that the vnode file should be locked
* upon entry to this function.
*
* However, tty_read and tty_write, the read/write ops for the tty chardev,
* are potentially blocking. To avoid deadlock, you should unlock the file
* before calling the chardev's read, and lock it again after. If you fail
* to do this, a shell reading from /dev/tty0 for instance, will block all
* access to the /dev/tty0 vnode. This means that if someone runs `ls /dev/`,
* while a shell is reading from `/dev/tty0`, the `ls` call will hang.
*
* Also, if a vnode represents a chardev, you can access the chardev using
* vnode->vn_dev.chardev.
*
*/
static ssize_t chardev_file_read(vnode_t *file, size_t pos, void *buf,
size_t count)
{
// check if the vnode represetns a chardev
if (file->vn_dev.chardev == NULL)
{
return -ENXIO;
}
// Unlock the file and call read
vunlock(file);
ssize_t ret = file->vn_dev.chardev->cd_ops->read(file->vn_dev.chardev, pos, buf, count);
vlock(file);
return ret;
}
/*
* Make a write by deferring to the underlying chardev and its write operation.
*
* Return what the chardev's write returned.
*
* See the comments from chardev_file_read above for hints.
*
*/
static long chardev_file_write(vnode_t *file, size_t pos, const void *buf,
size_t count)
{
// check if the vnode represents a chardev
if (file->vn_dev.chardev == NULL)
{
return -ENXIO;
}
// Unlock the file and call write
vunlock(file);
long ret = file->vn_dev.chardev->cd_ops->write(file->vn_dev.chardev, pos, buf, count);
vlock(file);
return ret;
}
/*
* For this and the following chardev functions, simply defer to the underlying
* chardev's corresponding operations.
*/
static long chardev_file_mmap(vnode_t *file, mobj_t **ret)
{
// check if the vnode represents a chardev
chardev_t *dev = file->vn_dev.chardev;
if (dev == NULL)
{
return -ENXIO;
}
// call the chardev's mmap operation
return dev->cd_ops->mmap(file, ret);
}
static long chardev_file_fill_pframe(vnode_t *file, pframe_t *pf)
{
// check if the vnode represents a chardev
chardev_t *dev = file->vn_dev.chardev;
if (dev == NULL)
{
return -ENXIO;
}
// call the chardev's fill_pframe operation
return dev->cd_ops->fill_pframe(file, pf);
}
static long chardev_file_flush_pframe(vnode_t *file, pframe_t *pf)
{
// check if the vnode represents a chardev
chardev_t *dev = file->vn_dev.chardev;
if (dev == NULL)
{
return -ENXIO;
}
// call the chardev's flush_pframe operation
return dev->cd_ops->flush_pframe(file, pf);
}
static ssize_t blockdev_file_read(vnode_t *file, size_t pos, void *buf,
size_t count)
{
return -ENOTSUP;
}
static long blockdev_file_write(vnode_t *file, size_t pos, const void *buf,
size_t count)
{
return -ENOTSUP;
}
static long blockdev_file_mmap(vnode_t *file, mobj_t **ret) { return -ENOTSUP; }
static long blockdev_file_fill_pframe(vnode_t *file, pframe_t *pf)
{
return -ENOTSUP;
}
static long blockdev_file_flush_pframe(vnode_t *file, pframe_t *pf)
{
return -ENOTSUP;
}
|