3 tridge@valinux.com, 2001
10 #define DEVICE_NAME "trd"
11 #define DEVICE_REQUEST do_trd_request
12 #define DEVICE_NR(device) (MINOR(device))
14 #include <linux/major.h>
15 #include <linux/slab.h>
16 #include <linux/vmalloc.h>
17 #include <linux/blk.h>
18 #include <linux/init.h>
19 #include <linux/module.h>
20 #include <asm/setup.h>
21 #include <asm/uaccess.h>
23 #define TRD_BLOCK_SIZE 1024
24 #define TRD_SIZE (trd_size<<10)
26 static int trd_blocksizes[MAX_DEVS];
27 static int trd_blk_sizes[MAX_DEVS];
28 static void **trd_base[MAX_DEVS];
30 static unsigned trd_size = 4096;
32 MODULE_PARM (trd_size, "1i");
34 static void do_trd_request(request_queue_t * q)
36 u_long start, ofs, len, len1;
43 minor = MINOR(CURRENT->rq_dev);
44 start = CURRENT->sector << 9;
45 len = CURRENT->current_nr_sectors << 9;
47 if ((start + len) > TRD_SIZE) {
48 printk(KERN_ERR DEVICE_NAME ": bad access: block=%ld, count=%ld\n",
50 CURRENT->current_nr_sectors);
55 if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) {
56 printk(KERN_ERR DEVICE_NAME ": bad command: %d\n", CURRENT->cmd);
62 page = start / PAGE_SIZE;
63 ofs = start % PAGE_SIZE;
64 addr = (void *) (((char *)(trd_base[minor][page])) + ofs);
67 if (ofs + len1 > PAGE_SIZE) {
68 len1 = PAGE_SIZE - ofs;
71 if (CURRENT->cmd == READ) {
72 memcpy(CURRENT->buffer, (char *)addr, len1);
74 memcpy((char *)addr, CURRENT->buffer, len1);
85 static int trd_allocate(int minor)
89 /* it might be already allocated */
90 if (trd_base[minor]) return 0;
92 trd_base[minor] = (void **)vmalloc(sizeof(void *)*trd_pages);
93 if (!trd_base[minor]) goto nomem;
94 memset(trd_base[minor], 0, sizeof(void *)*trd_pages);
96 for (i=0;i<trd_pages;i++) {
97 trd_base[minor][i] = (void *)__get_free_page(GFP_USER);
98 if (!trd_base[minor][i]) goto nomem;
99 /* we have to zero it to ensure private data doesn't leak */
100 memset(trd_base[minor][i], 0, PAGE_SIZE);
103 printk(KERN_INFO DEVICE_NAME ": Allocated %dk to minor %d\n",
104 TRD_SIZE>>10, minor);
109 if (trd_base[minor]) {
110 for (i=0;i<trd_pages;i++) {
111 if (trd_base[minor][i])
112 free_page((unsigned long)trd_base[minor][i]);
114 vfree(trd_base[minor]);
115 trd_base[minor] = NULL;
118 printk(KERN_ERR DEVICE_NAME ": Unable to allocate trd of size %d\n",
124 static int trd_open(struct inode *inode, struct file *filp)
127 int minor = MINOR(inode->i_rdev);
129 if (minor >= MAX_DEVS) return -ENODEV;
131 ret = trd_allocate(minor);
132 if (ret != 0) return ret;
139 static int trd_release(struct inode *inode, struct file *filp)
145 static int trd_ioctl(struct inode *inode, struct file *file,
146 unsigned int cmd, unsigned long arg)
148 if (!capable(CAP_SYS_ADMIN))
155 return put_user(TRD_SIZE >> 9, (long *) arg);
157 printk(KERN_ERR DEVICE_NAME ": unknown ioctl 0x%x\n", cmd);
163 static struct block_device_operations trd_fops =
166 release: trd_release,
171 static int trd_init(void)
175 trd_pages = (TRD_SIZE + (PAGE_SIZE-1)) / PAGE_SIZE;
177 if (register_blkdev(MAJOR_NR, DEVICE_NAME, &trd_fops)) {
178 printk(KERN_ERR DEVICE_NAME ": Unable to register_blkdev(%d)\n", MAJOR_NR);
182 for (i=0;i<MAX_DEVS;i++) {
183 trd_blocksizes[i] = TRD_BLOCK_SIZE;
184 trd_blk_sizes[i] = trd_size;
187 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
188 blksize_size[MAJOR_NR] = trd_blocksizes;
189 blk_size[MAJOR_NR] = trd_blk_sizes;
191 printk(KERN_DEBUG DEVICE_NAME ": trd initialised size=%dk\n",
197 static void __exit trd_cleanup(void)
201 unregister_blkdev(MAJOR_NR, DEVICE_NAME);
203 for (minor=0;minor<MAX_DEVS;minor++) {
204 if (!trd_base[minor]) continue;
205 for (i=0;i<trd_pages;i++) {
206 free_page((unsigned long)trd_base[minor][i]);
208 vfree(trd_base[minor]);
209 trd_base[minor] = NULL;
211 printk(KERN_DEBUG DEVICE_NAME ": trd released\n");
214 module_init(trd_init);
215 module_exit(trd_cleanup);
216 MODULE_DESCRIPTION("trivial ramdisk");