diff --git a/fs/direct-io.c b/fs/direct-io.c index b912270942fa..9f34bb9b1ecb 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -104,22 +104,6 @@ struct dio { unsigned cur_page_len; /* Nr of bytes at cur_page_offset */ sector_t cur_page_block; /* Where it starts */ - /* - * Page fetching state. These variables belong to dio_refill_pages(). - */ - int curr_page; /* changes */ - int total_pages; /* doesn't change */ - unsigned long curr_user_address;/* changes */ - - /* - * Page queue. These variables belong to dio_refill_pages() and - * dio_get_page(). - */ - struct page *pages[DIO_PAGES]; /* page buffer */ - unsigned head; /* next page to process */ - unsigned tail; /* last valid page + 1 */ - int page_errors; /* errno from get_user_pages() */ - /* BIO completion state */ spinlock_t bio_lock; /* protects BIO fields below */ unsigned long refcount; /* direct_io_worker() and bios */ @@ -131,6 +115,28 @@ struct dio { int is_async; /* is IO async ? */ int io_error; /* IO error in completion path */ ssize_t result; /* IO result */ + + /* + * Page fetching state. These variables belong to dio_refill_pages(). + */ + int curr_page; /* changes */ + int total_pages; /* doesn't change */ + unsigned long curr_user_address;/* changes */ + + /* + * Page queue. These variables belong to dio_refill_pages() and + * dio_get_page(). + */ + unsigned head; /* next page to process */ + unsigned tail; /* last valid page + 1 */ + int page_errors; /* errno from get_user_pages() */ + + /* + * pages[] (and any fields placed after it) are not zeroed out at + * allocation time. Don't add new fields after pages[] unless you + * wish that they not be zeroed. + */ + struct page *pages[DIO_PAGES]; /* page buffer */ }; /* @@ -1151,10 +1157,16 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } } - dio = kzalloc(sizeof(*dio), GFP_KERNEL); + dio = kmalloc(sizeof(*dio), GFP_KERNEL); retval = -ENOMEM; if (!dio) goto out; + /* + * Believe it or not, zeroing out the page array caused a .5% + * performance regression in a database benchmark. So, we take + * care to only zero out what's needed. + */ + memset(dio, 0, offsetof(struct dio, pages)); /* * For block device access DIO_NO_LOCKING is used,