-
Notifications
You must be signed in to change notification settings - Fork 5
/
mount.c
416 lines (321 loc) · 10.8 KB
/
mount.c
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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
/*
This file contains the code that will create a file system, mount
a file system and unmount a file system.
THIS CODE COPYRIGHT DOMINIC GIAMPAOLO. NO WARRANTY IS EXPRESSED
OR IMPLIED. YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com).
Dominic Giampaolo
dbg@be.com
*/
#include "myfs.h"
#ifndef min_c
#define min_c(a, b) (((a) < (b)) ? (a) : (b))
#endif /* min_c */
myfs_info *
myfs_create_fs(char *device, char *name, int block_size, char *opts)
{
int dev_block_size, bshift, warned = 0;
char *ptr;
fs_off_t num_dev_blocks;
myfs_info *myfs;
if ((block_size % sizeof(myfs_inode)) != 0) {
printf("ERROR: inode size %d is not an even divisor of the block "
"size %d\n", sizeof(myfs_inode), block_size);
printf(" check myfs.h for more details and info.\n");
return NULL;
}
if (name == NULL)
name = "untitled";
for(ptr=name; *ptr; ptr++) {
if (*ptr == '/') {
if (warned == 0) {
fprintf(stderr, "Volume name: %s contains the '/' character. "
"They are being converted to '-' for safety.\n", name);
warned = 1;
}
*ptr = '-';
}
}
if (block_size < 512) {
printf("minimum block size is 512 bytes\n");
block_size = 512;
}
for(bshift=0; bshift < sizeof(int)*8; bshift++)
if ((1 << bshift) == block_size)
break;
if (bshift >= sizeof(int)*8) {
printf("block_size %d is not a power of two!\n", block_size);
return NULL;
}
myfs = (myfs_info *)calloc(1, sizeof(myfs_info));
if (myfs == NULL) {
printf("can't allocate mem for myfs_info struct\n");
return NULL;
}
myfs->fd = -1;
myfs->nsid = (nspace_id)myfs; /* we can only do this when creating */
myfs->dsb.magic1 = SUPER_BLOCK_MAGIC1;
myfs->dsb.magic2 = SUPER_BLOCK_MAGIC2;
myfs->dsb.magic3 = SUPER_BLOCK_MAGIC3;
myfs->dsb.fs_byte_order = MYFS_BIG_ENDIAN; /* checked when mounting */
myfs->sem = create_sem(MAX_READERS, "myfs_sem");
if (myfs->sem < 0) {
printf("can't create semaphore!\n");
goto cleanup;
}
myfs->fd = open(device, O_RDWR);
if (myfs->fd < 0) {
printf("can't open device %s\n", device);
goto cleanup;
}
dev_block_size = get_device_block_size(myfs->fd);
num_dev_blocks = get_num_device_blocks(myfs->fd);
if (block_size < dev_block_size) {
printf("warning: fs block size too small, set to device block size %d\n",
dev_block_size);
block_size = dev_block_size;
}
if ((block_size % dev_block_size) != 0) {
printf("error: block size %d is not an even multiple of ",
block_size);
printf("device block size %d\n", dev_block_size);
goto cleanup;
}
myfs->dsb.block_size = block_size;
myfs->dsb.block_shift = bshift;
myfs->dev_block_conversion = block_size / dev_block_size;
myfs->dev_block_size = dev_block_size;
myfs->dsb.num_blocks = num_dev_blocks / myfs->dev_block_conversion;
init_cache_for_device(myfs->fd, num_dev_blocks / myfs->dev_block_conversion);
if (init_tmp_blocks(myfs) != 0) {
printf("init_tmp_blocks failed\n");
goto cleanup;
}
if (myfs_create_storage_map(myfs) != 0) {
printf("create storage map failed\n");
goto cleanup;
}
if (myfs_create_inodes(myfs) != 0) {
printf("create inodes failed\n");
goto cleanup;
}
if (myfs_create_journal(myfs) != 0) {
printf("create journal failed\n");
goto cleanup;
}
if (myfs_create_root_dir(myfs) != 0) {
printf("create root dir failed\n");
goto cleanup;
}
strncpy(myfs->dsb.name, name,
min_c(sizeof(myfs->dsb.name) - 1, strlen(name)));
/* now it's finally safe to write this */
if (write_super_block(myfs) != 0) {
printf("creating superblock failed\n");
goto cleanup;
}
return myfs;
cleanup:
if (myfs) {
/* making the file system failed so make sure block zero is bogus */
if (myfs->fd >= 0) {
static char block[4096];
memset(block, 0xff, sizeof(block));
write_blocks(myfs, 0, block, 1);
}
myfs_shutdown_storage_map(myfs);
myfs_shutdown_inodes(myfs);
myfs_shutdown_journal(myfs);
shutdown_tmp_blocks(myfs);
close(myfs->fd);
delete_sem(myfs->sem);
free(myfs);
}
return NULL;
}
static int
super_block_is_sane(myfs_info *myfs)
{
fs_off_t num_dev_blocks;
int block_size;
if (myfs->dsb.magic1 != SUPER_BLOCK_MAGIC1 ||
myfs->dsb.magic2 != SUPER_BLOCK_MAGIC2 ||
myfs->dsb.magic3 != SUPER_BLOCK_MAGIC3) {
printf("warning: super block magic numbers are wrong:\n");
printf("0x%x (0x%x) 0x%x (0x%x) 0x%x (0x%x)\n",
myfs->dsb.magic1, SUPER_BLOCK_MAGIC1,
myfs->dsb.magic2, SUPER_BLOCK_MAGIC2,
myfs->dsb.magic3, SUPER_BLOCK_MAGIC3);
return 0;
}
if ((myfs->dsb.block_size % myfs->dev_block_size) != 0) {
printf("warning: fs block size %d not a multiple of ",
myfs->dsb.block_size);
printf(" device block size %d\n", myfs->dev_block_size);
return 0;
}
block_size = get_device_block_size(myfs->fd);
if (block_size == 0) {
printf("warning: could not fetch block size\n");
return 0;
}
/* make sure that the partition is as big as the super block
says it is */
num_dev_blocks = get_num_device_blocks(myfs->fd);
if (myfs->dsb.num_blocks * myfs->dsb.block_size >
num_dev_blocks * block_size) {
printf("warning: fs blocks %lx larger than device blocks %lx\n",
myfs->dsb.num_blocks * (myfs->dsb.block_size/block_size),
num_dev_blocks);
return 0;
}
if (myfs->dsb.block_size != (1 << myfs->dsb.block_shift)) {
int i;
printf("warning: block_shift %d does not match block size %d\n",
myfs->dsb.block_shift, myfs->dsb.block_size);
if (myfs->dsb.block_shift > 8 && myfs->dsb.block_shift < 16) {
printf("setting block_size to %d\n", (1 << myfs->dsb.block_shift));
myfs->dsb.block_size = (1 << myfs->dsb.block_shift);
} else {
for(i=0; i < sizeof(int) * 8; i++)
if ((1 << i) == myfs->dsb.block_size)
break;
if (i >= sizeof(int) * 8 || i > 16) {
printf("neither block_size nor block_shift make sense!\n");
return 0;
}
myfs->dsb.block_shift = i;
printf("setting block_shift to %d\n", i);
}
}
return 1;
}
int
myfs_mount(nspace_id nsid, const char *device, ulong flags,
void *parms, size_t len, void **data, vnode_id *vnid)
{
int ret = 0, oflags = O_RDWR;
char buff[128];
myfs_info *myfs;
myfs = (myfs_info *)calloc(1, sizeof(myfs_info));
if (myfs == NULL) {
printf("no memory for myfs structure!\n");
return ENOMEM;
}
myfs->nsid = nsid;
*data = (void *)myfs;
sprintf(buff, "myfs:%s", device);
myfs->sem = create_sem(MAX_READERS, buff);
if (myfs->sem < 0) {
printf("could not create myfs sem!\n");
ret = ENOMEM;
goto error0;
}
myfs->fd = open(device, oflags);
if (myfs->fd < 0) {
printf("could not open %s to try and mount a myfs\n", device);
ret = ENODEV;
goto error1;
}
if (read_super_block(myfs) != 0) {
printf("could not read super block on device %s\n", device);
ret = EBADF;
goto error2;
}
if (super_block_is_sane(myfs) == 0) {
printf("bad super block\n");
ret = EBADF;
goto error2;
}
if ((myfs->dsb.block_size % sizeof(myfs_inode)) != 0) {
printf("ERROR: inode size %d is not an even divisor of the block "
"size %d\n", sizeof(myfs_inode), myfs->dsb.block_size);
printf(" check myfs.h for more details and info.\n");
ret = EINVAL;
goto error2;
}
if (init_cache_for_device(myfs->fd, myfs->dsb.num_blocks) != 0) {
printf("could not initialize cache access for fd %d\n", myfs->fd);
ret = EBADF;
goto error2;
}
if (init_tmp_blocks(myfs) != 0) {
printf("could not init tmp blocks\n");
ret = ENOMEM;
goto error2;
}
if (myfs_init_journal(myfs) != 0) {
printf("could not initialize the journal\n");
ret = EBADF;
goto error3;
}
if (myfs_init_inodes(myfs) != 0) {
printf("could not initialize inodes\n");
ret = ENOMEM;
goto error5;
}
if (myfs_init_storage_map(myfs) != 0) {
printf("could not initialize the storage map\n");
ret = EBADF;
goto error6;
}
*vnid = myfs->dsb.root_inum;
if (myfs_read_vnode(myfs, *vnid, 0, (void **)&myfs->root_dir) != 0) {
printf("could not read root dir inode\n");
ret = EBADF;
goto error7;
}
if (new_vnode(myfs->nsid, *vnid, (void *)myfs->root_dir) != 0) {
printf("could not initialize a vnode for the root directory!\n");
ret = ENOMEM;
goto error7;
}
return 0;
error7:
myfs_shutdown_storage_map(myfs);
error6:
myfs_shutdown_inodes(myfs);
error5:
myfs_shutdown_journal(myfs);
error3:
shutdown_tmp_blocks(myfs);
error2:
remove_cached_device_blocks(myfs->fd, NO_WRITES);
close(myfs->fd);
error1:
delete_sem(myfs->sem);
error0:
memset(myfs, 0xff, sizeof(*myfs)); /* yeah, I'm paranoid */
free(myfs);
return ret;
}
/*
note that the order in which things are done here is *very*
important. don't mess with it unless you know what you're doing
*/
int
myfs_unmount(void *ns)
{
myfs_info *myfs = (myfs_info *)ns;
if (myfs == NULL)
return EINVAL;
sync_journal(myfs);
myfs_shutdown_storage_map(myfs);
myfs_shutdown_inodes(myfs);
/*
have to do this after the above steps because the above steps
might actually have to do transactions
*/
sync_journal(myfs);
remove_cached_device_blocks(myfs->fd, ALLOW_WRITES);
myfs_shutdown_journal(myfs);
write_super_block(myfs);
shutdown_tmp_blocks(myfs);
close(myfs->fd);
if (myfs->sem > 0)
delete_sem(myfs->sem);
memset(myfs, 0xff, sizeof(*myfs)); /* trash it just to be sure */
free(myfs);
return 0;
}