gnbd_main.c
来自「openGFS , a kind of file system.」· C语言 代码 · 共 722 行 · 第 1/2 页
C
722 行
} dev = (gnbd_device_t *) kmalloc(sizeof(gnbd_device_t), GFP_KERNEL); if (!dev) { printe ("insufficient memory to create space for gnbd request\n"); return -ENOMEM; } err = (int) copy_from_user((void *) dev, (void *) arg, sizeof(gnbd_device_t)); if (err) { printe("Bad address in argument?!?!?\n"); goto dev_fail; } if (dev->length != 0) { dev_name = (char *) kmalloc(sizeof(char) * dev->length, GFP_KERNEL); if (!dev_name) { printe ("insufficient memory to create space for device name\n"); goto exit; } printd("dev->length = %d\n", dev->length); err = (int) copy_from_user((void *) dev_name, (void *) dev->name, dev->length); if (err) { printe("Bad Address for device name?!?!?!\n"); goto exit; } printd("dev_name = \"%s\"\n", dev_name); } else { dev->name = NULL; } if (dev->action == GNBD_DEV_CREATE) { if (dev->name == NULL) { printe("No device name?!?!\n"); err = -EINVAL; } else err = init_device(dev_name, dev->length); if (err > 0) { dev->minor_nr = err; err = (int) copy_to_user((void *) arg, (void *) dev, sizeof(gnbd_device_t)); if (err) { printe("Bad address in argument?!?!?\n"); goto exit; } } goto exit; } else if (dev->action == GNBD_DEV_REMOVE) { if (dev->name != NULL) { for (i = 0; i < max_check; i++) if (gnbd_devices[i] != NULL && strncmp(gnbd_device_names[i], dev_name, strlen(gnbd_device_names[i])) == 0) { cleanup_device(i); goto exit; } printe("couldn't find a device named \"%s\"\n", dev_name); err = -EINVAL; } else { if (gnbd_devices[dev->minor_nr] != NULL) { cleanup_device(dev->minor_nr); goto exit; } printe("couldn't find a device with minor number %d\n", dev->minor_nr); err = -EINVAL; } } exit: kfree(dev_name); dev_fail: kfree(dev); return err;}static int gnbd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int minor = MINOR(inode->i_rdev); switch (cmd) { case GNBD_ACTION: if (!capable(CAP_SYS_ADMIN)) return -EPERM; return gnbd_action(minor, (gnbd_action_t *)arg); case GNBD_DEVICE: if (!capable(CAP_SYS_ADMIN)) return -EPERM; return gnbd_device_work((gnbd_device_t *)arg); case GNBD_BLKSSZESET: /* * Not sure if this is completely thought through. It really * should be looked at again when my mind isn't so loopie. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; if ((arg & 511) || (arg > PAGE_SIZE)) return -EINVAL; gnbd_blksizes[minor] = arg; break; case HDIO_GETGEO: { /* * get geometry: we are faking it...... * trim size to a multiple of 64 (32KB), have 16 sectors, and 4 * heads, and whatever we need for cylinders. * ?data start at sector 4? */ struct hd_geometry *geo = (struct hd_geometry *)arg; int size = (gnbd_sizes[minor]*2) & 0x3f; if (!geo) return -EINVAL; put_user(size >> 6, &geo->cylinders); put_user(4, &geo->heads); put_user(16, &geo->sectors); put_user(4, &geo->start); break; } case BLKRRPART: /* re-read partition table: can't do it */ return -EINVAL; default: /* try generic block code if everything else fails */ return blk_ioctl(inode->i_rdev, cmd, arg); }}void my_end_request(struct request *req){ if (end_that_request_first(req, !req->errors, "gnbd")) return; end_that_request_last(req);}/* * gnbd_request * This is where the kernel finally asks us to go get those blocks of data. */static void gnbd_request(request_queue_t * q){ gnbd_t *device; struct request *req; int num; u32 len; u64 offset; while (1) { if (q->plugged) return; INIT_REQUEST; num = DEVICE_NR(CURRENT_DEV); device = gnbd_devices[num]; if (ISgnbdDisConnected(device)) { printe("server disconnected, quitting request_fn\n"); return; } req = CURRENT; blkdev_dequeue_request(req); /* Check if the minor number is in range */ if (num >= max_check || gnbd_devices[num] == NULL) { /* print the message at most five times */ static int foo = 0; if (foo++ < 5) printe("request for unknown device\n"); my_end_request(req); continue; } /* pointer to device structure, from the global array */ /* mmmm, hardcoded city... */ offset = (u64) (req->sector) * (u64) GNBD_HARDSECT; len = req->current_nr_sectors << 9; /* should this sleep? or somesimular type action? * Well, it needs to do SOMEthing else. */ /* if( ISgnbdDisConnected(device) ) { static int UNIQUE_NAME = 0; if (UNIQUE_NAME++ < 5) printe("Not logged into a server!\n"); my_end_request(req); continue; } */ if (offset + len > device->size) { static int UNIQUE_NAME = 0; if (UNIQUE_NAME++ < 5) printe("request past end of device\n"); my_end_request(req); continue; } cmd_RW(device, req, len, offset); }}static int gnbd_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data){ int i; gnbd_t *dev; unsigned int ipaddr = 0; char down_msg[17]; count = 0; /* ignore how much it wants */ count = sprintf(buf, "gnbd major number : %d\n\n", gnbd_major); for (i = 1; i < max_check; i++) { if (gnbd_devices[i] == NULL) continue; dev = gnbd_devices[i]; ipaddr = be32_to_cpu(dev->servip); if (dev->good_connect == 0) strcpy(down_msg, "CONNECTION BROKE"); else strcpy(down_msg, ""); count += sprintf(buf + count, "Device: /%s/%s\n" "-------------------\n" " Minor # : %d\n" " IP : %u.%u.%u.%u\n" " Port : %u\n" " State : %s %s %s\n\n", &gnbd_device_names[i][5], down_msg, i, (unsigned char) (0xff & (ipaddr >> 24)), (unsigned char) (0xff & (ipaddr >> 16)), (unsigned char) (0xff & (ipaddr >> 8)), (unsigned char) (0xff & ipaddr), be16_to_cpu(dev->servport), ISgnbdOpened(dev) ? "Open" : "Close", ISgnbdConnected(dev) ? "Connected" : "Disconnected", ISgnbdPending(dev) ? "Pending" : "Clear"); if (count > (PAGE_SIZE - 380)) break; } *eof = 1; return count;}intgnbd_no_merge(request_queue_t * q, struct request *req, struct buffer_head *bh, int max_segments){ return 0;}intgnbd_no_merge_req(request_queue_t * q, struct request *req, struct request *next, int max_segments){ return 0;}/* * Finally, the module stuff */static int __init gnbd_init(void){ int result, i; struct proc_dir_entry *gnbd_proc_entry; init_MUTEX(&c_init); /* * Register your major, and accept a dynamic number */ result = register_blkdev(gnbd_major, "gnbd", &gnbd_device_ops); if (result < 0) { printw("can't get major %d\n", gnbd_major); return result; } if (gnbd_major == 0) gnbd_major = result; /* dynamic */ gnbd_gendisk.major = gnbd_major; /* was unknown at load time */ blk_init_queue(BLK_DEFAULT_QUEUE(gnbd_major), gnbd_request); /*blk_queue_pluggable(BLK_DEFAULT_QUEUE(gnbd_major), gnbd_plug_fn); */ (BLK_DEFAULT_QUEUE(gnbd_major))->front_merge_fn = gnbd_no_merge; (BLK_DEFAULT_QUEUE(gnbd_major))->back_merge_fn = gnbd_no_merge; (BLK_DEFAULT_QUEUE(gnbd_major))->merge_requests_fn = gnbd_no_merge_req; blk_queue_headactive(BLK_DEFAULT_QUEUE(gnbd_major), 0); read_ahead[gnbd_major] = rahead; result = -ENOMEM; /* for the possible errors */ for (i = 0; i < 256; i++) gnbd_blksizes[i] = BLOCK_SIZE; blksize_size[gnbd_major] = gnbd_blksizes; for (i = 0; i < 256; i++) gnbd_sizes[i] = 0; /* This is zero so that unused gnbd devices don't show up on /proc/partition */ blk_size[gnbd_major] = gnbd_sizes; /* in blocks.. */ /* * allocate the devices -- we can't have them static, as the number * can be specified at load time */ for (i = 0; i < 256; i++) { gnbd_partitions[i].nr_sects = 2 * gnbd_sizes[i]; /* 512 size sectors */ gnbd_partitions[i].start_sect = 0; /* disable partition checking */ } add_gendisk(&gnbd_gendisk); result = init_device("gnbd_comm", 10); if (result != 0) { if (result > 0) cleanup_device(result); printe("couldn't initialize gnbdcomm\n"); goto fail; } gnbd_proc_entry = create_proc_read_entry("gnbd", S_IFREG|S_IRUGO, &proc_root, gnbd_proc_read, NULL); if (gnbd_proc_entry) return 0;fail: del_gendisk(&gnbd_gendisk); blk_size[gnbd_major] = NULL; blksize_size[gnbd_major] = NULL; read_ahead[gnbd_major] = 0; blk_cleanup_queue(BLK_DEFAULT_QUEUE(gnbd_major)); unregister_blkdev(gnbd_major, "gnbd"); return result;}static void __exit gnbd_exit(void){ int i; /* first of all, flush it all and reset all the data structures */ for (i = 0; i <= max_check; i++) { if (gnbd_devices[i]) cleanup_device(i); } del_gendisk(&gnbd_gendisk); blk_cleanup_queue(BLK_DEFAULT_QUEUE(gnbd_major)); read_ahead[gnbd_major] = 0; blk_size[gnbd_major] = NULL; blksize_size[gnbd_major] = NULL; remove_proc_entry("gnbd", &proc_root); unregister_blkdev(gnbd_major, "gnbd");}module_init(gnbd_init);module_exit(gnbd_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?