+ if (fp->f_type == DTYPE_SOCKET) {
+ u.u_error = 0; /* XXX */
+ soclose(fp->f_socket, nouser);
+ if (nouser == 0 && u.u_error)
+ return;
+ fp->f_socket = 0;
+ fp->f_count = 0;
+ return;
+ }
+ flag = fp->f_flag;
+ ip = fp->f_inode;
+ dev = (dev_t)ip->i_rdev;
+ mode = ip->i_mode & IFMT;
+ ilock(ip);
+ iput(ip);
+ fp->f_count = 0;
+
+ switch (mode) {
+
+ case IFCHR:
+ cfunc = cdevsw[major(dev)].d_close;
+#ifdef EFS
+ /*
+ * Every close() must call the driver if the
+ * extended file system is being used -- not
+ * just the last close. Pass along the file
+ * pointer for reference later.
+ */
+ if (major(dev) == efs_major) {
+ (*cfunc)(dev, flag, fp, nouser);
+ return;
+ }
+#endif
+ break;
+
+ case IFBLK:
+ /*
+ * We don't want to really close the device if it is mounted
+ */
+ for (mp = mount; mp < &mount[NMOUNT]; mp++)
+ if (mp->m_bufp != NULL && mp->m_dev == dev)
+ return;
+ cfunc = bdevsw[major(dev)].d_close;
+ break;
+
+ default:
+ return;
+ }
+ for (fp = file; fp < fileNFILE; fp++) {
+ if (fp->f_type == DTYPE_SOCKET) /* XXX */
+ continue;
+ if (fp->f_count && (ip = fp->f_inode) &&
+ ip->i_rdev == dev && (ip->i_mode&IFMT) == mode)
+ return;
+ }
+ if (mode == IFBLK) {
+ /*
+ * On last close of a block device (that isn't mounted)
+ * we must invalidate any in core blocks
+ */
+ bflush(dev);
+ binval(dev);
+ }
+ (*cfunc)(dev, flag, fp);
+}
+
+#ifdef CAD
+/*
+ * chfile -- change all references to the inode named by
+ * device/inum to the file referred to by fd.
+ * Used by init to remove all references to the device.
+ */
+chfile()
+{
+ register struct file *fp;
+ register struct inode *from;
+ register struct inode *to;
+ off_t offset;
+ dev_t dev;
+ int rw;
+ struct a {
+ int device; /* actually dev_t */
+ int inum; /* actually ino_t */
+ int fd;
+ } *uap;
+
+ if (!suser()) {
+ u.u_error = EPERM;
+ return;
+ }
+ uap = (struct a *) u.u_ap;
+ fp = getf(uap->fd);
+ if (fp == NULL) {
+ u.u_error = EBADF;
+ return;
+ }
+ if (fp->f_type == DTYPE_SOCKET) {
+ u.u_error = EINVAL;
+ return;
+ }
+ for (from = &inode[0]; from < &inode[ninode]; from++)
+ if (from->i_number == (ino_t)uap->inum
+ && from->i_dev == (dev_t)uap->device)
+ break;
+ if (from >= &inode[ninode]) {
+ u.u_error = ENXIO;
+ return;
+ }
+ offset = fp->f_offset;
+ to = fp->f_inode;
+ from->i_count++;
+ for (fp = &file[0]; fp < &file[nfile]; fp++) {
+ if (fp->f_count > 0 && fp->f_inode == from) {
+ fp->f_inode = to;
+ to->i_count++;
+ fp->f_offset = offset;
+ rw |= fp->f_flag & FWRITE;
+ iput(from);
+ }
+ }
+ /*
+ * This inode is no longer referenced.
+ * Switch out to the appropriate close
+ * routine, if required
+ */
+ dev = (dev_t)from->i_un.i_rdev;
+ switch(from->i_mode & IFMT) {
+
+ case IFCHR:
+ (*cdevsw[major(dev)].d_close)(dev, rw);
+ break;
+
+ case IFBLK:
+ (*bdevsw[major(dev)].d_close)(dev, rw);
+ break;
+
+ default:
+ break;
+ }
+ iput(from);