On Thu, May 21, 2009 at 07:05:17PM +0200, Attilio Rao wrote: > 2009/5/21 Kostik Belousov <kostik...@gmail.com>: > > On Thu, May 21, 2009 at 09:23:15AM -0700, Scott Long wrote: > >> Kostik Belousov wrote: > >> >We do have the KPI for the callers that cannot drop the locks and need > >> >to do destroy_dev, destroy_dev_sched(9). > >> > >> Good to know, I'll look at destroy_dev_sched(). I'd rather not have to > >> roll my own decoupled version. And I understand the argument about > >> destroy_dev being a drain point for the API. However, what about > >> create_dev()? Making that non-blocking would help a lot. > > > > create_dev() can be made non-blocking, and this is the first argument pro > > Attilio patch. > > > > From the quick look, all that is needed is to replace M_WAITOK with > > M_NOWAIT inside prep_cdevsw() and devfs_alloc(). Untested patch below. > > > > diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c > > index 4041911..f470ee8 100644 > > --- a/sys/fs/devfs/devfs_devs.c > > +++ b/sys/fs/devfs/devfs_devs.c > > @@ -120,7 +120,7 @@ devfs_alloc(void) > > struct cdev *cdev; > > struct timespec ts; > > > > - cdp = malloc(sizeof *cdp, M_CDEVP, M_USE_RESERVE | M_ZERO | > > M_WAITOK); > > + cdp = malloc(sizeof *cdp, M_CDEVP, M_USE_RESERVE | M_ZERO | > > M_NOWAIT); > > > > cdp->cdp_dirents = &cdp->cdp_dirent0; > > cdp->cdp_dirent0 = NULL; > > diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c > > index 284f482..acdd44a 100644 > > --- a/sys/kern/kern_conf.c > > +++ b/sys/kern/kern_conf.c > > @@ -559,7 +559,7 @@ prep_cdevsw(struct cdevsw *devsw) > > return; > > if (devsw->d_flags & D_NEEDGIANT) { > > dev_unlock(); > > - dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); > > + dsw2 = malloc(sizeof *dsw2, M_DEVT, M_NOWAIT); > > dev_lock(); > > } else > > dsw2 = NULL; > > You need to check return values here if it returns NULL. > > IMHO, having a non-sleepable version of destroy_dev(), create_dev() > and such would be ideal. > Ideally, we should resolve all the sleeping point and do the conversion. > I'm unable to check the code right now.
Sure. Something like this. diff --git a/share/man/man9/make_dev.9 b/share/man/man9/make_dev.9 index b39ca8b..0844e64 100644 --- a/share/man/man9/make_dev.9 +++ b/share/man/man9/make_dev.9 @@ -133,6 +133,7 @@ The following values are currently accepted: .Pp .Bd -literal -offset indent -compact MAKEDEV_REF reference the created device +MAKEDEV_NOWAIT do not sleep, may return NULL .Ed .Pp The diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index 4041911..79f7893 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -114,17 +114,21 @@ SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev_priv, CTLFLAG_RD, 0, sizeof(struct cdev_priv), "sizeof(struct cdev_priv)"); struct cdev * -devfs_alloc(void) +devfs_alloc(int flags) { struct cdev_priv *cdp; struct cdev *cdev; struct timespec ts; - cdp = malloc(sizeof *cdp, M_CDEVP, M_USE_RESERVE | M_ZERO | M_WAITOK); + cdp = malloc(sizeof *cdp, M_CDEVP, M_USE_RESERVE | M_ZERO | + ((flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK)); + if (cdp == NULL) + return (NULL); cdp->cdp_dirents = &cdp->cdp_dirent0; cdp->cdp_dirent0 = NULL; cdp->cdp_maxdirent = 0; + cdp->cdp_inode = 0; cdev = &cdp->cdp_c; @@ -132,6 +136,7 @@ devfs_alloc(void) LIST_INIT(&cdev->si_children); vfs_timestamp(&ts); cdev->si_atime = cdev->si_mtime = cdev->si_ctime = ts; + cdev->si_cred = NULL; return (cdev); } diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h index 5a61dd4..f5612e1 100644 --- a/sys/fs/devfs/devfs_int.h +++ b/sys/fs/devfs/devfs_int.h @@ -70,7 +70,7 @@ struct cdev_priv { #define cdev2priv(c) member2struct(cdev_priv, cdp_c, c) -struct cdev *devfs_alloc(void); +struct cdev *devfs_alloc(int); void devfs_free(struct cdev *); void devfs_create(struct cdev *dev); void devfs_destroy(struct cdev *dev); diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index 284f482..082f5d3 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -482,7 +482,7 @@ giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) static void -notify(struct cdev *dev, const char *ev) +notify(struct cdev *dev, const char *ev, int flags) { static const char prefix[] = "cdev="; char *data; @@ -491,7 +491,8 @@ notify(struct cdev *dev, const char *ev) if (cold) return; namelen = strlen(dev->si_name); - data = malloc(namelen + sizeof(prefix), M_TEMP, M_NOWAIT); + data = malloc(namelen + sizeof(prefix), M_TEMP, + (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); if (data == NULL) return; memcpy(data, prefix, sizeof(prefix) - 1); @@ -501,17 +502,17 @@ notify(struct cdev *dev, const char *ev) } static void -notify_create(struct cdev *dev) +notify_create(struct cdev *dev, int flags) { - notify(dev, "CREATE"); + notify(dev, "CREATE", flags); } static void notify_destroy(struct cdev *dev) { - notify(dev, "DESTROY"); + notify(dev, "DESTROY", 0); } static struct cdev * @@ -549,24 +550,27 @@ fini_cdevsw(struct cdevsw *devsw) devsw->d_flags &= ~D_INIT; } -static void -prep_cdevsw(struct cdevsw *devsw) +static int +prep_cdevsw(struct cdevsw *devsw, int flags) { struct cdevsw *dsw2; mtx_assert(&devmtx, MA_OWNED); if (devsw->d_flags & D_INIT) - return; + return (1); if (devsw->d_flags & D_NEEDGIANT) { dev_unlock(); - dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); + dsw2 = malloc(sizeof *dsw2, M_DEVT, + (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK); dev_lock(); + if (dsw2 == NULL && !(devsw->d_flags & D_INIT)) + return (0); } else dsw2 = NULL; if (devsw->d_flags & D_INIT) { if (dsw2 != NULL) cdevsw_free_devlocked(dsw2); - return; + return (1); } if (devsw->d_version != D_VERSION_01) { @@ -622,6 +626,7 @@ prep_cdevsw(struct cdevsw *devsw) if (dsw2 != NULL) cdevsw_free_devlocked(dsw2); + return (1); } struct cdev * @@ -632,9 +637,15 @@ make_dev_credv(int flags, struct cdevsw *devsw, int unit, struct cdev *dev; int i; - dev = devfs_alloc(); + dev = devfs_alloc(flags); + if (dev == NULL) + return (NULL); dev_lock(); - prep_cdevsw(devsw); + if (!prep_cdevsw(devsw, flags)) { + dev_unlock(); + devfs_free(dev); + return (NULL); + } dev = newdev(devsw, unit, dev); if (flags & MAKEDEV_REF) dev_refl(dev); @@ -661,8 +672,6 @@ make_dev_credv(int flags, struct cdevsw *devsw, int unit, dev->si_flags |= SI_NAMED; if (cr != NULL) dev->si_cred = crhold(cr); - else - dev->si_cred = NULL; dev->si_uid = uid; dev->si_gid = gid; dev->si_mode = mode; @@ -671,7 +680,7 @@ make_dev_credv(int flags, struct cdevsw *devsw, int unit, clean_unrhdrl(devfs_inos); dev_unlock_and_free(); - notify_create(dev); + notify_create(dev, flags); return (dev); } @@ -746,7 +755,7 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...) int i; KASSERT(pdev != NULL, ("NULL pdev")); - dev = devfs_alloc(); + dev = devfs_alloc(0); dev_lock(); dev->si_flags |= SI_ALIAS; dev->si_flags |= SI_NAMED; @@ -763,7 +772,7 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...) clean_unrhdrl(devfs_inos); dev_unlock(); - notify_create(dev); + notify_create(dev, 0); return (dev); } @@ -947,9 +956,9 @@ clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev ** * the end of the list. */ unit = *up; - ndev = devfs_alloc(); + ndev = devfs_alloc(0); dev_lock(); - prep_cdevsw(csw); + prep_cdevsw(csw, 0); low = extra; de = dl = NULL; cd = *cdp; diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 05c4bb5..7b65862 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -263,6 +263,7 @@ struct cdev *make_dev_cred(struct cdevsw *_devsw, int _unit, const char *_fmt, ...) __printflike(7, 8); #define MAKEDEV_REF 0x1 #define MAKEDEV_WHTOUT 0x2 +#define MAKEDEV_NOWAIT 0x4 struct cdev *make_dev_credf(int _flags, struct cdevsw *_devsw, int _unit, struct ucred *_cr, uid_t _uid, gid_t _gid, int _mode,
pgpsFTn2Ge7UU.pgp
Description: PGP signature