Changeset 2482

Show
Ignore:
Timestamp:
04/27/04 03:10:49 (9 years ago)
Author:
mds
Message:

move initialization to kernel thread to fix oops

Ticket #1573


Another update for his issue [kernel panic triggered by bmcsensors}:

The source of the problem are the non-atomic kernel mallocs for device
registration called from an interrupt context - this doesn't seem to be
supported and as observed can crash the kernel.

A possible solution is to create a kernel thread on initialisation,
leave that thread hanging round while the device scan runs, and finaly
signal the init thread when device scan is complete to finish
initialisation be registing the sensors found during scan.

A patch implementing such a scheme was created by Yvon JEGOU, I'll post
it here again.

Thanks, Martin


Hi Mark,

I don't fully understand... sorry if I'm slow.
is the problem doing mallocs from an interrupt context or non-atomic
mallocs?
what's non-atomic about the malloc?
how did we get in an interrupt context?

Being no kernel programmer this is fairly hard form me to answer; lets
see how far I get

The problem is non-atomic kmallocs from an interrupt context.

Non-atomic refers to the flags specified in the kmalloc call (GFP_ATOMIC
vs. GFP_KERNEL) (Ref.  http://lwn.net/Articles/22909/)

Scanning for sensors is triggered by sending an ipmi message in
bmcsensors_reserve_sdr. Building the list of sensors and finally
creating the required proc entries happens on subsequent reception of
ipmi messages in the ipmi call-back. If I understand correctly how
things interact, that would be in an interrupt context.

Where bmcsensors blows up when trying to register lots of sensors is the

-> bmcsensors_command (which is the i2c-ipmi call-back)
-> bmcsensors_msg_handler
-> bmcsensors_rcv_msg
-> bmcsensors_rcv_sdr_msg
-> bmcsensors_build_proc_table
-> i2c_register_entry
-> create_proc_entry
-> proc_create
-> kmalloc

sequence.

My limited understanding of kernel programming is that if memory is
allocated in an interrupt context, GFP_ATOMIC must be used.

While the kmallocs done directly by bmcsensors_build_proc_table would be
fixable, the calls in proc_create_entry are obviously not changeable.
This makes proc_create and its callers unsafe for use in an interrupt
context.

The patch works around this limitation by creating a separate kernel
thread from sm_bmcsensors_init and calling bmcsensors_build_proc_table
from this thread after scanning for sesnsors has finished.

Hope I've managed to adequately explain what I think is wrong.

Bye, Martin

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • lm-sensors/trunk/kernel/chips/bmcsensors.c

    r2333 r2482  
    2727#include <linux/init.h> 
    2828#include <asm/io.h> 
     29/* for kernel thread ... */ 
     30#include <asm/atomic.h> 
     31#include <asm/semaphore.h> 
     32#include <linux/smp_lock.h> 
     33#include <asm/errno.h> 
    2934#include "version.h" 
    3035 
     
    6166static void bmcsensors_update_client(struct i2c_client *client); 
    6267static void bmcsensors_reserve_sdr(void); 
     68static void bmc_do_pause(unsigned int amount); /* YJ for debug */ 
    6369 
    6470 
     
    159165 
    160166enum states {STATE_INIT, STATE_RESERVE, STATE_SDR, STATE_SDRPARTIAL, 
    161              STATE_READING, STATE_UNCANCEL, STATE_DONE}; 
     167             STATE_READING, STATE_UNCANCEL, STATE_PROCTABLE, STATE_DONE}; 
     168/* YJ : added extra state STATE_PROCTABLE for thread activity */ 
    162169static int state; 
    163170static int receive_counter; 
     
    182189#define STYPE_MAX       4               /* the last sensor type we are interested in */ 
    183190static u8 bmcs_count[STYPE_MAX + 1]; 
    184 static const u8 bmcs_max[STYPE_MAX + 1] = {0, 20, 20, 20, 20}; 
     191static const u8 bmcs_max[STYPE_MAX + 1] = {0, 20, 40, 20, 20}; 
     192/* YJ: on poweredge 1750, we need                 ^^            */ 
    185193 
    186194/************************************/ 
    187  
     195/* YJ ... */ 
     196static int thread_pid= 0; 
     197static DECLARE_MUTEX_LOCKED(bmc_sem); 
     198/* ... YJ */ 
     199/************************************/ 
    188200 
    189201/* unpack based on string type, convert to normal, null terminate */ 
     
    311323        u8 id[SDR_MAX_UNPACKED_ID_LENGTH]; 
    312324 
     325         
     326        printk(KERN_INFO "bmcsensors.o: building proc table\n"); 
    313327        if(!(bmcsensors_dir_table = kmalloc((sdrd_count + 1) * sizeof(struct ctl_table), GFP_KERNEL))) { 
    314328                printk(KERN_ERR "bmcsensors.o: no memory\n"); 
     
    452466                if(ipmi_sdr_partial_size < 8) { 
    453467                        printk(KERN_INFO "bmcsensors.o: IPMI buffers too small, giving up\n"); 
     468                        up (&bmc_sem); /* should wait for thread exit ! */ 
    454469                        return STATE_DONE; 
    455470                } 
     
    483498 
    484499        nextrecord = (data[2] << 8) | data[1]; 
     500        /* printk(KERN_INFO "bmcsensors.o: nextrecord %d \n", nextrecord); */ 
     501 
     502 
    485503        type = data[6]; 
    486504        if(type == 1 || type == 2) {            /* known SDR type */ 
     
    556574                                bmcs_count[stype]++; 
    557575                                sdrd_count++; 
     576                                if (sdrd_count>=MAX_SDR_ENTRIES) nextrecord = 0xffff; /*YJ*/ 
     577 
    558578                        } 
    559579                } 
     
    582602#endif 
    583603        } 
     604        if (nextrecord>=6224) { 
     605          nextrecord = 0xffff; /*YJ stop sensor scan on poweredge 1750 */ 
     606        } 
    584607                         
    585608        if(nextrecord == 0xFFFF) { 
     
    587610                        printk(KERN_INFO "bmcsensors.o: No recognized sensors found.\n"); 
    588611                        /* unregister?? */ 
     612                        rstate = STATE_DONE; 
     613                        up (&bmc_sem); /* should wait for thread exit !!! */ 
    589614                } else { 
    590                         bmcsensors_build_proc_table(); 
    591                 } 
    592                 rstate = STATE_DONE; 
     615                  /* YJ ...*/ 
     616                  printk(KERN_INFO "bmcsensors.o: all sensors detected\n"); 
     617                  rstate = STATE_PROCTABLE; 
     618                  /* YJ bmcsensors_build_proc_table() call by thread */ 
     619                  /* ... YJ */ 
     620                } 
     621 
    593622        } else { 
     623 
    594624                bmcsensors_get_sdr(0, nextrecord, 0); 
    595625        } 
     
    615645                case STATE_SDRPARTIAL: 
    616646                        state = bmcsensors_rcv_sdr_msg(msg, state); 
     647                        /*YJ ...*/ 
     648                        if (state==STATE_PROCTABLE){ 
     649 
     650#ifdef DEBUG 
     651                          printk(KERN_DEBUG "releasing thread\n"); 
     652#endif 
     653 
     654                          up (&bmc_sem); 
     655                        } 
     656                         /*YJ bmcsensors_build_proc_table() called by thread */  
     657                        /* ... YJ */ 
    617658                        break; 
    618659 
     
    632673 
    633674                case STATE_DONE: 
     675                case STATE_PROCTABLE: 
    634676                        break; 
    635677 
     
    650692                               "bmcsensors.o: Too many reservations cancelled, giving up\n"); 
    651693                        state = STATE_DONE; 
     694                        up (&bmc_sem); /* YJ : should make sure thread exited ! */ 
    652695                } else { 
    653696#ifdef DEBUG 
     
    658701                        state = STATE_UNCANCEL; 
    659702                } 
    660         } else if (msg->msg.data[0] != 0 && msg->msg.data[0] != 0xca) { 
     703        } else if (msg->msg.data[0] != 0 && msg->msg.data[0] != 0xca && 
     704                   msg->msg.data[0] != 0xce) { 
     705          /* YJ : accept  0xce */ 
    661706                printk(KERN_ERR 
    662707                       "bmcsensors.o: Error 0x%x on cmd 0x%x/0x%x; state = %d; probably fatal.\n", 
     
    696741        tx_message.data_len = 0; 
    697742        tx_message.data = NULL; 
     743        printk(KERN_INFO "bmcsensors.o: reserve_sdr...\n"); 
    698744        bmcsensors_send_message(&tx_message); 
    699745} 
     
    734780static int bmcsensors_attach_adapter(struct i2c_adapter *adapter) 
    735781{ 
    736         if(adapter->algo->id != I2C_ALGO_IPMI) 
     782        printk(KERN_INFO "bmcsensors.o: attach_adapter...\n"); 
     783  
     784        if(adapter->algo->id != I2C_ALGO_IPMI){ 
     785          printk(KERN_INFO "bmcsensors.o: attach_adapter, expected 0x%x, got 0x%x\n", I2C_ALGO_IPMI, adapter->algo->id); 
    737786                return 0; 
     787        } 
    738788 
    739789        if(bmcsensors_initialized >= 2) { 
     
    9661016#endif 
    9671017 
     1018/* YJ ... */ 
     1019static int bmc_thread(void *dummy){ 
     1020 
     1021  lock_kernel(); 
     1022  daemonize(); 
     1023  unlock_kernel(); 
     1024 
     1025  strcpy(current->comm, "bmc-sensors"); 
     1026 
     1027  if(down_interruptible(&bmc_sem)) { 
     1028 
     1029   printk("exiting..."); 
     1030 
     1031   thread_pid= 0; 
     1032   up (&bmc_sem); 
     1033 
     1034   return 0; 
     1035  } 
     1036 
     1037  if (state == STATE_PROCTABLE){ 
     1038 
     1039    bmcsensors_build_proc_table(); 
     1040     
     1041    state = STATE_DONE; 
     1042     
     1043    printk(KERN_INFO "bmcsensors.o: bmcsensor thread done\n" ); 
     1044     
     1045  } 
     1046 
     1047  thread_pid= 0; 
     1048  
     1049  up (&bmc_sem); 
     1050 
     1051  return 0; 
     1052} 
     1053/* ... YJ */ 
     1054 
    9681055static int __init sm_bmcsensors_init(void) 
    9691056{ 
    9701057        printk(KERN_INFO "bmcsensors.o version %s (%s)\n", LM_VERSION, LM_DATE); 
     1058        /* YJ ... */ 
     1059        init_MUTEX_LOCKED(&bmc_sem); 
     1060 
     1061        thread_pid= kernel_thread(bmc_thread, NULL, 0); 
     1062 
     1063        if (thread_pid<0){ 
     1064          printk(KERN_ERR "bmcsensors.o : Could not initialize bmc thread.  Aborting\n"); 
     1065          return 0; 
     1066        } 
     1067        /* ... YJ */ 
     1068 
    9711069        return i2c_add_driver(&bmcsensors_driver); 
    9721070} 
     
    9741072static void __exit sm_bmcsensors_exit(void) 
    9751073{ 
    976         i2c_del_driver(&bmcsensors_driver); 
     1074  int j; 
     1075  j= 0; 
     1076  /* YJ ... */ 
     1077  printk(KERN_INFO "bmcsensors.o sleeping a while\n"); 
     1078  while( (j++ < 50)){ 
     1079    bmc_do_pause(HZ / 25); 
     1080  } 
     1081  if (thread_pid > 0){ 
     1082    printk(KERN_INFO "bmcsensors.o stopping kernel thread\n"); 
     1083    state= STATE_DONE; 
     1084    j= 0; 
     1085    up (&bmc_sem); 
     1086    printk(KERN_INFO "bmcsensors.o waiting...\n"); 
     1087    /* make sure kernel thread does not access driver memory any more */ 
     1088    while((thread_pid > 0)&& (j++ < 100)){ 
     1089      bmc_do_pause(HZ / 25); 
     1090    } 
     1091    printk(KERN_INFO "bmcsensors.o OK\n"); 
     1092  } 
     1093  j= 0; 
     1094  /* sleep for debug... not necessary ? */ 
     1095  printk(KERN_INFO "bmcsensors.o sleeping again\n"); 
     1096  while( (j++ < 50)){ 
     1097    bmc_do_pause(HZ / 25); 
     1098  } 
     1099  /* ...YJ */ 
     1100  printk(KERN_INFO "bmcsensors.o i2c cleanup\n"); 
     1101  i2c_del_driver(&bmcsensors_driver); 
    9771102} 
    9781103