Skip to content

Commit 6f7f660

Browse files
committed
ipmi:msghandler: Export and fix panic messaging capability
Don't have the other users that do things at panic time (the watchdog) do all this themselves, provide a function to do it. Also, with the new design where most stuff happens at thread context, a few things needed to be fixed to avoid doing locking in a panic context. Signed-off-by: Corey Minyard <cminyard@mvista.com>
1 parent be816bc commit 6f7f660

File tree

2 files changed

+41
-19
lines changed

2 files changed

+41
-19
lines changed

drivers/char/ipmi/ipmi_msghandler.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,6 +2284,7 @@ static int i_ipmi_request(struct ipmi_user *user,
22842284
{
22852285
struct ipmi_smi_msg *smi_msg;
22862286
struct ipmi_recv_msg *recv_msg;
2287+
int run_to_completion = READ_ONCE(intf->run_to_completion);
22872288
int rv = 0;
22882289

22892290
if (user) {
@@ -2317,7 +2318,8 @@ static int i_ipmi_request(struct ipmi_user *user,
23172318
}
23182319
}
23192320

2320-
mutex_lock(&intf->users_mutex);
2321+
if (!run_to_completion)
2322+
mutex_lock(&intf->users_mutex);
23212323
if (intf->in_shutdown) {
23222324
rv = -ENODEV;
23232325
goto out_err;
@@ -2363,7 +2365,8 @@ static int i_ipmi_request(struct ipmi_user *user,
23632365

23642366
smi_send(intf, intf->handlers, smi_msg, priority);
23652367
}
2366-
mutex_unlock(&intf->users_mutex);
2368+
if (!run_to_completion)
2369+
mutex_unlock(&intf->users_mutex);
23672370

23682371
out:
23692372
if (rv && user)
@@ -4559,7 +4562,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
45594562
&& (msg->data[1] == IPMI_SEND_MSG_CMD)
45604563
&& (msg->user_data == NULL)) {
45614564

4562-
if (intf->in_shutdown)
4565+
if (intf->in_shutdown || intf->run_to_completion)
45634566
goto out;
45644567

45654568
/*
@@ -4631,6 +4634,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
46314634
*/
46324635
struct ipmi_recv_msg *recv_msg;
46334636

4637+
if (intf->run_to_completion)
4638+
goto out;
4639+
46344640
chan = msg->data[2] & 0x0f;
46354641
if (chan >= IPMI_MAX_CHANNELS)
46364642
/* Invalid channel number */
@@ -4653,6 +4659,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
46534659
&& (msg->rsp[1] == IPMI_GET_MSG_CMD)) {
46544660
struct ipmi_channel *chans;
46554661

4662+
if (intf->run_to_completion)
4663+
goto out;
4664+
46564665
/* It's from the receive queue. */
46574666
chan = msg->rsp[3] & 0xf;
46584667
if (chan >= IPMI_MAX_CHANNELS) {
@@ -4727,6 +4736,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
47274736
} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
47284737
&& (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) {
47294738
/* It's an asynchronous event. */
4739+
if (intf->run_to_completion)
4740+
goto out;
4741+
47304742
requeue = handle_read_event_rsp(intf, msg);
47314743
} else {
47324744
/* It's a response from the local BMC. */
@@ -4855,15 +4867,6 @@ static void smi_work(struct work_struct *t)
48554867

48564868
list_del(&msg->link);
48574869

4858-
/*
4859-
* I would like for this check (and user->destroyed)
4860-
* to go away, but it's possible that an interface is
4861-
* processing a message that belongs to the user while
4862-
* the user is being deleted. When that response
4863-
* comes back, it could be queued after the user is
4864-
* destroyed. This is simpler than handling it in the
4865-
* interface.
4866-
*/
48674870
if (refcount_read(&user->destroyed) == 0) {
48684871
ipmi_free_recv_msg(msg);
48694872
} else {
@@ -5222,9 +5225,9 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
52225225
/*
52235226
* Inside a panic, send a message and wait for a response.
52245227
*/
5225-
static void ipmi_panic_request_and_wait(struct ipmi_smi *intf,
5226-
struct ipmi_addr *addr,
5227-
struct kernel_ipmi_msg *msg)
5228+
static void _ipmi_panic_request_and_wait(struct ipmi_smi *intf,
5229+
struct ipmi_addr *addr,
5230+
struct kernel_ipmi_msg *msg)
52285231
{
52295232
struct ipmi_smi_msg smi_msg;
52305233
struct ipmi_recv_msg recv_msg;
@@ -5254,6 +5257,15 @@ static void ipmi_panic_request_and_wait(struct ipmi_smi *intf,
52545257
ipmi_poll(intf);
52555258
}
52565259

5260+
void ipmi_panic_request_and_wait(struct ipmi_user *user,
5261+
struct ipmi_addr *addr,
5262+
struct kernel_ipmi_msg *msg)
5263+
{
5264+
user->intf->run_to_completion = 1;
5265+
_ipmi_panic_request_and_wait(user->intf, addr, msg);
5266+
}
5267+
EXPORT_SYMBOL(ipmi_panic_request_and_wait);
5268+
52575269
static void event_receiver_fetcher(struct ipmi_smi *intf,
52585270
struct ipmi_recv_msg *msg)
52595271
{
@@ -5322,7 +5334,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
53225334
}
53235335

53245336
/* Send the event announcing the panic. */
5325-
ipmi_panic_request_and_wait(intf, &addr, &msg);
5337+
_ipmi_panic_request_and_wait(intf, &addr, &msg);
53265338

53275339
/*
53285340
* On every interface, dump a bunch of OEM event holding the
@@ -5358,7 +5370,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
53585370
msg.data = NULL;
53595371
msg.data_len = 0;
53605372
intf->null_user_handler = device_id_fetcher;
5361-
ipmi_panic_request_and_wait(intf, &addr, &msg);
5373+
_ipmi_panic_request_and_wait(intf, &addr, &msg);
53625374

53635375
if (intf->local_event_generator) {
53645376
/* Request the event receiver from the local MC. */
@@ -5367,7 +5379,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
53675379
msg.data = NULL;
53685380
msg.data_len = 0;
53695381
intf->null_user_handler = event_receiver_fetcher;
5370-
ipmi_panic_request_and_wait(intf, &addr, &msg);
5382+
_ipmi_panic_request_and_wait(intf, &addr, &msg);
53715383
}
53725384
intf->null_user_handler = NULL;
53735385

@@ -5419,7 +5431,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
54195431
memcpy_and_pad(data+5, 11, p, size, '\0');
54205432
p += size;
54215433

5422-
ipmi_panic_request_and_wait(intf, &addr, &msg);
5434+
_ipmi_panic_request_and_wait(intf, &addr, &msg);
54235435
}
54245436
}
54255437

include/linux/ipmi.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,14 @@ extern int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data);
344344
/* Helper function for computing the IPMB checksum of some data. */
345345
unsigned char ipmb_checksum(unsigned char *data, int size);
346346

347+
/*
348+
* For things that must send messages at panic time, like the IPMI watchdog
349+
* driver that extends the reset time on a panic, use this to send messages
350+
* from panic context. Note that this puts the driver into a mode that
351+
* only works at panic time, so only use it then.
352+
*/
353+
void ipmi_panic_request_and_wait(struct ipmi_user *user,
354+
struct ipmi_addr *addr,
355+
struct kernel_ipmi_msg *msg);
356+
347357
#endif /* __LINUX_IPMI_H */

0 commit comments

Comments
 (0)