Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/fs/sfs/sfs_fs.c
2116 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
* SFS filesystem
32
*
33
* Filesystem-level interface routines.
34
*/
35
36
#include <types.h>
37
#include <kern/errno.h>
38
#include <lib.h>
39
#include <array.h>
40
#include <bitmap.h>
41
#include <uio.h>
42
#include <vfs.h>
43
#include <device.h>
44
#include <sfs.h>
45
46
/* Shortcuts for the size macros in kern/sfs.h */
47
#define SFS_FS_BITMAPSIZE(sfs) SFS_BITMAPSIZE((sfs)->sfs_super.sp_nblocks)
48
#define SFS_FS_BITBLOCKS(sfs) SFS_BITBLOCKS((sfs)->sfs_super.sp_nblocks)
49
50
/*
51
* Routine for doing I/O (reads or writes) on the free block bitmap.
52
* We always do the whole bitmap at once; writing individual sectors
53
* might or might not be a worthwhile optimization.
54
*
55
* The free block bitmap consists of SFS_BITBLOCKS 512-byte sectors of
56
* bits, one bit for each sector on the filesystem. The number of
57
* blocks in the bitmap is thus rounded up to the nearest multiple of
58
* 512*8 = 4096. (This rounded number is SFS_BITMAPSIZE.) This means
59
* that the bitmap will (in general) contain space for some number of
60
* invalid sectors that are actually beyond the end of the disk
61
* device. This is ok. These sectors are supposed to be marked "in
62
* use" by mksfs and never get marked "free".
63
*
64
* The sectors used by the superblock and the bitmap itself are
65
* likewise marked in use by mksfs.
66
*/
67
68
static
69
int
70
sfs_mapio(struct sfs_fs *sfs, enum uio_rw rw)
71
{
72
uint32_t j, mapsize;
73
char *bitdata;
74
int result;
75
76
/* Number of blocks in the bitmap. */
77
mapsize = SFS_FS_BITBLOCKS(sfs);
78
79
/* Pointer to our bitmap data in memory. */
80
bitdata = bitmap_getdata(sfs->sfs_freemap);
81
82
/* For each sector in the bitmap... */
83
for (j=0; j<mapsize; j++) {
84
85
/* Get a pointer to its data */
86
void *ptr = bitdata + j*SFS_BLOCKSIZE;
87
88
/* and read or write it. The bitmap starts at sector 2. */
89
if (rw == UIO_READ) {
90
result = sfs_rblock(sfs, ptr, SFS_MAP_LOCATION+j);
91
}
92
else {
93
result = sfs_wblock(sfs, ptr, SFS_MAP_LOCATION+j);
94
}
95
96
/* If we failed, stop. */
97
if (result) {
98
return result;
99
}
100
}
101
return 0;
102
}
103
104
/*
105
* Sync routine. This is what gets invoked if you do FS_SYNC on the
106
* sfs filesystem structure.
107
*/
108
109
static
110
int
111
sfs_sync(struct fs *fs)
112
{
113
struct sfs_fs *sfs;
114
unsigned i, num;
115
int result;
116
117
vfs_biglock_acquire();
118
119
/*
120
* Get the sfs_fs from the generic abstract fs.
121
*
122
* Note that the abstract struct fs, which is all the VFS
123
* layer knows about, is actually a member of struct sfs_fs.
124
* The pointer in the struct fs points back to the top of the
125
* struct sfs_fs - essentially the same object. This can be a
126
* little confusing at first.
127
*
128
* The following diagram may help:
129
*
130
* struct sfs_fs <-------------\
131
* : |
132
* : sfs_absfs (struct fs) | <------\
133
* : : | |
134
* : : various members | |
135
* : : | |
136
* : : fs_data ----------/ |
137
* : : ...|...
138
* : . VFS .
139
* : . layer .
140
* : other members .......
141
* :
142
* :
143
*
144
* This construct is repeated with vnodes and devices and other
145
* similar things all over the place in OS/161, so taking the
146
* time to straighten it out in your mind is worthwhile.
147
*/
148
149
sfs = fs->fs_data;
150
151
/* Go over the array of loaded vnodes, syncing as we go. */
152
num = vnodearray_num(sfs->sfs_vnodes);
153
for (i=0; i<num; i++) {
154
struct vnode *v = vnodearray_get(sfs->sfs_vnodes, i);
155
VOP_FSYNC(v);
156
}
157
158
/* If the free block map needs to be written, write it. */
159
if (sfs->sfs_freemapdirty) {
160
result = sfs_mapio(sfs, UIO_WRITE);
161
if (result) {
162
vfs_biglock_release();
163
return result;
164
}
165
sfs->sfs_freemapdirty = false;
166
}
167
168
/* If the superblock needs to be written, write it. */
169
if (sfs->sfs_superdirty) {
170
result = sfs_wblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
171
if (result) {
172
vfs_biglock_release();
173
return result;
174
}
175
sfs->sfs_superdirty = false;
176
}
177
178
vfs_biglock_release();
179
return 0;
180
}
181
182
/*
183
* Routine to retrieve the volume name. Filesystems can be referred
184
* to by their volume name followed by a colon as well as the name
185
* of the device they're mounted on.
186
*/
187
static
188
const char *
189
sfs_getvolname(struct fs *fs)
190
{
191
struct sfs_fs *sfs = fs->fs_data;
192
const char *ret;
193
194
vfs_biglock_acquire();
195
ret = sfs->sfs_super.sp_volname;
196
vfs_biglock_release();
197
198
return ret;
199
}
200
201
/*
202
* Unmount code.
203
*
204
* VFS calls FS_SYNC on the filesystem prior to unmounting it.
205
*/
206
static
207
int
208
sfs_unmount(struct fs *fs)
209
{
210
struct sfs_fs *sfs = fs->fs_data;
211
212
vfs_biglock_acquire();
213
214
/* Do we have any files open? If so, can't unmount. */
215
if (vnodearray_num(sfs->sfs_vnodes) > 0) {
216
vfs_biglock_release();
217
return EBUSY;
218
}
219
220
/* We should have just had sfs_sync called. */
221
KASSERT(sfs->sfs_superdirty == false);
222
KASSERT(sfs->sfs_freemapdirty == false);
223
224
/* Once we start nuking stuff we can't fail. */
225
vnodearray_destroy(sfs->sfs_vnodes);
226
bitmap_destroy(sfs->sfs_freemap);
227
228
/* The vfs layer takes care of the device for us */
229
(void)sfs->sfs_device;
230
231
/* Destroy the fs object */
232
kfree(sfs);
233
234
/* nothing else to do */
235
vfs_biglock_release();
236
return 0;
237
}
238
239
/*
240
* Mount routine.
241
*
242
* The way mount works is that you call vfs_mount and pass it a
243
* filesystem-specific mount routine. Said routine takes a device and
244
* hands back a pointer to an abstract filesystem. You can also pass
245
* a void pointer through.
246
*
247
* This organization makes cleanup on error easier. Hint: it may also
248
* be easier to synchronize correctly; it is important not to get two
249
* filesystem with the same name mounted at once, or two filesystems
250
* mounted on the same device at once.
251
*/
252
253
static
254
int
255
sfs_domount(void *options, struct device *dev, struct fs **ret)
256
{
257
int result;
258
struct sfs_fs *sfs;
259
260
vfs_biglock_acquire();
261
262
/* We don't pass any options through mount */
263
(void)options;
264
265
/*
266
* Make sure our on-disk structures aren't messed up
267
*/
268
KASSERT(sizeof(struct sfs_super)==SFS_BLOCKSIZE);
269
KASSERT(sizeof(struct sfs_inode)==SFS_BLOCKSIZE);
270
KASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_dir) == 0);
271
272
/*
273
* We can't mount on devices with the wrong sector size.
274
*
275
* (Note: for all intents and purposes here, "sector" and
276
* "block" are interchangeable terms. Technically a filesystem
277
* block may be composed of several hardware sectors, but we
278
* don't do that in sfs.)
279
*/
280
if (dev->d_blocksize != SFS_BLOCKSIZE) {
281
vfs_biglock_release();
282
return ENXIO;
283
}
284
285
/* Allocate object */
286
sfs = kmalloc(sizeof(struct sfs_fs));
287
if (sfs==NULL) {
288
vfs_biglock_release();
289
return ENOMEM;
290
}
291
292
/* Allocate array */
293
sfs->sfs_vnodes = vnodearray_create();
294
if (sfs->sfs_vnodes == NULL) {
295
kfree(sfs);
296
vfs_biglock_release();
297
return ENOMEM;
298
}
299
300
/* Set the device so we can use sfs_rblock() */
301
sfs->sfs_device = dev;
302
303
/* Load superblock */
304
result = sfs_rblock(sfs, &sfs->sfs_super, SFS_SB_LOCATION);
305
if (result) {
306
vnodearray_destroy(sfs->sfs_vnodes);
307
kfree(sfs);
308
vfs_biglock_release();
309
return result;
310
}
311
312
/* Make some simple sanity checks */
313
314
if (sfs->sfs_super.sp_magic != SFS_MAGIC) {
315
kprintf("sfs: Wrong magic number in superblock "
316
"(0x%x, should be 0x%x)\n",
317
sfs->sfs_super.sp_magic,
318
SFS_MAGIC);
319
vnodearray_destroy(sfs->sfs_vnodes);
320
kfree(sfs);
321
vfs_biglock_release();
322
return EINVAL;
323
}
324
325
if (sfs->sfs_super.sp_nblocks > dev->d_blocks) {
326
kprintf("sfs: warning - fs has %u blocks, device has %u\n",
327
sfs->sfs_super.sp_nblocks, dev->d_blocks);
328
}
329
330
/* Ensure null termination of the volume name */
331
sfs->sfs_super.sp_volname[sizeof(sfs->sfs_super.sp_volname)-1] = 0;
332
333
/* Load free space bitmap */
334
sfs->sfs_freemap = bitmap_create(SFS_FS_BITMAPSIZE(sfs));
335
if (sfs->sfs_freemap == NULL) {
336
vnodearray_destroy(sfs->sfs_vnodes);
337
kfree(sfs);
338
vfs_biglock_release();
339
return ENOMEM;
340
}
341
result = sfs_mapio(sfs, UIO_READ);
342
if (result) {
343
bitmap_destroy(sfs->sfs_freemap);
344
vnodearray_destroy(sfs->sfs_vnodes);
345
kfree(sfs);
346
vfs_biglock_release();
347
return result;
348
}
349
350
/* Set up abstract fs calls */
351
sfs->sfs_absfs.fs_sync = sfs_sync;
352
sfs->sfs_absfs.fs_getvolname = sfs_getvolname;
353
sfs->sfs_absfs.fs_getroot = sfs_getroot;
354
sfs->sfs_absfs.fs_unmount = sfs_unmount;
355
sfs->sfs_absfs.fs_data = sfs;
356
357
/* the other fields */
358
sfs->sfs_superdirty = false;
359
sfs->sfs_freemapdirty = false;
360
361
/* Hand back the abstract fs */
362
*ret = &sfs->sfs_absfs;
363
364
vfs_biglock_release();
365
return 0;
366
}
367
368
/*
369
* Actual function called from high-level code to mount an sfs.
370
*/
371
372
int
373
sfs_mount(const char *device)
374
{
375
return vfs_mount(device, NULL, sfs_domount);
376
}
377
378