Questions about a block driver???

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

 



I have been reading how to implement a block device driver in Chaper 12 from the <<Linux device driver>> 2nd, which is available on http://www.xml.com/ldd/chapter/book/ . The block driver also simulate a harddisk using physical memory. There is a "struct Sbull_Dev" associated with each device.

There are things that I can't figure out by reading the source code. My question are: (1) By default, each device has two megbytes. The 'Sbull_Dev.size' is used to represent the size of the device. what I can't understand is these two megbytes has never been allocated, how can the device holds data. (2) the pointer variable 'Sbull_dev.data' is used to hold the data been transferred from the buffer cache. But the pointer has never been assigned to pointer to any memory, and has never been allocated. How can the pointer hold the tranferred data???
(3) This is related to the second question. At the clean_up function, the pointer variable 'Sbull_Dev.data' is freed using 'vfree'. If a pointer has never been allocated, how the pointer can be freed.

I just list the necessary code which is related to my questions: (1) the struct for each device. (2) the tranfer function from the request queue to the device memory. (3) the init module function. (4) the clean up function.

(1) the struct associated with each device
typedef struct Sbull_Dev {
  int size;
  int usage;
  struct timer_list timer;
  spinlock_t lock;
  u8 *data;
} Sbull_Dev;





(2) The transfer function from the request queue to the device memory. The pointer variable 'ptr' is used to hold the transferred data. But the variable is never allocated or assigned to other variable. How can the pointer holds the transferred data.
/*
 * Perform an actual transfer.
 */
static int sbull_transfer(Sbull_Dev *device, const struct request *req)
{
    int size;
    u8 *ptr;
   
    ptr = device->data + req->sector * sbull_hardsect;
    size = req->current_nr_sectors * sbull_hardsect;

    /* Make sure that the transfer fits within the device. */
    if (ptr + size > device->data + sbull_blksize*sbull_size) {
        static int count = 0;
        if (count++ < 5)
            printk(KERN_WARNING "sbull: request past end of device\n");
        return 0;
    }

    /* Looks good, do the transfer. */
    switch(req->cmd) {
        case READ:
            memcpy(req->buffer, ptr, size); /* from sbull to buffer */
            return 1;
        case WRITE:
            memcpy(ptr, req->buffer, size); /* from buffer to sbull */
            return 1;
        default:
            /* can't happen */
            return 0;
    }
}




(3) The init module function. The two megbytes is never been allocated.
int sbull_init(void)
{
    int result, i;

    /*
     * Copy the (static) cfg variables to public prefixed ones to allow
     * snoozing with a debugger.
     */
    sbull_major    = major;
    sbull_devs     = devs;
    sbull_rahead   = rahead;
    sbull_size     = size;
    sbull_blksize  = blksize;
    sbull_hardsect = hardsect;

    /*
     * Register your major, and accept a dynamic number
     */
    result = register_blkdev(sbull_major, "sbull", &sbull_bdops);
    if (result < 0) {
        printk(KERN_WARNING "sbull: can't get major %d\n",sbull_major);
        return result;
    }
    if (sbull_major == 0) sbull_major = result; /* dynamic */
    major = sbull_major; /* Use `major' later on to save typing */

    /*
     * Assign the other needed values: request, rahead, size, blksize,
     * hardsect. All the minor devices feature the same value.
     * Note that `sbull' defines all of them to allow testing non-default
     * values. A real device could well avoid setting values in global
     * arrays if it uses the default values.
     */

    read_ahead[major] = sbull_rahead;
    result = -ENOMEM; /* for the possible errors */

    sbull_sizes = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);
    if (!sbull_sizes)
        goto fail_malloc;
    for (i=0; i < sbull_devs; i++) /* all the same size */
        sbull_sizes[i] = sbull_size;
    blk_size[major]=sbull_sizes;

    sbull_blksizes = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);
    if (!sbull_blksizes)
        goto fail_malloc;
    for (i=0; i < sbull_devs; i++) /* all the same blocksize */
        sbull_blksizes[i] = sbull_blksize;
    blksize_size[major]=sbull_blksizes;

    sbull_hardsects = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);
    if (!sbull_hardsects)
        goto fail_malloc;
    for (i=0; i < sbull_devs; i++) /* all the same hardsect */
        sbull_hardsects[i] = sbull_hardsect;
    hardsect_size[major]=sbull_hardsects;

    /* FIXME: max_readahead and max_sectors */
   
    /*
     * allocate the devices -- we can't have them static, as the number
     * can be specified at load time
     */

    sbull_devices = kmalloc(sbull_devs * sizeof (Sbull_Dev), GFP_KERNEL);
    if (!sbull_devices)
        goto fail_malloc;
    memset(sbull_devices, 0, sbull_devs * sizeof (Sbull_Dev));
    for (i=0; i < sbull_devs; i++) {
        /* data and usage remain zeroed */
        sbull_devices[i].size = 1024 * sbull_size;
        init_timer(&(sbull_devices[i].timer));
        sbull_devices[i].timer.data = "" long)(sbull_devices+i);
        sbull_devices[i].timer.function = sbull_expires;
        spin_lock_init(&sbull_devices[i].lock);
    }

    /*
     * Get the queue set up, and register our (nonexistent) partitions.
     */ 

    if (noqueue)
        blk_queue_make_request(BLK_DEFAULT_QUEUE(major), sbull_make_request);
    else
        blk_init_queue(BLK_DEFAULT_QUEUE(major), sbull_request);
   
    /* A no-op in 2.4.0, but all drivers seem to do it anyway */
    for (i = 0; i < sbull_devs; i++)
            register_disk(NULL, MKDEV(major, i), 1, &sbull_bdops,
                            sbull_size << 1);

