gnbd_main.c

来自「openGFS , a kind of file system.」· C语言 代码 · 共 722 行 · 第 1/2 页

C
722
字号
/* * *    Copyright 1999 Regents of the University of Minnesota *    Portions Copyright 1999-2001 Sistina Software, Inc. *    Portions Copyright 2001 The OpenGFS Project * *    This is free software released under the GNU General Public License. *    There is no warranty for this software.  See the file COPYING for *    details. * *    See the file AUTHORS for a list of contributors. * *//* * This was heavily infulenced by sbull from the `Linux Device Drivers' book * by Alessandro Rubini. And the original nbd. and a bunch of work I did on * the glm. *//* * 2001/10/01  Christoph Hellwig <hch@caldera.de> *	Use {add,del}_gendisk instead of touching gendisk_head directly * 2001/10/15  Christoph Hellwig <hch@caldera.de> *	Use generic block ioctl code, remove spurious fsync_dev */#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/slab.h>	#include <linux/fs.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/hdreg.h>#include <linux/ioctl.h>#include <linux/proc_fs.h>#include <linux/genhd.h>#include <linux/blkpg.h>#include <asm/system.h>#include <asm/uaccess.h>#define MAJOR_NR gnbd_major	/* force definitions on in blk.h */int gnbd_major;			/* must be declared before including blk.h */#define DEVICE_NR(device) MINOR(device)	/* gnbd has no partition bits */#define DEVICE_NAME "gnbd"	/* name for messaging */#define DEVICE_INTR gnbd_intrptr	/* pointer to the bottom half */#define DEVICE_NO_RANDOM	/* no entropy to contribute */#define DEVICE_OFF(d)		/* do-nothing */#define DEVICE_ON(d)		/* do-nothing */#define DEVICE_REQUEST gnbd_request#define LOCAL_END_REQUEST#define GNBD_MAX_DEV 256	/* the absolute max number of devices gnbd will				   allow. Can't be changed */#ifndef MAX_DEVICES		/* the max number that gnbd is configured to use */#define MAX_DEVICES 10		/* effects the size of config.. It makes the */#endif				/* interface much prettier, and no one should */			    /* need more than 10 clients on any machine */			    /* it can be changed in the makefile */#define GNBD_HARDSECT 512	/* .5k sectors */#include <linux/blk.h>#include "trans.h"#include "gnbd_macros.h"#include "gnbd_kern.h"#include "gnbd.h"MODULE_AUTHOR("The OpenGFS Project, Ben Marzinski");MODULE_DESCRIPTION("GFS-friendly network block device");MODULE_LICENSE("GPL");static int rahead = 1;MODULE_PARM(rahead, "i");MODULE_PARM_DESC(rahead, "Select number of readahead blocks (per request)");static int gnbd_devs;static int max_check;static struct semaphore c_init;static gnbd_t *gnbd_devices[256];static int gnbd_blksizes[256];static int gnbd_sizes[256];static char *gnbd_device_names[256];static struct hd_struct gnbd_partitions[256];static int gnbd_open(struct inode *, struct file *);static int gnbd_release(struct inode *, struct file *);static int gnbd_ioctl(struct inode *, struct file *,		unsigned int, unsigned long);static struct block_device_operations gnbd_device_ops = {	open:		gnbd_open,	release:	gnbd_release,	ioctl:		gnbd_ioctl,};/* * This structure is needed for /proc/partitions.  Making the device * partitionable with a max of zero partitions seems to be the easiest * solution to the passemble problem */static struct gendisk gnbd_gendisk = {	major:		0,	/* DYNAMIC */	major_name:	DEVICE_NAME,	part:		gnbd_partitions,	sizes:		gnbd_sizes,	nr_real:	256,	fops:		&gnbd_device_ops,#ifdef _HAVE_GENDISK_DEVICE_NAMES	device_names:	gnbd_device_names,#endif};static int gnbd_connect(int num, gnbd_t * dev){	int err = 0;	if (ISgnbdDisConnected(dev)) {		printd(" loggin into %x:%x\n", dev->servip, dev->servport);		err = trans_start_up(dev);		if (err < 0) {			printd("failed trans_start_up\n");			return err;		}			gnbd_sizes[num] = dev->size / 1024;		gnbd_partitions[num].nr_sects = 2 * gnbd_sizes[num];	}	return err;}/* * Open and close * * Ok, the new order of things. There is no such thing as a bad ip, thus  * there is no such thing as a setup state. * There is an Opened state that just tells us if the device is opened by * any process. Basically, if usage != 0 then Opened=True; * There is also a Connected state. This replaces the loggedin marker. * Since it means pretty much the exact same thing. Difference being that * now just because a device is disconnected, doesn't mean you can't open * and read or write to it... * * minor 0 is /dev/gnbdcomm and CANNOT hook to a server ever!  * This gives us a device that we can always open and do ioctls. */static int gnbd_open(struct inode *inode, struct file *file){	gnbd_t *dev;	int minor = MINOR(inode->i_rdev);	int error = 0;	if (minor >= max_check || !gnbd_devices[minor])		return -ENODEV;	MOD_INC_USE_COUNT;	dev = gnbd_devices[minor];	if (minor) { /* don't connect minor 0 */		error = gnbd_connect(minor, dev);		if (error)			goto fail;		dev->usage++;	}	return 0;fail:	MOD_DEC_USE_COUNT;	return error;}static int gnbd_release(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	gnbd_t *dev = gnbd_devices[minor];	dev->usage--;	if (minor && !dev->usage)	/* ie. ! ISgnbdOpened(dev) */		/* smart enough not to do anything if its already been done */		trans_shutdown(dev, 1);	MOD_DEC_USE_COUNT;	return 0;}static int gnbd_action(int num, gnbd_action_t * arg){	gnbd_t *dev;	gnbd_action_t act;	int err = 0;	memset(&act, 0, sizeof(gnbd_action_t));	err = get_user(act.action, &arg->action);	err = get_user(act.device, &arg->device);	err = get_user(act.ip, &arg->ip);	err = get_user(act.port, &arg->port);	printd("gnbd action %x, device %x\n", act.action, act.device);	if (act.device >= max_check || gnbd_devices[act.device] == NULL) {		err = -EINVAL;		goto exit_gnbd_action;	}	/* If opened a device other than /dev/gnbdcomm, setting the device field	 * in the gnbd_action_t to zero means we want the device we opened.	 * If opened the gnbdcomm, and act.device is zero, its an error.	 */	if (num == 0 && act.device == 0) {		err = -EINVAL;		goto exit_gnbd_action;	}	if (act.device != 0)		num = act.device;	dev = gnbd_devices[num];	switch (act.action) {	case GNBD_ACT_SetIPPort:		printd(" ::SetIPPort::dev %u:: ip %x port %u\n",		       num, act.ip, act.port);		dev->servip = act.ip;		dev->servport = act.port;		break;	case GNBD_ACT_Connect:		printd(" ::Connect::dev %u::\n", num);		err = gnbd_connect(num, dev);		if (err < 0) {			printd("exitting Connect due to error : %d\n", err);			dev->good_connect = 0;			break;		}		dev->good_connect = 1;		if (ISgnbdOpened(dev) || ISgnbdPending(dev))			break;		printd("rolling through to disconnect\n");	case GNBD_ACT_Disconnect:		printd(" ::DisConnect::dev %u::\n", num);		if (ISgnbdConnected(dev)) {			printd("Shutting down now\n");			trans_shutdown(dev, 0);		}		break;	case GNBD_ACT_ForceClose:		printd(" ::ForceClose::dev %u::\n", num);		if (ISgnbdConnected(dev)) {			/* This is correct, but we might need to do more */			trans_shutdown(dev, 1);			wake_up(&dev->gassed);		}		break;	default:		printi("Null action\n");		break;	}      exit_gnbd_action:	return err;}static int init_device(char *name, int length){	int found = -1;	int minor_num;	gnbd_t *temp;	down(&c_init);	for (minor_num = 0; minor_num <= max_check; minor_num++) {		if (gnbd_devices[minor_num] == NULL) {			if (found == -1)				found = minor_num;		} else if (gnbd_device_names[minor_num] &&			   strcmp(gnbd_device_names[minor_num], name) == 0) {			printe("gnbd_device name '%s' already in use\n", name);			up(&c_init);			return -EEXIST;		}	}	if (found < 0) {		printe("could not find a free minor number\n");		up(&c_init);		return -ENODEV;	}	minor_num = found;	temp = kmalloc(sizeof(gnbd_t), GFP_KERNEL);	if (!temp) {		printe("could not allocate memory for device %s\n", name);		up(&c_init);		return -ENOMEM;	}	gnbd_device_names[minor_num] = kmalloc(sizeof(char) * (length + 5),					       GFP_KERNEL);	if (gnbd_device_names[minor_num] == NULL) {		kfree(temp);		printe("couldn't allocate memory for device name: %s\n", name);		up(&c_init);		return -ENOMEM;	}	strcpy(gnbd_device_names[minor_num], "gnbd/");	strncat(gnbd_device_names[minor_num], name, length);	memset(temp, 0, sizeof(gnbd_t));	temp->size = 0;	temp->recvd_run = 0;	init_MUTEX(&temp->sender);	init_MUTEX_LOCKED(&temp->tiodmux);	init_MUTEX(&temp->tqmux);	temp->Rhead = NULL;	init_waitqueue_head(&temp->gassed);	gnbd_devices[minor_num] = temp;	if (minor_num == max_check && max_check < 255)		max_check++;	gnbd_devs++;	up(&c_init);	return minor_num;}/* Major problem... Semaphore is pretty useless.  It needs to make sure that * the device is not currently in use.  Otherwise bad things could happer*/static void cleanup_device(int minor_num){	down(&c_init);	if (minor_num == max_check - 1)		max_check--;	gnbd_devs--;	gnbd_sizes[minor_num] = 0;	gnbd_partitions[minor_num].nr_sects = 0;	if (gnbd_device_names[minor_num] != NULL) {		kfree(gnbd_device_names[minor_num]);		gnbd_device_names[minor_num] = NULL;	}	if (gnbd_devices[minor_num] != NULL) {		kfree(gnbd_devices[minor_num]);		gnbd_devices[minor_num] = NULL;	}	up(&c_init);	return;}static int gnbd_device_work(gnbd_device_t * arg){	int err = 0;	int i;	gnbd_device_t *dev;	char *dev_name = NULL;	if (!arg) {		printe("no argument was sent to gnbd_device_work!?!?\n");		return -EINVAL;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?