?? block-io.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 void blockio_bio_endio(struct bio *bio, int error){ struct tio_work *tio_work = bio->bi_private; 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);}/* * 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, error %d\n", path, err); 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) = volume->lun; *(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(¶ms, ",")) != 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(bio_data->path); 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 + -