diff options
| -rw-r--r-- | arch/ia64/sn/kernel/mca.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c index 857774bb2c9a..6546db6abdba 100644 --- a/arch/ia64/sn/kernel/mca.c +++ b/arch/ia64/sn/kernel/mca.c | |||
| @@ -37,6 +37,11 @@ static u64 *sn_oemdata_size, sn_oemdata_bufsize; | |||
| 37 | * This function is the callback routine that SAL calls to log error | 37 | * This function is the callback routine that SAL calls to log error |
| 38 | * info for platform errors. buf is appended to sn_oemdata, resizing as | 38 | * info for platform errors. buf is appended to sn_oemdata, resizing as |
| 39 | * required. | 39 | * required. |
| 40 | * Note: this is a SAL to OS callback, running under the same rules as the SAL | ||
| 41 | * code. SAL calls are run with preempt disabled so this routine must not | ||
| 42 | * sleep. vmalloc can sleep so print_hook cannot resize the output buffer | ||
| 43 | * itself, instead it must set the required size and return to let the caller | ||
| 44 | * resize the buffer then redrive the SAL call. | ||
| 40 | */ | 45 | */ |
| 41 | static int print_hook(const char *fmt, ...) | 46 | static int print_hook(const char *fmt, ...) |
| 42 | { | 47 | { |
| @@ -47,18 +52,8 @@ static int print_hook(const char *fmt, ...) | |||
| 47 | vsnprintf(buf, sizeof(buf), fmt, args); | 52 | vsnprintf(buf, sizeof(buf), fmt, args); |
| 48 | va_end(args); | 53 | va_end(args); |
| 49 | len = strlen(buf); | 54 | len = strlen(buf); |
| 50 | while (*sn_oemdata_size + len + 1 > sn_oemdata_bufsize) { | 55 | if (*sn_oemdata_size + len <= sn_oemdata_bufsize) |
| 51 | u8 *newbuf = vmalloc(sn_oemdata_bufsize += 1000); | 56 | memcpy(*sn_oemdata + *sn_oemdata_size, buf, len); |
| 52 | if (!newbuf) { | ||
| 53 | printk(KERN_ERR "%s: unable to extend sn_oemdata\n", | ||
| 54 | __FUNCTION__); | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | memcpy(newbuf, *sn_oemdata, *sn_oemdata_size); | ||
| 58 | vfree(*sn_oemdata); | ||
| 59 | *sn_oemdata = newbuf; | ||
| 60 | } | ||
| 61 | memcpy(*sn_oemdata + *sn_oemdata_size, buf, len + 1); | ||
| 62 | *sn_oemdata_size += len; | 57 | *sn_oemdata_size += len; |
| 63 | return 0; | 58 | return 0; |
| 64 | } | 59 | } |
| @@ -98,7 +93,20 @@ sn_platform_plat_specific_err_print(const u8 * sect_header, u8 ** oemdata, | |||
| 98 | sn_oemdata = oemdata; | 93 | sn_oemdata = oemdata; |
| 99 | sn_oemdata_size = oemdata_size; | 94 | sn_oemdata_size = oemdata_size; |
| 100 | sn_oemdata_bufsize = 0; | 95 | sn_oemdata_bufsize = 0; |
| 101 | ia64_sn_plat_specific_err_print(print_hook, (char *)sect_header); | 96 | *sn_oemdata_size = PAGE_SIZE; /* first guess at how much data will be generated */ |
| 97 | while (*sn_oemdata_size > sn_oemdata_bufsize) { | ||
| 98 | u8 *newbuf = vmalloc(*sn_oemdata_size); | ||
| 99 | if (!newbuf) { | ||
| 100 | printk(KERN_ERR "%s: unable to extend sn_oemdata\n", | ||
| 101 | __FUNCTION__); | ||
| 102 | return 1; | ||
| 103 | } | ||
| 104 | vfree(*sn_oemdata); | ||
| 105 | *sn_oemdata = newbuf; | ||
| 106 | sn_oemdata_bufsize = *sn_oemdata_size; | ||
| 107 | *sn_oemdata_size = 0; | ||
| 108 | ia64_sn_plat_specific_err_print(print_hook, (char *)sect_header); | ||
| 109 | } | ||
| 102 | up(&sn_oemdata_mutex); | 110 | up(&sn_oemdata_mutex); |
| 103 | return 0; | 111 | return 0; |
| 104 | } | 112 | } |
