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
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>
33 #include <minix/vfsif.h>
37 #if ENABLE_SYSCALL_STATS
38 EXTERN
unsigned long calls_stats
[NCALLS
];
41 FORWARD
_PROTOTYPE( void fs_init
, (void) );
42 FORWARD
_PROTOTYPE( void get_work
, (void) );
43 FORWARD
_PROTOTYPE( void init_root
, (void) );
44 FORWARD
_PROTOTYPE( void service_pm
, (void) );
47 /*===========================================================================*
49 *===========================================================================*/
52 /* This is the main program of the file system. The main loop consists of
53 * three major activities: getting new work, processing the work, and sending
54 * the reply. This loop never terminates as long as the file system runs.
60 /* This is the main loop that gets work, processes it, and sends replies. */
62 get_work(); /* sets who and call_nr */
63 fp
= &fproc
[who_p
]; /* pointer to proc table struct */
64 super_user
= (fp
->fp_effuid
== SU_UID
? TRUE
: FALSE
); /* su? */
66 if (who_e
== PM_PROC_NR
&& call_nr
!= PROC_EVENT
)
67 printf("FS: strange, got message %d from PM\n", call_nr
);
69 /* Check for special control messages first. */
70 if ((call_nr
& NOTIFY_MESSAGE
)) {
71 if (call_nr
== PROC_EVENT
)
73 /* PM tries to get FS to do something */
76 else if (call_nr
== SYN_ALARM
)
78 /* Alarm timer expired. Used only for select().
81 fs_expire_timers(m_in
.NOTIFY_TIMESTAMP
);
85 /* Device notifies us of an event. */
91 printf("after call %d from %d/%d\n",
92 call_nr
, who_p
, who_e
);
93 panic(__FILE__
, "check_vrefs failed at line", __LINE__
);
103 if (error
!= SUSPEND
) reply(who_e
, error
);
107 /* Call the internal function that does the work. */
108 if (call_nr
< 0 || call_nr
>= NCALLS
) {
110 /* Not supposed to happen. */
111 printf("FS, warning illegal %d system call by %d\n",
113 } else if (fp
->fp_pid
== PID_FREE
) {
116 "FS, bad process, who = %d, call_nr = %d, endpt1 = %d\n",
117 who_e
, call_nr
, m_in
.endpt1
);
119 #if ENABLE_SYSCALL_STATS
120 calls_stats
[call_nr
]++;
122 error
= (*call_vec
[call_nr
])();
125 /* Copy the results back to the user and send reply. */
126 if (error
!= SUSPEND
) { reply(who_e
, error
); }
132 printf("after call %d from %d/%d\n", call_nr
, who_p
, who_e
);
133 panic(__FILE__
, "check_vrefs failed at line", __LINE__
);
139 return(OK
); /* shouldn't come here */
142 /*===========================================================================*
144 *===========================================================================*/
145 PRIVATE
void get_work()
147 /* Normally wait for new input. However, if 'reviving' is
148 * nonzero, a suspended process must be awakened.
150 register struct fproc
*rp
;
153 /* Revive a suspended process. */
154 for (rp
= &fproc
[0]; rp
< &fproc
[NR_PROCS
]; rp
++)
155 if (rp
->fp_pid
!= PID_FREE
&& rp
->fp_revived
== REVIVING
) {
156 who_p
= (int)(rp
- fproc
);
157 who_e
= rp
->fp_endpoint
;
158 call_nr
= rp
->fp_fd
& BYTE
;
159 m_in
.fd
= (rp
->fp_fd
>>8) & BYTE
;
160 m_in
.buffer
= rp
->fp_buffer
;
161 m_in
.nbytes
= rp
->fp_nbytes
;
162 rp
->fp_suspended
= NOT_SUSPENDED
; /*no longer hanging*/
163 rp
->fp_revived
= NOT_REVIVING
;
165 /* This should be a pipe I/O, not a device I/O.
166 * If it is, it'll 'leak' grants.
168 assert(!GRANT_VALID(rp
->fp_grant
));
171 panic(__FILE__
,"get_work couldn't revive anyone", NO_NUM
);
176 /* Normal case. No one to revive. */
177 if ((r
=receive(ANY
, &m_in
)) != OK
)
178 panic(__FILE__
,"fs receive error", r
);
179 who_e
= m_in
.m_source
;
180 who_p
= _ENDPOINT_P(who_e
);
182 if(who_p
< -NR_TASKS
|| who_p
>= NR_PROCS
)
183 panic(__FILE__
,"receive process out of range", who_p
);
184 if(who_p
>= 0 && fproc
[who_p
].fp_endpoint
== NONE
) {
185 printf("FS: ignoring request from %d, endpointless slot %d (%d)\n",
186 m_in
.m_source
, who_p
, m_in
.m_type
);
189 if(who_p
>= 0 && fproc
[who_p
].fp_endpoint
!= who_e
) {
190 printf("FS: receive endpoint inconsistent (%d, %d, %d).\n",
191 who_e
, fproc
[who_p
].fp_endpoint
, who_e
);
192 panic(__FILE__
, "FS: inconsistent endpoint ", NO_NUM
);
195 call_nr
= m_in
.m_type
;
201 /*===========================================================================*
203 *===========================================================================*/
204 PUBLIC
void reply(whom
, result
)
205 int whom
; /* process to reply to */
206 int result
; /* result of the call (usually OK or error #) */
208 /* Send a reply to a user process. If the send fails, just ignore it. */
210 m_out
.reply_type
= result
;
211 s
= send(whom
, &m_out
);
212 if (s
!= OK
) printf("VFS: couldn't send reply %d to %d: %d\n",
216 /*===========================================================================*
218 *===========================================================================*/
219 PRIVATE
void fs_init()
221 /* Initialize global variables, tables, etc. */
222 register struct inode
*rip
;
223 register struct fproc
*rfp
;
227 /* Clear endpoint field */
228 last_login_fs_e
= NONE
;
229 mount_m_in
.m1_p3
= (char *) NONE
;
231 /* Initialize the process table with help of the process manager messages.
232 * Expect one message for each system process with its slot number and pid.
233 * When no more processes follow, the magic process number NONE is sent.
234 * Then, stop and synchronize with the PM.
237 if (OK
!= (s
=receive(PM_PROC_NR
, &mess
)))
238 panic(__FILE__
,"FS couldn't receive from PM", s
);
239 if (NONE
== mess
.PR_ENDPT
) break;
241 rfp
= &fproc
[mess
.PR_SLOT
];
242 rfp
->fp_pid
= mess
.PR_PID
;
243 rfp
->fp_endpoint
= mess
.PR_ENDPT
;
244 rfp
->fp_realuid
= (uid_t
) SYS_UID
;
245 rfp
->fp_effuid
= (uid_t
) SYS_UID
;
246 rfp
->fp_realgid
= (gid_t
) SYS_GID
;
247 rfp
->fp_effgid
= (gid_t
) SYS_GID
;
249 rfp
->fp_grant
= GRANT_INVALID
;
251 } while (TRUE
); /* continue until process NONE */
252 mess
.m_type
= OK
; /* tell PM that we succeeded */
253 s
= send(PM_PROC_NR
, &mess
); /* send synchronization message */
255 /* All process table entries have been set. Continue with FS initialization.
256 * Certain relations must hold for the file system to work at all. Some
257 * extra block_size requirements are checked at super-block-read-in time.
259 if (OPEN_MAX
> 127) panic(__FILE__
,"OPEN_MAX > 127", NO_NUM
);
261 if (NR_BUFS < 6) panic(__FILE__,"NR_BUFS < 6", NO_NUM);
262 if (V1_INODE_SIZE != 32) panic(__FILE__,"V1 inode size != 32", NO_NUM);
263 if (V2_INODE_SIZE != 64) panic(__FILE__,"V2 inode size != 64", NO_NUM);
264 if (OPEN_MAX > 8 * sizeof(long))
265 panic(__FILE__,"Too few bits in fp_cloexec", NO_NUM);
268 /* The following initializations are needed to let dev_opcl succeed .*/
269 fp
= (struct fproc
*) NULL
;
270 who_e
= who_p
= FS_PROC_NR
;
272 build_dmap(); /* build device table and map boot driver */
273 init_root(); /* init root device and load super block */
274 init_select(); /* init select() structures */
276 /* The root device can now be accessed; set process directories. */
277 for (rfp
=&fproc
[0]; rfp
< &fproc
[NR_PROCS
]; rfp
++) {
278 FD_ZERO(&(rfp
->fp_filp_inuse
));
279 if (rfp
->fp_pid
!= PID_FREE
) {
281 rfp
->fp_rd
= get_vnode_x(ROOT_FS_E
, ROOT_INODE
);
282 rfp
->fp_wd
= get_vnode_x(ROOT_FS_E
, ROOT_INODE
);
284 } else rfp
->fp_endpoint
= NONE
;
288 /*===========================================================================*
290 *===========================================================================*/
291 PRIVATE
void init_root()
294 struct vnode
*root_node
;
298 struct readsuper_req sreq
;
299 struct readsuper_res sres
;
301 /* Open the root device. */
302 root_dev
= DEV_IMGRD
;
303 ROOT_FS_E
= MFS_PROC_NR
;
305 /* Wait FS login message */
306 if (last_login_fs_e
!= ROOT_FS_E
) {
307 /* Wait FS login message */
308 if (receive(ROOT_FS_E
, &m
) != OK
) {
309 printf("VFS: Error receiving login request from FS_e %d\n",
311 panic(__FILE__
, "Error receiving login request from root filesystem\n", ROOT_FS_E
);
313 if (m
.m_type
!= FS_READY
) {
314 printf("VFS: Invalid login request from FS_e %d\n",
316 panic(__FILE__
, "Error receiving login request from root filesystem\n", ROOT_FS_E
);
319 last_login_fs_e
= NONE
;
321 /* Initialize vmnt table */
322 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
)
327 /* We'll need a vnode for the root inode, check whether there is one */
328 if ((root_node
= get_free_vnode(__FILE__
, __LINE__
)) == NIL_VNODE
) {
329 panic(__FILE__
,"Cannot get free vnode", r
);
332 /* Get driver process' endpoint */
333 dp
= &dmap
[(root_dev
>> MAJOR
) & BYTE
];
334 if (dp
->dmap_driver
== NONE
) {
335 panic(__FILE__
,"No driver for root device", r
);
338 /* Open the device the file system lives on. */
339 if ((r
= dev_open(root_dev
, ROOT_FS_E
, (R_BIT
|W_BIT
))) != OK
)
340 panic(__FILE__
,"Cannot open root device", r
);
343 /* Request for reading superblock and root inode */
344 sreq
.fs_e
= ROOT_FS_E
;
346 sreq
.boottime
= boottime
;
347 sreq
.driver_e
= dp
->dmap_driver
;
349 sreq
.slink_storage
= user_fullpath
;
353 if ((r
= req_readsuper(&sreq
, &sres
)) != OK
) {
355 panic(__FILE__
,"Cannot read superblock from root", r
);
358 /* Fill in root node's fields */
359 root_node
->v_fs_e
= sres
.fs_e
;
360 root_node
->v_inode_nr
= sres
.inode_nr
;
361 root_node
->v_mode
= sres
.fmode
;
362 root_node
->v_size
= sres
.fsize
;
363 root_node
->v_sdev
= NO_DEV
;
364 root_node
->v_fs_count
= 0; /* Is this correct? */
365 root_node
->v_ref_count
= 1;
367 /* Fill in max file size and blocksize for the vmnt */
368 vmp
->m_fs_e
= sres
.fs_e
;
369 vmp
->m_dev
= root_dev
;
370 vmp
->m_block_size
= sres
.blocksize
;
371 vmp
->m_max_file_size
= sres
.maxsize
;
372 vmp
->m_driver_e
= dp
->dmap_driver
;
375 /* Root node is indeed on the partition */
376 root_node
->v_vmnt
= vmp
;
377 root_node
->v_dev
= vmp
->m_dev
;
379 /* Root directory is mounted on itself */
380 vmp
->m_mounted_on
= root_node
;
381 root_node
->v_ref_count
++;
382 vmp
->m_root_node
= root_node
;
385 /*===========================================================================*
387 *===========================================================================*/
388 PRIVATE
void service_pm()
394 /* Ask PM for work until there is nothing left to do */
397 m
.m_type
= PM_GET_WORK
;
398 r
= sendrec(PM_PROC_NR
, &m
);
401 panic("VFS", "service_pm: sendrec failed", r
);
403 if (m
.m_type
== PM_IDLE
) {
410 boottime
= m
.PM_STIME_TIME
;
412 /* Send new time for all FS processes */
413 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; ++vmp
) {
415 req_stime(vmp
->m_fs_e
, boottime
);
417 /* No need to report status to PM */
420 pm_setsid(m
.PM_SETSID_PROC
);
422 /* No need to report status to PM */
426 pm_setgid(m
.PM_SETGID_PROC
, m
.PM_SETGID_EGID
,
429 /* No need to report status to PM */
433 pm_setuid(m
.PM_SETUID_PROC
, m
.PM_SETUID_EGID
,
436 /* No need to report status to PM */
440 pm_fork(m
.PM_FORK_PPROC
, m
.PM_FORK_CPROC
,
443 /* No need to report status to PM */
448 pm_exit(m
.PM_EXIT_PROC
);
450 /* Reply dummy status to PM for synchronization */
451 m
.m_type
= (call
== PM_EXIT_TR
? PM_EXIT_REPLY_TR
:
453 /* Keep m.PM_EXIT_PROC */
455 r
= send(PM_PROC_NR
, &m
);
457 panic(__FILE__
, "service_pm: send failed", r
);
462 unpause(m
.PM_UNPAUSE_PROC
);
464 /* No need to report status to PM */
470 /* Reply dummy status to PM for synchronization */
471 m
.m_type
= PM_REBOOT_REPLY
;
472 r
= send(PM_PROC_NR
, &m
);
474 panic(__FILE__
, "service_pm: send failed", r
);
478 r
= pm_exec(m
.PM_EXEC_PROC
, m
.PM_EXEC_PATH
,
479 m
.PM_EXEC_PATH_LEN
, m
.PM_EXEC_FRAME
,
480 m
.PM_EXEC_FRAME_LEN
);
482 /* Reply status to PM */
483 m
.m_type
= PM_EXEC_REPLY
;
484 /* Keep m.PM_EXEC_PROC */
487 r
= send(PM_PROC_NR
, &m
);
489 panic(__FILE__
, "service_pm: send failed", r
);
493 r
= pm_dumpcore(m
.PM_CORE_PROC
,
494 (struct mem_map
*)m
.PM_CORE_SEGPTR
);
496 /* Reply status to PM */
497 m
.m_type
= PM_CORE_REPLY
;
498 /* Keep m.PM_CORE_PROC */
501 r
= send(PM_PROC_NR
, &m
);
503 panic(__FILE__
, "service_pm: send failed", r
);
507 panic("VFS", "service_pm: unknown call", m
.m_type
);