⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 block-io.c

📁 ISCSI target.It can be used to make up a IPSAN system.
💻 C
字号:
/* * Target device block I/O. * * Based on file I/O driver from FUJITA Tomonori * (C) 2004 - 2005 FUJITA Tomonori <tomof@acm.org> * (C) 2006 Andre Brinkmann <brinkman at hni dot upb dot de> * (C) 2007 Ross Walker <rswwalker at hotmail dot com> * (C) 2007 Ming Zhang <blackmagic02881 at gmail dot com> * This code is licenced under the GPL. */#include <linux/parser.h>#include <linux/blkdev.h>#include <linux/buffer_head.h>#include "iscsi.h"#include "iscsi_dbg.h"#include "iotype.h"struct blockio_data {	char *path;	struct block_device *bdev;};struct tio_work {	atomic_t error;	atomic_t bios_remaining;	struct completion tio_complete;};static intblockio_bio_endio(struct bio *bio, unsigned int bytes_done, int error){	struct tio_work *tio_work = bio->bi_private;	/* Ignore partials */	if (bio->bi_size)		return 1;	error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? error : -EIO;	if (error)		atomic_set(&tio_work->error, error);	/* If last bio signal completion */	if (atomic_dec_and_test(&tio_work->bios_remaining))		complete(&tio_work->tio_complete);	bio_put(bio);	return 0;}/* * Blockio_make_request(): The function translates an iscsi-request into * a number of requests to the corresponding block device. */static intblockio_make_request(struct iet_volume *volume, struct tio *tio, int rw){	struct blockio_data *bio_data = volume->private;	struct request_queue *bdev_q = bdev_get_queue(bio_data->bdev);	struct tio_work *tio_work;	struct bio *tio_bio = NULL, *bio = NULL, *biotail = NULL;	u32 offset = tio->offset;	u32 size = tio->size;	u32 tio_index = 0;	int max_pages = 1;	int err = 0;	loff_t ppos = ((loff_t) tio->idx << PAGE_SHIFT) + offset;	/* Calculate max_pages for bio_alloc (memory saver) */	if (bdev_q)		max_pages = bio_get_nr_vecs(bio_data->bdev);	tio_work = kzalloc(sizeof (*tio_work), GFP_KERNEL);	if (!tio_work)		return -ENOMEM;	atomic_set(&tio_work->error, 0);	atomic_set(&tio_work->bios_remaining, 0);	init_completion(&tio_work->tio_complete);	/* Main processing loop, allocate and fill all bios */	while (tio_index < tio->pg_cnt) {		bio = bio_alloc(GFP_KERNEL, min(max_pages, BIO_MAX_PAGES));		if (!bio) {			err = -ENOMEM;			goto out;		}		bio->bi_sector = ppos >> volume->blk_shift;		bio->bi_bdev = bio_data->bdev;		bio->bi_end_io = blockio_bio_endio;		bio->bi_private = tio_work;		if (tio_bio)			biotail = biotail->bi_next = bio;		else			tio_bio = biotail = bio;		atomic_inc(&tio_work->bios_remaining);		/* Loop for filling bio */		while (tio_index < tio->pg_cnt) {			unsigned int bytes = PAGE_SIZE - offset;			if (bytes > size)				bytes = size;			if (!bio_add_page(bio, tio->pvec[tio_index], bytes, offset))				break;			size -= bytes;			ppos += bytes;			offset = 0;			tio_index++;		}	}	/* Walk the list, submitting bios 1 by 1 */	while (tio_bio) {		bio = tio_bio;		tio_bio = tio_bio->bi_next;		bio->bi_next = NULL;		submit_bio(rw, bio);	}	if (bdev_q && bdev_q->unplug_fn)		bdev_q->unplug_fn(bdev_q);	wait_for_completion(&tio_work->tio_complete);	err = atomic_read(&tio_work->error);	kfree(tio_work);	return err;out:	while (tio_bio) {		bio = tio_bio;		tio_bio = tio_bio->bi_next;		bio_put(bio);	}	kfree(tio_work);	return err;}static intblockio_open_path(struct iet_volume *volume, const char *path){	struct blockio_data *bio_data = volume->private;	struct block_device *bdev;	int flags = LUReadonly(volume) ? MS_RDONLY : 0;	int err = 0;	bio_data->path = kstrdup(path, GFP_KERNEL);	if (!bio_data->path)		return -ENOMEM;	bdev = open_bdev_excl(path, flags, THIS_MODULE);	if (IS_ERR(bdev)) {		err = PTR_ERR (bdev);		eprintk("Can't open device %s \n", path);		bio_data->bdev = NULL;	} else {		bio_data->bdev = bdev;		fsync_bdev(bio_data->bdev);	}	return err;}static intset_scsiid(struct iet_volume *volume, const char *id){	size_t len;	if ((len = strlen(id)) > SCSI_ID_LEN - VENDOR_ID_LEN) {		eprintk("SCSI ID too long, %zd provided, %u max\n", len,			SCSI_ID_LEN - VENDOR_ID_LEN);		return -EINVAL;	}	memcpy(volume->scsi_id + VENDOR_ID_LEN, id, len);	return 0;}static voidgen_scsiid(struct iet_volume *volume, struct inode *inode){	int i;	u32 *p;	strlcpy(volume->scsi_id, VENDOR_ID, VENDOR_ID_LEN);	for (i = VENDOR_ID_LEN; i < SCSI_ID_LEN; i++)		if (volume->scsi_id[i])			return;	/* If a scsi id doesn't exist generate a 16 byte one:	 * Bytes   1-4: target type	 * Bytes   5-8: target id	 * Bytes  9-12: inode number	 * Bytes 13-16: device type	 */	p = (u32 *) (volume->scsi_id + VENDOR_ID_LEN);	*(p + 0) = volume->target->trgt_param.target_type;	*(p + 1) = volume->target->tid;	*(p + 2) = (unsigned int) inode->i_ino;	*(p + 3) = (unsigned int) inode->i_sb->s_dev;}static intset_scsisn(struct iet_volume *volume, const char *sn){	size_t len;	if ((len = strlen(sn)) > SCSI_SN_LEN) {		eprintk("SCSI SN too long, %zd provided, %u max\n", len,			SCSI_SN_LEN);		return -EINVAL;	}	memcpy(volume->scsi_sn, sn, len);	return 0;}/* Create an enumeration of our accepted actions */enum{	Opt_scsiid, Opt_scsisn, Opt_path, Opt_ignore, Opt_err,};/* Create a match table using our action enums and their matching options */static match_table_t tokens = {	{Opt_scsiid, "ScsiId=%s"},	{Opt_scsisn, "ScsiSN=%s"},	{Opt_path, "Path=%s"},	{Opt_ignore, "Type=%s"},	{Opt_ignore, "IOMode=%s"},	{Opt_err, NULL},};static intparse_blockio_params (struct iet_volume *volume, char *params){	int err = 0;	char *p, *q;	/* Loop through parameters separated by commas, look up our	 * parameter in match table, return enumeration and arguments	 * select case based on the returned enum and run the action */	while ((p = strsep(&params, ",")) != NULL) {		substring_t args[MAX_OPT_ARGS];		int token;		if (!*p)			continue;		token = match_token(p, tokens, args);		switch (token) {		case Opt_scsiid:			if (!(q = match_strdup(&args[0]))) {				err = -ENOMEM;				goto out;			}			err = set_scsiid(volume, q);			kfree(q);			if (err < 0)				goto out;			break;		case Opt_scsisn:			if (!(q = match_strdup(&args[0]))) {				err = -ENOMEM;				goto out;			}			err = set_scsisn(volume, q);			kfree(q);			if (err < 0)				goto out;			break;		case Opt_path:			if (!(q = match_strdup(&args[0]))) {				err = -ENOMEM;				goto out;			}			err = blockio_open_path(volume, q);			kfree(q);			if (err < 0)				goto out;			break;		case Opt_ignore:			break;		default:			eprintk("Bad option %s for Lun %u on Target %s \n",				p, volume->lun, volume->target->name);			return -EINVAL;		}	}  out:	return err;}static voidblockio_detach(struct iet_volume *volume){	struct blockio_data *bio_data = volume->private;	if (bio_data->bdev)		close_bdev_excl(bio_data->bdev);	kfree(volume->private);}static intblockio_attach (struct iet_volume *volume, char *args){	struct blockio_data *bio_data;	int err = 0;	if (volume->private) {		eprintk("Lun %u already attached on Target %s \n",			volume->lun, volume->target->name);		return -EBUSY;	}	bio_data = kzalloc(sizeof (*bio_data), GFP_KERNEL);	if (!bio_data)		return -ENOMEM;	volume->private = bio_data;	if ((err = parse_blockio_params(volume, args)) < 0) {		eprintk("Error attaching Lun %u to Target %s \n",			volume->lun, volume->target->name);		goto out;	}	/* Assign a vendor id, generate scsi id if none exists */	gen_scsiid(volume, bio_data->bdev->bd_inode);	volume->blk_shift = SECTOR_SIZE_BITS;	volume->blk_cnt = bio_data->bdev->bd_inode->i_size >> volume->blk_shift;  out:	if (err < 0)		blockio_detach(volume);	return err;}static voidblockio_show(struct iet_volume *volume, struct seq_file *seq){	struct blockio_data *bio_data = volume->private;	/* Used to display blockio volume info in /proc/net/iet/volumes */	seq_printf(seq, " path:%s\n", bio_data->path);}struct iotype blockio = {	.name = "blockio",	.attach = blockio_attach,	.make_request = blockio_make_request,	.detach = blockio_detach,	.show = blockio_show,};

⌨️ 快捷键说明

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