2 * a loop that gets messages requesting work, carries out the work, and sends
5 * The entry points into this file are:
6 * main: main program of the Virtual File System
7 * reply: send a reply to a process after the requested work is done
10 * Jul 2006 (Balazs Gerofi)
20 #include <sys/ioc_memory.h>
21 #include <sys/svrctl.h>
22 #include <sys/select.h>
23 #include <minix/callnr.h>
24 #include <minix/com.h>
25 #include <minix/keymap.h>
26 #include <minix/const.h>
27 #include <minix/endpoint.h>
28 #include <minix/safecopies.h>
29 #include <minix/debug.h>
34 #include <minix/vfsif.h>
38 #if ENABLE_SYSCALL_STATS
39 EXTERN
unsigned long calls_stats
[NCALLS
];
42 FORWARD
_PROTOTYPE( void get_work
, (void) );
43 FORWARD
_PROTOTYPE( void init_root
, (void) );
44 FORWARD
_PROTOTYPE( void service_pm
, (void) );
46 /* SEF functions and variables. */
47 FORWARD
_PROTOTYPE( void sef_local_startup
, (void) );
48 FORWARD
_PROTOTYPE( int sef_cb_init_fresh
, (int type
, sef_init_info_t
*info
) );
50 /*===========================================================================*
52 *===========================================================================*/
55 /* This is the main program of the file system. The main loop consists of
56 * three major activities: getting new work, processing the work, and sending
57 * the reply. This loop never terminates as long as the file system runs.
61 /* SEF local startup. */
64 /* This is the main loop that gets work, processes it, and sends replies. */
67 get_work(); /* sets who and call_nr */
69 if (call_nr
== DEV_REVIVE
)
73 endpt
= m_in
.REP_ENDPT
;
74 if(endpt
== FS_PROC_NR
) {
75 endpt
= suspended_ep(m_in
.m_source
, m_in
.REP_IO_GRANT
);
77 printf("FS: proc with "
78 "grant %d from %d not found (revive)\n",
79 m_in
.REP_IO_GRANT
, m_in
.m_source
);
83 revive(endpt
, m_in
.REP_STATUS
);
86 if (call_nr
== DEV_REOPEN_REPL
)
91 if (call_nr
== DEV_CLOSE_REPL
)
96 if (call_nr
== DEV_SEL_REPL1
)
101 if (call_nr
== DEV_SEL_REPL2
)
107 /* Check for special control messages first. */
108 if (is_notify(call_nr
)) {
111 /* Alarm timer expired. Used only for select().
114 fs_expire_timers(m_in
.NOTIFY_TIMESTAMP
);
118 /* Device notifies us of an event. */
125 /* We only expect notify()s from tasks. */
127 printf("FS: ignoring message from %d (%d)\n",
132 /* Now it's safe to set and check fp. */
133 fp
= &fproc
[who_p
]; /* pointer to proc table struct */
134 super_user
= (fp
->fp_effuid
== SU_UID
? TRUE
: FALSE
); /* su? */
137 if(fp_is_blocked(fp
)) {
138 printf("VFS: requester %d call %d: suspended\n",
140 panic("requester suspended");
145 if (who_e
== PM_PROC_NR
) {
157 error
= do_mapdriver();
158 if (error
!= SUSPEND
) reply(who_e
, error
);
162 /* Call the internal function that does the work. */
163 if (call_nr
< 0 || call_nr
>= NCALLS
) {
165 /* Not supposed to happen. */
166 printf("VFS: illegal %d system call by %d\n",
168 } else if (fp
->fp_pid
== PID_FREE
) {
171 "FS, bad process, who = %d, call_nr = %d, endpt1 = %d\n",
172 who_e
, call_nr
, m_in
.endpt1
);
174 #if ENABLE_SYSCALL_STATS
175 calls_stats
[call_nr
]++;
178 error
= (*call_vec
[call_nr
])();
182 /* Copy the results back to the user and send reply. */
183 if (error
!= SUSPEND
) { reply(who_e
, error
); }
187 return(OK
); /* shouldn't come here */
190 /*===========================================================================*
191 * sef_local_startup *
192 *===========================================================================*/
193 PRIVATE
void sef_local_startup()
195 /* Register init callbacks. */
196 sef_setcb_init_fresh(sef_cb_init_fresh
);
197 sef_setcb_init_restart(sef_cb_init_fail
);
199 /* No live update support for now. */
201 /* Let SEF perform startup. */
205 /*===========================================================================*
206 * sef_cb_init_fresh *
207 *===========================================================================*/
208 PRIVATE
int sef_cb_init_fresh(int type
, sef_init_info_t
*info
)
210 /* Initialize the virtual file server. */
212 register struct fproc
*rfp
;
214 struct vnode
*root_vp
;
217 /* Clear endpoint field */
218 last_login_fs_e
= NONE
;
219 mount_m_in
.m1_p3
= (char *) NONE
;
221 /* Initialize the process table with help of the process manager messages.
222 * Expect one message for each system process with its slot number and pid.
223 * When no more processes follow, the magic process number NONE is sent.
224 * Then, stop and synchronize with the PM.
227 if (OK
!= (s
=sef_receive(PM_PROC_NR
, &mess
)))
228 panic("FS couldn't receive from PM: %d", s
);
230 if (mess
.m_type
!= PM_INIT
)
231 panic("unexpected message from PM: %d", mess
.m_type
);
233 if (NONE
== mess
.PM_PROC
) break;
235 rfp
= &fproc
[mess
.PM_SLOT
];
236 rfp
->fp_pid
= mess
.PM_PID
;
237 rfp
->fp_endpoint
= mess
.PM_PROC
;
238 rfp
->fp_realuid
= (uid_t
) SYS_UID
;
239 rfp
->fp_effuid
= (uid_t
) SYS_UID
;
240 rfp
->fp_realgid
= (gid_t
) SYS_GID
;
241 rfp
->fp_effgid
= (gid_t
) SYS_GID
;
243 rfp
->fp_grant
= GRANT_INVALID
;
244 rfp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
245 rfp
->fp_revived
= NOT_REVIVING
;
247 } while (TRUE
); /* continue until process NONE */
248 mess
.m_type
= OK
; /* tell PM that we succeeded */
249 s
= send(PM_PROC_NR
, &mess
); /* send synchronization message */
251 /* All process table entries have been set. Continue with FS initialization.
252 * Certain relations must hold for the file system to work at all. Some
253 * extra block_size requirements are checked at super-block-read-in time.
255 if (OPEN_MAX
> 127) panic("OPEN_MAX > 127");
257 /* The following initializations are needed to let dev_opcl succeed .*/
258 fp
= (struct fproc
*) NULL
;
259 who_e
= who_p
= FS_PROC_NR
;
261 build_dmap(); /* build device table and map boot driver */
262 init_root(); /* init root device and load super block */
263 init_select(); /* init select() structures */
266 vmp
= &vmnt
[0]; /* Should be the root filesystem */
267 if (vmp
->m_dev
== NO_DEV
)
268 panic("vfs: no root filesystem");
269 root_vp
= vmp
->m_root_node
;
271 /* The root device can now be accessed; set process directories. */
272 for (rfp
=&fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
273 FD_ZERO(&(rfp
->fp_filp_inuse
));
274 if (rfp
->fp_pid
!= PID_FREE
) {
277 rfp
->fp_rd
= root_vp
;
279 rfp
->fp_wd
= root_vp
;
281 } else rfp
->fp_endpoint
= NONE
;
284 system_hz
= sys_hz();
289 FIXME("VFS: DO_SANITYCHECKS is on");
295 /*===========================================================================*
297 *===========================================================================*/
298 PRIVATE
void get_work()
300 /* Normally wait for new input. However, if 'reviving' is
301 * nonzero, a suspended process must be awakened.
303 int r
, found_one
, fd_nr
;
305 register struct fproc
*rp
;
307 while (reviving
!= 0) {
310 /* Revive a suspended process. */
311 for (rp
= &fproc
[0]; rp
< &fproc
[NR_PROCS
]; rp
++)
312 if (rp
->fp_pid
!= PID_FREE
&& rp
->fp_revived
== REVIVING
) {
313 int blocked_on
= rp
->fp_blocked_on
;
315 who_p
= (int)(rp
- fproc
);
316 who_e
= rp
->fp_endpoint
;
317 call_nr
= rp
->fp_fd
& BYTE
;
319 m_in
.fd
= (rp
->fp_fd
>>8) & BYTE
;
320 m_in
.buffer
= rp
->fp_buffer
;
321 m_in
.nbytes
= rp
->fp_nbytes
;
322 /*no longer hanging*/
323 rp
->fp_blocked_on
= FP_BLOCKED_ON_NONE
;
324 rp
->fp_revived
= NOT_REVIVING
;
326 /* This should be a pipe I/O, not a device I/O.
327 * If it is, it'll 'leak' grants.
329 assert(!GRANT_VALID(rp
->fp_grant
));
331 if (blocked_on
== FP_BLOCKED_ON_PIPE
)
334 fd_nr
= (rp
->fp_fd
>> 8);
337 r
= rw_pipe((call_nr
== READ
) ? READING
:
338 WRITING
, who_e
, fd_nr
, f
,
339 rp
->fp_buffer
, rp
->fp_nbytes
);
348 panic("get_work couldn't revive anyone");
353 /* Normal case. No one to revive. */
354 if ((r
=sef_receive(ANY
, &m_in
)) != OK
)
355 panic("fs sef_receive error: %d", r
);
356 who_e
= m_in
.m_source
;
357 who_p
= _ENDPOINT_P(who_e
);
360 * negative who_p is never used to access the fproc array. Negative numbers
361 * (kernel tasks) are treated in a special way
363 if(who_p
>= (int)(sizeof(fproc
) / sizeof(struct fproc
)))
364 panic("receive process out of range: %d", who_p
);
365 if(who_p
>= 0 && fproc
[who_p
].fp_endpoint
== NONE
) {
366 printf("FS: ignoring request from %d, endpointless slot %d (%d)\n",
367 m_in
.m_source
, who_p
, m_in
.m_type
);
370 if(who_p
>= 0 && fproc
[who_p
].fp_endpoint
!= who_e
) {
371 if(fproc
[who_p
].fp_endpoint
== NONE
) {
372 printf("slot unknown even\n");
374 printf("FS: receive endpoint inconsistent (source %d, who_p %d, stored ep %d, who_e %d).\n",
375 m_in
.m_source
, who_p
, fproc
[who_p
].fp_endpoint
, who_e
);
377 panic("FS: inconsistent endpoint ");
381 call_nr
= m_in
.m_type
;
387 /*===========================================================================*
389 *===========================================================================*/
390 PUBLIC
void reply(whom
, result
)
391 int whom
; /* process to reply to */
392 int result
; /* result of the call (usually OK or error #) */
394 /* Send a reply to a user process. If the send fails, just ignore it. */
398 if (call_nr
== SYMLINK
)
399 printf("vfs:reply: replying %d for call %d\n", result
, call_nr
);
402 m_out
.reply_type
= result
;
403 s
= sendnb(whom
, &m_out
);
404 if (s
!= OK
) printf("VFS: couldn't send reply %d to %d: %d\n",
408 /*===========================================================================*
410 *===========================================================================*/
411 PRIVATE
void init_root()
415 struct vnode
*root_node
;
419 struct node_details res
;
421 /* Open the root device. */
422 root_dev
= DEV_IMGRD
;
423 ROOT_FS_E
= MFS_PROC_NR
;
425 /* Wait FS login message */
426 if (last_login_fs_e
!= ROOT_FS_E
) {
427 /* Wait FS login message */
428 if (sef_receive(ROOT_FS_E
, &m
) != OK
) {
429 printf("VFS: Error receiving login request from FS_e %d\n",
431 panic("Error receiving login request from root filesystem: %d", ROOT_FS_E
);
433 if (m
.m_type
!= FS_READY
) {
434 printf("VFS: Invalid login request from FS_e %d\n",
436 panic("Error receiving login request from root filesystem: %d", ROOT_FS_E
);
439 last_login_fs_e
= NONE
;
441 /* Initialize vmnt table */
442 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
447 /* We'll need a vnode for the root inode, check whether there is one */
448 if ((root_node
= get_free_vnode()) == NIL_VNODE
)
449 panic("Cannot get free vnode: %d", r
);
452 /* Get driver process' endpoint */
453 dp
= &dmap
[(root_dev
>> MAJOR
) & BYTE
];
454 if (dp
->dmap_driver
== NONE
) {
455 panic("No driver for root device: %d", r
);
458 label
= dp
->dmap_label
;
459 if (strlen(label
) == 0)
461 panic("vfs:init_root: no label for major: %d", root_dev
>> MAJOR
);
465 r
= req_readsuper(ROOT_FS_E
, label
, root_dev
, 0 /*!readonly*/,
468 panic("Cannot read superblock from root: %d", r
);
471 /* Fill in root node's fields */
472 root_node
->v_fs_e
= res
.fs_e
;
473 root_node
->v_inode_nr
= res
.inode_nr
;
474 root_node
->v_mode
= res
.fmode
;
475 root_node
->v_size
= res
.fsize
;
476 root_node
->v_sdev
= NO_DEV
;
477 root_node
->v_fs_count
= 1;
478 root_node
->v_ref_count
= 1;
480 /* Fill in max file size and blocksize for the vmnt */
481 vmp
->m_fs_e
= res
.fs_e
;
482 vmp
->m_dev
= root_dev
;
485 /* Root node is indeed on the partition */
486 root_node
->v_vmnt
= vmp
;
487 root_node
->v_dev
= vmp
->m_dev
;
489 /* Root directory is not mounted on a vnode. */
490 vmp
->m_mounted_on
= NULL
;
491 vmp
->m_root_node
= root_node
;
492 strcpy(vmp
->m_label
, "fs_imgrd"); /* FIXME: obtain this from RS */
495 /*===========================================================================*
497 *===========================================================================*/
498 PRIVATE
void service_pm()
504 pm_setuid(m_in
.PM_PROC
, m_in
.PM_EID
, m_in
.PM_RID
);
506 m_out
.m_type
= PM_SETUID_REPLY
;
507 m_out
.PM_PROC
= m_in
.PM_PROC
;
512 pm_setgid(m_in
.PM_PROC
, m_in
.PM_EID
, m_in
.PM_RID
);
514 m_out
.m_type
= PM_SETGID_REPLY
;
515 m_out
.PM_PROC
= m_in
.PM_PROC
;
520 pm_setsid(m_in
.PM_PROC
);
522 m_out
.m_type
= PM_SETSID_REPLY
;
523 m_out
.PM_PROC
= m_in
.PM_PROC
;
528 r
= pm_exec(m_in
.PM_PROC
, m_in
.PM_PATH
, m_in
.PM_PATH_LEN
,
529 m_in
.PM_FRAME
, m_in
.PM_FRAME_LEN
);
531 /* Reply status to PM */
532 m_out
.m_type
= PM_EXEC_REPLY
;
533 m_out
.PM_PROC
= m_in
.PM_PROC
;
539 pm_exit(m_in
.PM_PROC
);
541 /* Reply dummy status to PM for synchronization */
542 m_out
.m_type
= PM_EXIT_REPLY
;
543 m_out
.PM_PROC
= m_in
.PM_PROC
;
548 r
= pm_dumpcore(m_in
.PM_PROC
,
549 NULL
/* (struct mem_map *) m_in.PM_SEGPTR */);
551 /* Reply status to PM */
552 m_out
.m_type
= PM_CORE_REPLY
;
553 m_out
.PM_PROC
= m_in
.PM_PROC
;
560 pm_fork(m_in
.PM_PPROC
, m_in
.PM_PROC
, m_in
.PM_CPID
);
562 m_out
.m_type
= (call_nr
== PM_FORK
) ? PM_FORK_REPLY
: PM_SRV_FORK_REPLY
;
563 m_out
.PM_PROC
= m_in
.PM_PROC
;
567 pm_setgroups(m_in
.PM_PROC
, m_in
.PM_GROUP_NO
, m_in
.PM_GROUP_ADDR
);
569 m_out
.m_type
= PM_SETGROUPS_REPLY
;
570 m_out
.PM_PROC
= m_in
.PM_PROC
;
575 unpause(m_in
.PM_PROC
);
577 m_out
.m_type
= PM_UNPAUSE_REPLY
;
578 m_out
.PM_PROC
= m_in
.PM_PROC
;
585 /* Reply dummy status to PM for synchronization */
586 m_out
.m_type
= PM_REBOOT_REPLY
;
591 printf("VFS: don't know how to handle PM request %x\n", call_nr
);
596 r
= send(PM_PROC_NR
, &m_out
);
598 panic("service_pm: send failed: %d", r
);