source: branches/minix3-book/servers/fs/main.c@ 11

Last change on this file since 11 was 4, checked in by Mattia Monga, 14 years ago

Importazione sorgenti libro

File size: 14.7 KB
Line 
1/* This file contains the main program of the File System. It consists of
2 * a loop that gets messages requesting work, carries out the work, and sends
3 * replies.
4 *
5 * The entry points into this file are:
6 * main: main program of the File System
7 * reply: send a reply to a process after the requested work is done
8 *
9 */
10
11struct super_block; /* proto.h needs to know this */
12
13#include "fs.h"
14#include <fcntl.h>
15#include <string.h>
16#include <stdio.h>
17#include <signal.h>
18#include <stdlib.h>
19#include <sys/ioc_memory.h>
20#include <sys/svrctl.h>
21#include <minix/callnr.h>
22#include <minix/com.h>
23#include <minix/keymap.h>
24#include <minix/const.h>
25#include "buf.h"
26#include "file.h"
27#include "fproc.h"
28#include "inode.h"
29#include "param.h"
30#include "super.h"
31
32FORWARD _PROTOTYPE( void fs_init, (void) );
33FORWARD _PROTOTYPE( int igetenv, (char *var, int optional) );
34FORWARD _PROTOTYPE( void get_work, (void) );
35FORWARD _PROTOTYPE( void load_ram, (void) );
36FORWARD _PROTOTYPE( void load_super, (Dev_t super_dev) );
37
38/*===========================================================================*
39 * main *
40 *===========================================================================*/
41PUBLIC int main()
42{
43/* This is the main program of the file system. The main loop consists of
44 * three major activities: getting new work, processing the work, and sending
45 * the reply. This loop never terminates as long as the file system runs.
46 */
47 sigset_t sigset;
48 int error;
49
50 fs_init();
51
52 /* This is the main loop that gets work, processes it, and sends replies. */
53 while (TRUE) {
54 get_work(); /* sets who and call_nr */
55
56 fp = &fproc[who]; /* pointer to proc table struct */
57 super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */
58
59 /* Check for special control messages first. */
60 if (call_nr == SYS_SIG) {
61 sigset = m_in.NOTIFY_ARG;
62 if (sigismember(&sigset, SIGKSTOP)) {
63 do_sync();
64 sys_exit(0); /* never returns */
65 }
66 } else if (call_nr == SYN_ALARM) {
67 /* Not a user request; system has expired one of our timers,
68 * currently only in use for select(). Check it.
69 */
70 fs_expire_timers(m_in.NOTIFY_TIMESTAMP);
71 } else if ((call_nr & NOTIFY_MESSAGE)) {
72 /* Device notifies us of an event. */
73 dev_status(&m_in);
74 } else {
75 /* Call the internal function that does the work. */
76 if (call_nr < 0 || call_nr >= NCALLS) {
77 error = ENOSYS;
78 printf("FS, warning illegal %d system call by %d\n", call_nr, who);
79 } else if (fp->fp_pid == PID_FREE) {
80 error = ENOSYS;
81 printf("FS, bad process, who = %d, call_nr = %d, slot1 = %d\n",
82 who, call_nr, m_in.slot1);
83 } else {
84 error = (*call_vec[call_nr])();
85 }
86
87 /* Copy the results back to the user and send reply. */
88 if (error != SUSPEND) { reply(who, error); }
89 if (rdahed_inode != NIL_INODE) {
90 read_ahead(); /* do block read ahead */
91 }
92 }
93 }
94 return(OK); /* shouldn't come here */
95}
96
97/*===========================================================================*
98 * get_work *
99 *===========================================================================*/
100PRIVATE void get_work()
101{
102 /* Normally wait for new input. However, if 'reviving' is
103 * nonzero, a suspended process must be awakened.
104 */
105 register struct fproc *rp;
106
107 if (reviving != 0) {
108 /* Revive a suspended process. */
109 for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++)
110 if (rp->fp_revived == REVIVING) {
111 who = (int)(rp - fproc);
112 call_nr = rp->fp_fd & BYTE;
113 m_in.fd = (rp->fp_fd >>8) & BYTE;
114 m_in.buffer = rp->fp_buffer;
115 m_in.nbytes = rp->fp_nbytes;
116 rp->fp_suspended = NOT_SUSPENDED; /*no longer hanging*/
117 rp->fp_revived = NOT_REVIVING;
118 reviving--;
119 return;
120 }
121 panic(__FILE__,"get_work couldn't revive anyone", NO_NUM);
122 }
123
124 /* Normal case. No one to revive. */
125 if (receive(ANY, &m_in) != OK) panic(__FILE__,"fs receive error", NO_NUM);
126 who = m_in.m_source;
127 call_nr = m_in.m_type;
128}
129
130/*===========================================================================*
131 * buf_pool *
132 *===========================================================================*/
133PRIVATE void buf_pool(void)
134{
135/* Initialize the buffer pool. */
136
137 register struct buf *bp;
138
139 bufs_in_use = 0;
140 front = &buf[0];
141 rear = &buf[NR_BUFS - 1];
142
143 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) {
144 bp->b_blocknr = NO_BLOCK;
145 bp->b_dev = NO_DEV;
146 bp->b_next = bp + 1;
147 bp->b_prev = bp - 1;
148 }
149 buf[0].b_prev = NIL_BUF;
150 buf[NR_BUFS - 1].b_next = NIL_BUF;
151
152 for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next;
153 buf_hash[0] = front;
154
155}
156
157/*===========================================================================*
158 * reply *
159 *===========================================================================*/
160PUBLIC void reply(whom, result)
161int whom; /* process to reply to */
162int result; /* result of the call (usually OK or error #) */
163{
164/* Send a reply to a user process. It may fail (if the process has just
165 * been killed by a signal), so don't check the return code. If the send
166 * fails, just ignore it.
167 */
168 int s;
169 m_out.reply_type = result;
170 s = send(whom, &m_out);
171 if (s != OK) printf("FS: couldn't send reply %d: %d\n", result, s);
172}
173
174/*===========================================================================*
175 * fs_init *
176 *===========================================================================*/
177PRIVATE void fs_init()
178{
179/* Initialize global variables, tables, etc. */
180 register struct inode *rip;
181 register struct fproc *rfp;
182 message mess;
183 int s;
184
185 /* Initialize the process table with help of the process manager messages.
186 * Expect one message for each system process with its slot number and pid.
187 * When no more processes follow, the magic process number NONE is sent.
188 * Then, stop and synchronize with the PM.
189 */
190 do {
191 if (OK != (s=receive(PM_PROC_NR, &mess)))
192 panic(__FILE__,"FS couldn't receive from PM", s);
193 if (NONE == mess.PR_PROC_NR) break;
194
195 rfp = &fproc[mess.PR_PROC_NR];
196 rfp->fp_pid = mess.PR_PID;
197 rfp->fp_realuid = (uid_t) SYS_UID;
198 rfp->fp_effuid = (uid_t) SYS_UID;
199 rfp->fp_realgid = (gid_t) SYS_GID;
200 rfp->fp_effgid = (gid_t) SYS_GID;
201 rfp->fp_umask = ~0;
202
203 } while (TRUE); /* continue until process NONE */
204 mess.m_type = OK; /* tell PM that we succeeded */
205 s=send(PM_PROC_NR, &mess); /* send synchronization message */
206
207 /* All process table entries have been set. Continue with FS initialization.
208 * Certain relations must hold for the file system to work at all. Some
209 * extra block_size requirements are checked at super-block-read-in time.
210 */
211 if (OPEN_MAX > 127) panic(__FILE__,"OPEN_MAX > 127", NO_NUM);
212 if (NR_BUFS < 6) panic(__FILE__,"NR_BUFS < 6", NO_NUM);
213 if (V1_INODE_SIZE != 32) panic(__FILE__,"V1 inode size != 32", NO_NUM);
214 if (V2_INODE_SIZE != 64) panic(__FILE__,"V2 inode size != 64", NO_NUM);
215 if (OPEN_MAX > 8 * sizeof(long))
216 panic(__FILE__,"Too few bits in fp_cloexec", NO_NUM);
217
218 /* The following initializations are needed to let dev_opcl succeed .*/
219 fp = (struct fproc *) NULL;
220 who = FS_PROC_NR;
221
222 buf_pool(); /* initialize buffer pool */
223 build_dmap(); /* build device table and map boot driver */
224 load_ram(); /* init RAM disk, load if it is root */
225 load_super(root_dev); /* load super block for root device */
226 init_select(); /* init select() structures */
227
228 /* The root device can now be accessed; set process directories. */
229 for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
230 if (rfp->fp_pid != PID_FREE) {
231 rip = get_inode(root_dev, ROOT_INODE);
232 dup_inode(rip);
233 rfp->fp_rootdir = rip;
234 rfp->fp_workdir = rip;
235 }
236 }
237}
238
239/*===========================================================================*
240 * igetenv *
241 *===========================================================================*/
242PRIVATE int igetenv(key, optional)
243char *key;
244int optional;
245{
246/* Ask kernel for an integer valued boot environment variable. */
247 char value[64];
248 int i;
249
250 if ((i = env_get_param(key, value, sizeof(value))) != OK) {
251 if (!optional)
252 printf("FS: Warning, couldn't get monitor param: %d\n", i);
253 return 0;
254 }
255 return(atoi(value));
256}
257
258/*===========================================================================*
259 * load_ram *
260 *===========================================================================*/
261PRIVATE void load_ram(void)
262{
263/* Allocate a RAM disk with size given in the boot parameters. If a RAM disk
264 * image is given, the copy the entire image device block-by-block to a RAM
265 * disk with the same size as the image.
266 * If the root device is not set, the RAM disk will be used as root instead.
267 */
268 register struct buf *bp, *bp1;
269 u32_t lcount, ram_size_kb;
270 zone_t zones;
271 struct super_block *sp, *dsp;
272 block_t b;
273 Dev_t image_dev;
274 static char sbbuf[MIN_BLOCK_SIZE];
275 int block_size_image, block_size_ram, ramfs_block_size;
276 int s;
277
278 /* Get some boot environment variables. */
279 root_dev = igetenv("rootdev", 0);
280 image_dev = igetenv("ramimagedev", 0);
281 ram_size_kb = igetenv("ramsize", 0);
282
283 /* Open the root device. */
284 if (dev_open(root_dev, FS_PROC_NR, R_BIT|W_BIT) != OK)
285 panic(__FILE__,"Cannot open root device",NO_NUM);
286
287 /* If we must initialize a ram disk, get details from the image device. */
288 if (root_dev == DEV_RAM) {
289 u32_t fsmax, probedev;
290
291 /* If we are running from CD, see if we can find it. */
292 if (igetenv("cdproberoot", 1) && (probedev=cdprobe()) != NO_DEV) {
293 char devnum[10];
294 struct sysgetenv env;
295
296 /* If so, this is our new RAM image device. */
297 image_dev = probedev;
298
299 /* Tell PM about it, so userland can find out about it
300 * with sysenv interface.
301 */
302 env.key = "cdproberoot";
303 env.keylen = strlen(env.key);
304 sprintf(devnum, "%d", (int) probedev);
305 env.val = devnum;
306 env.vallen = strlen(devnum);
307 svrctl(MMSETPARAM, &env);
308 }
309
310 /* Open image device for RAM root. */
311 if (dev_open(image_dev, FS_PROC_NR, R_BIT) != OK)
312 panic(__FILE__,"Cannot open RAM image device", NO_NUM);
313
314 /* Get size of RAM disk image from the super block. */
315 sp = &super_block[0];
316 sp->s_dev = image_dev;
317 if (read_super(sp) != OK)
318 panic(__FILE__,"Bad RAM disk image FS", NO_NUM);
319
320 lcount = sp->s_zones << sp->s_log_zone_size; /* # blks on root dev*/
321
322 /* Stretch the RAM disk file system to the boot parameters size, but
323 * no further than the last zone bit map block allows.
324 */
325 if (ram_size_kb*1024 < lcount*sp->s_block_size)
326 ram_size_kb = lcount*sp->s_block_size/1024;
327 fsmax = (u32_t) sp->s_zmap_blocks * CHAR_BIT * sp->s_block_size;
328 fsmax = (fsmax + (sp->s_firstdatazone-1)) << sp->s_log_zone_size;
329 if (ram_size_kb*1024 > fsmax*sp->s_block_size)
330 ram_size_kb = fsmax*sp->s_block_size/1024;
331 }
332
333 /* Tell RAM driver how big the RAM disk must be. */
334 m_out.m_type = DEV_IOCTL;
335 m_out.PROC_NR = FS_PROC_NR;
336 m_out.DEVICE = RAM_DEV;
337 m_out.REQUEST = MIOCRAMSIZE; /* I/O control to use */
338 m_out.POSITION = (ram_size_kb * 1024); /* request in bytes */
339 if ((s=sendrec(MEM_PROC_NR, &m_out)) != OK)
340 panic("FS","sendrec from MEM failed", s);
341 else if (m_out.REP_STATUS != OK) {
342 /* Report and continue, unless RAM disk is required as root FS. */
343 if (root_dev != DEV_RAM) {
344 report("FS","can't set RAM disk size", m_out.REP_STATUS);
345 return;
346 } else {
347 panic(__FILE__,"can't set RAM disk size", m_out.REP_STATUS);
348 }
349 }
350
351 /* See if we must load the RAM disk image, otherwise return. */
352 if (root_dev != DEV_RAM)
353 return;
354
355 /* Copy the blocks one at a time from the image to the RAM disk. */
356 printf("Loading RAM disk onto /dev/ram:\33[23CLoaded: 0 KB");
357
358 inode[0].i_mode = I_BLOCK_SPECIAL; /* temp inode for rahead() */
359 inode[0].i_size = LONG_MAX;
360 inode[0].i_dev = image_dev;
361 inode[0].i_zone[0] = image_dev;
362
363 block_size_ram = get_block_size(DEV_RAM);
364 block_size_image = get_block_size(image_dev);
365
366 /* RAM block size has to be a multiple of the root image block
367 * size to make copying easier.
368 */
369 if (block_size_image % block_size_ram) {
370 printf("\nram block size: %d image block size: %d\n",
371 block_size_ram, block_size_image);
372 panic(__FILE__, "ram disk block size must be a multiple of "
373 "the image disk block size", NO_NUM);
374 }
375
376 /* Loading blocks from image device. */
377 for (b = 0; b < (block_t) lcount; b++) {
378 int rb, factor;
379 bp = rahead(&inode[0], b, (off_t)block_size_image * b, block_size_image);
380 factor = block_size_image/block_size_ram;
381 for(rb = 0; rb < factor; rb++) {
382 bp1 = get_block(root_dev, b * factor + rb, NO_READ);
383 memcpy(bp1->b_data, bp->b_data + rb * block_size_ram,
384 (size_t) block_size_ram);
385 bp1->b_dirt = DIRTY;
386 put_block(bp1, FULL_DATA_BLOCK);
387 }
388 put_block(bp, FULL_DATA_BLOCK);
389 if (b % 11 == 0)
390 printf("\b\b\b\b\b\b\b\b\b%6ld KB", ((long) b * block_size_image)/1024L);
391 }
392
393 /* Commit changes to RAM so dev_io will see it. */
394 do_sync();
395
396 printf("\rRAM disk of %u KB loaded onto /dev/ram.", (unsigned) ram_size_kb);
397 if (root_dev == DEV_RAM) printf(" Using RAM disk as root FS.");
398 printf(" \n");
399
400 /* Invalidate and close the image device. */
401 invalidate(image_dev);
402 dev_close(image_dev);
403
404 /* Resize the RAM disk root file system. */
405 if (dev_io(DEV_READ, root_dev, FS_PROC_NR,
406 sbbuf, SUPER_BLOCK_BYTES, MIN_BLOCK_SIZE, 0) != MIN_BLOCK_SIZE) {
407 printf("WARNING: ramdisk read for resizing failed\n");
408 }
409 dsp = (struct super_block *) sbbuf;
410 if (dsp->s_magic == SUPER_V3)
411 ramfs_block_size = dsp->s_block_size;
412 else
413 ramfs_block_size = STATIC_BLOCK_SIZE;
414 zones = (ram_size_kb * 1024 / ramfs_block_size) >> sp->s_log_zone_size;
415
416 dsp->s_nzones = conv2(sp->s_native, (u16_t) zones);
417 dsp->s_zones = conv4(sp->s_native, zones);
418 if (dev_io(DEV_WRITE, root_dev, FS_PROC_NR,
419 sbbuf, SUPER_BLOCK_BYTES, MIN_BLOCK_SIZE, 0) != MIN_BLOCK_SIZE) {
420 printf("WARNING: ramdisk write for resizing failed\n");
421 }
422}
423
424/*===========================================================================*
425 * load_super *
426 *===========================================================================*/
427PRIVATE void load_super(super_dev)
428dev_t super_dev; /* place to get superblock from */
429{
430 int bad;
431 register struct super_block *sp;
432 register struct inode *rip;
433
434 /* Initialize the super_block table. */
435 for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
436 sp->s_dev = NO_DEV;
437
438 /* Read in super_block for the root file system. */
439 sp = &super_block[0];
440 sp->s_dev = super_dev;
441
442 /* Check super_block for consistency. */
443 bad = (read_super(sp) != OK);
444 if (!bad) {
445 rip = get_inode(super_dev, ROOT_INODE); /* inode for root dir */
446 if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3) bad++;
447 }
448 if (bad) panic(__FILE__,"Invalid root file system", NO_NUM);
449
450 sp->s_imount = rip;
451 dup_inode(rip);
452 sp->s_isup = rip;
453 sp->s_rd_only = 0;
454 return;
455}
Note: See TracBrowser for help on using the repository browser.