Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 25 Dec 2016 19:49:09 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310553 - head/sys/compat/linuxkpi/common/include/linux
Message-ID:  <201612251949.uBPJn9TS081353@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Sun Dec 25 19:49:09 2016
New Revision: 310553
URL: https://svnweb.freebsd.org/changeset/base/310553

Log:
  Improve LinuxKPI device support. Only delete own BSD devices and not
  the ones obtained through devclass_get_device(). Some minor code
  cleanups while at it.
  
  Obtained from:	kmacy @
  MFC after:	1 week
  Sponsored by:	Mellanox Technologies

Modified:
  head/sys/compat/linuxkpi/common/include/linux/device.h

Modified: head/sys/compat/linuxkpi/common/include/linux/device.h
==============================================================================
--- head/sys/compat/linuxkpi/common/include/linux/device.h	Sun Dec 25 19:38:07 2016	(r310552)
+++ head/sys/compat/linuxkpi/common/include/linux/device.h	Sun Dec 25 19:49:09 2016	(r310553)
@@ -63,6 +63,14 @@ struct device {
 	struct device	*parent;
 	struct list_head irqents;
 	device_t	bsddev;
+	/*
+	 * The following flag is used to determine if the LinuxKPI is
+	 * responsible for detaching the BSD device or not. If the
+	 * LinuxKPI got the BSD device using devclass_get_device(), it
+	 * must not try to detach or delete it, because it's already
+	 * done somewhere else.
+	 */
+	bool		bsddev_attached_here;
 	dev_t		devt;
 	struct class	*class;
 	void		(*release)(struct device *dev);
@@ -208,23 +216,36 @@ static inline struct device *kobj_to_dev
 static inline void
 device_initialize(struct device *dev)
 {
-	device_t bsddev;
+	device_t bsddev = NULL;
+	int unit = -1;
 
-	bsddev = NULL;
 	if (dev->devt) {
-		int unit = MINOR(dev->devt);
+		unit = MINOR(dev->devt);
 		bsddev = devclass_get_device(dev->class->bsdclass, unit);
+		dev->bsddev_attached_here = false;
+	} else if (dev->parent == NULL) {
+		bsddev = devclass_get_device(dev->class->bsdclass, 0);
+		dev->bsddev_attached_here = false;
+	} else {
+		dev->bsddev_attached_here = true;
+	}
+
+	if (bsddev == NULL && dev->parent != NULL) {
+		bsddev = device_add_child(dev->parent->bsddev,
+		    dev->class->kobj.name, unit);
 	}
+
 	if (bsddev != NULL)
 		device_set_softc(bsddev, dev);
 
 	dev->bsddev = bsddev;
+	MPASS(dev->bsddev != NULL);
 	kobject_init(&dev->kobj, &linux_dev_ktype);
 }
 
 static inline int
 device_add(struct device *dev)
-{	
+{
 	if (dev->bsddev != NULL) {
 		if (dev->devt == 0)
 			dev->devt = makedev(0, device_get_unit(dev->bsddev));
@@ -256,13 +277,13 @@ device_create_groups_vargs(struct class 
 		goto error;
 	}
 
-	device_initialize(dev);
 	dev->devt = devt;
 	dev->class = class;
 	dev->parent = parent;
 	dev->groups = groups;
 	dev->release = device_create_release;
-	dev->bsddev = devclass_get_device(dev->class->bsdclass, MINOR(devt));
+	/* device_initialize() needs the class and parent to be set */
+	device_initialize(dev);
 	dev_set_drvdata(dev, drvdata);
 
 	retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
@@ -298,17 +319,21 @@ device_create_with_groups(struct class *
 static inline int
 device_register(struct device *dev)
 {
-	device_t bsddev;
-	int unit;
+	device_t bsddev = NULL;
+	int unit = -1;
 
-	bsddev = NULL;
-	unit = -1;
+	if (dev->bsddev != NULL)
+		goto done;
 
 	if (dev->devt) {
 		unit = MINOR(dev->devt);
 		bsddev = devclass_get_device(dev->class->bsdclass, unit);
+		dev->bsddev_attached_here = false;
 	} else if (dev->parent == NULL) {
 		bsddev = devclass_get_device(dev->class->bsdclass, 0);
+		dev->bsddev_attached_here = false;
+	} else {
+		dev->bsddev_attached_here = true;
 	}
 	if (bsddev == NULL && dev->parent != NULL) {
 		bsddev = device_add_child(dev->parent->bsddev,
@@ -320,6 +345,7 @@ device_register(struct device *dev)
 		device_set_softc(bsddev, dev);
 	}
 	dev->bsddev = bsddev;
+done:
 	kobject_init(&dev->kobj, &linux_dev_ktype);
 	kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
 
@@ -334,7 +360,7 @@ device_unregister(struct device *dev)
 	bsddev = dev->bsddev;
 	dev->bsddev = NULL;
 
-	if (bsddev != NULL) {
+	if (bsddev != NULL && dev->bsddev_attached_here) {
 		mtx_lock(&Giant);
 		device_delete_child(device_get_parent(bsddev), bsddev);
 		mtx_unlock(&Giant);
@@ -350,7 +376,7 @@ device_del(struct device *dev)
 	bsddev = dev->bsddev;
 	dev->bsddev = NULL;
 
-	if (bsddev != NULL) {
+	if (bsddev != NULL && dev->bsddev_attached_here) {
 		mtx_lock(&Giant);
 		device_delete_child(device_get_parent(bsddev), bsddev);
 		mtx_unlock(&Giant);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612251949.uBPJn9TS081353>