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