Subject: Disklabels arrive for 2.11BSD (#264 part 15 of 18) Index: sys,bin,usr.lib,(many more)/ 2.11BSD Description: The moving the partitions tables out of the disk drivers and to a disklabel residing on the media has been on the wish list for many many years. Disklabels have finally arrived for 2.11BSD! Repeat-By: Observation. Also a reading of the setup and installation documentation for previous 2BSD releases (2.9, 2.10, 2.11) all have a paragraph similar to this present: "It is possible to change the partitions by changing the code for the table in the disk driver. Since it's desirable to do this, these tables really should be read off each pack...." Fix: This is part 15 of 18. Gather all parts before doing anything except reading the instructions which are in #250 (part 1). Updated by this part are: /usr/src/sys/sys/sys_inode.c /usr/src/sys/sys/init_main.c /usr/src/sys/sys/ufs_mount.c /usr/src/sys/sys/ufs_disksubr.c ufs_disksubr.c is a new file added by unpacking the shar file included below. The disklabel read, write and ioctl code is contained in this file. Other changes include a new calling convention to device driver open and close entry points. Three arguments are now passed rather than two. The third argument is the type of device (S_IFBLK or S_IFCHR) and is used by disk drivers to keep track of which partitions are open on a drive. init_main.c was modifed to check the filesystem type of the swap partition. If the driver for the swap device supports labels then the partition used for swapping *must* be of type 'swap'. This is aimed at protecting data partitions by not allowing the kernel to swap on a live (type "2.11BSD") filesystem. Cut where indicated and save to a file (/tmp/264). Then: cd /tmp sh 264 sh sys.shar patch -p0 < sys.patch rm 264 sys.shar sys.patch ---------------------------cut here-------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # sys.shar # sys.patch # This archive created: Tue Jun 27 22:29:34 1995 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'sys.shar' then echo shar: "will not over-write existing file 'sys.shar'" else sed 's/^0//' << \SHAR_EOF > 'sys.shar' 0#! /bin/sh 0# This is a shell archive, meaning: 0# 1. Remove everything above the #! /bin/sh line. 0# 2. Save the resulting text in a file. 0# 3. Execute the file with /bin/sh (not csh) to create: 0# /sys/sys/ufs_disksubr.c 0# This archive created: Mon Jun 19 21:24:38 1995 0export PATH; PATH=/bin:/usr/bin:$PATH 0if test -f '/sys/sys/ufs_disksubr.c' 0then 0 echo shar: "will not over-write existing file '/sys/sys/ufs_disksubr.c'" 0else 0sed 's/^X//' << \SHAR_EOF > '/sys/sys/ufs_disksubr.c' 0X/* 0X * Copyright (c) 1982, 1986, 1988, 1993 0X * The Regents of the University of California. All rights reserved. 0X * (c) UNIX System Laboratories, Inc. 0X * All or some portions of this file are derived from material licensed 0X * to the University of California by American Telephone and Telegraph 0X * Co. or Unix System Laboratories, Inc. and are reproduced herein with 0X * the permission of UNIX System Laboratories, Inc. 0X * 0X * Redistribution and use in source and binary forms, with or without 0X * modification, are permitted provided that the following conditions 0X * are met: 0X * 1. Redistributions of source code must retain the above copyright 0X * notice, this list of conditions and the following disclaimer. 0X * 2. Redistributions in binary form must reproduce the above copyright 0X * notice, this list of conditions and the following disclaimer in the 0X * documentation and/or other materials provided with the distribution. 0X * 3. All advertising materials mentioning features or use of this software 0X * must display the following acknowledgement: 0X * This product includes software developed by the University of 0X * California, Berkeley and its contributors. 0X * 4. Neither the name of the University nor the names of its contributors 0X * may be used to endorse or promote products derived from this software 0X * without specific prior written permission. 0X * 0X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 0X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 0X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 0X * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 0X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 0X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 0X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 0X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 0X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 0X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 0X * SUCH DAMAGE. 0X * 0X * @(#)ufs_disksubr.c 8.5.3 (2.11BSD GTE) 1995/06/16 0X */ 0X 0X#include 0X#include 0X#include 0X#include 0X#include 0X#include 0X#include 0X#include 0X#include 0X#include 0X 0X/* 0X * Attempt to read a disk label from a device using the indicated stategy 0X * routine. The label must be partly set up before this: secpercyl and 0X * anything required in the strategy routine (e.g., sector size) must be 0X * filled in before calling us. Returns NULL on success and an error 0X * string on failure. 0X */ 0Xchar * 0Xreaddisklabel(dev, strat, lp) 0X dev_t dev; 0X int (*strat)(); 0X register struct disklabel *lp; 0X { 0X register struct buf *bp; 0X struct disklabel *dlp; 0X char *msg = NULL; 0X 0X if (lp->d_secperunit == 0) 0X lp->d_secperunit = 0x1fffffffL; 0X lp->d_npartitions = 1; 0X if (lp->d_partitions[0].p_size == 0) 0X lp->d_partitions[0].p_size = 0x1fffffffL; 0X lp->d_partitions[0].p_offset = 0; 0X 0X bp = geteblk(); 0X bp->b_dev = dev; 0X bp->b_blkno = LABELSECTOR; 0X bp->b_bcount = lp->d_secsize; /* Probably should wire this to 512 */ 0X bp->b_flags = B_BUSY | B_READ; 0X bp->b_cylin = LABELSECTOR / lp->d_secpercyl; 0X (*strat)(bp); 0X biowait(bp); 0X if (u.u_error) 0X msg = "I/O error"; 0X else 0X { 0X dlp = (struct disklabel *)mapin(bp); 0X if (dlp->d_magic != DISKMAGIC || 0X dlp->d_magic2 != DISKMAGIC) 0X { 0X if (msg == NULL) 0X msg = "no disk label"; 0X } 0X else if (dlp->d_npartitions > MAXPARTITIONS || dkcksum(dlp)) 0X msg = "disk label corrupted"; 0X else 0X bcopy(dlp, lp, sizeof (struct disklabel)); 0X mapout(bp); 0X } 0X bp->b_flags = B_INVAL | B_AGE; 0X brelse(bp); 0X return(msg); 0X } 0X 0X/* 0X * Check new disk label for sensibility before setting it. 'olp' must point 0X * to a kernel resident (or mapped in) label. 'nlp' points to the new label 0X * usually present on the stack (having been passed in via ioctl from an 0X * application). 0X */ 0Xint 0Xsetdisklabel(olp, nlp, openmask) 0X struct disklabel *olp; 0X register struct disklabel *nlp; 0X u_short openmask; 0X{ 0X int i; 0X register struct partition *opp, *npp; 0X 0X if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 0X dkcksum(nlp) != 0) 0X return (EINVAL); 0X while ((i = ffs((long)openmask)) != 0) { 0X i--; 0X openmask &= ~(1 << i); 0X if (nlp->d_npartitions <= i) 0X return (EBUSY); 0X opp = &olp->d_partitions[i]; 0X npp = &nlp->d_partitions[i]; 0X if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 0X return (EBUSY); 0X /* 0X * Copy internally-set partition information 0X * if new label doesn't include it. XXX 0X */ 0X if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 0X npp->p_fstype = opp->p_fstype; 0X npp->p_fsize = opp->p_fsize; 0X npp->p_frag = opp->p_frag; 0X } 0X } 0X nlp->d_checksum = 0; 0X nlp->d_checksum = dkcksum(nlp); 0X bcopy(nlp, olp, sizeof (struct disklabel)); 0X return (0); 0X} 0X 0X/* 0X * Write disk label back to device after modification. 0X */ 0Xint 0Xwritedisklabel(dev, strat, lp) 0X dev_t dev; 0X int (*strat)(); 0X register struct disklabel *lp; 0X{ 0X struct buf *bp; 0X struct disklabel *dlp; 0X int labelpart; 0X int error = 0; 0X 0X labelpart = dkpart(dev); 0X if (lp->d_partitions[labelpart].p_offset != 0) { 0X if (lp->d_partitions[0].p_offset != 0) 0X return (EXDEV); /* not quite right */ 0X labelpart = 0; 0X } 0X bp = geteblk(); 0X bp->b_dev = makedev(major(dev), dkminor(dkunit(dev), labelpart)); 0X bp->b_blkno = LABELSECTOR; 0X bp->b_bcount = lp->d_secsize; /* probably should wire to 512 */ 0X bp->b_flags = B_READ; 0X (*strat)(bp); 0X biowait(bp); 0X if (u.u_error) 0X goto done; 0X dlp = (struct disklabel *)mapin(bp); 0X if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 0X dkcksum(dlp) == 0) { 0X bcopy(lp, dlp, sizeof (struct disklabel)); 0X mapout(bp); 0X bp->b_flags = B_WRITE; 0X (*strat)(bp); 0X biowait(bp); 0X error = u.u_error; 0X } else { 0X error = ESRCH; 0X mapout(bp); 0X } 0Xdone: 0X brelse(bp); 0X return(error); 0X} 0X 0X/* 0X * Compute checksum for disk label. 0X */ 0Xdkcksum(lp) 0X struct disklabel *lp; 0X{ 0X register u_short *start, *end; 0X register u_short sum = 0; 0X 0X start = (u_short *)lp; 0X end = (u_short *)&lp->d_partitions[lp->d_npartitions]; 0X while (start < end) 0X sum ^= *start++; 0X return (sum); 0X} 0X 0X/* 0X * This is new for 2.11BSD. It is a common routine that checks for 0X * opening a partition that overlaps other currently open partitions. 0X * 0X * NOTE: if 'c' is not the entire drive (as is the case with the old, 0X * nonstandard, haphazard and overlapping partition tables) the warning 0X * message will be erroneously issued in some valid situations. 0X*/ 0X 0X#define RAWPART 2 /* 'c' */ /* XXX */ 0X 0Xdkoverlapchk(openmask, dev, label, name) 0X int openmask; 0X dev_t dev; 0X memaddr label; 0X char *name; 0X { 0X int unit = dkunit(dev); 0X int part = dkpart(dev); 0X int partmask = 1 << part; 0X int i; 0X daddr_t start, end; 0X register struct disklabel *lp = (struct disklabel *)SEG5; 0X register struct partition *pp; 0X 0X if ((openmask & partmask) == 0 && part != RAWPART) 0X { 0X mapseg5(label, LABELDESC); 0X pp = &lp->d_partitions[part]; 0X start = pp->p_offset; 0X end = pp->p_offset + pp->p_size; 0X i = 0; 0X for (pp = lp->d_partitions; i < lp->d_npartitions; pp++,i++) 0X { 0X if (pp->p_offset + pp->p_size <= start || 0X pp->p_offset >= end || i == RAWPART) 0X continue; 0X if (openmask & (1 << i)) 0X log(LOG_WARNING, 0X "%s%d%c: overlaps open part (%c)\n", 0X name, unit, part + 'a', i + 'a'); 0X } 0X normalseg5(); 0X } 0X return(0); 0X } 0X 0X/* 0X * It was noticed that the ioctl processing of disklabels was the same 0X * for every disk driver. Disk drivers should call this routine after 0X * handling ioctls (if any) particular to themselves. 0X*/ 0X 0Xioctldisklabel(dev, cmd, data, flag, disk, strat) 0X dev_t dev; 0X int cmd; 0X register caddr_t data; 0X int flag; 0X register struct dkdevice *disk; 0X int (*strat)(); 0X { 0X struct disklabel label; 0X register struct disklabel *lp = &label; 0X int error; 0X int flags; 0X 0X/* 0X * Copy in mapped out label to the local copy on the stack. We're in the 0X * high kernel at this point so saving the mapping is not necessary. 0X*/ 0X mapseg5(disk->dk_label, LABELDESC); 0X bcopy((struct disklabel *)SEG5, lp, sizeof (*lp)); 0X normalseg5(); 0X 0X switch (cmd) 0X { 0X case DIOCGDINFO: 0X bcopy(lp, (struct disklabel *)data, sizeof (*lp)); 0X return(0); 0X/* 0X * Used internally by the kernel in init_main to verify that 'swapdev' 0X * is indeed a FS_SWAP partition. 0X * 0X * NOTE: the label address is the external click address! 0X*/ 0X case DIOCGPART: 0X ((struct partinfo *)data)->disklab = 0X (struct disklabel *)disk->dk_label; 0X ((struct partinfo *)data)->part = 0X &disk->dk_parts[dkpart(dev)]; 0X return(0); 0X case DIOCWLABEL: 0X if ((flag & FWRITE) == 0) 0X return(EBADF); 0X if (*(int *)data) 0X disk->dk_flags |= DKF_WLABEL; 0X else 0X disk->dk_flags &= ~DKF_WLABEL; 0X return(0); 0X case DIOCSDINFO: 0X if ((flag & FWRITE) == 0) 0X return(EBADF); 0X error = setdisklabel(lp, (struct disklabel *)data, 0X disk->dk_flags & DKF_WLABEL ? 0 0X : disk->dk_openmask); 0X/* 0X * If no error was encountered setting the disklabel then we must copy 0X * out the new label from the local copy to the mapped out label. Also 0X * update the partition tables (which are resident in the kernel). 0X*/ 0X if (error == 0) 0X { 0X mapseg5(disk->dk_label, LABELDESC); 0X bcopy(lp,(struct disklabel *)SEG5,sizeof (*lp)); 0X normalseg5(); 0X bcopy(&lp->d_partitions, &disk->dk_parts, 0X sizeof (lp->d_partitions)); 0X } 0X return(error); 0X case DIOCWDINFO: 0X if ((flag & FWRITE) == 0) 0X return(EBADF); 0X error = setdisklabel(lp, (struct disklabel *)data, 0X disk->dk_flags & DKF_WLABEL ? 0 0X : disk->dk_openmask); 0X if (error) 0X return(error); 0X/* 0X * Copy to external label. Ah - need to also update the kernel resident 0X * partition tables! 0X*/ 0X mapseg5(disk->dk_label, LABELDESC); 0X bcopy(lp,(struct disklabel *)SEG5,sizeof (*lp)); 0X normalseg5(); 0X bcopy(&lp->d_partitions, &disk->dk_parts, 0X sizeof (lp->d_partitions)); 0X 0X/* 0X * We use the 'a' partition to write the label. This probably shouldn't 0X * be wired in here but it's not worth creating another macro for. Is it? 0X * The flags are faked to write enable the label area and that the drive is 0X * alive - it better be at this point or there is a problem in the open routine. 0X*/ 0X flags = disk->dk_flags; 0X disk->dk_flags |= (DKF_ALIVE | DKF_WLABEL); 0X error = writedisklabel(dev & ~7, strat, lp); 0X disk->dk_flags = flags; 0X return(error); 0X } 0X return(EINVAL); 0X } 0SHAR_EOF 0fi 0exit 0 0# End of shell archive SHAR_EOF fi if test -f 'sys.patch' then echo shar: "will not over-write existing file 'sys.patch'" else sed 's/^0//' << \SHAR_EOF > 'sys.patch' 0*** /usr/src/sys/sys/sys_inode.c.old Fri Jan 6 23:36:24 1995 0--- /usr/src/sys/sys/sys_inode.c Sun May 21 17:04:37 1995 0*************** 0*** 3,9 **** 0 * All rights reserved. The Berkeley software License Agreement 0 * specifies the terms and conditions for redistribution. 0 * 0! * @(#)sys_inode.c 1.3 (2.11BSD GTE) 1/6/95 0 */ 0 0 #include "param.h" 0--- 3,9 ---- 0 * All rights reserved. The Berkeley software License Agreement 0 * specifies the terms and conditions for redistribution. 0 * 0! * @(#)sys_inode.c 1.5 (2.11BSD GTE) 1995/05/21 0 */ 0 0 #include "param.h" 0*************** 0*** 486,492 **** 0 u.u_error = EINTR; /* ??? */ 0 return; 0 } 0! (*cfunc)(dev, flag); 0 } 0 0 /* 0--- 486,492 ---- 0 u.u_error = EINTR; /* ??? */ 0 return; 0 } 0! (*cfunc)(dev, flag, mode); 0 } 0 0 /* 0*************** 0*** 640,646 **** 0 return(EPERM); 0 } 0 } 0! return ((*cdevsw[maj].d_open)(dev, mode)); 0 0 case IFBLK: 0 if ((u_int)maj >= nblkdev) 0--- 640,646 ---- 0 return(EPERM); 0 } 0 } 0! return ((*cdevsw[maj].d_open)(dev, mode, S_IFCHR)); 0 0 case IFBLK: 0 if ((u_int)maj >= nblkdev) 0*************** 0*** 667,673 **** 0 if (securelevel > 0 && (error = ufs_mountedon(dev))) 0 return(error); 0 #endif 0! return ((*bdevsw[maj].d_open)(dev, mode)); 0 } 0 return (0); 0 } 0--- 667,673 ---- 0 if (securelevel > 0 && (error = ufs_mountedon(dev))) 0 return(error); 0 #endif 0! return ((*bdevsw[maj].d_open)(dev, mode, S_IFBLK)); 0 } 0 return (0); 0 } 0*** /usr/src/sys/sys/init_main.c.old Fri Jan 6 21:58:25 1995 0--- /usr/src/sys/sys/init_main.c Mon May 22 20:20:55 1995 0*************** 0*** 3,9 **** 0 * All rights reserved. The Berkeley software License Agreement 0 * specifies the terms and conditions for redistribution. 0 * 0! * @(#)init_main.c 1.7 (2.11BSD GTE) 1/6/95 0 */ 0 0 #include "param.h" 0--- 3,9 ---- 0 * All rights reserved. The Berkeley software License Agreement 0 * specifies the terms and conditions for redistribution. 0 * 0! * @(#)init_main.c 1.9 (2.11BSD GTE) 1995/05/22 0 */ 0 0 #include "param.h" 0*************** 0*** 14,22 **** 0--- 14,24 ---- 0 #include "mount.h" 0 #include "map.h" 0 #include "proc.h" 0+ #include "ioctl.h" 0 #include "inode.h" 0 #include "conf.h" 0 #include "buf.h" 0+ #include "fcntl.h" 0 #include "vm.h" 0 #include "clist.h" 0 #include "uba.h" 0*************** 0*** 24,29 **** 0--- 26,33 ---- 0 #include "systm.h" 0 #include "kernel.h" 0 #include "namei.h" 0+ #include "disklabel.h" 0+ #include "stat.h" 0 #ifdef QUOTA 0 #include "quota.h" 0 #endif 0*************** 0*** 57,62 **** 0--- 61,68 ---- 0 register struct fs *fs; 0 time_t toytime, toyclk(); 0 daddr_t swsize; 0+ int (*ioctl)(); 0+ struct partinfo dpart; 0 0 startup(); 0 0*************** 0*** 147,156 **** 0 * 'swplo' was a hack which has _finally_ gone away! It was never anything 0 * but 0 and caused a number of double word adds in the kernel. 0 */ 0! (*bdevsw[major(swapdev)].d_open)(swapdev, B_READ|B_WRITE); 0 swsize = (*bdevsw[major(swapdev)].d_psize)(swapdev); 0! if (swsize < 0) 0! panic("swsize"); /* don't want to panic, but what ? */ 0 if (swsize > (daddr_t)65535) 0 swsize = 65535; 0 nswap = swsize; 0--- 153,176 ---- 0 * 'swplo' was a hack which has _finally_ gone away! It was never anything 0 * but 0 and caused a number of double word adds in the kernel. 0 */ 0! (*bdevsw[major(swapdev)].d_open)(swapdev, FREAD|FWRITE, S_IFBLK); 0 swsize = (*bdevsw[major(swapdev)].d_psize)(swapdev); 0! if (swsize <= 0) 0! panic("swsiz"); /* don't want to panic, but what ? */ 0! 0! /* 0! * Next we make sure that we do not swap on a partition unless it is of 0! * type FS_SWAP. If the driver does not have an ioctl entry point or if 0! * retrieving the partition information fails then the driver does not 0! * support labels and we proceed normally, otherwise the partition must be 0! * a swap partition (so that we do not swap on top of a filesystem by mistake). 0! */ 0! ioctl = cdevsw[major(swapdev)].d_ioctl; 0! if (ioctl && !(*ioctl)(swapdev, DIOCGPART, (caddr_t)&dpart, FREAD)) 0! { 0! if (dpart.part->p_fstype != FS_SWAP) 0! panic("swtyp"); 0! } 0 if (swsize > (daddr_t)65535) 0 swsize = 65535; 0 nswap = swsize; 0*************** 0*** 180,186 **** 0 0 #ifdef INET 0 if (netoff = netinit()) 0! printf("Network init failed\n"); 0 else 0 NETSTART(); 0 #endif 0--- 200,206 ---- 0 0 #ifdef INET 0 if (netoff = netinit()) 0! printf("netinit failed\n"); 0 else 0 NETSTART(); 0 #endif 0*** /usr/src/sys/sys/ufs_mount.c.old Fri Jan 6 21:20:24 1995 0--- /usr/src/sys/sys/ufs_mount.c Sun May 21 17:18:30 1995 0*************** 0*** 3,9 **** 0 * All rights reserved. The Berkeley software License Agreement 0 * specifies the terms and conditions for redistribution. 0 * 0! * @(#)ufs_mount.c 1.3 (2.11BSD GTE) 1/6/95 0 */ 0 0 #include "param.h" 0--- 3,9 ---- 0 * All rights reserved. The Berkeley software License Agreement 0 * specifies the terms and conditions for redistribution. 0 * 0! * @(#)ufs_mount.c 1.5 (2.11BSD GTE) 1995/05/21 0 */ 0 0 #include "param.h" 0*************** 0*** 18,23 **** 0--- 18,24 ---- 0 #include "file.h" 0 #include "namei.h" 0 #include "conf.h" 0+ #include "stat.h" 0 #ifdef QUOTA 0 #include "quota.h" 0 #endif 0*************** 0*** 81,87 **** 0 int needclose = 0; 0 0 error = 0! (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE); 0 if (error) 0 goto out; 0 needclose = 1; 0--- 82,88 ---- 0 int needclose = 0; 0 0 error = 0! (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE, S_IFBLK); 0 if (error) 0 goto out; 0 needclose = 1; 0*************** 0*** 133,139 **** 0 if (tp) 0 brelse(tp); 0 if (needclose) { 0! (*bdevsw[major(dev)].d_close)(dev, ronly? FREAD : FREAD|FWRITE); 0 binval(dev); 0 } 0 u.u_error = error; 0--- 134,141 ---- 0 if (tp) 0 brelse(tp); 0 if (needclose) { 0! (*bdevsw[major(dev)].d_close)(dev, 0! ronly? FREAD : FREAD|FWRITE, S_IFBLK); 0 binval(dev); 0 } 0 u.u_error = error; 0*************** 0*** 189,195 **** 0 irele(ip); 0 mp->m_inodp = 0; 0 mp->m_dev = 0; 0! (*bdevsw[major(dev)].d_close)(dev, 0); 0 binval(dev); 0 return (0); 0 } 0--- 191,197 ---- 0 irele(ip); 0 mp->m_inodp = 0; 0 mp->m_dev = 0; 0! (*bdevsw[major(dev)].d_close)(dev, 0, S_IFBLK); 0 binval(dev); 0 return (0); 0 } SHAR_EOF fi exit 0 # End of shell archive