diag: Fix concurrency issues when processing userspace inputs

Diag does not properly accomodate multiple clients when processing
certain types of userspace inputs. With multiple clients running this
will lead to concurrency issues.  Make modifications to use a memory
pool to support multiple clients.

Also, there is a memory leak issue related to dci initialization and
exit. In addition, requested logging modes are not being validated.
Make modifications to the code to correct these issues.

Change-Id: Ieda46434b58683184ae4e16ccd1c609f21ab7962
Signed-off-by: Dixon Peterson <dixonp@codeaurora.org>
diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c
index 0cd8267..bd339e2 100644
--- a/drivers/char/diag/diagmem.c
+++ b/drivers/char/diag/diagmem.c
@@ -45,6 +45,15 @@
 								 GFP_ATOMIC);
 			}
 		}
+	} else if (pool_type == POOL_TYPE_USER) {
+		if (driver->diag_user_pool) {
+			if (driver->count_user_pool < driver->poolsize_user) {
+				atomic_add(1,
+					(atomic_t *)&driver->count_user_pool);
+				buf = mempool_alloc(driver->diag_user_pool,
+					GFP_ATOMIC);
+			}
+		}
 	} else if (pool_type == POOL_TYPE_WRITE_STRUCT) {
 		if (driver->diag_write_struct_pool) {
 			if (driver->count_write_struct_pool <
@@ -98,8 +107,9 @@
 			mempool_destroy(driver->diagpool);
 			driver->diagpool = NULL;
 		} else if (driver->ref_count == 0 && pool_type ==
-							POOL_TYPE_ALL)
-			printk(KERN_ALERT "Unable to destroy COPY mempool");
+							POOL_TYPE_ALL) {
+			pr_err("diag: Unable to destroy COPY mempool");
+		}
 	}
 
 	if (driver->diag_hdlc_pool) {
@@ -107,8 +117,19 @@
 			mempool_destroy(driver->diag_hdlc_pool);
 			driver->diag_hdlc_pool = NULL;
 		} else if (driver->ref_count == 0 && pool_type ==
-							POOL_TYPE_ALL)
-			printk(KERN_ALERT "Unable to destroy HDLC mempool");
+							POOL_TYPE_ALL) {
+			pr_err("diag: Unable to destroy HDLC mempool");
+		}
+	}
+
+	if (driver->diag_user_pool) {
+		if (driver->count_user_pool == 0 && driver->ref_count == 0) {
+			mempool_destroy(driver->diag_user_pool);
+			driver->diag_user_pool = NULL;
+		} else if (driver->ref_count == 0 && pool_type ==
+							POOL_TYPE_ALL) {
+			pr_err("diag: Unable to destroy USER mempool");
+		}
 	}
 
 	if (driver->diag_write_struct_pool) {
@@ -119,8 +140,9 @@
 			mempool_destroy(driver->diag_write_struct_pool);
 			driver->diag_write_struct_pool = NULL;
 		} else if (driver->ref_count == 0 && pool_type ==
-								POOL_TYPE_ALL)
-			printk(KERN_ALERT "Unable to destroy STRUCT mempool");
+							POOL_TYPE_ALL) {
+			pr_err("diag: Unable to destroy STRUCT mempool");
+		}
 	}
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	for (index = 0; index < MAX_HSIC_CH; index++) {
@@ -163,16 +185,25 @@
 			mempool_free(buf, driver->diagpool);
 			atomic_add(-1, (atomic_t *)&driver->count);
 		} else
-			pr_err("diag: Attempt to free up DIAG driver "
-	       "mempool memory which is already free %d", driver->count);
+			pr_err("diag: Attempt to free up DIAG driver mempool memory which is already free %d",
+							driver->count);
 	} else if (pool_type == POOL_TYPE_HDLC) {
 		if (driver->diag_hdlc_pool != NULL &&
 			 driver->count_hdlc_pool > 0) {
 			mempool_free(buf, driver->diag_hdlc_pool);
 			atomic_add(-1, (atomic_t *)&driver->count_hdlc_pool);
 		} else
-			pr_err("diag: Attempt to free up DIAG driver "
-	"HDLC mempool which is already free %d ", driver->count_hdlc_pool);
+			pr_err("diag: Attempt to free up DIAG driver HDLC mempool which is already free %d ",
+						driver->count_hdlc_pool);
+	} else if (pool_type == POOL_TYPE_USER) {
+		if (driver->diag_user_pool != NULL &&
+			driver->count_user_pool > 0) {
+			mempool_free(buf, driver->diag_user_pool);
+			atomic_add(-1, (atomic_t *)&driver->count_user_pool);
+		} else {
+			pr_err("diag: Attempt to free up DIAG driver USER mempool which is already free %d ",
+						driver->count_user_pool);
+		}
 	} else if (pool_type == POOL_TYPE_WRITE_STRUCT) {
 		if (driver->diag_write_struct_pool != NULL &&
 			 driver->count_write_struct_pool > 0) {
@@ -180,9 +211,8 @@
 			atomic_add(-1,
 				 (atomic_t *)&driver->count_write_struct_pool);
 		} else
-			pr_err("diag: Attempt to free up DIAG driver "
-			   "USB structure mempool which is already free %d ",
-				    driver->count_write_struct_pool);
+			pr_err("diag: Attempt to free up DIAG driver USB structure mempool which is already free %d ",
+					driver->count_write_struct_pool);
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE
 	} else if (pool_type == POOL_TYPE_HSIC ||
 				pool_type == POOL_TYPE_HSIC_2) {
@@ -229,18 +259,25 @@
 		driver->diag_hdlc_pool = mempool_create_kmalloc_pool(
 				driver->poolsize_hdlc, driver->itemsize_hdlc);
 
+	if (driver->count_user_pool == 0)
+		driver->diag_user_pool = mempool_create_kmalloc_pool(
+				driver->poolsize_user, driver->itemsize_user);
+
 	if (driver->count_write_struct_pool == 0)
 		driver->diag_write_struct_pool = mempool_create_kmalloc_pool(
 		driver->poolsize_write_struct, driver->itemsize_write_struct);
 
 	if (!driver->diagpool)
-		printk(KERN_INFO "Cannot allocate diag mempool\n");
+		pr_err("diag: Cannot allocate diag mempool\n");
 
 	if (!driver->diag_hdlc_pool)
-		printk(KERN_INFO "Cannot allocate diag HDLC mempool\n");
+		pr_err("diag: Cannot allocate diag HDLC mempool\n");
+
+	if (!driver->diag_user_pool)
+		pr_err("diag: Cannot allocate diag USER mempool\n");
 
 	if (!driver->diag_write_struct_pool)
-		printk(KERN_INFO "Cannot allocate diag USB struct mempool\n");
+		pr_err("diag: Cannot allocate diag USB struct mempool\n");
 }
 
 #ifdef CONFIG_DIAGFWD_BRIDGE_CODE