From: Alex Hornung Date: Fri, 19 Nov 2010 09:18:18 +0000 (+0000) Subject: vn - Major overhaul X-Git-Tag: v2.10.0~582 X-Git-Url: http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/1398353708029eb9dda9861e12c2efb4e66e8122 vn - Major overhaul * Now that we can do proper disk cloning we do so. vn_create will now return the top device of the disk (the one that belongs to the disk subsystem and not us) if asked to do so. This is then passed back from the clone handler so that we have a real cloned disk. * Remove all sorts of old hacks, mostly related to finding vn's and strange cdev lists that were not being used anymore anyways. * Avoid the destruction/detachment of devices that are in use by keeping track of whether they are open or not and checking the opencount provided by the disk susbsystem. * Fix a memory leak related to adding references to devs but never releasing them. Dragonfly-bug: http://bugs.dragonflybsd.org/issue1561 (partly) --- diff --git a/sys/dev/disk/vn/vn.c b/sys/dev/disk/vn/vn.c index e4ab6cf..8a1ea36 100644 --- a/sys/dev/disk/vn/vn.c +++ b/sys/dev/disk/vn/vn.c @@ -131,7 +131,7 @@ struct vn_softc { int sc_maxactive; /* max # of active requests */ struct buf sc_tab; /* transfer queue */ u_long sc_options; /* options */ - cdev_t sc_devlist; /* devices that refer to this unit */ + cdev_t sc_dev; /* devices that refer to this unit */ SLIST_ENTRY(vn_softc) sc_list; }; @@ -140,6 +140,8 @@ static SLIST_HEAD(, vn_softc) vn_list; /* sc_flags */ #define VNF_INITED 0x01 #define VNF_READONLY 0x02 +#define VNF_OPENED 0x10 +#define VNF_DESTROY 0x20 static u_long vn_options; @@ -152,7 +154,7 @@ static int vnget (cdev_t dev, struct vn_softc *vn , struct vn_user *vnu); static int vn_modevent (module_t, int, void *); static int vniocattach_file (struct vn_softc *, struct vn_ioctl *, cdev_t dev, int flag, struct ucred *cred); static int vniocattach_swap (struct vn_softc *, struct vn_ioctl *, cdev_t dev, int flag, struct ucred *cred); -static cdev_t vn_create(int unit, struct devfs_bitmap *bitmap); +static cdev_t vn_create(int unit, struct devfs_bitmap *bitmap, int clone); static int vnclone(struct dev_clone_args *ap) @@ -160,7 +162,7 @@ vnclone(struct dev_clone_args *ap) int unit; unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(vn), 0); - ap->a_dev = vn_create(unit, &DEVFS_CLONE_BITMAP(vn)); + ap->a_dev = vn_create(unit, &DEVFS_CLONE_BITMAP(vn), 1); return 0; } @@ -168,6 +170,22 @@ vnclone(struct dev_clone_args *ap) static int vnclose(struct dev_close_args *ap) { + cdev_t dev = ap->a_head.a_dev; + struct vn_softc *vn; + + vn = dev->si_drv1; + KKASSERT(vn != NULL); + + vn->sc_flags &= ~VNF_OPENED; + + /* The disk has been detached and can now be safely destroyed */ + if (vn->sc_flags & VNF_DESTROY) { + KKASSERT(disk_getopencount(&vn->sc_disk) == 0); + disk_destroy(&vn->sc_disk); + devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(vn), dkunit(dev)); + SLIST_REMOVE(&vn_list, vn, vn_softc, sc_list); + kfree(vn, M_DEVBUF); + } return (0); } @@ -191,45 +209,9 @@ vninitvn(struct vn_softc *vn, cdev_t dev) vn->sc_unit = unit; dev->si_drv1 = vn; - vn->sc_devlist = dev; - if (vn->sc_devlist->si_drv1 == NULL) { - reference_dev(vn->sc_devlist); - vn->sc_devlist->si_drv1 = vn; - vn->sc_devlist->si_drv2 = NULL; - } - if (vn->sc_devlist != dev) { - dev->si_drv1 = vn; - dev->si_drv2 = vn->sc_devlist; - vn->sc_devlist = dev; - reference_dev(dev); - } - SLIST_INSERT_HEAD(&vn_list, vn, sc_list); -} - -/* - * Called only when si_drv1 is NULL. Locate the associated vn node and - * attach the device to it. - */ -static struct vn_softc * -vnfindvn(cdev_t dev) -{ - int unit; - struct vn_softc *vn; - - unit = dkunit(dev); - SLIST_FOREACH(vn, &vn_list, sc_list) { - if (vn->sc_unit == unit) { - dev->si_drv1 = vn; - dev->si_drv2 = vn->sc_devlist; - vn->sc_devlist = dev; - reference_dev(dev); - break; - } - } - - KKASSERT(vn != NULL); + vn->sc_dev = dev; - return vn; + SLIST_INSERT_HEAD(&vn_list, vn, sc_list); } static int @@ -242,8 +224,8 @@ vnopen(struct dev_open_args *ap) * Locate preexisting device */ - if ((vn = dev->si_drv1) == NULL) - vn = vnfindvn(dev); + vn = dev->si_drv1; + KKASSERT(vn != NULL); /* * Update si_bsize fields for device. This data will be overriden by @@ -265,6 +247,7 @@ vnopen(struct dev_open_args *ap) kprintf("vnopen(%s, 0x%x, 0x%x)\n", devtoname(dev), ap->a_oflags, ap->a_devtype); + vn->sc_flags |= VNF_OPENED; return(0); } @@ -287,8 +270,8 @@ vnstrategy(struct dev_strategy_args *ap) int error; unit = dkunit(dev); - if ((vn = dev->si_drv1) == NULL) - vn = vnfindvn(dev); + vn = dev->si_drv1; + KKASSERT(vn != NULL); bp = bio->bio_buf; @@ -446,6 +429,9 @@ vnioctl(struct dev_ioctl_args *ap) if (vn->sc_flags & VNF_INITED) return(EBUSY); + if (vn->sc_flags & VNF_DESTROY) + return(ENXIO); + if (vio->vn_file == NULL) error = vniocattach_swap(vn, vio, dev, ap->a_fflag, ap->a_cred); else @@ -463,7 +449,7 @@ vnioctl(struct dev_ioctl_args *ap) * How are these problems handled for removable and failing * hardware devices? (Hint: They are not) */ - if (count_dev(vn->sc_devlist) > 1) + if ((disk_getopencount(&vn->sc_disk)) > 1) return (EBUSY); vnclear(vn); @@ -471,9 +457,7 @@ vnioctl(struct dev_ioctl_args *ap) kprintf("vnioctl: CLRed\n"); if (dkunit(dev) >= VN_PREALLOCATED_UNITS) { - devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(vn), dkunit(dev)); - disk_destroy(&vn->sc_disk); - SLIST_REMOVE(&vn_list, vn, vn_softc, sc_list); + vn->sc_flags |= VNF_DESTROY; } break; @@ -844,14 +828,23 @@ vnsize(struct dev_psize_args *ap) } static cdev_t -vn_create(int unit, struct devfs_bitmap *bitmap) +vn_create(int unit, struct devfs_bitmap *bitmap, int clone) { struct vn_softc *vn; struct disk_info info; - cdev_t dev; + cdev_t dev, ret_dev; vn = vncreatevn(); - dev = disk_create(unit, &vn->sc_disk, &vn_ops); + if (clone) { + /* + * For clone devices we need to return the top-level cdev, + * not the raw dev we'd normally work with. + */ + dev = disk_create_clone(unit, &vn->sc_disk, &vn_ops); + ret_dev = vn->sc_disk.d_cdev; + } else { + ret_dev = dev = disk_create(unit, &vn->sc_disk, &vn_ops); + } vninitvn(vn, dev); bzero(&info, sizeof(struct disk_info)); @@ -867,7 +860,7 @@ vn_create(int unit, struct devfs_bitmap *bitmap) if (bitmap != NULL) devfs_clone_bitmap_set(bitmap, unit); - return dev; + return ret_dev; } static int @@ -883,26 +876,33 @@ vn_modevent(module_t mod, int type, void *data) GID_OPERATOR, 0640, "vn"); for (i = 0; i < VN_PREALLOCATED_UNITS; i++) { - vn_create(i, &DEVFS_CLONE_BITMAP(vn)); + vn_create(i, &DEVFS_CLONE_BITMAP(vn), 0); } break; + case MOD_UNLOAD: - destroy_autoclone_dev(dev, &DEVFS_CLONE_BITMAP(vn)); - /* fall through */ case MOD_SHUTDOWN: while ((vn = SLIST_FIRST(&vn_list)) != NULL) { + /* + * XXX: no idea if we can return EBUSY even in the + * shutdown case, so err on the side of caution + * and just rip stuff out on shutdown. + */ + if (type != MOD_SHUTDOWN) { + if (vn->sc_flags & VNF_OPENED) + return (EBUSY); + } + + disk_destroy(&vn->sc_disk); + SLIST_REMOVE_HEAD(&vn_list, sc_list); + if (vn->sc_flags & VNF_INITED) vnclear(vn); - /* Cleanup all cdev_t's that refer to this unit */ - disk_destroy(&vn->sc_disk); - while ((dev = vn->sc_devlist) != NULL) { - vn->sc_devlist = dev->si_drv2; - dev->si_drv1 = dev->si_drv2 = NULL; - destroy_dev(dev); - } + kfree(vn, M_DEVBUF); } + destroy_autoclone_dev(dev, &DEVFS_CLONE_BITMAP(vn)); dev_ops_remove_all(&vn_ops); break; default: