/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- sfs_mapio
- sfs_sync
- sfs_getvolname
- sfs_unmount
- sfs_domount
- sfs_mount
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 }