LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-04-2010, 09:10 AM   #1
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092
Blog Entries: 1

Rep: Reputation: 90
more linux development newbie questions about sbull.c


Hi!

I'm working on the sbull.c code from http://www.kernel-labs.org/?q=blockdriver.

Because of the difference between the linux version used to develop that code at the time and what I'm using right now (kubuntu lucid) there appears to have been some api changes.

One of them is not having elv_next_request anymore but blk_fetch_request. But now I find more things have changed. What do I have to call instead now?

For example, end_request is not anymore. I find blk_end_request from linux/blkdev.h but it expects a third argument. There's another function called blk_end_request_cur that expects the same two arguments in sbull.c. Can I use that function instead?
 
Old 12-04-2010, 11:21 AM   #2
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092

Original Poster
Blog Entries: 1

Rep: Reputation: 90
Though I'm still not there yet, I think I'm getting close to it. The .c file can be compiled but I'm getting a warning that I'm sure will be a problem if I try to load the module.

The code is like this right now
Code:
/*
 * A sample, extra-simple block driver.
 *
 * Copyright 2003 Eklektix, Inc.  Redistributable under the terms
 * of the GNU GPL.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h> /* printk() */
#include <linux/fs.h>     /* everything... */
#include <linux/errno.h>  /* error codes */
#include <linux/types.h>  /* size_t */
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/blkdev.h>

MODULE_LICENSE("Dual BSD/GPL");
static char *Version = "1.3";

static int major_num = 0;
module_param(major_num, int, 0);
static int hardsect_size = 512;
module_param(hardsect_size, int, 0);
static int nsectors = 1024;  /* How big the drive is */
module_param(nsectors, int, 0);

/*
 * We can tweak our hardware sector size, but the kernel talks to us
 * in terms of small sectors, always.
 */
#define KERNEL_SECTOR_SIZE 512

/*
 * Our request queue.
 */
static struct request_queue *Queue;

/*
 * The internal representation of our device.
 */
static struct sbd_device {
    unsigned long size;
    spinlock_t lock;
    u8 *data;
    struct gendisk *gd;
} Device;


/*
 * Handle an I/O request.
 */
static void sbd_transfer(struct sbd_device *dev, struct request *q)
{
    unsigned long offset = blk_rq_pos(q)*hardsect_size;
    unsigned long nbytes = blk_rq_cur_sectors(q)*hardsect_size;
    
    if ((offset + nbytes) > dev->size) {
        printk (KERN_NOTICE "sbd: Beyond-end write (%ld %ld)\n", offset, nbytes);
        return;
    }
    if (rq_data_dir(q))
        // write
        memcpy(dev->data + offset, q->buffer, nbytes);
    else
        // read
        memcpy(q->buffer, dev->data + offset, nbytes);
}

static void sbd_request(struct request_queue *q)
{
    struct request *req;

    while ((req = blk_fetch_request(q)) != NULL) {
        if (! blk_fs_request(req)) {
            printk (KERN_NOTICE "Skip non-CMD request\n");
            blk_end_request_cur(req, 0);
            continue;
        }
        sbd_transfer(&Device, req);
        blk_end_request_cur(req, 1);
    }
}



/*
 * Ioctl.
 */
int sbd_ioctl (struct inode *inode, struct file *filp,
                 unsigned int cmd, unsigned long arg)
{
        long size;
        struct hd_geometry geo;

        switch(cmd) {
        /*
         * The only command we need to interpret is HDIO_GETGEO, since
         * we can't partition the drive otherwise.  We have no real
         * geometry, of course, so make something up.
         */
            case HDIO_GETGEO:
                size = Device.size*(hardsect_size/KERNEL_SECTOR_SIZE);
                geo.cylinders = (size & ~0x3f) >> 6;
                geo.heads = 4;
                geo.sectors = 16;
                geo.start = 4;
                if (copy_to_user((void *) arg, &geo, sizeof(geo)))
                        return -EFAULT;
                return 0;
    }

    return -ENOTTY; /* unknown command */
}




/*
 * The device operations structure.
 */
static struct block_device_operations sbd_ops = {
    .owner           = THIS_MODULE,
    .ioctl           = sbd_ioctl
};

