vinumio.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,103 行 · 第 1/3 页

C
1,103
字号
    vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN);	    /* get space for the config data */    CHECKALLOC(vhdr, "Can't allocate config data");    vhdr->magic = VINUM_MAGIC;				    /* magic number */    vhdr->config_length = MAXCONFIG;			    /* length of following config info */    config = Malloc(MAXCONFIG);				    /* get space for the config data */    CHECKALLOC(config, "Can't allocate config data");    format_config(config, MAXCONFIG);    error = 0;						    /* no errors yet */    for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {	drive = &vinum_conf.drive[driveno];		    /* point to drive */	if (drive->state > drive_referenced) {	    LOCKDRIVE(drive);				    /* don't let it change */	    /*	     * First, do some drive consistency checks.  Some	     * of these are kludges, others require a process	     * context and couldn't be done before 	     */	    if ((drive->devicename[0] == '\0')		    /* XXX we keep getting these nameless drives */	    ||(drive->label.name[0] == '\0')) {		    /* XXX we keep getting these nameless drives */		unlockdrive(drive);		log(LOG_WARNING,		    "Removing incomplete drive, index %d\n",		    driveno);		if (drive->vp)				    /* how can it be open without a name? */		    close_drive(drive);		free_drive(drive);			    /* get rid of it */		break;	    }	    if ((drive->vp == NULL)			    /* drive not open */	    &&(drive->state > drive_down)) {		    /* and it thinks it's not down */		unlockdrive(drive);		set_drive_state(driveno, drive_down, setstate_force); /* tell it what's what */		continue;	    }	    if ((drive->state == drive_down)		    /* it's down */	    &&(drive->vp != NULL)) {			    /* but open, */		unlockdrive(drive);		close_drive(drive);			    /* close it */	    } else if (drive->state > drive_down) {		getmicrotime(&drive->label.last_update);    /* time of last update is now */		bcopy((char *) &drive->label,		    /* and the label info from the drive structure */		    (char *) &vhdr->label,		    sizeof(vhdr->label));		if ((drive->state != drive_unallocated)		    && (drive->state != drive_referenced)) { /* and it's a real drive */		    wlabel_on = 1;			    /* enable writing the label */		    error = VOP_IOCTL(drive->vp,	    /* make the label writeable */			DIOCWLABEL,			(caddr_t) & wlabel_on,			FWRITE,			NOCRED,			curproc);		    if (error == 0)			error = write_drive(drive, (char *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET);		    if (error == 0)			error = write_drive(drive, config, MAXCONFIG, VINUM_CONFIG_OFFSET); /* first config copy */		    if (error == 0)			error = write_drive(drive, config, MAXCONFIG, VINUM_CONFIG_OFFSET + MAXCONFIG);	/* second copy */		    wlabel_on = 0;			    /* enable writing the label */		    if (error == 0)			VOP_IOCTL(drive->vp,		    /* make the label non-writeable again */			    DIOCWLABEL,			    (caddr_t) & wlabel_on,			    FWRITE,			    NOCRED,			    curproc);		    unlockdrive(drive);		    if (error) {			log(LOG_ERR,			    "vinum: Can't write config to %s, error %d\n",			    drive->devicename,			    error);			set_drive_state(drive->driveno, drive_down, setstate_force);		    } else			written_config = 1;		    /* we've written it on at least one drive */		}	    } else					    /* not worth looking at, */		unlockdrive(drive);			    /* just unlock it again */	}    }    Free(vhdr);    Free(config);}/* * Disk labels are a mess.  The correct way to access them * is with the DIOC[GSW]DINFO ioctls, but some programs, such * as newfs, access the disk directly, so we have to write * things there.  We do this only on request.  If a user * request tries to read it directly, we fake up one on the fly. *//* * get_volume_label returns a label structure to lp, which * is allocated by the caller  */void get_volume_label(struct volume *vol, struct disklabel *lp){    bzero(lp, sizeof(struct disklabel));    strncpy(lp->d_typename, "vinum", sizeof(lp->d_typename));    lp->d_type = DTYPE_VINUM;    strncpy(lp->d_packname, vol->name, min(sizeof(lp->d_packname), sizeof(vol->name)));    lp->d_rpm = 14400 * vol->plexes;			    /* to keep them guessing */    lp->d_interleave = 1;    lp->d_flags = 0;    /*     * Fitting unto the vine, a vinum has a single     *  track with all its sectors      */    lp->d_secsize = DEV_BSIZE;				    /* bytes per sector */    lp->d_nsectors = vol->size;				    /* data sectors per track */    lp->d_ntracks = 1;					    /* tracks per cylinder */    lp->d_ncylinders = 1;				    /* data cylinders per unit */    lp->d_secpercyl = vol->size;			    /* data sectors per cylinder */    lp->d_secperunit = vol->size;			    /* data sectors per unit */    lp->d_bbsize = BBSIZE;    lp->d_sbsize = SBSIZE;    lp->d_magic = DISKMAGIC;    lp->d_magic2 = DISKMAGIC;    /*     * Set up partitions a, b and c to be identical     * and the size of the volume.  a is UFS, b is     * swap, c is nothing      */    lp->d_partitions[0].p_size = vol->size;    lp->d_partitions[0].p_fsize = 1024;    lp->d_partitions[0].p_fstype = FS_BSDFFS;		    /* FreeBSD File System :-) */    lp->d_partitions[0].p_fsize = 1024;			    /* FS fragment size */    lp->d_partitions[0].p_frag = 8;			    /* and fragments per block */    lp->d_partitions[SWAP_PART].p_size = vol->size;    lp->d_partitions[SWAP_PART].p_fstype = FS_SWAP;	    /* swap partition */    lp->d_partitions[LABEL_PART].p_size = vol->size;    lp->d_npartitions = LABEL_PART + 1;    strncpy(lp->d_packname, vol->name, min(sizeof(lp->d_packname), sizeof(vol->name)));    lp->d_checksum = dkcksum(lp);}/* Write a volume label.  This implements the VINUM_LABEL ioctl. */int write_volume_label(int volno){    struct disklabel *lp;    struct buf *bp;    struct disklabel *dlp;    struct volume *vol;    int error;    lp = (struct disklabel *) Malloc((sizeof(struct disklabel) + (DEV_BSIZE - 1)) & (DEV_BSIZE - 1));    if (lp == 0)	return ENOMEM;    if ((unsigned) (volno) >= (unsigned) vinum_conf.volumes_allocated) /* invalid volume */	return ENOENT;    vol = &VOL[volno];					    /* volume in question */    if (vol->state <= volume_uninit)			    /* nothing there */	return ENXIO;    else if (vol->state < volume_up)			    /* not accessible */	return EIO;					    /* I/O error */    get_volume_label(vol, lp);				    /* get the label */    /*     * Now write to disk.  This code is derived from the     * system writedisklabel (), which does silly things     * like reading the label and refusing to write     * unless it's already there. */    bp = geteblk((int) lp->d_secsize);			    /* get a buffer */    bp->b_dev = minor(vol->devno) | (CDEV_MAJOR << MAJORDEV_SHIFT); /* our own raw volume */    bp->b_blkno = LABELSECTOR * ((int) lp->d_secsize / DEV_BSIZE);    bp->b_bcount = lp->d_secsize;    bzero(bp->b_data, lp->d_secsize);    dlp = (struct disklabel *) bp->b_data;    *dlp = *lp;    bp->b_flags &= ~B_INVAL;    bp->b_flags |= B_BUSY | B_WRITE;    vinumstrategy(bp);					    /* write it out */    error = biowait(bp);    bp->b_flags |= B_INVAL | B_AGE;    brelse(bp);    return error;}/* Initialize a subdisk */int initsd(int sdno){    return 0;}/* Look at all disks on the system for vinum slices */int vinum_scandisk(char *devicename[], int drives){    struct drive *volatile drive;    volatile int driveno;    int firstdrive;					    /* first drive in this list */    volatile int gooddrives;				    /* number of usable drives found */    int firsttime;					    /* set if we have never configured before */    int error;    struct nameidata nd;				    /* mount point credentials */    char *config_text;					    /* read the config info from disk into here */    char *volatile cptr;				    /* pointer into config information */    char *eptr;						    /* end pointer into config information */    char *config_line;					    /* copy the config line to */    volatile int status;    int *volatile drivelist;				    /* list of drive indices */#define DRIVENAMELEN 64#define DRIVEPARTS   35					    /* max partitions per drive, excluding c */    char partname[DRIVENAMELEN];			    /* for creating partition names */    status = 0;						    /* success indication */    vinum_conf.flags |= VF_READING_CONFIG;		    /* reading config from disk */    gooddrives = 0;					    /* number of usable drives found */    firstdrive = vinum_conf.drives_used;		    /* the first drive */    firsttime = vinum_conf.drives_used == 0;		    /* are we a virgin? */    /* allocate a drive pointer list */    drivelist = (int *) Malloc(drives * DRIVEPARTS * sizeof(int));    CHECKALLOC(drivelist, "Can't allocate memory");    /* Open all drives and find which was modified most recently */    for (driveno = 0; driveno < drives; driveno++) {	char part;					    /* UNIX partition */	for (part = 'a'; part < 'i'; part++)	    if (part != 'c') {				    /* don't do the c partition */		snprintf(partname,			    /* /dev/sd0a */		    DRIVENAMELEN,		    "%s%c",		    devicename[driveno],		    part);		drive = check_drive(partname);		    /* try to open it */		if ((drive->lasterror != 0)		    /* didn't work, */		||(drive->state != drive_up))		    free_drive(drive);			    /* get rid of it */		else if (drive->flags & VF_CONFIGURED)	    /* already read this config, */		    log(LOG_WARNING,			"vinum: already read config from %s\n",	/* say so */			drive->label.name);		else {		    drivelist[gooddrives] = drive->driveno; /* keep the drive index */		    drive->flags &= ~VF_NEWBORN;	    /* which is no longer newly born */		    gooddrives++;		}	    }    }    if (gooddrives == 0) {	log(LOG_WARNING, "vinum: no drives found\n");	return ENOENT;    }    /*     * We now have at least one drive     * open.  Sort them in order of config time     * and merge the config info with what we     * have already      */    qsort(drivelist, gooddrives, sizeof(int), drivecmp);    config_text = (char *) Malloc(MAXCONFIG * 2);	    /* allocate buffers */    CHECKALLOC(config_text, "Can't allocate memory");    config_line = (char *) Malloc(MAXCONFIGLINE * 2);	    /* allocate buffers */    CHECKALLOC(config_line, "Can't allocate memory");    for (driveno = 0; driveno < gooddrives; driveno++) {    /* now include the config */	drive = &DRIVE[drivelist[driveno]];		    /* point to the drive */	if (firsttime && (driveno == 0))		    /* we've never configured before, */	    log(LOG_INFO, "vinum: reading configuration from %s\n", drive->devicename);	else	    log(LOG_INFO, "vinum: updating configuration from %s\n", drive->devicename);	/* XXX Transition until we can get things changed */	if (drive->partinfo.part->p_fstype == FS_UNUSED)    /* still set to unused */	    log(LOG_WARNING,		"vinum: %s partition type is 'unused', should be 'vinum'\n",		drive->devicename);	/* Read in both copies of the configuration information */	error = read_drive(drive, config_text, MAXCONFIG * 2, VINUM_CONFIG_OFFSET);	if (error != 0) {	    log(LOG_ERR, "vinum: Can't read device %s, error %d\n", drive->devicename, error);	    Free(config_text);	    Free(config_line);	    free_drive(drive);				    /* give it back */	    status = error;	}	/*	 * XXX At this point, check that the two copies are the same, and do something useful if not.	 * In particular, consider which is newer, and what this means for the integrity of the	 * data on the drive 	 */	else {	    vinum_conf.drives_used++;			    /* another drive in use */	    /* Parse the configuration, and add it to the global configuration */	    for (cptr = config_text; *cptr != '\0';) {	    /* love this style(9) */		volatile int parse_status;		    /* return value from parse_config */		for (eptr = config_line; (*cptr != '\n') && (*cptr != '\0');) /* until the end of the line */		    *eptr++ = *cptr++;		*eptr = '\0';				    /* and delimit */		if (setjmp(command_fail) == 0) {	    /* come back here on error and continue */		    parse_status = parse_config(config_line, &keyword_set, 1); /* parse the config line */		    if (parse_status < 0) {		    /* error in config */			/*			   * This config should have been parsed in user			   * space.  If we run into problems here, something			   * serious is afoot.  Complain and let the user			   * snarf the config to see what's wrong 			 */			log(LOG_ERR,			    "vinum: Config error on drive %s, aborting integration\n",			    nd.ni_dirp);			Free(config_text);			Free(config_line);			free_drive(drive);		    /* give it back */			status = EINVAL;		    }		}		while (*cptr == '\n')		    cptr++;				    /* skip to next line */	    }	}	drive->flags |= VF_CONFIGURED;			    /* read this drive's configuration */    }    Free(config_text);    Free(drivelist);    vinum_conf.flags &= ~VF_READING_CONFIG;		    /* no longer reading from disk */    if (status != 0)	throw_rude_remark(status, "Couldn't read configuration");    updateconfig(VF_READING_CONFIG);			    /* update from disk config */    return 0;}/* * Compare the modification dates of the drives, for qsort. * Return 1 if a < b, 0 if a == b, 01 if a > b: in other * words, sort backwards  */int drivecmp(const void *va, const void *vb){    const struct drive *a = &DRIVE[*(const int *) va];    const struct drive *b = &DRIVE[*(const int *) vb];    if ((a->label.last_update.tv_sec == b->label.last_update.tv_sec)	&& (a->label.last_update.tv_usec == b->label.last_update.tv_usec))	return 0;    else if ((a->label.last_update.tv_sec > b->label.last_update.tv_sec)	    || ((a->label.last_update.tv_sec == b->label.last_update.tv_sec)	    && (a->label.last_update.tv_usec > b->label.last_update.tv_usec)))	return -1;    else	return 1;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?