RAM Disk device driver for the Linux Kernel

A RAM Disk device driver for the Linux Kernel which allocates a chunk of memory and presents it as a block device.


  1. /*
  2.  * A RAM Disk device driver for the Linux Kernel which allocates a chunk of
  3.  * memory and presents it as a block device.
  4.  *
  5.  * Based on sbd.c by Pat Patterson at blog.superpat.com
  6.  * Also uses file I/O functions based on some other drivers
  7.  */
  8.  
  9. #include <linux/module.h>
  10. #include <linux/moduleparam.h>
  11. #include <linux/init.h>
  12.  
  13. #include <linux/sched.h>
  14. #include <linux/kernel.h>       /* printk() */
  15. #include <linux/slab.h>         /* kmalloc() */
  16. #include <linux/fs.h>           /* everything... */
  17. #include <linux/errno.h>        /* error codes */
  18. #include <linux/timer.h>
  19. #include <linux/types.h>        /* size_t */
  20. #include <linux/vmalloc.h>      /* vmalloc() */
  21. #include <linux/fcntl.h>        /* O_ACCMODE */
  22. #include <linux/hdreg.h>        /* HDIO_GETGEO */
  23. #include <linux/kdev_t.h>
  24. #include <linux/vmalloc.h>
  25. #include <linux/genhd.h>
  26. #include <linux/blkdev.h>
  27. #include <linux/buffer_head.h>  /* invalidate_bdev */
  28. #include <linux/bio.h>
  29.  
  30. #include <linux/crypto.h>
  31.  
  32. MODULE_LICENSE("GPL");
  33.  
  34. #define PREFIX KERN_DEBUG "##NEWMOD: "
  35.  
  36. /* minor number and partition management */
  37. #define NEWMOD_MINORS   16
  38. #define MINOR_SHIFT     4
  39. #define DEVNUM(kdevnum) (MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT
  40.  
  41. /* Default crypto key */
  42. #define DEFAULT_KEY "1234567890123456"
  43. #define DEFAULT_KEY_LEN 16
  44.  
  45. /* Data file for loading/unloading data */
  46. #define DATA_FILE "/newmod_data"
  47.  
  48. /* device major number */
  49. static int newmod_major = 0;
  50. module_param(newmod_major, int, 0);
  51.  
  52. /* sector size (in bytes) */
  53. static int logical_block_size = 512;
  54. module_param(logical_block_size, int, 0);
  55.  
  56. /* number of sectors (1024 * 512 = 524288 = ~524 kB*/
  57. static int nsectors = 1024;
  58. module_param(nsectors, int, 0);
  59.  
  60. /* We can tweak our hardware sector size, but the kernel talks to us
  61.  * in terms of small sectors, always. */
  62. #define KERNEL_SECTOR_SIZE 512
  63.  
  64. /* Our request queue */
  65. static struct request_queue *Queue;
  66.  
  67. /* the device data */
  68. static struct newmod_device {
  69.         unsigned long size;             /* device size in sectors */
  70.         u8 *data;                       /* the data array */
  71.         spinlock_t lock;                /* for mutual exclusion */
  72.         struct gendisk *gd;             /* the gendisk structure */
  73. } Device;
  74.  
  75. /******************************** CRITICAL NOTE ********************************
  76.  *
  77.  * The crypto key must be 16 bytes long. Any shorter and crypto_cipher_setkey
  78.  * Will return error. Keylen must be 16 bytes.
  79.  *
  80.  ******************************************************************************/
  81. struct crypto_cipher *tfm;
  82. static char *key = DEFAULT_KEY;
  83. module_param(key, charp, 0);
  84. static int keylen = DEFAULT_KEY_LEN;
  85. module_param(keylen, int, 0);
  86.  
  87. /* Handle an I/O request */
  88. static void newmod_transfer(struct newmod_device *dev, sector_t sector,
  89.                 unsigned long nsect, char *buffer, int write) {
  90.         /* nsect is the number of sectors we're reading/writing,
  91.          * sector is the sector we're starting from. */
  92.         unsigned long offset = sector * logical_block_size;
  93.         unsigned long nbytes = nsect * logical_block_size;
  94.         int i, err;
  95.  
  96.  
  97.         /* check that we're reading within bound */
  98.         if ((offset + nbytes) > dev->size) {
  99.                 printk(PREFIX "Transfer: too far. offset: %ld. nbytes: %ld.\n",
  100.                                 offset, nbytes);
  101.                 return;
  102.         }
  103.        
  104.         /* returns an error code or 0 on success */
  105.         err = crypto_cipher_setkey(tfm, key, keylen);
  106.         printk(PREFIX "setting key returned <%d>\n", err);
  107.  
  108.         /*
  109.          * If we're writing, copy data from buffer into device data.
  110.          * If we're reading, copy device data into buffer.
  111.          *
  112.          * To use the crypto function calls, just copy one block at
  113.          * a time into the dextination from the source, until the
  114.          * number of transfered bytes has reached the desired amount
  115.          */
  116.         if (write) {
  117.                 printk(PREFIX "Transfer: Writing %lu bytes.\n", nbytes);
  118. //              memcpy(dev->data + offset, buffer, nbytes);
  119.  
  120.                 for (= 0; i < nbytes; i += crypto_cipher_blocksize(tfm)) {
  121.                         /* Using tfm, encrypt data from source and put it in
  122.                          * destination. The crypto function encrypts data
  123.                          * in blocks that aren't 1 byte each.
  124.                          * crypto_cipher_encrypt_one returns nothing. */
  125.                         crypto_cipher_encrypt_one(
  126.                                         tfm,                    /* crypto info */
  127.                                         dev->data + offset + i, /* destination */
  128.                                         buffer + i              /* source */
  129.                                         );
  130.                 }
  131.         } else {
  132.                 printk(PREFIX "Transfer: Reading %lu bytes.\n", nbytes);
  133. //              memcpy(buffer, dev->data + offset, nbytes);
  134.                
  135.                 for (= 0; i < nbytes; i += crypto_cipher_blocksize(tfm)) {
  136.                         crypto_cipher_decrypt_one(
  137.                                         tfm,                    /* crypto data */
  138.                                         buffer + i,             /* destination */
  139.                                         dev->data + offset + i  /* source */
  140.                                         );
  141.                 }
  142.        
  143.         }
  144.         printk(PREFIX "Transfer: done.\n");
  145.  
  146.         /* debug code */
  147. /*      {
  148.                 unsigned long len;
  149.                 u8 *dst;
  150.                 u8 *src;
  151.  
  152.                 len = nbytes;
  153.                 if (write) {
  154.                         dst = dev->data + offset;
  155.                         src = buffer;
  156.                 } else {
  157.                         dst = buffer;
  158.                         src = dev->data + offset;
  159.                 }
  160.  
  161.                 src = dev->data + offset;
  162.                 dst = buffer;
  163.  
  164.                 printk("Transfer: dev->data data:\n");
  165.                 len = nbytes;
  166.                 while(len--)
  167.                         printk("%u", (unsigned)*src++);
  168.  
  169.                 printk("Transfer: buffer data:\n");
  170.                 len = nbytes;
  171.                 while(len--)
  172.                         printk("%u", (unsigned)*dst++);
  173.  
  174.                 printk("transferred.\n"
  175.         }
  176. */
  177.         /* print the data that was transferred, and from where */
  178. //      printk(PREFIX "Data in device:\n");
  179. //      for (i = 0; i < nbytes; i++)
  180. //              printk(PREFIX "   Byte %d: %c\n", i, (unsigned char)(dev->data + offset + i));
  181.  
  182. //      printk(PREFIX "Data in buffer:\n");
  183. //      for (i = 0; i < nbytes; i++)
  184. //              printk(PREFIX "   Byte %d: %c\n", i, (unsigned char)(buffer + i));
  185. }
  186.  
  187. /* handle a request */
  188. static void newmod_request(struct request_queue *q) {
  189.         struct request *req;
  190.  
  191.         printk(PREFIX "request: Handling requests\n");
  192.  
  193.         /* fetch the request at the top of queue */
  194.         req = blk_fetch_request(q);
  195.  
  196.         /* iterate through every request in the queue */
  197.         while (req != NULL) {
  198.                 /* if we have no request or a request of the wrong type,
  199.                  * skip it and continue */
  200.                 if ((req == NULL) || (req->cmd_type != REQ_TYPE_FS)) {
  201.                         printk(PREFIX "request: Received non-fs request\n");
  202.  
  203.                         __blk_end_request_all(req, -EIO);
  204.                         req = blk_fetch_request(q);
  205.  
  206.                         continue;
  207.                 }
  208.                 /* call my data transfer function */
  209.                 newmod_transfer(&Device,                /* my device data */
  210.                                 blk_rq_pos(req),        /* request sector */
  211.                                 blk_rq_cur_sectors(req),/* number of sectors */
  212.                                 req->buffer,            /* buffer to fill */
  213.                                 rq_data_dir(req));      /* read/write? */
  214.        
  215.                 printk(PREFIX "request: did a transfer.\n");
  216.  
  217.                 /* End current request, then fetch the next one.
  218.                  * __blk_end_request_cur returns 0 on success */
  219.                 if (!__blk_end_request_cur(req, 0))
  220.                         req = blk_fetch_request(q);
  221.         }
  222.         printk(PREFIX "request: finished all the requests.\n");
  223. }
  224.  
  225. /*
  226.  * The HDIO_GETGEO ioctl is handled in blkdev_ioctl(), which
  227.  * calls this. We need to implement getgeo, since we can't
  228.  * use tools such as fdisk to partition the drive otherwise.
  229.  */
  230. int newmod_getgeo(struct block_device * block_device,
  231.                   struct hd_geometry * geo) {
  232.         long size;
  233.  
  234.         printk(PREFIX "getgeo: Making stuff up.\n");
  235.  
  236.         /* make stuff up */
  237.         size = Device.size * (logical_block_size * KERNEL_SECTOR_SIZE);
  238.  
  239.         geo->cylinders = (size & ~0x3f) >> 6;
  240.         geo->heads = 4;
  241.         geo->sectors = 16;
  242.         geo->start = 0;
  243.         return 0;
  244. }
  245.  
  246. /* define the file operations */
  247. static struct block_device_operations newmod_ops = {
  248.         .owner = THIS_MODULE,
  249.         .getgeo = newmod_getgeo
  250. };
  251.  
  252. /* Initialize the device and announce it to the kernel */
  253. static int __init newmod_init(void)
  254. {
  255.         /* variables for file I/O */
  256.         mm_segment_t oldfs;
  257.         struct file *filp = NULL;
  258.         unsigned long long offset = 0;
  259.         ssize_t read_size;
  260.         int ret;
  261.  
  262.         printk(PREFIX "init: start\n");
  263.  
  264.         /* register the block device with the value given */
  265.         newmod_major = register_blkdev(newmod_major, "newmod");
  266.  
  267.         /* register_blkdev() returns negative on failure, whether the input is
  268.          * zero or a requested major number. */
  269.         if (newmod_major < 0) {
  270.                 printk(PREFIX "INIT: failed to register blockdev\n");
  271.                 return -EBUSY;
  272.         }
  273.  
  274.         /* setup the device. There is only one. */
  275.         memset(&Device, 0, sizeof(struct newmod_device));
  276.         Device.size = nsectors * logical_block_size;
  277.         Device.data = vmalloc(Device.size);
  278.  
  279.         memset(Device.data, 0, Device.size);
  280.  
  281.         /* check allocation */
  282.         if (Device.data == NULL) {
  283.                 printk(PREFIX "Init: Failed to allocate Device.data\n");
  284.                 unregister_blkdev(newmod_major, "newmod");
  285.                 return -ENOMEM;
  286.         }
  287.         printk(PREFIX "Init: device size is %ld.\n", Device.size);
  288.  
  289.         /* Now copy the device data from a file. If it doesn't exist, create
  290.          * it. */
  291.         oldfs = get_fs();
  292.         set_fs(get_ds());
  293.         filp = filp_open(DATA_FILE, O_RDONLY | O_CREAT, S_IRWXUGO);
  294.  
  295.         printk(PREFIX "init: attempted to open <%s>.\n", DATA_FILE);
  296.  
  297.         /* IS_ERR checks nor NULL and also error codes. If we failed to read
  298.          * the data from the previous run of this module, we can just blow it
  299.          * all away and start over with fresh data. It's not that bad */
  300.         if (IS_ERR(filp)) {
  301.                 printk(PREFIX "Init: Failed to open file <%s> for reading.\n",
  302.                                 DATA_FILE);
  303.                 set_fs(oldfs);
  304.         } else {
  305.                 /* read as many bytes from the file as will fit in our data buffer */
  306.                 read_size = vfs_read(filp, Device.data, Device.size, &offset);
  307.                 printk(PREFIX "Init: Read from file returned %d. offset: %llu.\n",
  308.                                 read_size, offset);
  309.                 /* close the file after we're done */
  310.                 set_fs(oldfs);
  311.                 ret = filp_close(filp, 0);
  312.                 printk(PREFIX "Init: Closed file, returned %d.\n", ret);
  313.         }
  314.  
  315.         /* initialize spinlock. Can't find the documentation. */
  316.         spin_lock_init(&Device.lock);
  317.  
  318.         /* Prepare the request queue for use with this block device. The


Learn More :