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 + -
显示快捷键?