Re: 2.5.41 - kernel NULL pointer

From: Andrew Morton (akpm@digeo.com)
Date: Thu Oct 10 2002 - 18:03:42 EST


Cliff White wrote:
>
> System is 2-CPU PIII
> Attempting to start the SAP DB. Get this msg:
> SAP cannot open the sys devspace (which is on filesystem)
> DB setup does include one raw partition.
> Further details upon request
> cliffw
>
> Unable to handle kernel NULL pointer dereference at virtual address 00000000
> ...
> [<c01711a9>] generic_file_direct_IO+0x59/0x73

The raw driver was broken by the NFS direct IO merge. It's
unbroken in Linus' current tree. And some additional fixes
are needed on top of that.

--- 2.5.41/fs/direct-io.c~dio-bio-add-fix-1 Thu Oct 10 15:21:51 2002
+++ 2.5.41-akpm/fs/direct-io.c Thu Oct 10 15:52:50 2002
@@ -388,7 +388,7 @@ static void dio_prep_bio(struct dio *dio
 /*
  * There is no bio. Make one now.
  */
-static int dio_new_bio(struct dio *dio)
+static int dio_new_bio(struct dio *dio, sector_t blkno)
 {
         sector_t sector;
         int ret, nr_pages;
@@ -396,7 +396,7 @@ static int dio_new_bio(struct dio *dio)
         ret = dio_bio_reap(dio);
         if (ret)
                 goto out;
- sector = dio->next_block_in_bio << (dio->blkbits - 9);
+ sector = blkno << (dio->blkbits - 9);
         nr_pages = min(dio->pages_left, bio_get_nr_vecs(dio->map_bh.b_bdev));
         BUG_ON(nr_pages <= 0);
         ret = dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages);
@@ -408,22 +408,28 @@ out:
 
 static int
 dio_bio_add_page(struct dio *dio, struct page *page,
- unsigned int bv_len, unsigned int bv_offset)
+ unsigned int bv_len, unsigned int bv_offset, sector_t blkno)
 {
         int ret = 0;
 
         if (bv_len == 0)
                 goto out;
 
+ /* Take a ref against the page each time it is placed into a BIO */
         page_cache_get(page);
         if (bio_add_page(dio->bio, page, bv_len, bv_offset)) {
                 dio_bio_submit(dio);
- ret = dio_new_bio(dio);
+ ret = dio_new_bio(dio, blkno);
                 if (ret == 0) {
                         ret = bio_add_page(dio->bio, page, bv_len, bv_offset);
                         BUG_ON(ret != 0);
+ } else {
+ /* The page didn't make it into a BIO */
+ page_cache_release(page);
                 }
         }
+
+ /* Drop the ref which was taken in get_user_pages() */
         page_cache_release(page);
         dio->pages_left--;
 out:
@@ -460,6 +466,7 @@ int do_direct_IO(struct dio *dio)
                 int new_page; /* Need to insert this page into the BIO? */
                 unsigned int bv_offset;
                 unsigned int bv_len;
+ sector_t curr_blkno;
 
                 page = dio_get_page(dio);
                 if (IS_ERR(page)) {
@@ -470,6 +477,7 @@ int do_direct_IO(struct dio *dio)
                 new_page = 1;
                 bv_offset = 0;
                 bv_len = 0;
+ curr_blkno = 0;
                 while (block_in_page < blocks_per_page) {
                         unsigned this_chunk_bytes; /* # of bytes mapped */
                         unsigned this_chunk_blocks; /* # of blocks */
@@ -494,7 +502,7 @@ int do_direct_IO(struct dio *dio)
 
                         dio_prep_bio(dio);
                         if (dio->bio == NULL) {
- ret = dio_new_bio(dio);
+ ret = dio_new_bio(dio, dio->next_block_in_bio);
                                 if (ret)
                                         goto out;
                                 new_page = 1;
@@ -503,6 +511,7 @@ int do_direct_IO(struct dio *dio)
                         if (new_page) {
                                 bv_len = 0;
                                 bv_offset = block_in_page << blkbits;
+ curr_blkno = dio->next_block_in_bio;
                                 new_page = 0;
                         }
 
@@ -530,7 +539,7 @@ next_block:
                         if (dio->block_in_file == dio->final_block_in_request)
                                 break;
                 }
- ret = dio_bio_add_page(dio, page, bv_len, bv_offset);
+ ret = dio_bio_add_page(dio, page, bv_len, bv_offset, curr_blkno);
                 if (ret)
                         goto out;
                 block_in_page = 0;

.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Oct 15 2002 - 22:00:39 EST