|
|
| version 1.14, 2004/05/03 18:46:34 | version 1.15, 2004/05/19 22:53:06 |
|---|---|
| Line 113 static struct vnodeopv_desc spec_vnodeop | Line 113 static struct vnodeopv_desc spec_vnodeop |
| VNODEOP_SET(spec_vnodeop_opv_desc); | VNODEOP_SET(spec_vnodeop_opv_desc); |
| extern int dev_ref_debug; | |
| /* | /* |
| * spec_vnoperate(struct vnodeop_desc *a_desc, ...) | * spec_vnoperate(struct vnodeop_desc *a_desc, ...) |
| */ | */ |
| Line 135 static int | Line 137 static int |
| spec_open(struct vop_open_args *ap) | spec_open(struct vop_open_args *ap) |
| { | { |
| struct vnode *vp = ap->a_vp; | struct vnode *vp = ap->a_vp; |
| dev_t dev = vp->v_rdev; | dev_t dev; |
| int error; | int error; |
| int isblk = (vp->v_type == VBLK) ? 1 : 0; | |
| const char *cp; | const char *cp; |
| /* | /* |
| Line 145 spec_open(struct vop_open_args *ap) | Line 148 spec_open(struct vop_open_args *ap) |
| if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) | if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) |
| return (ENXIO); | return (ENXIO); |
| if (dev_dport(dev) == NULL) | /* |
| return ENXIO; | * Resolve the device. If the vnode is already open v_rdev may |
| * already be resolved. However, if the device changes out from | |
| * under us we report it (and, for now, we allow it). | |
| */ | |
| if (vp->v_rdev != NULL) { | |
| dev = udev2dev(vp->v_udev, isblk); | |
| if (dev != vp->v_rdev) { | |
| printf( | |
| "Warning: spec_open: dev %s was lost", | |
| vp->v_rdev->si_name); | |
| v_release_rdev(vp); | |
| error = v_associate_rdev(vp, | |
| udev2dev(vp->v_udev, isblk)); | |
| if (error) | |
| printf(", reacquisition failed\n"); | |
| else | |
| printf(", reacquisition successful\n"); | |
| } else { | |
| error = 0; | |
| } | |
| } else { | |
| error = v_associate_rdev(vp, udev2dev(vp->v_udev, isblk)); | |
| } | |
| if (error) | |
| return(error); | |
| dev = vp->v_rdev; | |
| /* Make this field valid before any I/O in ->d_open */ | /* |
| * Make this field valid before any I/O in ->d_open. XXX the | |
| * device itself should probably be required to initialize | |
| * this field in d_open. | |
| */ | |
| if (!dev->si_iosize_max) | if (!dev->si_iosize_max) |
| dev->si_iosize_max = DFLTPHYS; | dev->si_iosize_max = DFLTPHYS; |
| Line 163 spec_open(struct vop_open_args *ap) | Line 196 spec_open(struct vop_open_args *ap) |
| /* | /* |
| * Never allow opens for write if the device is mounted R/W | * Never allow opens for write if the device is mounted R/W |
| */ | */ |
| if (vp->v_specmountpoint != NULL && | if (vp->v_rdev && vp->v_rdev->si_mountpoint && |
| !(vp->v_specmountpoint->mnt_flag & MNT_RDONLY)) | !(vp->v_rdev->si_mountpoint->mnt_flag & MNT_RDONLY)) { |
| return (EBUSY); | error = EBUSY; |
| goto done; | |
| } | |
| /* | /* |
| * When running in secure mode, do not allow opens | * When running in secure mode, do not allow opens |
| * for writing if the device is mounted | * for writing if the device is mounted |
| */ | */ |
| if (securelevel >= 1 && vp->v_specmountpoint != NULL) | if (securelevel >= 1 && vfs_mountedon(vp)) { |
| return (EPERM); | error = EPERM; |
| goto done; | |
| } | |
| /* | /* |
| * When running in very secure mode, do not allow | * When running in very secure mode, do not allow |
| * opens for writing of any devices. | * opens for writing of any devices. |
| */ | */ |
| if (securelevel >= 2) | if (securelevel >= 2) { |
| return (EPERM); | error = EPERM; |
| goto done; | |
| } | |
| } | } |
| /* XXX: Special casing of ttys for deadfs. Probably redundant */ | /* XXX: Special casing of ttys for deadfs. Probably redundant */ |
| if (dev_dflags(dev) & D_TTY) | if (dev_dflags(dev) & D_TTY) |
| vp->v_flag |= VISTTY; | vp->v_flag |= VISTTY; |
| /* | |
| * dev_dopen() is always called for each open. dev_dclose() is | |
| * only called for the last close unless D_TRACKCLOSE is set. | |
| */ | |
| VOP_UNLOCK(vp, NULL, 0, ap->a_td); | VOP_UNLOCK(vp, NULL, 0, ap->a_td); |
| error = dev_dopen(dev, ap->a_mode, S_IFCHR, ap->a_td); | error = dev_dopen(dev, ap->a_mode, S_IFCHR, ap->a_td); |
| vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, ap->a_td); | vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, ap->a_td); |
| if (error) | if (error) |
| return (error); | goto done; |
| if (dev_dflags(dev) & D_TTY) { | if (dev_dflags(dev) & D_TTY) { |
| if (dev->si_tty) { | if (dev->si_tty) { |
| Line 215 spec_open(struct vop_open_args *ap) | Line 258 spec_open(struct vop_open_args *ap) |
| dev_dname(dev), cp); | dev_dname(dev), cp); |
| } | } |
| } | } |
| ++vp->v_opencount; | |
| if (dev_ref_debug) | |
| printf("spec_open: %s %d\n", dev->si_name, vp->v_opencount); | |
| done: | |
| if (error) { | |
| if (vp->v_opencount == 0) | |
| v_release_rdev(vp); | |
| } | |
| return (error); | return (error); |
| } | } |
| Line 430 spec_strategy(struct vop_strategy_args * | Line 481 spec_strategy(struct vop_strategy_args * |
| * and write counts for disks that have associated filesystems. | * and write counts for disks that have associated filesystems. |
| */ | */ |
| vp = ap->a_vp; | vp = ap->a_vp; |
| if (vn_isdisk(vp, NULL) && (mp = vp->v_specmountpoint) != NULL) { | if (vn_isdisk(vp, NULL) && (mp = vp->v_rdev->si_mountpoint) != NULL) { |
| if ((bp->b_flags & B_READ) == 0) { | if ((bp->b_flags & B_READ) == 0) { |
| if (bp->b_lock.lk_lockholder == LK_KERNTHREAD) | if (bp->b_lock.lk_lockholder == LK_KERNTHREAD) |
| mp->mnt_stat.f_asyncwrites++; | mp->mnt_stat.f_asyncwrites++; |
| Line 443 spec_strategy(struct vop_strategy_args * | Line 494 spec_strategy(struct vop_strategy_args * |
| mp->mnt_stat.f_syncreads++; | mp->mnt_stat.f_syncreads++; |
| } | } |
| } | } |
| #if 0 | bp->b_dev = vp->v_rdev; |
| KASSERT(devsw(bp->b_dev) != NULL, | |
| ("No devsw on dev %s responsible for buffer %p\n", | |
| devtoname(bp->b_dev), bp)); | |
| KASSERT(devsw(bp->b_dev)->d_strategy != NULL, | |
| ("No strategy on dev %s responsible for buffer %p\n", | |
| devtoname(bp->b_dev), bp)); | |
| #endif | |
| BUF_STRATEGY(bp, 0); | BUF_STRATEGY(bp, 0); |
| return (0); | return (0); |
| } | } |
| Line 520 spec_close(struct vop_close_args *ap) | Line 564 spec_close(struct vop_close_args *ap) |
| struct proc *p = ap->a_td->td_proc; | struct proc *p = ap->a_td->td_proc; |
| struct vnode *vp = ap->a_vp; | struct vnode *vp = ap->a_vp; |
| dev_t dev = vp->v_rdev; | dev_t dev = vp->v_rdev; |
| int error; | |
| /* | /* |
| * Hack: a tty device that is a controlling terminal | * Hack: a tty device that is a controlling terminal |
| Line 530 spec_close(struct vop_close_args *ap) | Line 575 spec_close(struct vop_close_args *ap) |
| * if the reference count is 2 (this last descriptor | * if the reference count is 2 (this last descriptor |
| * plus the session), release the reference from the session. | * plus the session), release the reference from the session. |
| */ | */ |
| if (vcount(vp) == 2 && p && (vp->v_flag & VXLOCK) == 0 && | reference_dev(dev); |
| vp == p->p_session->s_ttyvp) { | if (vcount(vp) == 2 && vp->v_opencount == 1 && |
| p && (vp->v_flag & VXLOCK) == 0 && vp == p->p_session->s_ttyvp) { | |
| vrele(vp); | vrele(vp); |
| p->p_session->s_ttyvp = NULL; | p->p_session->s_ttyvp = NULL; |
| } | } |
| /* | /* |
| * We do not want to really close the device if it | * Vnodes can be opened and close multiple times. Do not really |
| * is still in use unless we are trying to close it | * close the device unless (1) it is being closed forcibly, |
| * forcibly. Since every use (buffer, vnode, swap, cmap) | * (2) the device wants to track closes, or (3) this is the last |
| * holds a reference to the vnode, and because we mark | * vnode doing its last close on the device. |
| * any other vnodes that alias this device, when the | * |
| * sum of the reference counts on all the aliased | * XXX the VXLOCK (force close) case can leave vnodes referencing |
| * vnodes descends to one, we are on last close. | * a closed device. |
| */ | */ |
| if (vp->v_flag & VXLOCK) { | if ((vp->v_flag & VXLOCK) || |
| /* Forced close */ | (dev_dflags(dev) & D_TRACKCLOSE) || |
| } else if (dev_dflags(dev) & D_TRACKCLOSE) { | (vcount(vp) <= 1 && vp->v_opencount == 1)) { |
| /* Keep device updated on status */ | error = dev_dclose(dev, ap->a_fflag, S_IFCHR, ap->a_td); |
| } else if (vcount(vp) > 1) { | } else { |
| return (0); | error = 0; |
| } | } |
| return (dev_dclose(dev, ap->a_fflag, S_IFCHR, ap->a_td)); | |
| /* | |
| * Track the actual opens and closes on the vnode. The last close | |
| * disassociates the rdev. | |
| */ | |
| KKASSERT(vp->v_opencount > 0); | |
| if (dev_ref_debug) | |
| printf("spec_close: %s %d\n", dev->si_name, vp->v_opencount - 1); | |
| if (--vp->v_opencount == 0) | |
| v_release_rdev(vp); | |
| release_dev(dev); | |
| return(error); | |
| } | } |
| /* | /* |
| Line 631 spec_getpages(struct vop_getpages_args * | Line 689 spec_getpages(struct vop_getpages_args * |
| * the device. i.e. it's usually '/dev'. We need the physical block | * the device. i.e. it's usually '/dev'. We need the physical block |
| * size for the device itself. | * size for the device itself. |
| * | * |
| * We can't use v_specmountpoint because it only exists when the | * We can't use v_rdev->si_mountpoint because it only exists when the |
| * block device is mounted. However, we can use v_rdev. | * block device is mounted. However, we can use v_rdev. |
| */ | */ |