|
|
| version 1.29, 2004/04/08 17:56:48 | version 1.30, 2004/05/19 22:52:58 |
|---|---|
| Line 192 static void vbusy(struct vnode *vp); | Line 192 static void vbusy(struct vnode *vp); |
| static void vfree(struct vnode *vp); | static void vfree(struct vnode *vp); |
| static void vmaybefree(struct vnode *vp); | static void vmaybefree(struct vnode *vp); |
| extern int dev_ref_debug; | |
| /* | /* |
| * NOTE: the vnode interlock must be held on call. | * NOTE: the vnode interlock must be held on call. |
| */ | */ |
| Line 1458 reassignbuf(bp, newvp) | Line 1460 reassignbuf(bp, newvp) |
| break; | break; |
| case VCHR: | case VCHR: |
| case VBLK: | case VBLK: |
| if (newvp->v_specmountpoint != NULL) { | if (newvp->v_rdev && |
| newvp->v_rdev->si_mountpoint != NULL) { | |
| delay = metadelay; | delay = metadelay; |
| break; | break; |
| } | } |
| Line 1541 reassignbuf(bp, newvp) | Line 1544 reassignbuf(bp, newvp) |
| * Used for mounting the root file system. | * Used for mounting the root file system. |
| */ | */ |
| int | int |
| bdevvp(dev, vpp) | bdevvp(dev_t dev, struct vnode **vpp) |
| dev_t dev; | |
| struct vnode **vpp; | |
| { | { |
| struct vnode *vp; | struct vnode *vp; |
| struct vnode *nvp; | struct vnode *nvp; |
| Line 1559 bdevvp(dev, vpp) | Line 1560 bdevvp(dev, vpp) |
| return (error); | return (error); |
| } | } |
| vp = nvp; | vp = nvp; |
| vp->v_type = VBLK; | vp->v_type = VCHR; |
| addalias(vp, dev); | vp->v_udev = dev->si_udev; |
| *vpp = vp; | *vpp = vp; |
| return (0); | return (0); |
| } | } |
| /* | int |
| * Add a vnode to the alias list hung off the dev_t. | v_associate_rdev(struct vnode *vp, dev_t dev) |
| * | |
| * The reason for this gunk is that multiple vnodes can reference | |
| * the same physical device, so checking vp->v_usecount to see | |
| * how many users there are is inadequate; the v_usecount for | |
| * the vnodes need to be accumulated. vcount() does that. | |
| */ | |
| void | |
| addaliasu(struct vnode *nvp, udev_t nvp_rdev) | |
| { | { |
| dev_t dev; | lwkt_tokref ilock; |
| if (nvp->v_type != VBLK && nvp->v_type != VCHR) | if (dev == NULL || dev == NODEV) |
| panic("addaliasu on non-special vnode"); | return(ENXIO); |
| dev = udev2dev(nvp_rdev, nvp->v_type == VBLK ? 1 : 0); | if (dev_is_good(dev) == 0) |
| if (dev != NODEV) { | return(ENXIO); |
| nvp->v_rdev = dev; | KKASSERT(vp->v_rdev == NULL); |
| addalias(nvp, dev); | if (dev_ref_debug) |
| } else | printf("Z1"); |
| nvp->v_rdev = NULL; | vp->v_rdev = reference_dev(dev); |
| lwkt_gettoken(&ilock, &spechash_token); | |
| SLIST_INSERT_HEAD(&dev->si_hlist, vp, v_specnext); | |
| lwkt_reltoken(&ilock); | |
| return(0); | |
| } | } |
| void | void |
| addalias(struct vnode *nvp, dev_t dev) | v_release_rdev(struct vnode *vp) |
| { | { |
| lwkt_tokref ilock; | lwkt_tokref ilock; |
| dev_t dev; | |
| if (nvp->v_type != VBLK && nvp->v_type != VCHR) | if ((dev = vp->v_rdev) != NULL) { |
| panic("addalias on non-special vnode"); | lwkt_gettoken(&ilock, &spechash_token); |
| SLIST_REMOVE(&dev->si_hlist, vp, vnode, v_specnext); | |
| if (dev_ref_debug) | |
| printf("Y2"); | |
| vp->v_rdev = NULL; | |
| release_dev(dev); | |
| lwkt_reltoken(&ilock); | |
| } | |
| } | |
| nvp->v_rdev = dev; | /* |
| lwkt_gettoken(&ilock, &spechash_token); | * Add a vnode to the alias list hung off the dev_t. We only associate |
| SLIST_INSERT_HEAD(&dev->si_hlist, nvp, v_specnext); | * the device number with the vnode. The actual device is not associated |
| lwkt_reltoken(&ilock); | * until the vnode is opened (usually in spec_open()), and will be |
| * disassociated on last close. | |
| */ | |
| void | |
| addaliasu(struct vnode *nvp, udev_t nvp_udev) | |
| { | |
| if (nvp->v_type != VBLK && nvp->v_type != VCHR) | |
| panic("addaliasu on non-special vnode"); | |
| nvp->v_udev = nvp_udev; | |
| } | } |
| /* | /* |
| Line 2150 vop_revoke(ap) | Line 2164 vop_revoke(ap) |
| tsleep((caddr_t)vp, 0, "vop_revokeall", 0); | tsleep((caddr_t)vp, 0, "vop_revokeall", 0); |
| return (0); | return (0); |
| } | } |
| dev = vp->v_rdev; | |
| /* | |
| * If the vnode has a device association, scrap all vnodes associated | |
| * with the device. Don't let the device disappear on us while we | |
| * are scrapping the vnodes. | |
| */ | |
| if (vp->v_type != VCHR && vp->v_type != VBLK) | |
| return(0); | |
| if ((dev = vp->v_rdev) == NULL) { | |
| if ((dev = udev2dev(vp->v_udev, vp->v_type == VBLK)) == NODEV) | |
| return(0); | |
| } | |
| reference_dev(dev); | |
| for (;;) { | for (;;) { |
| lwkt_gettoken(&ilock, &spechash_token); | lwkt_gettoken(&ilock, &spechash_token); |
| vq = SLIST_FIRST(&dev->si_hlist); | vq = SLIST_FIRST(&dev->si_hlist); |
| lwkt_reltoken(&ilock); | lwkt_reltoken(&ilock); |
| if (!vq) | if (vq == NULL) |
| break; | break; |
| vgone(vq); | vgone(vq); |
| } | } |
| release_dev(dev); | |
| return (0); | return (0); |
| } | } |
| Line 2232 vgonel(struct vnode *vp, lwkt_tokref_t v | Line 2259 vgonel(struct vnode *vp, lwkt_tokref_t v |
| * if it is on one. | * if it is on one. |
| */ | */ |
| if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_rdev != NULL) { | if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_rdev != NULL) { |
| lwkt_gettoken(&ilock, &spechash_token); | v_release_rdev(vp); |
| SLIST_REMOVE(&vp->v_hashchain, vp, vnode, v_specnext); | |
| freedev(vp->v_rdev); | |
| lwkt_reltoken(&ilock); | |
| vp->v_rdev = NULL; | |
| } | } |
| /* | /* |
| Line 2290 vfinddev(dev, type, vpp) | Line 2313 vfinddev(dev, type, vpp) |
| } | } |
| /* | /* |
| * Calculate the total number of references to a special device. | * Calculate the total number of references to a special device. This |
| * routine may only be called for VBLK and VCHR vnodes since v_rdev is | |
| * an overloaded field. Since udev2dev can now return NODEV, we have | |
| * to check for a NULL v_rdev. | |
| */ | */ |
| int | int |
| vcount(vp) | count_dev(dev_t dev) |
| struct vnode *vp; | |
| { | { |
| lwkt_tokref ilock; | lwkt_tokref ilock; |
| struct vnode *vq; | struct vnode *vp; |
| int count; | int count = 0; |
| count = 0; | if (SLIST_FIRST(&dev->si_hlist)) { |
| lwkt_gettoken(&ilock, &spechash_token); | lwkt_gettoken(&ilock, &spechash_token); |
| SLIST_FOREACH(vq, &vp->v_hashchain, v_specnext) | SLIST_FOREACH(vp, &dev->si_hlist, v_specnext) { |
| count += vq->v_usecount; | count += vp->v_usecount; |
| lwkt_reltoken(&ilock); | } |
| return (count); | lwkt_reltoken(&ilock); |
| } | |
| return(count); | |
| } | } |
| /* | |
| * Same as above, but using the dev_t as argument | |
| */ | |
| int | int |
| count_dev(dev) | count_udev(udev_t udev) |
| dev_t dev; | |
| { | { |
| struct vnode *vp; | dev_t dev; |
| vp = SLIST_FIRST(&dev->si_hlist); | if ((dev = udev2dev(udev, 0)) == NODEV) |
| if (vp == NULL) | return(0); |
| return (0); | return(count_dev(dev)); |
| return(vcount(vp)); | } |
| int | |
| vcount(struct vnode *vp) | |
| { | |
| if (vp->v_rdev == NULL) | |
| return(0); | |
| return(count_dev(vp->v_rdev)); | |
| } | } |
| /* | /* |
| Line 2557 SYSCTL_PROC(_kern, KERN_VNODE, vnode, CT | Line 2586 SYSCTL_PROC(_kern, KERN_VNODE, vnode, CT |
| * Check to see if a filesystem is mounted on a block device. | * Check to see if a filesystem is mounted on a block device. |
| */ | */ |
| int | int |
| vfs_mountedon(vp) | vfs_mountedon(struct vnode *vp) |
| struct vnode *vp; | |
| { | { |
| dev_t dev; | |
| if (vp->v_specmountpoint != NULL) | if ((dev = vp->v_rdev) == NULL) |
| dev = udev2dev(vp->v_udev, (vp->v_type == VBLK)); | |
| if (dev != NODEV && dev->si_mountpoint) | |
| return (EBUSY); | return (EBUSY); |
| return (0); | return (0); |
| } | } |
| Line 3266 sync_print(ap) | Line 3297 sync_print(ap) |
| } | } |
| /* | /* |
| * extract the dev_t from a VBLK or VCHR | * extract the dev_t from a VBLK or VCHR. The vnode must have been opened |
| * (or v_rdev might be NULL). | |
| */ | */ |
| dev_t | dev_t |
| vn_todev(vp) | vn_todev(struct vnode *vp) |
| struct vnode *vp; | |
| { | { |
| if (vp->v_type != VBLK && vp->v_type != VCHR) | if (vp->v_type != VBLK && vp->v_type != VCHR) |
| return (NODEV); | return (NODEV); |
| KKASSERT(vp->v_rdev != NULL); | |
| return (vp->v_rdev); | return (vp->v_rdev); |
| } | } |
| /* | /* |
| * Check if vnode represents a disk device | * Check if vnode represents a disk device. The vnode does not need to be |
| * opened. | |
| */ | */ |
| int | int |
| vn_isdisk(vp, errp) | vn_isdisk(struct vnode *vp, int *errp) |
| struct vnode *vp; | |
| int *errp; | |
| { | { |
| dev_t dev; | |
| if (vp->v_type != VBLK && vp->v_type != VCHR) { | if (vp->v_type != VBLK && vp->v_type != VCHR) { |
| if (errp != NULL) | if (errp != NULL) |
| *errp = ENOTBLK; | *errp = ENOTBLK; |
| return (0); | return (0); |
| } | } |
| if (vp->v_rdev == NULL) { | |
| if ((dev = vp->v_rdev) == NULL) | |
| dev = udev2dev(vp->v_udev, (vp->v_type == VBLK)); | |
| if (dev == NULL || dev == NODEV) { | |
| if (errp != NULL) | if (errp != NULL) |
| *errp = ENXIO; | *errp = ENXIO; |
| return (0); | return (0); |
| } | } |
| if (!dev_dport(vp->v_rdev)) { | if (dev_is_good(dev) == 0) { |
| if (errp != NULL) | if (errp != NULL) |
| *errp = ENXIO; | *errp = ENXIO; |
| return (0); | return (0); |
| } | } |
| if (!(dev_dflags(vp->v_rdev) & D_DISK)) { | if ((dev_dflags(dev) & D_DISK) == 0) { |
| if (errp != NULL) | if (errp != NULL) |
| *errp = ENOTBLK; | *errp = ENOTBLK; |
| return (0); | return (0); |