A trivial I/O module - Error

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux