diag: Release mutex in corner case
DIAG driver maintains a table for all registrations by remote
peripherals and user space applications. In certain cases, the
number of registrations can exceed table capacity. Thus, diag
re-allocates the table memory, to fit in all registrations.
This re-allocation stops at a threshold, even if requirement
is greater than threshold.
In such a corner case, if the requirement is greater than threshold,
then the mutex might remain locked after filling the table upto full
capacity. Adding unlocking condition to release mutex in such cases.
Change-Id: Iefd02795b531e17ff7cfe3be152e32b3e82c68fb
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7d28604..371d319 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -52,8 +52,8 @@
#define MAX_EQUIP_ID 12
/* Maximum number of pkt reg supported at initialization*/
-extern unsigned int diag_max_registration;
-extern unsigned int diag_threshold_registration;
+extern unsigned int diag_max_reg;
+extern unsigned int diag_threshold_reg;
#define APPEND_DEBUG(ch) \
do { \
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index e24d896..efba92b 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -60,8 +60,8 @@
static unsigned int max_clients = 15;
static unsigned int threshold_client_limit = 30;
/* This is the maximum number of pkt registrations supported at initialization*/
-unsigned int diag_max_registration = 600;
-unsigned int diag_threshold_registration = 750;
+unsigned int diag_max_reg = 600;
+unsigned int diag_threshold_reg = 750;
/* Timer variables */
static struct timer_list drain_timer;
@@ -230,7 +230,7 @@
}
#endif /* DIAG over USB */
/* Delete the pkt response table entry for the exiting process */
- for (i = 0; i < diag_max_registration; i++)
+ for (i = 0; i < diag_max_reg; i++)
if (driver->table[i].process_id == current->tgid)
driver->table[i].process_id = 0;
@@ -286,13 +286,13 @@
mutex_lock(&driver->diagchar_mutex);
/* reset polling flag */
driver->polling_reg_flag = 0;
- for (i = 0; i < diag_max_registration; i++) {
+ for (i = 0; i < diag_max_reg; i++) {
if (driver->table[i].client_id == proc_num) {
driver->table[i].process_id = 0;
}
}
/* re-scan the registration table */
- for (i = 0; i < diag_max_registration; i++) {
+ for (i = 0; i < diag_max_reg; i++) {
if (diag_find_polling_reg(i) == 1) {
driver->polling_reg_flag = 1;
break;
@@ -335,7 +335,7 @@
struct bindpkt_params_per_process *pkt_params =
(struct bindpkt_params_per_process *) ioarg;
mutex_lock(&driver->diagchar_mutex);
- for (i = 0; i < diag_max_registration; i++) {
+ for (i = 0; i < diag_max_reg; i++) {
if (driver->table[i].process_id == 0) {
diag_add_reg(i, pkt_params->params,
&success, &count_entries);
@@ -347,19 +347,20 @@
}
}
}
- if (i < diag_threshold_registration) {
+ if (i < diag_threshold_reg) {
/* Increase table size by amount required */
- diag_max_registration += pkt_params->count -
+ diag_max_reg += pkt_params->count -
count_entries;
/* Make sure size doesnt go beyond threshold */
- if (diag_max_registration > diag_threshold_registration)
- diag_max_registration =
- diag_threshold_registration;
+ if (diag_max_reg > diag_threshold_reg) {
+ diag_max_reg = diag_threshold_reg;
+ pr_info("diag: best case memory allocation\n");
+ }
temp_buf = krealloc(driver->table,
- diag_max_registration*sizeof(struct
+ diag_max_reg*sizeof(struct
diag_master_table), GFP_KERNEL);
if (!temp_buf) {
- diag_max_registration -= pkt_params->count -
+ diag_max_reg -= pkt_params->count -
count_entries;
pr_alert("diag: Insufficient memory for reg.");
mutex_unlock(&driver->diagchar_mutex);
@@ -367,7 +368,7 @@
} else {
driver->table = temp_buf;
}
- for (j = i; j < diag_max_registration; j++) {
+ for (j = i; j < diag_max_reg; j++) {
diag_add_reg(j, pkt_params->params,
&success, &count_entries);
if (pkt_params->count > count_entries) {
@@ -377,6 +378,7 @@
return success;
}
}
+ mutex_unlock(&driver->diagchar_mutex);
} else {
mutex_unlock(&driver->diagchar_mutex);
pr_err("Max size reached, Pkt Registration failed for"
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 079e04b..7f26856 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -598,7 +598,7 @@
}
pr_debug("diag: %d %d %d", cmd_code, subsys_id, subsys_cmd_code);
- for (i = 0; i < diag_max_registration; i++) {
+ for (i = 0; i < diag_max_reg; i++) {
entry = driver->table[i];
if (entry.process_id != NO_PROCESS) {
if (entry.cmd_code == cmd_code && entry.subsys_id ==
@@ -1374,7 +1374,7 @@
, GFP_KERNEL)) == NULL)
goto err;
if (driver->table == NULL &&
- (driver->table = kzalloc(diag_max_registration*
+ (driver->table = kzalloc(diag_max_reg*
sizeof(struct diag_master_table),
GFP_KERNEL)) == NULL)
goto err;