static int __init sbd_init(void)
{
/*
 * Set up our internal device.
 */
    Device.size = nsectors*hardsect_size;
    spin_lock_init(&Device.lock);
    Device.data = vmalloc(Device.size);
    if (Device.data == NULL)
        return -ENOMEM;
/*
 * Get a request queue.
 */
    Queue = blk_init_queue(sbd_request, &Device.lock);
    if (Queue == NULL)
            goto out;
    blk_queue_logical_block_size(Queue, hardsect_size);
/*
 * Get registered.
 */
    major_num = register_blkdev(major_num, "sbd");
    if (major_num <= 0) {
        printk(KERN_WARNING "sbd: unable to get major number\n");
        goto out;
    }
/*
 * And the gendisk structure.
 */
    Device.gd = alloc_disk(16);
    if (! Device.gd)
        goto out_unregister;
    Device.gd->major = major_num;
    Device.gd->first_minor = 0;
    Device.gd->fops = &sbd_ops;
    Device.gd->private_data = &Device;
    strcpy (Device.gd->disk_name, "sbd0");
    set_capacity(Device.gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));
    Device.gd->queue = Queue;
    add_disk(Device.gd);

    return 0;

  out_unregister:
    unregister_blkdev(major_num, "sbd");
  out:
    vfree(Device.data);
    return -ENOMEM;
}

static void __exit sbd_exit(void)
{
    del_gendisk(Device.gd);
    put_disk(Device.gd);
    unregister_blkdev(major_num, "sbd");
    blk_cleanup_queue(Queue);
    vfree(Device.data);
}

module_init(sbd_init);
module_exit(sbd_exit);
This is from sbd.c that I found somewhere from Jonathan Corbet. It's the same sbull driver so we're still talking about the same thing.

Now, if you look carefully, you'll see that I changed the definition of bsd_transfer from
Code:
static void sbd_transfer(struct sbd_device *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)
to

Code:
static void sbd_transfer(struct sbd_device *dev, struct request *q)
That's because everything I needed to pass sbd_transfer was in the request so no point in passing separate things when I had everything in request (I hope not to be messing up).

Now I want to make sure I won't things right in a couple of members I had to change from the request.

Before it was:
Code:
unsigned long offset = sector*hardsect_size;
unsigned long nbytes = nsect*hardsect_size;
[b]sector was taken from the request as request->current_nr_sectors, nsect was req->buffer.
Now I have
Code:
unsigned long offset = blk_rq_pos(q)*hardsect_size;
unsigned long nbytes = blk_rq_cur_sectors(q)*hardsect_size;
[q] being the request as received in sbd_transfer. Those are the equivalent functions, right?

ANd finally, I'm getting a warning when I compile:
Code:
sbd.c:129: warning: initialization from incompatible pointer type
That's when I try to set the fops. I think it's because the definition of .ioctl is this function:
Code:
int sbd_ioctl (struct inode *inode, struct file *filp,
                 unsigned int cmd, unsigned long arg)
But when looking at blkdev.h it is like this:
Code:
int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
So the signatures are not the same. How do I correct this? Thanks in advance for your help.

Update

The original code is here: http://lwn.net/Articles/58720/

Last edited by eantoranz; 12-04-2010 at 11:23 AM. Reason: adding link to original code
 
Old 12-04-2010, 02:13 PM   #3
sriram87
LQ Newbie
 
Registered: Jan 2008
Posts: 11

Rep: Reputation: 1
There is a rewrite of the block device driver for the newer kernel. You can find it here
http://goo.gl/w2OZT
 
1 members found this post helpful.
Old 12-05-2010, 10:41 AM   #4
eantoranz
Senior Member
 
Registered: Apr 2003
Location: Costa Rica
Distribution: Kubuntu, Debian, Knoppix
Posts: 2,092

Original Poster
Blog Entries: 1

Rep: Reputation: 90
The code from here did work: http://blog.superpat.com/2010/05/04/...kernel-2-6-31/

It's an updated version of sbd for the new block layer API. I'll study it... thank you very much for your help!
 
  


Reply

Tags
api changes, driver, linux, sbull



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Newbie member looking to use Linux on a IBMT43 for ColdFire development. andersonf LinuxQuestions.org Member Intro 2 01-20-2007 03:54 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:00 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration