diff options
author | Borislav Petkov <petkovbb@googlemail.com> | 2008-04-27 09:38:32 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2008-04-27 09:38:32 -0400 |
commit | 41aa17069ea8d2b5cd2ca1ef7ff6cdb7c6abec95 (patch) | |
tree | bf622ae5f84894a20fba961d010e083372b19e4d /drivers/ide/ide-tape.c | |
parent | 4c3032d8a4d6c97bd6e02bcab524ef2428d89561 (diff) |
ide-tape: improve buffer allocation strategy
Instead of allocating pages for the buffer one by one, take advantage of the
buddy alloc system and request them 2^order at a time. This increases the chance
for bigger buffer parts to be contigious and reduces loop iteration count. While
at it, rename function __idetape_kmalloc_stage() to ide_tape_kmalloc_buffer().
[bart: fold with "ide-tape: fix mem leak" patch to preserve bisectability]
Signed-off-by: Borislav Petkov <petkovbb@gmail.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/ide-tape.c')
-rw-r--r-- | drivers/ide/ide-tape.c | 60 |
1 files changed, 37 insertions, 23 deletions
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 2275cd22902c..dc7abb25a8eb 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c | |||
@@ -1290,20 +1290,20 @@ out: | |||
1290 | } | 1290 | } |
1291 | 1291 | ||
1292 | /* | 1292 | /* |
1293 | * The function below uses __get_free_page to allocate a pipeline stage, along | 1293 | * The function below uses __get_free_pages to allocate a data buffer of size |
1294 | * with all the necessary small buffers which together make a buffer of size | ||
1295 | * tape->stage_size (or a bit more). We attempt to combine sequential pages as | 1294 | * tape->stage_size (or a bit more). We attempt to combine sequential pages as |
1296 | * much as possible. | 1295 | * much as possible. |
1297 | * | 1296 | * |
1298 | * It returns a pointer to the new allocated stage, or NULL if we can't (or | 1297 | * It returns a pointer to the newly allocated buffer, or NULL in case of |
1299 | * don't want to) allocate a stage. | 1298 | * failure. |
1300 | */ | 1299 | */ |
1301 | static idetape_stage_t *__idetape_kmalloc_stage(idetape_tape_t *tape, int full, | 1300 | static idetape_stage_t *ide_tape_kmalloc_buffer(idetape_tape_t *tape, int full, |
1302 | int clear) | 1301 | int clear) |
1303 | { | 1302 | { |
1304 | idetape_stage_t *stage; | 1303 | idetape_stage_t *stage; |
1305 | struct idetape_bh *prev_bh, *bh; | 1304 | struct idetape_bh *prev_bh, *bh; |
1306 | int pages = tape->pages_per_stage; | 1305 | int pages = tape->pages_per_stage; |
1306 | unsigned int order, b_allocd; | ||
1307 | char *b_data = NULL; | 1307 | char *b_data = NULL; |
1308 | 1308 | ||
1309 | stage = kmalloc(sizeof(idetape_stage_t), GFP_KERNEL); | 1309 | stage = kmalloc(sizeof(idetape_stage_t), GFP_KERNEL); |
@@ -1315,46 +1315,60 @@ static idetape_stage_t *__idetape_kmalloc_stage(idetape_tape_t *tape, int full, | |||
1315 | bh = stage->bh; | 1315 | bh = stage->bh; |
1316 | if (bh == NULL) | 1316 | if (bh == NULL) |
1317 | goto abort; | 1317 | goto abort; |
1318 | bh->b_reqnext = NULL; | 1318 | |
1319 | bh->b_data = (char *) __get_free_page(GFP_KERNEL); | 1319 | order = fls(pages) - 1; |
1320 | bh->b_data = (char *) __get_free_pages(GFP_KERNEL, order); | ||
1320 | if (!bh->b_data) | 1321 | if (!bh->b_data) |
1321 | goto abort; | 1322 | goto abort; |
1323 | b_allocd = (1 << order) * PAGE_SIZE; | ||
1324 | pages &= (order-1); | ||
1325 | |||
1322 | if (clear) | 1326 | if (clear) |
1323 | memset(bh->b_data, 0, PAGE_SIZE); | 1327 | memset(bh->b_data, 0, b_allocd); |
1324 | bh->b_size = PAGE_SIZE; | 1328 | bh->b_reqnext = NULL; |
1329 | bh->b_size = b_allocd; | ||
1325 | atomic_set(&bh->b_count, full ? bh->b_size : 0); | 1330 | atomic_set(&bh->b_count, full ? bh->b_size : 0); |
1326 | 1331 | ||
1327 | while (--pages) { | 1332 | while (pages) { |
1328 | b_data = (char *) __get_free_page(GFP_KERNEL); | 1333 | order = fls(pages) - 1; |
1334 | b_data = (char *) __get_free_pages(GFP_KERNEL, order); | ||
1329 | if (!b_data) | 1335 | if (!b_data) |
1330 | goto abort; | 1336 | goto abort; |
1337 | b_allocd = (1 << order) * PAGE_SIZE; | ||
1338 | |||
1331 | if (clear) | 1339 | if (clear) |
1332 | memset(b_data, 0, PAGE_SIZE); | 1340 | memset(b_data, 0, b_allocd); |
1333 | if (bh->b_data == b_data + PAGE_SIZE) { | 1341 | |
1334 | bh->b_size += PAGE_SIZE; | 1342 | /* newly allocated page frames below buffer header or ...*/ |
1335 | bh->b_data -= PAGE_SIZE; | 1343 | if (bh->b_data == b_data + b_allocd) { |
1344 | bh->b_size += b_allocd; | ||
1345 | bh->b_data -= b_allocd; | ||
1336 | if (full) | 1346 | if (full) |
1337 | atomic_add(PAGE_SIZE, &bh->b_count); | 1347 | atomic_add(b_allocd, &bh->b_count); |
1338 | continue; | 1348 | continue; |
1339 | } | 1349 | } |
1350 | /* they are above the header */ | ||
1340 | if (b_data == bh->b_data + bh->b_size) { | 1351 | if (b_data == bh->b_data + bh->b_size) { |
1341 | bh->b_size += PAGE_SIZE; | 1352 | bh->b_size += b_allocd; |
1342 | if (full) | 1353 | if (full) |
1343 | atomic_add(PAGE_SIZE, &bh->b_count); | 1354 | atomic_add(b_allocd, &bh->b_count); |
1344 | continue; | 1355 | continue; |
1345 | } | 1356 | } |
1346 | prev_bh = bh; | 1357 | prev_bh = bh; |
1347 | bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); | 1358 | bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); |
1348 | if (!bh) { | 1359 | if (!bh) { |
1349 | free_page((unsigned long) b_data); | 1360 | free_pages((unsigned long) b_data, order); |
1350 | goto abort; | 1361 | goto abort; |
1351 | } | 1362 | } |
1352 | bh->b_reqnext = NULL; | 1363 | bh->b_reqnext = NULL; |
1353 | bh->b_data = b_data; | 1364 | bh->b_data = b_data; |
1354 | bh->b_size = PAGE_SIZE; | 1365 | bh->b_size = b_allocd; |
1355 | atomic_set(&bh->b_count, full ? bh->b_size : 0); | 1366 | atomic_set(&bh->b_count, full ? bh->b_size : 0); |
1356 | prev_bh->b_reqnext = bh; | 1367 | prev_bh->b_reqnext = bh; |
1368 | |||
1369 | pages &= (order-1); | ||
1357 | } | 1370 | } |
1371 | |||
1358 | bh->b_size -= tape->excess_bh_size; | 1372 | bh->b_size -= tape->excess_bh_size; |
1359 | if (full) | 1373 | if (full) |
1360 | atomic_sub(tape->excess_bh_size, &bh->b_count); | 1374 | atomic_sub(tape->excess_bh_size, &bh->b_count); |
@@ -1837,7 +1851,7 @@ static int idetape_init_read(ide_drive_t *drive) | |||
1837 | " 0 now\n"); | 1851 | " 0 now\n"); |
1838 | tape->merge_stage_size = 0; | 1852 | tape->merge_stage_size = 0; |
1839 | } | 1853 | } |
1840 | tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0); | 1854 | tape->merge_stage = ide_tape_kmalloc_buffer(tape, 0, 0); |
1841 | if (!tape->merge_stage) | 1855 | if (!tape->merge_stage) |
1842 | return -ENOMEM; | 1856 | return -ENOMEM; |
1843 | tape->chrdev_dir = IDETAPE_DIR_READ; | 1857 | tape->chrdev_dir = IDETAPE_DIR_READ; |
@@ -2115,7 +2129,7 @@ static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, | |||
2115 | "should be 0 now\n"); | 2129 | "should be 0 now\n"); |
2116 | tape->merge_stage_size = 0; | 2130 | tape->merge_stage_size = 0; |
2117 | } | 2131 | } |
2118 | tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0); | 2132 | tape->merge_stage = ide_tape_kmalloc_buffer(tape, 0, 0); |
2119 | if (!tape->merge_stage) | 2133 | if (!tape->merge_stage) |
2120 | return -ENOMEM; | 2134 | return -ENOMEM; |
2121 | tape->chrdev_dir = IDETAPE_DIR_WRITE; | 2135 | tape->chrdev_dir = IDETAPE_DIR_WRITE; |
@@ -2495,7 +2509,7 @@ static void idetape_write_release(ide_drive_t *drive, unsigned int minor) | |||
2495 | idetape_tape_t *tape = drive->driver_data; | 2509 | idetape_tape_t *tape = drive->driver_data; |
2496 | 2510 | ||
2497 | idetape_empty_write_pipeline(drive); | 2511 | idetape_empty_write_pipeline(drive); |
2498 | tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0); | 2512 | tape->merge_stage = ide_tape_kmalloc_buffer(tape, 1, 0); |
2499 | if (tape->merge_stage != NULL) { | 2513 | if (tape->merge_stage != NULL) { |
2500 | idetape_pad_zeros(drive, tape->blk_size * | 2514 | idetape_pad_zeros(drive, tape->blk_size * |
2501 | (tape->user_bs_factor - 1)); | 2515 | (tape->user_bs_factor - 1)); |