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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
|
/*
* FILE: vnode.h
* AUTH: mcc
* DESC:
* DATE: Fri Mar 13 18:54:11 1998
* $Id: vnode.h,v 1.2.2.2 2006/06/04 01:02:32 afenn Exp $
*/
#pragma once
#include "drivers/blockdev.h"
#include "drivers/chardev.h"
#include "drivers/dev.h"
#include "mm/mobj.h"
#include "mm/pframe.h"
#include "proc/kmutex.h"
#include "util/list.h"
struct fs;
struct dirent;
struct stat;
struct file;
struct vnode;
struct kmutex;
#define VNODE_LOADING 0
#define VNODE_LOADED 1
typedef struct vnode_ops
{
/* The following functions map directly to their corresponding
* system calls. Unless otherwise noted, they return 0 on
* success, and -errno on failure.
*/
/* Operations that can be performed on non-directory files: */
/*
* read transfers at most count bytes from file into buf. It
* begins reading from the file at pos bytes into the file. On
* success, it returns the number of bytes transferred, or 0 if the
* end of the file has been reached (pos >= file->vn_len).
*/
ssize_t (*read)(struct vnode *file, size_t pos, void *buf, size_t count);
/*
* write transfers count bytes from buf into file. It begins
* writing at pos bytes into the file. If offset+count extends
* past the end of the file, the file's length will be increased.
* If offset is before the end of the file, the existing data is
* overwritten. On success, it returns the number of bytes
* transferred.
*/
ssize_t (*write)(struct vnode *file, size_t pos, const void *buf,
size_t count);
/*
* Implementations should supply an mobj through the "ret"
* argument (not by setting vma->vma_obj). If for any reason
* this cannot be done an appropriate error code should be
* returned instead.
*/
long (*mmap)(struct vnode *file, struct mobj **ret);
/* Operations that can be performed on directory files: */
/*
* mknod creates a special specified by name and namelen in the
* directory pointed to by dir with the specified mode and devid.
*
* Upon success, ret must point to the newly created file.
*/
long (*mknod)(struct vnode *dir, const char *name, size_t namelen, int mode,
devid_t devid, struct vnode **ret);
/*
* lookup attempts to find the file specified by name and namelen in the
* directory pointed to by dir.
*
* Upon success, ret must point to the child vnode.
*/
long (*lookup)(struct vnode *dir, const char *name, size_t namelen,
struct vnode **out);
/*
* Creates a directory entry in dir specified by name and namelen pointing
* to the inode of target.
*/
long (*link)(struct vnode *dir, const char *name, size_t namelen,
struct vnode *target);
/*
* unlink removes the directory entry in dir corresponding to the file
* specified by name and namelen.
*/
long (*unlink)(struct vnode *dir, const char *name, size_t namelen);
/*
* rename
*/
long (*rename)(struct vnode *olddir, const char *oldname, size_t oldnamelen,
struct vnode *newdir, const char *newname,
size_t newnamelen);
/*
* mkdir creates a directory specified by name and namelen in the
* directory pointed to by out.
*
* Upon success, out must point to the newly created directory.
* Upon failure, out must be unchanged.
*/
long (*mkdir)(struct vnode *dir, const char *name, size_t namelen,
struct vnode **out);
/*
* rmdir removes the directory specified by name and namelen from dir.
* The directory to be removed must be empty: the only directory entries
* must be "." and "..".
*/
long (*rmdir)(struct vnode *dir, const char *name, size_t namelen);
/*
* readdir reads one directory entry from the dir into the struct
* dirent. On success, it returns the amount that offset should be
* increased by to obtain the next directory entry with a
* subsequent call to readdir. If the end of the file as been
* reached (offset == file->vn_len), no directory entry will be
* read and 0 will be returned.
*/
ssize_t (*readdir)(struct vnode *dir, size_t pos, struct dirent *d);
/* Operations that can be performed on any type of "file" (
* includes normal file, directory, block/byte device */
/*
* stat sets the fields in the given buf, filling it with
* information about file.
*/
long (*stat)(struct vnode *vnode, struct stat *buf);
/*
* acquire is called on a vnode when a file takes its first
* reference to the vnode. The file is passed in.
*/
long (*acquire)(struct vnode *vnode, struct file *file);
/*
* release is called on a vnode when the refcount of a file
* descriptor that has it open comes down to 0. Each call to
* acquire has exactly one matching call to release with the
* same file that was passed to acquire.
*/
long (*release)(struct vnode *vnode, struct file *file);
long (*get_pframe)(struct vnode *vnode, size_t pagenum, long forwrite,
pframe_t **pfp);
/*
* Read the page of 'vnode' containing 'offset' into the
* page-aligned and page-sized buffer pointed to by
* 'buf'.
*/
long (*fill_pframe)(struct vnode *vnode, pframe_t *pf);
/*
* Write the contents of the page-aligned and page-sized
* buffer pointed to by 'buf' to the page of 'vnode'
* containing 'offset'.
*/
long (*flush_pframe)(struct vnode *vnode, pframe_t *pf);
/*
* This will truncate the file to have a length of zero
* Should only be used on regular files, not directories.
*/
void (*truncate_file)(struct vnode *vnode);
} vnode_ops_t;
typedef struct vnode
{
/*
* Function pointers to the implementations of file operations (the
* functions are provided by the filesystem implementation).
*/
struct vnode_ops *vn_ops;
/*
* The filesystem to which this vnode belongs. This is initialized by
* the VFS subsystem when the vnode is first created and should never
* change.
*/
struct fs *vn_fs;
#ifdef __MOUNTING__
/* This field is used only for implementing mount points (not required) */
/* This field points the the root of the file system mounted at
* this vnode. If no file system is mounted at this point this is a
* self pointer (i.e. vn->vn_mount = vn). See vget for why this is
* makes things easier for us. */
struct vnode *vn_mount;
#endif
/*
* The object responsible for managing the memory where pages read
* from this file reside. The VFS subsystem may use this field, but it
* does not need to create it.
*/
struct mobj vn_mobj;
/*
* A number which uniquely identifies this vnode within its filesystem.
* (Similar and usually identical to what you might know as the inode
* number of a file).
*/
ino_t vn_vno;
/*
* File type. See stat.h.
*/
int vn_mode;
/*
* Length of file. Initialized at the fs-implementation-level (in the
* 'read_vnode' fs_t entry point). Maintained at the filesystem
* implementation level (within the implementations of relevant vnode
* entry points).
*/
size_t vn_len;
/*
* A generic pointer which the file system can use to store any extra
* data it needs.
*/
void *vn_i;
/*
* The device identifier.
* Only relevant to vnodes representing device files.
*/
devid_t vn_devid;
/*
* The state of the vnode. Can either be loading or loaded. The vnode
* cannot be used until the vnode is in the loaded state. Potential
* users should wait on `vn_waitq` if the vnode is being loaded.
* This field is protected by the 'vn_state_lock'.
*/
int vn_state;
/*
* Allows vnode users to wait on the vnode, until the vnode is ready.
*/
ktqueue_t vn_waitq;
union {
chardev_t *chardev;
blockdev_t *blockdev;
} vn_dev;
/* Used (only) by the v{get,ref,put} facilities (vfs/vnode.c): */
list_link_t vn_link; /* link on system vnode list */
} vnode_t;
void init_special_vnode(vnode_t *vn);
/* Core vnode management routines: */
/*
* Obtain a vnode representing the file that filesystem 'fs' identifies
* by inode number 'vnum'; returns the vnode_t corresponding to the
* given filesystem and vnode number. If a vnode for the given file
* already exists (it already has an entry in the system inode table) then
* the reference count of that vnode is incremented and it is returned.
* Otherwise a new vnode is created in the system inode table with a
* reference count of 1.
* This function has no unsuccessful return.
*
* MAY BLOCK.
*/
struct vnode *vget(struct fs *fs, ino_t vnum);
/*
* Lock a vnode (locks vn_mobj).
*/
void vlock(vnode_t *vn);
/*
* Lock two vnodes in order! This prevents the A/B locking problem when locking
* two directories or two files.
*/
void vlock_in_order(vnode_t *a, vnode_t *b);
/*
* Acquires a vnode locked (see vget above)
*/
vnode_t *vget_locked(struct fs *fs, ino_t ino);
/**
* Unlock and put a vnode (see vput)
*/
void vput_locked(struct vnode **vnp);
/**
* Unlocks a vnode
*/
void vunlock(vnode_t *vn);
/**
* Unlocks two vnodes (effectively just 2 unlocks)
*/
void vunlock_in_order(vnode_t *a, vnode_t *b);
/*
* Increments the reference count of the provided vnode
* (i.e. the refcount of vn_mobj).
*/
void vref(vnode_t *vn);
/*
* This function decrements the reference count on this vnode
* (i.e. the refcount of vn_mobj).
*
* If, as a result of this, refcount reaches zero, the underlying
* fs's 'delete_vnode' entry point will be called and the vnode will be
* freed.
*
* If the linkcount of the corresponding on inode on the filesystem is zero,
* then the inode will be freed.
*
*/
void vput(vnode_t **vnp);
/* Auxilliary: */
/* Unmounting (shutting down the VFS) is the primary reason for the
* existence of the following three routines (when unmounting an s5 fs,
* they are used in the order that they are listed here): */
/*
* Checks to see if there are any actively-referenced vnodes
* belonging to the specified filesystem.
* Returns -EBUSY if there is at least one such actively-referenced
* vnode, and 0 otherwise.
*
*/
long vfs_is_in_use(struct fs *fs);
/*
* Returns the number of vnodes from this filesystem that are in
* use.
*/
size_t vfs_count_active_vnodes(struct fs *fs);
/* Diagnostic: */
/*
* Prints the vnodes that are in use. Specifying a fs_t will restrict
* the vnodes to just that fs. Specifying NULL will print all vnodes
* in the entire system.
*
* Note that this is currently unimplemented.
*/
void vnode_print(struct fs *fs);
|