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,

Attachment: pgpsFTn2Ge7UU.pgp
Description: PGP signature

Reply via email to