Commit c21c3ad0 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] convert direct-io to use bio_add_page()

From Badari Pavlati.

Use bio_add_page() in direct-io.c.
parent 7b88e5e0
......@@ -23,12 +23,6 @@
#include <linux/rwsem.h>
#include <asm/atomic.h>
/*
* The largest-sized BIO which this code will assemble, in bytes. Set this
* to PAGE_SIZE if your drivers are broken.
*/
#define DIO_BIO_MAX_SIZE (16*1024)
/*
* How many user pages to map in one call to get_user_pages(). This determines
* the size of a structure on the stack.
......@@ -38,7 +32,6 @@
struct dio {
/* BIO submission state */
struct bio *bio; /* bio under assembly */
struct bio_vec *bvec; /* current bvec in that bio */
struct inode *inode;
int rw;
unsigned blkbits; /* doesn't change */
......@@ -180,15 +173,10 @@ dio_bio_alloc(struct dio *dio, struct block_device *bdev,
return -ENOMEM;
bio->bi_bdev = bdev;
bio->bi_vcnt = nr_vecs;
bio->bi_idx = 0;
bio->bi_size = 0;
bio->bi_sector = first_sector;
bio->bi_io_vec[0].bv_page = NULL;
bio->bi_end_io = dio_bio_end_io;
dio->bio = bio;
dio->bvec = NULL; /* debug */
return 0;
}
......@@ -196,14 +184,11 @@ static void dio_bio_submit(struct dio *dio)
{
struct bio *bio = dio->bio;
bio->bi_vcnt = bio->bi_idx;
bio->bi_idx = 0;
bio->bi_private = dio;
atomic_inc(&dio->bio_count);
submit_bio(dio->rw, bio);
dio->bio = NULL;
dio->bvec = NULL;
dio->boundary = 0;
}
......@@ -394,8 +379,7 @@ static void dio_prep_bio(struct dio *dio)
if (dio->bio == NULL)
return;
if (dio->bio->bi_idx == dio->bio->bi_vcnt ||
dio->boundary ||
if (dio->boundary ||
dio->last_block_in_bio != dio->next_block_in_bio - 1)
dio_bio_submit(dio);
}
......@@ -406,19 +390,44 @@ static void dio_prep_bio(struct dio *dio)
static int dio_new_bio(struct dio *dio)
{
sector_t sector;
int ret;
int ret, nr_pages;
ret = dio_bio_reap(dio);
if (ret)
goto out;
sector = dio->next_block_in_bio << (dio->blkbits - 9);
ret = dio_bio_alloc(dio, dio->map_bh.b_bdev, sector,
DIO_BIO_MAX_SIZE / PAGE_SIZE);
nr_pages = min(dio->total_pages, BIO_MAX_PAGES);
ret = dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages);
dio->boundary = 0;
out:
return ret;
}
static int
dio_bio_add_page(struct dio *dio, struct page *page,
unsigned int bv_len, unsigned int bv_offset)
{
int ret = 0;
if (bv_len == 0)
goto out;
page_cache_get(page);
if (bio_add_page(dio->bio, page, bv_len, bv_offset)) {
dio_bio_submit(dio);
ret = dio_new_bio(dio);
if (ret == 0) {
ret = bio_add_page(dio->bio, page, bv_len, bv_offset);
BUG_ON(ret != 0);
}
}
page_cache_release(page);
out:
return ret;
}
/*
* Walk the user pages, and the file, mapping blocks to disk and emitting BIOs.
*
......@@ -439,13 +448,15 @@ int do_direct_IO(struct dio *dio)
const unsigned blocks_per_page = PAGE_SIZE >> blkbits;
struct page *page;
unsigned block_in_page;
int ret;
int ret = 0;
/* The I/O can start at any block offset within the first page */
block_in_page = dio->first_block_in_page;
while (dio->block_in_file < dio->final_block_in_request) {
int new_page; /* Need to insert this page into the BIO? */
unsigned int bv_offset;
unsigned int bv_len;
page = dio_get_page(dio);
if (IS_ERR(page)) {
......@@ -454,15 +465,16 @@ int do_direct_IO(struct dio *dio)
}
new_page = 1;
bv_offset = 0;
bv_len = 0;
while (block_in_page < blocks_per_page) {
struct bio *bio;
unsigned this_chunk_bytes; /* # of bytes mapped */
unsigned this_chunk_blocks; /* # of blocks */
unsigned u;
ret = get_more_blocks(dio);
if (ret)
goto fail_release;
goto out;
/* Handle holes */
if (!buffer_mapped(&dio->map_bh)) {
......@@ -481,24 +493,19 @@ int do_direct_IO(struct dio *dio)
if (dio->bio == NULL) {
ret = dio_new_bio(dio);
if (ret)
goto fail_release;
goto out;
new_page = 1;
}
bio = dio->bio;
if (new_page) {
dio->bvec = &bio->bi_io_vec[bio->bi_idx];
page_cache_get(page);
dio->bvec->bv_page = page;
dio->bvec->bv_len = 0;
dio->bvec->bv_offset = block_in_page << blkbits;
bio->bi_idx++;
bv_len = 0;
bv_offset = block_in_page << blkbits;
new_page = 0;
}
/* Work out how much disk we can add to this page */
this_chunk_blocks = dio->blocks_available;
u = (PAGE_SIZE - (dio->bvec->bv_offset + dio->bvec->bv_len)) >> blkbits;
u = (PAGE_SIZE - (bv_len + bv_offset)) >> blkbits;
if (this_chunk_blocks > u)
this_chunk_blocks = u;
u = dio->final_block_in_request - dio->block_in_file;
......@@ -507,8 +514,7 @@ int do_direct_IO(struct dio *dio)
this_chunk_bytes = this_chunk_blocks << blkbits;
BUG_ON(this_chunk_bytes == 0);
dio->bvec->bv_len += this_chunk_bytes;
bio->bi_size += this_chunk_bytes;
bv_len += this_chunk_bytes;
dio->next_block_in_bio += this_chunk_blocks;
dio->last_block_in_bio = dio->next_block_in_bio - 1;
dio->boundary = buffer_boundary(&dio->map_bh);
......@@ -521,13 +527,11 @@ int do_direct_IO(struct dio *dio)
if (dio->block_in_file == dio->final_block_in_request)
break;
}
ret = dio_bio_add_page(dio, page, bv_len, bv_offset);
if (ret)
goto out;
block_in_page = 0;
page_cache_release(page);
}
ret = 0;
goto out;
fail_release:
page_cache_release(page);
out:
return ret;
}
......@@ -543,7 +547,6 @@ direct_io_worker(int rw, struct inode *inode, const struct iovec *iov,
size_t bytes, tot_bytes = 0;
dio.bio = NULL;
dio.bvec = NULL;
dio.inode = inode;
dio.rw = rw;
dio.blkbits = blkbits;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment