aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Asbock <masbock@us.ibm.com>2005-06-21 20:16:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-21 22:07:35 -0400
commit8818760512424f60ad9fafb7a087b007a9274eb3 (patch)
treefb49ce398750f42803d4631a24e4a2ffe35d79d7
parent278d72ae8803ffcd16070c95fe1d53f4466dc741 (diff)
[PATCH] ibmasm driver: fix race in command refcount logic
This patch fixes a race in the command reference counting logic by putting spinlocks around kobject_put() in the command_put function. - Also added debug messages. - Changed a memcpy to memcpy_fromio since we are reading from io space. Signed-off-by: Max Asbock <masbock@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/misc/ibmasm/command.c30
-rw-r--r--drivers/misc/ibmasm/dot_command.c10
-rw-r--r--drivers/misc/ibmasm/heartbeat.c13
-rw-r--r--drivers/misc/ibmasm/ibmasm.h7
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c2
-rw-r--r--drivers/misc/ibmasm/r_heartbeat.c2
6 files changed, 51 insertions, 13 deletions
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
index 245b0058381d..07a085ccbd5b 100644
--- a/drivers/misc/ibmasm/command.c
+++ b/drivers/misc/ibmasm/command.c
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include "ibmasm.h" 25#include "ibmasm.h"
26#include "lowlevel.h"
26 27
27static void exec_next_command(struct service_processor *sp); 28static void exec_next_command(struct service_processor *sp);
28static void free_command(struct kobject *kobj); 29static void free_command(struct kobject *kobj);
@@ -31,8 +32,9 @@ static struct kobj_type ibmasm_cmd_kobj_type = {
31 .release = free_command, 32 .release = free_command,
32}; 33};
33 34
35static atomic_t command_count = ATOMIC_INIT(0);
34 36
35struct command *ibmasm_new_command(size_t buffer_size) 37struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size)
36{ 38{
37 struct command *cmd; 39 struct command *cmd;
38 40
@@ -55,11 +57,15 @@ struct command *ibmasm_new_command(size_t buffer_size)
55 57
56 kobject_init(&cmd->kobj); 58 kobject_init(&cmd->kobj);
57 cmd->kobj.ktype = &ibmasm_cmd_kobj_type; 59 cmd->kobj.ktype = &ibmasm_cmd_kobj_type;
60 cmd->lock = &sp->lock;
58 61
59 cmd->status = IBMASM_CMD_PENDING; 62 cmd->status = IBMASM_CMD_PENDING;
60 init_waitqueue_head(&cmd->wait); 63 init_waitqueue_head(&cmd->wait);
61 INIT_LIST_HEAD(&cmd->queue_node); 64 INIT_LIST_HEAD(&cmd->queue_node);
62 65
66 atomic_inc(&command_count);
67 dbg("command count: %d\n", atomic_read(&command_count));
68
63 return cmd; 69 return cmd;
64} 70}
65 71
@@ -68,6 +74,8 @@ static void free_command(struct kobject *kobj)
68 struct command *cmd = to_command(kobj); 74 struct command *cmd = to_command(kobj);
69 75
70 list_del(&cmd->queue_node); 76 list_del(&cmd->queue_node);
77 atomic_dec(&command_count);
78 dbg("command count: %d\n", atomic_read(&command_count));
71 kfree(cmd->buffer); 79 kfree(cmd->buffer);
72 kfree(cmd); 80 kfree(cmd);
73} 81}
@@ -94,8 +102,14 @@ static struct command *dequeue_command(struct service_processor *sp)
94 102
95static inline void do_exec_command(struct service_processor *sp) 103static inline void do_exec_command(struct service_processor *sp)
96{ 104{
105 char tsbuf[32];
106
107 dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
108
97 if (ibmasm_send_i2o_message(sp)) { 109 if (ibmasm_send_i2o_message(sp)) {
98 sp->current_command->status = IBMASM_CMD_FAILED; 110 sp->current_command->status = IBMASM_CMD_FAILED;
111 wake_up(&sp->current_command->wait);
112 command_put(sp->current_command);
99 exec_next_command(sp); 113 exec_next_command(sp);
100 } 114 }
101} 115}
@@ -111,14 +125,16 @@ static inline void do_exec_command(struct service_processor *sp)
111void ibmasm_exec_command(struct service_processor *sp, struct command *cmd) 125void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
112{ 126{
113 unsigned long flags; 127 unsigned long flags;
128 char tsbuf[32];
129
130 dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
114 131
115 spin_lock_irqsave(&sp->lock, flags); 132 spin_lock_irqsave(&sp->lock, flags);
116 133
117 if (!sp->current_command) { 134 if (!sp->current_command) {
118 command_get(cmd);
119 sp->current_command = cmd; 135 sp->current_command = cmd;
136 command_get(sp->current_command);
120 spin_unlock_irqrestore(&sp->lock, flags); 137 spin_unlock_irqrestore(&sp->lock, flags);
121
122 do_exec_command(sp); 138 do_exec_command(sp);
123 } else { 139 } else {
124 enqueue_command(sp, cmd); 140 enqueue_command(sp, cmd);
@@ -129,9 +145,9 @@ void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
129static void exec_next_command(struct service_processor *sp) 145static void exec_next_command(struct service_processor *sp)
130{ 146{
131 unsigned long flags; 147 unsigned long flags;
148 char tsbuf[32];
132 149
133 wake_up(&sp->current_command->wait); 150 dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
134 command_put(sp->current_command);
135 151
136 spin_lock_irqsave(&sp->lock, flags); 152 spin_lock_irqsave(&sp->lock, flags);
137 sp->current_command = dequeue_command(sp); 153 sp->current_command = dequeue_command(sp);
@@ -169,7 +185,9 @@ void ibmasm_receive_command_response(struct service_processor *sp, void *respons
169 if (!sp->current_command) 185 if (!sp->current_command)
170 return; 186 return;
171 187
172 memcpy(cmd->buffer, response, min(size, cmd->buffer_size)); 188 memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size));
173 cmd->status = IBMASM_CMD_COMPLETE; 189 cmd->status = IBMASM_CMD_COMPLETE;
190 wake_up(&sp->current_command->wait);
191 command_put(sp->current_command);
174 exec_next_command(sp); 192 exec_next_command(sp);
175} 193}
diff --git a/drivers/misc/ibmasm/dot_command.c b/drivers/misc/ibmasm/dot_command.c
index 478a8d898fc1..13c52f866e2e 100644
--- a/drivers/misc/ibmasm/dot_command.c
+++ b/drivers/misc/ibmasm/dot_command.c
@@ -33,7 +33,13 @@ void ibmasm_receive_message(struct service_processor *sp, void *message, int mes
33 u32 size; 33 u32 size;
34 struct dot_command_header *header = (struct dot_command_header *)message; 34 struct dot_command_header *header = (struct dot_command_header *)message;
35 35
36 if (message_size == 0)
37 return;
38
36 size = get_dot_command_size(message); 39 size = get_dot_command_size(message);
40 if (size == 0)
41 return;
42
37 if (size > message_size) 43 if (size > message_size)
38 size = message_size; 44 size = message_size;
39 45
@@ -67,7 +73,7 @@ int ibmasm_send_driver_vpd(struct service_processor *sp)
67 u8 *vpd_data; 73 u8 *vpd_data;
68 int result = 0; 74 int result = 0;
69 75
70 command = ibmasm_new_command(INIT_BUFFER_SIZE); 76 command = ibmasm_new_command(sp, INIT_BUFFER_SIZE);
71 if (command == NULL) 77 if (command == NULL)
72 return -ENOMEM; 78 return -ENOMEM;
73 79
@@ -121,7 +127,7 @@ int ibmasm_send_os_state(struct service_processor *sp, int os_state)
121 struct os_state_command *os_state_cmd; 127 struct os_state_command *os_state_cmd;
122 int result = 0; 128 int result = 0;
123 129
124 cmd = ibmasm_new_command(sizeof(struct os_state_command)); 130 cmd = ibmasm_new_command(sp, sizeof(struct os_state_command));
125 if (cmd == NULL) 131 if (cmd == NULL)
126 return -ENOMEM; 132 return -ENOMEM;
127 133
diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c
index ce09309174d6..f295401fac21 100644
--- a/drivers/misc/ibmasm/heartbeat.c
+++ b/drivers/misc/ibmasm/heartbeat.c
@@ -25,6 +25,7 @@
25#include <linux/notifier.h> 25#include <linux/notifier.h>
26#include "ibmasm.h" 26#include "ibmasm.h"
27#include "dot_command.h" 27#include "dot_command.h"
28#include "lowlevel.h"
28 29
29static int suspend_heartbeats = 0; 30static int suspend_heartbeats = 0;
30 31
@@ -62,7 +63,7 @@ void ibmasm_unregister_panic_notifier(void)
62 63
63int ibmasm_heartbeat_init(struct service_processor *sp) 64int ibmasm_heartbeat_init(struct service_processor *sp)
64{ 65{
65 sp->heartbeat = ibmasm_new_command(HEARTBEAT_BUFFER_SIZE); 66 sp->heartbeat = ibmasm_new_command(sp, HEARTBEAT_BUFFER_SIZE);
66 if (sp->heartbeat == NULL) 67 if (sp->heartbeat == NULL)
67 return -ENOMEM; 68 return -ENOMEM;
68 69
@@ -71,6 +72,12 @@ int ibmasm_heartbeat_init(struct service_processor *sp)
71 72
72void ibmasm_heartbeat_exit(struct service_processor *sp) 73void ibmasm_heartbeat_exit(struct service_processor *sp)
73{ 74{
75 char tsbuf[32];
76
77 dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
78 ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL);
79 dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
80 suspend_heartbeats = 1;
74 command_put(sp->heartbeat); 81 command_put(sp->heartbeat);
75} 82}
76 83
@@ -78,14 +85,16 @@ void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size
78{ 85{
79 struct command *cmd = sp->heartbeat; 86 struct command *cmd = sp->heartbeat;
80 struct dot_command_header *header = (struct dot_command_header *)cmd->buffer; 87 struct dot_command_header *header = (struct dot_command_header *)cmd->buffer;
88 char tsbuf[32];
81 89
90 dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
82 if (suspend_heartbeats) 91 if (suspend_heartbeats)
83 return; 92 return;
84 93
85 /* return the received dot command to sender */ 94 /* return the received dot command to sender */
86 cmd->status = IBMASM_CMD_PENDING; 95 cmd->status = IBMASM_CMD_PENDING;
87 size = min(size, cmd->buffer_size); 96 size = min(size, cmd->buffer_size);
88 memcpy(cmd->buffer, message, size); 97 memcpy_fromio(cmd->buffer, message, size);
89 header->type = sp_write; 98 header->type = sp_write;
90 ibmasm_exec_command(sp, cmd); 99 ibmasm_exec_command(sp, cmd);
91} 100}
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index 653a7d096a8b..ecce4ffd3e23 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -95,12 +95,17 @@ struct command {
95 size_t buffer_size; 95 size_t buffer_size;
96 int status; 96 int status;
97 struct kobject kobj; 97 struct kobject kobj;
98 spinlock_t *lock;
98}; 99};
99#define to_command(c) container_of(c, struct command, kobj) 100#define to_command(c) container_of(c, struct command, kobj)
100 101
101static inline void command_put(struct command *cmd) 102static inline void command_put(struct command *cmd)
102{ 103{
104 unsigned long flags;
105
106 spin_lock_irqsave(cmd->lock, flags);
103 kobject_put(&cmd->kobj); 107 kobject_put(&cmd->kobj);
108 spin_unlock_irqrestore(cmd->lock, flags);
104} 109}
105 110
106static inline void command_get(struct command *cmd) 111static inline void command_get(struct command *cmd)
@@ -159,7 +164,7 @@ struct service_processor {
159}; 164};
160 165
161/* command processing */ 166/* command processing */
162extern struct command *ibmasm_new_command(size_t buffer_size); 167extern struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size);
163extern void ibmasm_exec_command(struct service_processor *sp, struct command *cmd); 168extern void ibmasm_exec_command(struct service_processor *sp, struct command *cmd);
164extern void ibmasm_wait_for_response(struct command *cmd, int timeout); 169extern void ibmasm_wait_for_response(struct command *cmd, int timeout);
165extern void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size); 170extern void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size);
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index ca839162e4f7..5c550fcac2c4 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -321,7 +321,7 @@ static ssize_t command_file_write(struct file *file, const char __user *ubuff, s
321 if (command_data->command) 321 if (command_data->command)
322 return -EAGAIN; 322 return -EAGAIN;
323 323
324 cmd = ibmasm_new_command(count); 324 cmd = ibmasm_new_command(command_data->sp, count);
325 if (!cmd) 325 if (!cmd)
326 return -ENOMEM; 326 return -ENOMEM;
327 327
diff --git a/drivers/misc/ibmasm/r_heartbeat.c b/drivers/misc/ibmasm/r_heartbeat.c
index 93d9c1b2ad6f..f8fdb2d5417e 100644
--- a/drivers/misc/ibmasm/r_heartbeat.c
+++ b/drivers/misc/ibmasm/r_heartbeat.c
@@ -63,7 +63,7 @@ int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_
63 int times_failed = 0; 63 int times_failed = 0;
64 int result = 1; 64 int result = 1;
65 65
66 cmd = ibmasm_new_command(sizeof rhb_dot_cmd); 66 cmd = ibmasm_new_command(sp, sizeof rhb_dot_cmd);
67 if (!cmd) 67 if (!cmd)
68 return -ENOMEM; 68 return -ENOMEM;
69 69