#ifndef SBULL_DEBUG
    EXPORT_NO_SYMBOLS; /* otherwise, leave global symbols visible */
#endif

    printk ("<1>sbull: init complete, %d devs, size %d blks %d hs %d\n",
            sbull_devs, sbull_size, sbull_blksize, sbull_hardsect);

    if (noqueue)
        printk (KERN_INFO "sbull: using direct make_request\n");
   
    return 0; /* succeed */

  fail_malloc:
    read_ahead[major] = 0;
    if (sbull_sizes) kfree(sbull_sizes);
    blk_size[major] = NULL;
    if (sbull_blksizes) kfree(sbull_blksizes);
    blksize_size[major] = NULL;
    if (sbull_hardsects) kfree(sbull_hardsects);
    hardsect_size[major] = NULL;
    if (sbull_devices) kfree(sbull_devices);

    unregister_blkdev(major, "sbull");
    return result;
}



(4) The clean up function. Where the 'Sbull_Dev.data' is been vfreed, but which is never been allocated.
void sbull_cleanup(void)
{
    int i;

/*
 * Before anything else, get rid of the timer functions.  Set the "usage"
 * flag on each device as well, under lock, so that if the timer fires up
 * just before we delete it, it will either complete or abort.  Otherwise
 * we have nasty race conditions to worry about.
 */
    for (i = 0; i < sbull_devs; i++) {
        Sbull_Dev *dev = sbull_devices + i;
        del_timer(&dev->timer);
        spin_lock(&dev->lock);
        dev->usage++;
        spin_unlock(&dev->lock);
    }
   

    /* flush it all and reset all the data structures */


    for (i=0; i<sbull_devs; i++)
        fsync_dev(MKDEV(sbull_major, i)); /* flush the devices */
    unregister_blkdev(major, "sbull");
   
    blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));
 

    /* Clean up the global arrays */
    read_ahead[major] = 0;
    kfree(blk_size[major]);
    blk_size[major] = NULL;
    kfree(blksize_size[major]);
    blksize_size[major] = NULL;
    kfree(hardsect_size[major]);
    hardsect_size[major] = NULL;
    /* FIXME: max_readahead and max_sectors */


    /* finally, the usual cleanup */
    for (i=0; i < sbull_devs; i++) {
        if (sbull_devices[i].data)
            vfree(sbull_devices[i].data);
    }
    kfree(sbull_devices);
}


[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