Hi!
I am writing a very trivial module.
It uses submit_bio to write a page to a device and then read it back.
It works but submit_bio returns -5 error code when reading. Neverthless
the data is correctly read! The uptodate bit of bi_flags also does not
get set!
I am using k 2.26.29 on UML x86_64.
Any help?
TIA
/*
* ptm_bio01.c
* Using bio:
* Write a page to device.
* Read back that data.
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/blkdev.h>
#define MY_BLOCK_SIZE PAGE_SIZE
#define MODEFLAGS FMODE_READ|FMODE_WRITE /* Ex. FMODE_READ
(inlude/linux/fs.h) for opening read-only */
#define DEV "/dev/loop2"
MODULE_LICENSE("Dual BSD/GPL");
static struct bio *bio;
static struct page *page;
static struct block_device *bdev;
static void end_bio_write_sync(struct bio *bio, int err)
{ printk(KERN_INFO "Entering end_bio_write_sync ...\n");
end_page_writeback(page);
bio_put(bio);
if (err)
printk(KERN_INFO "end_bio_write_sync: Error n. %d\n",err);
printk(KERN_INFO "Exiting end_bio_write_sync ...\n");
}
static void end_bio_read_sync(struct bio *bio, int err)
{ int i;
short *page_data=page_address(page);
printk(KERN_INFO "Entering end_bio_read_sync ...\n");
/* *(int *)(bio->bi_private)=err; */
for (i=0;i<PAGE_SIZE/sizeof(*page_data);++i,page_data++)
{ if (*page_data!=i)
{ printk(KERN_INFO "Page data read does not match!!!\n");
break;
}
}
if (i==PAGE_SIZE/sizeof(*page_data))
printk(KERN_INFO "Page data read OK!\n");
bio_put(bio);
SetPageUptodate(page);
unlock_page(page);
if (err)
printk(KERN_INFO "end_bio_read_sync: Error n. %d\n",err);
printk(KERN_INFO "Exiting end_bio_read_sync ...\n");
}
/* static int __init ptm_bio01_init(void) */
/* I removed "__init" because initialization is all this module does */
static int ptm_bio01_init(void)
{ int err=0;
int flags=MODEFLAGS;
short *page_data;
int secsperpage=PAGE_SIZE/MY_BLOCK_SIZE;
int i;
printk(KERN_INFO "Writing a page - %d sectors\n",secsperpage);
/* Get a block device */
/* I used THIS_MODULE. Usually put the fstype here.
Everything it needs is a unique pointer of a owner */
bdev = open_bdev_exclusive(DEV, flags, THIS_MODULE);
if (IS_ERR(bdev))
{ err=PTR_ERR(bdev);
printk(KERN_INFO "Could not open_bdev_exclusive\n");
goto fail1;
}
/* Alloc and fill a page */
page=alloc_page(GFP_NOFS);
if (!page)
{ err=-ENOMEM;
printk(KERN_INFO "Could not alloc_page\n");
goto fail2;
}
lock_page(page);
page_data=page_address(page);
if (!page_data)
{ err=-1;
printk(KERN_INFO "Could not get the address of the page!!! Use
kmap(?)\n");
goto fail3;
}
for (i=0;i<PAGE_SIZE/sizeof(*page_data);++i,page_data++)
*page_data=i;
/* Alloc the bio for n. sects per page sectors */
bio=bio_alloc(GFP_NOIO, secsperpage);
if (!bio)
{ err=-ENOMEM;
printk(KERN_INFO "Could not allocate a bio W\n");
goto fail3;
}
bio->bi_sector=1; /* Device address in 512 bytes sectors.
1 -> 512 bytes from beginning of disk.
*/
bio->bi_bdev=bdev;
for (i=0;i<secsperpage;++i)
{ bio->bi_io_vec[i].bv_page=page;
bio->bi_io_vec[i].bv_len=MY_BLOCK_SIZE;
bio->bi_io_vec[i].bv_offset=i*MY_BLOCK_SIZE;
}
bio->bi_vcnt=secsperpage; /* how many bio_vec's */
bio->bi_idx=0; /* current index into bvl_vec */
bio->bi_size=PAGE_SIZE; /* residual I/O count */
bio->bi_end_io=end_bio_write_sync;
/* bio->bi_private=&err; */
bio_get(bio);
TestSetPageWriteback(page);
unlock_page(page);
submit_bio(WRITE, bio);
if (bio_flagged(bio, BIO_EOPNOTSUPP))
{ err=-EOPNOTSUPP;
printk(KERN_INFO "Could not submit_bio W\n");
goto fail4;
}
wait_on_page_writeback(page);
#if 1
bio_put(bio);
bio=bio_alloc(GFP_KERNEL, secsperpage);
if (!bio)
{ err=-ENOMEM;
printk(KERN_INFO "Could not allocate a bio R\n");
goto fail3;
}
/* Read the page */
bio->bi_sector=1; /* Device address in 512 bytes sectors.
1 -> 512 bytes from beginning of disk.
DDDD: Why 512 bytes? */
bio->bi_bdev=bdev;
for (i=0;i<secsperpage;++i)
{ bio->bi_io_vec[i].bv_page=page;
bio->bi_io_vec[i].bv_len=MY_BLOCK_SIZE;
bio->bi_io_vec[i].bv_offset=i*MY_BLOCK_SIZE;
}
bio->bi_vcnt=secsperpage; /* how many bio_vec's */
bio->bi_idx=0; /* current index into bvl_vec */
bio->bi_size=PAGE_SIZE; /* residual I/O count */
#endif
bio->bi_end_io=end_bio_read_sync;
/* bio->bi_private=&err; */
bio->bi_rw=0;
clear_bit(BIO_UPTODATE,&bio->bi_flags);
bio_get(bio);
lock_page(page);
/* Clear the page */
page_data=page_address(page);
if (!page_data)
{ unlock_page(page);
err=-1;
printk(KERN_INFO "Could not get the address of the page!!! Use
kmap(?)\n");
goto fail4;
}
memset(page_data,0,PAGE_SIZE);
ClearPageUptodate(page);
/* go and read */
submit_bio(READ, bio);
if (bio_flagged(bio, BIO_EOPNOTSUPP))
{ err=-EOPNOTSUPP;
printk(KERN_INFO "Could not submit_bio R\n");
goto fail4;
}
lock_page(page);
page_data=page_address(page);
if (!page_data)
{ err=-1;
printk(KERN_INFO "Could not get the address of the page!!! Use
kmap(?)\n");
goto fail4;
}
for (i=0;i<PAGE_SIZE/sizeof(*page_data);++i,page_data++)
{ if (*page_data!=i)
{ printk(KERN_INFO "Page data read does not match!!!\n");
break;
}
}
if (i==PAGE_SIZE/sizeof(*page_data))
printk(KERN_INFO "Page data read OK!\n");
unlock_page(page);
printk(KERN_INFO "Ending init!\n");
return 0;
fail4:
bio_put(bio);
fail3:
__free_page(page);
page=NULL;
fail2:
close_bdev_exclusive(bdev,flags);
bdev=NULL;
fail1:
if (err)
printk(KERN_INFO "Error n. %d\n",err);
return err;
}
static void __exit ptm_bio01_exit(void)
{ int flags=MODEFLAGS; /* Must be the same as in init */
if (atomic_read(&bio->bi_cnt))
{ bio_put(bio);
}
if (page && atomic_read(&page->_count))
{ __free_page(page);
}
if (bdev)
close_bdev_exclusive(bdev,flags);
printk(KERN_INFO "Going out ...\n");
}
module_init(ptm_bio01_init);
module_exit(ptm_bio01_exit);
--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to [email protected]
Please read the FAQ at http://kernelnewbies.org/FAQ