OBJ = main.o open.o read.o write.o pipe.o dmap.o \
device.o path.o mount.o link.o super.o inode.o \
cache.o cache2.o filedes.o stadir.o protect.o time.o \
- cmostime.o lock.o misc.o utility.o select.o timers.o table.o
+ cmostime.o lock.o misc.o utility.o select.o timers.o table.o \
+ cdprobe.o
# build local binary
all build: $(SERVER)
--- /dev/null
+/* This file contains some code to guess where we have to load the
+ * RAM image device from, if started from CD. (In this case it's hard
+ * to tell where this is without diving into BIOS heuristics.)
+ *
+ * There is some nasty hard-codery in here (e.g. AT minor device numbers,
+ * MINIX cd label) that can be improved on.
+ *
+ * Changes:
+ * Jul 14, 2005 Created (Ben Gras)
+ */
+
+#include "fs.h"
+#include "super.h"
+
+#include <minix/com.h>
+#include <string.h>
+
+/*===========================================================================*
+ * cdprobe *
+ *===========================================================================*/
+PUBLIC int cdprobe(void)
+{
+#define CD_SECTOR 2048
+#define AT_MAJOR 3
+#define AT_MINORS 4
+ int i, minors[AT_MINORS] = { 0, 5, 10, 15 }, dev = 0, found = 0;
+ char pvd[CD_SECTOR];
+ for(i = 0; i < AT_MINORS && !found; i++) {
+ struct super_block probe_super;
+ int r, minor;
+
+ dev = (AT_MAJOR << MAJOR) | minors[i];
+
+ /* 1. The drive should be a CD - which is not write-openable.
+ * Check for this.
+ */
+ if((r = dev_open(dev, FS_PROC_NR, R_BIT|W_BIT)) == OK) {
+ dev_close(dev);
+ continue;
+ }
+
+ /* 2. The drive should be a CD. Open whole drive and
+ * check for the PVD.
+ */
+ if((r = dev_open(dev, FS_PROC_NR, R_BIT)) != OK) {
+ continue;
+ }
+ if((r = dev_io(DEV_READ, dev, FS_PROC_NR, pvd,
+ 16*CD_SECTOR, sizeof(pvd), 0)) != sizeof(pvd)) {
+ dev_close(dev);
+ continue;
+ }
+ dev_close(dev);
+
+ /* Check PVD ID. */
+ if(pvd[0] != 1 || pvd[1] != 'C' || pvd[2] != 'D' ||
+ pvd[3] != '0' || pvd[4] != '0' || pvd[5] != '1' || pvd[6] != 1 ||
+ strncmp(pvd + 40, "MINIX", 5)) {
+ continue;
+ }
+
+ /* 3. Both c0dXp1 and p2 should have a superblock. */
+ for(minor = minors[i]+2; minor <= minors[i]+3; minor++) {
+ dev = (AT_MAJOR << MAJOR) | minor;
+ if((r = dev_open(dev, FS_PROC_NR, R_BIT)) != OK)
+ continue;
+ probe_super.s_dev = dev;
+ r = read_super(&probe_super);
+ dev_close(dev);
+ if(r != OK) {
+ break;
+ }
+ }
+
+ if(minor > minors[i]+3) {
+ /* Success? Then set dev to p1. */
+ dev = (AT_MAJOR << MAJOR) | (minors[i]+2);
+ found = 1;
+ break;
+ }
+ }
+
+ if(!found) return NO_DEV;
+
+ return dev;
+}
+
#include "fs.h"
#include <fcntl.h>
#include <string.h>
+#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/ioc_memory.h>
FORWARD _PROTOTYPE( void fs_init, (void) );
-FORWARD _PROTOTYPE( int igetenv, (char *var) );
+FORWARD _PROTOTYPE( int igetenv, (char *var, int optional) );
FORWARD _PROTOTYPE( void get_work, (void) );
FORWARD _PROTOTYPE( void load_ram, (void) );
FORWARD _PROTOTYPE( void load_super, (Dev_t super_dev) );
-
/*===========================================================================*
* main *
*===========================================================================*/
map_controllers(); /* map controller devices to drivers */
load_ram(); /* init RAM disk, load if it is root */
load_super(root_dev); /* load super block for root device */
+ init_select(); /* init select() structures */
/* The root device can now be accessed; set process directories. */
/*===========================================================================*
* igetenv *
*===========================================================================*/
-PRIVATE int igetenv(key)
+PRIVATE int igetenv(key, optional)
char *key;
+int optional;
{
/* Ask kernel for an integer valued boot environment variable. */
char value[64];
int i;
- if ((i = get_mon_param(key, value, sizeof(value))) != OK)
- printf("FS: Warning, couldn't get monitor param: %d\n", i);
+ if ((i = get_mon_param(key, value, sizeof(value))) != OK) {
+ if(!optional)
+ printf("FS: Warning, couldn't get monitor param: %d\n", i);
+ return 0;
+ }
return(atoi(value));
}
-
/*===========================================================================*
* load_ram *
*===========================================================================*/
int block_size_image, block_size_ram, ramfs_block_size;
/* Get some boot environment variables. */
- root_dev = igetenv("rootdev");
- image_dev = igetenv("ramimagedev");
- ram_size_kb = igetenv("ramsize");
+ root_dev = igetenv("rootdev", 0);
+ image_dev = igetenv("ramimagedev", 0);
+ ram_size_kb = igetenv("ramsize", 0);
/* Open the root device. */
- if (dev_open(root_dev, FS_PROC_NR, R_BIT|W_BIT) != OK) {
+ if (dev_open(root_dev, FS_PROC_NR, R_BIT|W_BIT) != OK)
panic(__FILE__,"Cannot open root device",NO_NUM);
- }
/* If we must initialize a ram disk, get details from the image device. */
if (root_dev == DEV_RAM || root_dev != image_dev) {
- u32_t fsmax;
+ u32_t fsmax, probedev;
+
+ /* If we are running from CD, see if we can find it. */
+ if(igetenv("cdproberoot", 1) && (probedev=cdprobe()) != NO_DEV) {
+ char devnum[10];
+ struct sysgetenv env;
+
+ /* If so, this is our new RAM image device. */
+ image_dev = probedev;
+
+ /* Tell PM about it, so userland can find out about it
+ * with sysenv interface.
+ */
+ env.key = "cdproberoot";
+ env.keylen = strlen(env.key);
+ sprintf(devnum, "%d", probedev);
+ env.val = devnum;
+ env.vallen = strlen(devnum);
+ svrctl(MMSETPARAM, &env);
+ }
+
+ /* Open image device for RAM root. */
if (dev_open(image_dev, FS_PROC_NR, R_BIT) != OK)
panic(__FILE__,"Cannot open RAM image device", NO_NUM);
block_size_ram = get_block_size(DEV_RAM);
block_size_image = get_block_size(image_dev);
- if(block_size_ram != block_size_image) {
- printf("ram block size: %d image block size: %d\n",
+ /* RAM block size has to be a multiple of the root image block
+ * size to make copying easier.
+ */
+ if(block_size_image % block_size_ram) {
+ printf("\nram block size: %d image block size: %d\n",
block_size_ram, block_size_image);
- panic(__FILE__,"ram disk and image disk block sizes must match", NO_NUM);
+ panic(__FILE__, "ram disk block size must be a multiple of the image disk block size", NO_NUM);
}
+ /* Loading blocks from image device. */
for (b = 0; b < (block_t) lcount; b++) {
+ int rb, factor;
bp = rahead(&inode[0], b, (off_t)block_size_image * b, block_size_image);
- bp1 = get_block(root_dev, b, NO_READ);
- memcpy(bp1->b_data, bp->b_data, (size_t) block_size_image);
- bp1->b_dirt = DIRTY;
+ factor = block_size_image/block_size_ram;
+ for(rb = 0; rb < factor; rb++) {
+ bp1 = get_block(root_dev, b * factor + rb, NO_READ);
+ memcpy(bp1->b_data, bp->b_data + rb * block_size_ram,
+ (size_t) block_size_ram);
+ bp1->b_dirt = DIRTY;
+ put_block(bp1, FULL_DATA_BLOCK);
+ }
put_block(bp, FULL_DATA_BLOCK);
- put_block(bp1, FULL_DATA_BLOCK);
- printf("\b\b\b\b\b\b\b%5ldK ", ((long) b * block_size_image)/1024L);
+ printf("\b\b\b\b\b\b\b\b%6ldK ", ((long) b * block_size_image)/1024L);
}
+ /* Commit changes to RAM so dev_io will see it. */
+ do_sync();
+
printf("\rRAM disk of %u kb loaded.\33[K", ram_size_kb);
if (root_dev == DEV_RAM) printf(" RAM disk is used as root FS.");
printf("\n\n");
_PROTOTYPE( int select_callback, (struct filp *, int ops) );
_PROTOTYPE( void select_forget, (int fproc) );
_PROTOTYPE( void select_timeout_check, (timer_t *) );
+_PROTOTYPE( void init_select, (void) );
_PROTOTYPE( int select_notified, (message *) );
/* timers.c */
_PROTOTYPE( void fs_set_timer, (timer_t *tp, int delta, tmr_func_t watchdog, int arg));
_PROTOTYPE( void fs_expire_timers, (clock_t now));
_PROTOTYPE( void fs_cancel_timer, (timer_t *tp));
+_PROTOTYPE( void fs_init_timer, (timer_t *tp));
+
+/* cdprobe.c */
+_PROTOTYPE( int cdprobe, (void));
FORWARD _PROTOTYPE(int select_request_file, (struct filp *f, int *ops, int block));
FORWARD _PROTOTYPE(int select_match_file, (struct filp *f));
-FORWARD _PROTOTYPE(int select_request_tty, (struct filp *f, int *ops, int block));
-FORWARD _PROTOTYPE(int select_request_inet, (struct filp *f, int *ops, int block));
-FORWARD _PROTOTYPE(int select_request_log, (struct filp *f, int *ops, int block));
+FORWARD _PROTOTYPE(int select_request_general, (struct filp *f, int *ops, int block));
FORWARD _PROTOTYPE(int select_major_match, (int match_major, struct filp *file));
FORWARD _PROTOTYPE(void select_cancel_all, (struct selectentry *e));
/* SELFD_FILE */
{ select_request_file, select_match_file, 0 },
/* SELFD_TTY (also PTY) */
- { select_request_tty, NULL, TTY_MAJOR },
+ { select_request_general, NULL, TTY_MAJOR },
/* SELFD_INET */
- { select_request_inet, NULL, INET_MAJOR },
+ { select_request_general, NULL, INET_MAJOR },
/* SELFD_PIPE (pipe(2) pipes and FS FIFOs) */
{ select_request_pipe, select_match_pipe, 0 },
/* SELFD_LOG (/dev/klog) */
- { select_request_log, NULL, LOG_MAJOR },
+ { select_request_general, NULL, LOG_MAJOR },
};
/* Open Group:
}
/*===========================================================================*
- * select_request_inet *
+ * select_request_general *
*===========================================================================*/
-PRIVATE int select_request_inet(struct filp *f, int *ops, int block)
-{
- int r, rops;
- rops = *ops;
- if(block) rops |= SEL_NOTIFY;
- *ops = dev_io(DEV_SELECT, f->filp_ino->i_zone[0], rops, NULL, 0, 0, 0);
- printf("select_request_inet: got reply %d from inet for %d on %d\n",
- *ops, rops, f->filp_ino->i_zone[0]);
- if(*ops < 0)
- return SEL_ERR;
- return SEL_OK;
-}
-
-/*===========================================================================*
- * select_request_log *
- *===========================================================================*/
-PRIVATE int select_request_log(struct filp *f, int *ops, int block)
+PRIVATE int select_request_general(struct filp *f, int *ops, int block)
{
int r, rops;
rops = *ops;
* operations that we are still interested in, if any.
*/
-restart_callback:
want_ops = 0;
type = -1;
for(s = 0; s < MAXSELECTS; s++) {
return OK;
}
+/*===========================================================================*
+ * init_select *
+ *===========================================================================*/
+PUBLIC void init_select(void)
+{
+ int s;
+
+ for(s = 0; s < MAXSELECTS; s++)
+ fs_init_timer(&selecttab[s].timer);
+}
/*===========================================================================*
* int select_forget *
-/* This file manages the super block table and the related data structures,
- * namely, the bit maps that keep track of which zones and which inodes are
+/* This file manages the super block table and the related data structures, * namely, the bit maps that keep track of which zones and which inodes are
* allocated and which are free. When a new inode or zone is needed, the
* appropriate bit map is searched for a free entry.
*
if(dev == NO_DEV)
panic(__FILE__,"request for block size of NO_DEV", NO_NUM);
- for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
- if (sp->s_dev == dev)
+ for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
+ if (sp->s_dev == dev) {
return(sp->s_block_size);
+ }
+ }
/* no mounted filesystem? use this block size then. */
return MIN_BLOCK_SIZE;
if((r = getuptime(&now)) != OK)
panic(__FILE__, "FS couldn't get uptime from system task.", NO_NUM);
- tmr_inittimer(tp);
tmr_arg(tp)->ta_int = arg;
old_head = tmrs_settimer(&fs_timers, tp, now+ticks, watchdog, &new_head);
#endif
}
+PUBLIC void fs_init_timer(timer_t *tp)
+{
+ tmr_inittimer(tp);
+}
+
PUBLIC void fs_cancel_timer(timer_t *tp)
{
clock_t new_head, old_head;