aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorMel Gorman <mel@csn.ul.ie>2009-12-07 16:10:46 -0500
committerJens Axboe <jens.axboe@oracle.com>2009-12-09 09:11:03 -0500
commita3b8d92d25212c5b6534ae9b347ed2858de78336 (patch)
treedd61cbc89814f179c85fd404fbe499142ea0d7fb /drivers/block
parent8b43aebdaa4fa3348dafd6f2f5f526bd3e8b84ac (diff)
block,xd: Delay allocation of DMA buffers until device is known
Loading the XD module triggers a warning like WARNING: at mm/page_alloc.c:1805 __alloc_pages_nodemask+0x127/0x48f() Hardware name: System Product Name Modules linked in: Pid: 1, comm: swapper Not tainted 2.6.32-rc8-git5 #1 Call Trace: [<c103d94b>] warn_slowpath_common+0x65/0x95 [<c103d98d>] warn_slowpath_null+0x12/0x15 [<c109550c>] __alloc_pages_nodemask+0x127/0x48f [<c10be964>] ? get_slab+0x8/0x50 [<c10b8979>] alloc_page_interleave+0x2e/0x6e [<c10b8a10>] alloc_pages_current+0x57/0x99 [<c2083a4a>] ? xd_init+0x0/0x482 [<c1094c38>] __get_free_pages+0xd/0x1e [<c2083a94>] xd_init+0x4a/0x482 [<c2082df0>] ? loop_init+0x104/0x16a [<c169162d>] ? loop_probe+0x0/0xaf [<c2083a4a>] ? xd_init+0x0/0x482 [<c1001143>] do_one_initcall+0x51/0x13f [<c204a307>] kernel_init+0x10b/0x15f [<c204a1fc>] ? kernel_init+0x0/0x15f [<c1004347>] kernel_thread_helper+0x7/0x10 ---[ end trace 686db6333ade6e7a ]--- xd: Out of memory. The warning is because the alloc_pages is called with an order >= MAX_ORDER. The simplistic reason is that get_order(0) returns garbage values when given 0 as a size. The more complex reason is that the XD driver initialisation is broken. It's not clear why this ever worked. XD allocates a buffer for DMA based on the value of xd_maxsectors. This value is determined by the exact type of controller in use but the value is determined *after* an attempt has been made to allocate the buffer. i.e. the requested size of the DMA buffer will always be 0. This patch alters how XD is initialised slightly by allocating the buffer when and if a device has actually been detected. The error paths are updated to suit the new logic. Signed-off-by: Mel Gorman <mel@csn.ul.ie> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/xd.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 0877d3628fda..d1fd032e7514 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -169,13 +169,6 @@ static int __init xd_init(void)
169 169
170 init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog; 170 init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
171 171
172 if (!xd_dma_buffer)
173 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
174 if (!xd_dma_buffer) {
175 printk(KERN_ERR "xd: Out of memory.\n");
176 return -ENOMEM;
177 }
178
179 err = -EBUSY; 172 err = -EBUSY;
180 if (register_blkdev(XT_DISK_MAJOR, "xd")) 173 if (register_blkdev(XT_DISK_MAJOR, "xd"))
181 goto out1; 174 goto out1;
@@ -202,6 +195,19 @@ static int __init xd_init(void)
202 xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma); 195 xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
203 } 196 }
204 197
198 /*
199 * With the drive detected, xd_maxsectors should now be known.
200 * If xd_maxsectors is 0, nothing was detected and we fall through
201 * to return -ENODEV
202 */
203 if (!xd_dma_buffer && xd_maxsectors) {
204 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
205 if (!xd_dma_buffer) {
206 printk(KERN_ERR "xd: Out of memory.\n");
207 goto out3;
208 }
209 }
210
205 err = -ENODEV; 211 err = -ENODEV;
206 if (!xd_drives) 212 if (!xd_drives)
207 goto out3; 213 goto out3;
@@ -249,15 +255,17 @@ out4:
249 for (i = 0; i < xd_drives; i++) 255 for (i = 0; i < xd_drives; i++)
250 put_disk(xd_gendisk[i]); 256 put_disk(xd_gendisk[i]);
251out3: 257out3:
252 release_region(xd_iobase,4); 258 if (xd_maxsectors)
259 release_region(xd_iobase,4);
260
261 if (xd_dma_buffer)
262 xd_dma_mem_free((unsigned long)xd_dma_buffer,
263 xd_maxsectors * 0x200);
253out2: 264out2:
254 blk_cleanup_queue(xd_queue); 265 blk_cleanup_queue(xd_queue);
255out1a: 266out1a:
256 unregister_blkdev(XT_DISK_MAJOR, "xd"); 267 unregister_blkdev(XT_DISK_MAJOR, "xd");
257out1: 268out1:
258 if (xd_dma_buffer)
259 xd_dma_mem_free((unsigned long)xd_dma_buffer,
260 xd_maxsectors * 0x200);
261 return err; 269 return err;
262Enomem: 270Enomem:
263 err = -ENOMEM; 271 err = -ENOMEM;