Browse Source

rpmsg: rpc: fix sysfs entry creation failures during recovery

The rpmsg-rpc driver exposes a character device for each remote
service (a rpmsg-rpc device) providing a bunch of remote execution
functions. The remote service can be running on any of the available
remote processors, and the supported functions are published as
different sysfs entries on that particular device. These rpmsg-rpc
devices are deleted and recreated as part of the reboot of the remote
processor during an error recovery. The sysfs entries are also deleted
and recreated. The current logic retains the associated rppc_device
structure and the underlying device pointer if there are any
applications actively using the character device at the time of the
rpmsg-rpc device removal, and reuses it upon the reprobe of the same
rpmsg-rpc device. The creation of the sysfs entries fails with -ENOENT
due to an invalid reference to a non-existing parent object, and this
is exposed first in 3.14 kernel due to the repartitioning of the core
sysfs code into a new common kernfs code.

Fix this by deleting the underlying device pointer in the driver's
.remove, and recreating it with the appropriate new rpmsg server
device as its parent in the driver's .probe function. A name
description field is also added to the representative rppc_device
structure for looking up the service on reprobe as the device name
cannot be used due to the deletion of the device pointer.

Signed-off-by: Suman Anna <s-anna@ti.com>
Suman Anna 11 years ago
parent
commit
330e368d27
2 changed files with 12 additions and 5 deletions
  1. 9 5
      drivers/rpmsg/rpmsg_rpc.c
  2. 3 0
      drivers/rpmsg/rpmsg_rpc_internal.h

+ 9 - 5
drivers/rpmsg/rpmsg_rpc.c

@@ -1160,7 +1160,7 @@ static int find_rpccdev_by_name(int id, void *p, void *data)
 {
 	struct rppc_device *rppcdev = p;
 
-	return strcmp(dev_name(rppcdev->dev), data) ? 0 : (int)p;
+	return strcmp(rppcdev->desc, data) ? 0 : (int)p;
 }
 
 /*
@@ -1188,7 +1188,8 @@ static int rppc_device_create(struct rpmsg_device *rpdev)
 
 static int rppc_probe(struct rpmsg_device *rpdev)
 {
-	int ret, major, minor;
+	int ret, minor;
+	int major = MAJOR(rppc_dev);
 	struct rppc_device *rppcdev = NULL;
 	dev_t dev;
 	char namedesc[RPMSG_NAME_SIZE];
@@ -1225,9 +1226,9 @@ static int rppc_probe(struct rpmsg_device *rpdev)
 
 	rppcdev->minor = minor;
 	rppcdev->rpdev = rpdev;
+	strncpy(rppcdev->desc, namedesc, RPMSG_NAME_SIZE);
 	dev_set_drvdata(&rpdev->dev, rppcdev);
 
-	major = MAJOR(rppc_dev);
 	cdev_init(&rppcdev->cdev, &rppc_fops);
 	rppcdev->cdev.owner = THIS_MODULE;
 	dev = MKDEV(major, minor);
@@ -1237,7 +1238,9 @@ static int rppc_probe(struct rpmsg_device *rpdev)
 		goto free_id;
 	}
 
-	rppcdev->dev = device_create(rppc_class, &rpdev->dev, dev, NULL,
+serv_up:
+	rppcdev->dev = device_create(rppc_class, &rpdev->dev,
+				     MKDEV(major, rppcdev->minor), NULL,
 				     namedesc);
 	if (IS_ERR(rppcdev->dev)) {
 		int ret = PTR_ERR(rppcdev->dev);
@@ -1247,7 +1250,6 @@ static int rppc_probe(struct rpmsg_device *rpdev)
 	}
 	dev_set_drvdata(rppcdev->dev, rppcdev);
 
-serv_up:
 	ret = rppc_device_create(rpdev);
 	if (ret) {
 		dev_err(&rpdev->dev, "failed to query channel info: %d\n", ret);
@@ -1317,6 +1319,8 @@ static void rppc_remove(struct rpmsg_device *rpdev)
 		rpc->state = RPPC_STATE_STALE;
 		wake_up_interruptible(&rpc->readq);
 	}
+	device_destroy(rppc_class, MKDEV(major, rppcdev->minor));
+	rppcdev->dev = NULL;
 	rppcdev->rpdev = NULL;
 	mutex_unlock(&rppcdev->lock);
 	mutex_unlock(&rppc_devices_lock);

+ 3 - 0
drivers/rpmsg/rpmsg_rpc_internal.h

@@ -13,6 +13,7 @@
 #include <linux/wait.h>
 #include <linux/fs.h>
 #include <linux/skbuff.h>
+#include <linux/rpmsg.h>
 
 typedef u32 virt_addr_t;
 typedef u32 dev_addr_t;
@@ -35,6 +36,7 @@ typedef u32 dev_addr_t;
  * @num_funcs: number of functions published by this remote server device
  * @cur_func: counter used while querying information for each function
  *	      associated with this remote server device
+ * @desc: description of the exposed service
  *
  * A rppc_device indicates the base remote server device that supports the
  * execution of a bunch of remote functions. Each such remote server device
@@ -53,6 +55,7 @@ struct rppc_device {
 	unsigned int minor;
 	u32 num_funcs;
 	u32 cur_func;
+	char desc[RPMSG_NAME_SIZE];
 };
 
 /**