Date: Wed, 22 Jan 2003 20:59:18 +0100 (MET) From: j@uriah.heep.sax.de (Joerg Wunsch) To: freebsd-current@freebsd.org Subject: Re: vinum root [Was: I want a sysctl kern.allow_shooting_into_my_foot!] Message-ID: <200301221959.h0MJxIiW088157@uriah.heep.sax.de> References: <20030122121739.GA758@cicely8.cicely.de> <25074.1043238359@critter.freebsd.dk> <20030122124403.GB758@cicely8.cicely.de> <20030122135404.B70341@uriah.heep.sax.de> <20030122130644.GA52953@tara.freenix.org>
next in thread | previous in thread | raw e-mail | index | archive | help
--=-=-=__Z6c+YyEsi+3q+W1ZhZc2+8GQT__=-=-= Ollivier Robert <roberto@keltia.freenix.fr> wrote: >> Oh, i should add: in my case, it's loaded before mounting the >> root (root is on vinum). > And how did you achieved this ? I thought vinum isn't able to do > that... Well, the patch for -current is currently only sitting here on my machine(s). Greg wanted to review it before i commit it, but i'll append it in case someone else wants to have a look at it. Under -current, the generic part of the kernel (namely mountroot() and its related functions) is already clean enough so no changes are needed there, only vinum needs a patch. Under -stable, the patch is already in the tree. Since mountroot() employs a very simple scheme to derive the dev_t of the root device from the given device name there, a patch to it was required, and all this is not very clean, but it works (see below). The basic concept is that you need to have the loader load the vinum module for you, and vinum needs to be told to configure itself early. Under -current (with the patch), put the following into /boot/loader.conf: vinum_load="YES" vinum.autostart="YES" Your /etc/fstab needs to have /dev/vinum/root (or whatever you name it) for the / filesystem; the loader will read this file, and pass the device name as the default root device to mountroot(). mountroot() then asks the drivers (by the trick of calling the undocumented event handler for disk_clone) to get a dev_t for the given name. Alternatively, any name entered after boot -a will be resolved the same way. So what the patch does is: . implement the logic to start vinum early . implement an event handler for dev_clone so vinum will get asked, too Under 4.x, put the following into loader.conf: vinum_load="YES" vinum.drives="/dev/da0 /dev/da1 /dev/da2" vinum.root="root" The logic to have vinum auto-scan the available disks is not yet there, so you explicitly need to name the devices to scan. (This part of the patch has been implemented first here under -current, but can perhaps be MFC'ed, too. The vinum.drives approach will also still work with the -current patch but is less convenient.) Also, since mountroot() has no way to ask the drivers to translate the given name into the corresponding dev_t, the trick with vinum.root is used; if this environment variable is set, vinum will pre-allocate the variable rootdev with the appropriate dev_t if the volume named by this has been found. The generic code will trust this value if the major # of the driver as figured out from the root device name matches the major # of the pre-allocated rootdev. I. e., it still gets /dev/vinum/root from the loader, strips the /dev/ (not needed at all inside the kernel), then scans until the first digit or slash, yielding "vinum" in that case. Now, if the major number of the preset rootdev matches the major # of vinum, the value will be taken. If rootdev has not been set, the traditional approach by deriving the minor # from the unit #, slice #, and partition name will be taken (using a hardcoded algorithm for this which is independent of the actual driver). All this gives the illusion that mountroot() would know how to handle /dev/vinum/root. ;-) Of course, what you cannot do is to boot -a, then enter an invalid name (so you'll get asked again), and then enter ufs:/dev/vinum/root: the previous invalid name has destroyed the preset rootdev value. At that point, you either need to abort or to enter a valid slice/partition. The biggest problem of all this is, of course, the bootstrapping step. The bootstrap still needs an `a' partition in order to read at least /boot/loader etc. from. The solution is to produce a faked overlay `a' partition that sits at exactly the point where the corresponding vinum subdisk of the root device is located. Another solution would be to setup a mini-root that only contains a boot/ directory in it, and use that one for partition `a', but that'll only cause other trouble (like "make install" not doing the right thing). While /boot/loader could perhaps be taught how to read something from a vinum volume, there's always the problem how to get at /boot/loader itself, so i have no other idea for this. A script could be provided that creates the faked `a' entry. -- cheers, J"org .-.-. --... ...-- -.. . DL8DTL http://www.sax.de/~joerg/ NIC: JW11-RIPE Never trust an operating system you don't have sources for. ;-) --=-=-=__Z6c+YyEsi+3q+W1ZhZc2+8GQT__=-=-= Content-Type: text/plain Content-Disposition: attachment; filename="vinumrootpatch" Index: vinum.c =================================================================== RCS file: /home/ncvs/src/sys/dev/vinum/vinum.c,v retrieving revision 1.49 diff -u -u -r1.49 vinum.c --- vinum.c 1 Apr 2002 21:30:36 -0000 1.49 +++ vinum.c 13 Jan 2003 21:13:33 -0000 @@ -66,6 +66,8 @@ STATIC int vinum_modevent(module_t mod, modeventtype_t type, void *unused); +STATIC void vinum_clone(void *arg, char *name, int namelen, dev_t *dev); + struct _vinum_conf vinum_conf; /* configuration information */ dev_t vinum_daemon_dev; @@ -79,6 +81,10 @@ void vinumattach(void *dummy) { + int i, rv; + char *cp, *cp1, *cp2, **drives, *drivep; + size_t alloclen; + /* modload should prevent multiple loads, so this is worth a panic */ if ((vinum_conf.flags & VF_LOADED) != 0) panic("vinum: already loaded"); @@ -135,6 +141,63 @@ bzero(SD, sizeof(struct sd) * INITIAL_SUBDISKS); vinum_conf.subdisks_allocated = INITIAL_SUBDISKS; /* number of sd slots allocated */ vinum_conf.subdisks_used = 0; /* and number in use */ + + EVENTHANDLER_REGISTER(dev_clone, vinum_clone, 0, 1000); + + /* + * See if the loader has passed us any of the + * autostart options. + */ + cp = drivep = NULL; +#ifndef VINUM_AUTOSTART + if ((cp = getenv("vinum.autostart")) != NULL) { + freeenv(cp); + cp = NULL; +#endif + rv = kernel_sysctlbyname(&thread0, "kern.disks", + NULL, NULL, + NULL, 0, + &alloclen); + if (rv) + log(LOG_NOTICE, + "sysctlbyname(\"kern.disks\") failed, rv = %d\n", + rv); + else { + drivep = malloc(alloclen, M_TEMP, M_WAITOK); + (void)kernel_sysctlbyname(&thread0, "kern.disks", + drivep, &alloclen, + NULL, 0, + NULL); + goto start; + } +#ifndef VINUM_AUTOSTART + } else +#endif + if ((cp = getenv("vinum.drives")) != NULL) { + start: + for (cp1 = cp? cp: drivep, i = 0, drives = 0; + *cp1 != '\0'; + i++) { + cp2 = cp1; + while (*cp1 != '\0' && *cp1 != ',' && *cp1 != ' ') + cp1++; + if (*cp1 != '\0') + *cp1++ = '\0'; + drives = realloc(drives, + (unsigned long)((i + 1) * sizeof(char *)), + M_TEMP, M_WAITOK); + drives[i] = cp2; + } + if (i == 0) + goto bailout; + rv = vinum_scandisk(drives, i); + if (rv) + log(LOG_NOTICE, "vinum_scandisk() returned %d\n", rv); + bailout: + freeenv(cp); + free(drives, M_TEMP); + free(drivep, M_TEMP); + } } /* @@ -490,6 +553,25 @@ return 0; /* err on the size of conservatism */ return size; +} + +void +vinum_clone(void *arg, char *name, int namelen, dev_t *dev) +{ + struct volume *vol; + int i; + + if (*dev != NODEV) + return; + if (strncmp(name, "vinum/", sizeof("vinum/") - 1) != 0) + return; + + name += sizeof("vinum/") - 1; + if ((i = find_volume(name, 0)) == -1) + return; + + vol = &VOL[i]; + *dev = vol->dev; } /* Local Variables: */ Index: vinumhdr.h =================================================================== RCS file: /home/ncvs/src/sys/dev/vinum/vinumhdr.h,v retrieving revision 1.27 diff -u -u -r1.27 vinumhdr.h --- vinumhdr.h 12 May 2002 20:49:41 -0000 1.27 +++ vinumhdr.h 13 Jan 2003 20:20:32 -0000 @@ -49,6 +49,7 @@ #include <sys/conf.h> #include <sys/mount.h> #include <sys/vnode.h> +#include <sys/sysctl.h> #endif #include <sys/errno.h> #include <sys/dkstat.h> Index: vinumio.c =================================================================== RCS file: /home/ncvs/src/sys/dev/vinum/vinumio.c,v retrieving revision 1.78 diff -u -u -r1.78 vinumio.c --- vinumio.c 22 Jan 2003 14:06:46 -0000 1.78 +++ vinumio.c 22 Jan 2003 19:38:55 -0000 @@ -50,32 +50,21 @@ int open_drive(struct drive *drive, struct thread *td, int verbose) { - struct nameidata nd; struct cdevsw *dsw; /* pointer to cdevsw entry */ - int error; if (drive->flags & VF_OPEN) /* open already, */ return EBUSY; /* don't do it again */ - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, drive->devicename, - curthread); - error = namei(&nd); - if (error) - return (error); - if (!vn_isdisk(nd.ni_vp, &error)) { - NDFREE(&nd, 0); - return (error); - } - drive->dev = udev2dev(nd.ni_vp->v_rdev->si_udev, 0); - NDFREE(&nd, 0); - - if (drive->dev == NULL) /* didn't find anything */ - return ENODEV; + drive->dev = getdiskbyname(drive->devicename); + if (drive->dev == NODEV) /* didn't find anything */ + return ENOENT; drive->dev->si_iosize_max = DFLTPHYS; dsw = devsw(drive->dev); - if (dsw == NULL) + if (dsw == NULL) /* sanity, should not happen */ drive->lasterror = ENOENT; + else if ((dsw->d_flags & D_DISK) == 0) + drive->lasterror = ENOTBLK; else drive->lasterror = (dsw->d_open) (drive->dev, FWRITE | FREAD, 0, NULL); @@ -145,11 +134,7 @@ int init_drive(struct drive *drive, int verbose) { - if (drive->devicename[0] != '/') { - drive->lasterror = EINVAL; - log(LOG_ERR, "vinum: Can't open drive without drive name\n"); - return EINVAL; - } + drive->lasterror = open_drive(drive, curthread, verbose); /* open the drive */ if (drive->lasterror) return drive->lasterror; --=-=-=__Z6c+YyEsi+3q+W1ZhZc2+8GQT__=-=-=-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200301221959.h0MJxIiW088157>