From patchwork Wed May 26 04:44:05 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leann Ogasawara X-Patchwork-Id: 53587 X-Patchwork-Delegate: leann.ogasawara@canonical.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 4E715B6F11 for ; Wed, 26 May 2010 14:44:22 +1000 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.69) (envelope-from ) id 1OH8TT-00049U-TY; Wed, 26 May 2010 05:44:11 +0100 Received: from adelie.canonical.com ([91.189.90.139]) by chlorine.canonical.com with esmtp (Exim 4.69) (envelope-from ) id 1OH8TR-00049O-Lk for kernel-team@lists.ubuntu.com; Wed, 26 May 2010 05:44:09 +0100 Received: from hutte.canonical.com ([91.189.90.181]) by adelie.canonical.com with esmtp (Exim 4.69 #1 (Debian)) id 1OH8TR-0008KF-JD for ; Wed, 26 May 2010 05:44:09 +0100 Received: from c-76-105-148-120.hsd1.or.comcast.net ([76.105.148.120] helo=[192.168.1.4]) by hutte.canonical.com with esmtpsa (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1OH8TQ-0001Tp-Pn for kernel-team@lists.ubuntu.com; Wed, 26 May 2010 05:44:09 +0100 Subject: [PATCH 1/1] [Maverick] UBUNTU: ubuntu: iscsitarget -- version 1.4.20.1 From: Leann Ogasawara To: kernel-team Date: Tue, 25 May 2010 21:44:05 -0700 Message-ID: <1274849045.24569.4257.camel@emiko> Mime-Version: 1.0 X-Mailer: Evolution 2.28.3 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.9 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com Hi All, Per our UDS Ubuntu kernel delta review session we identified that iscsitarget could be updated to a newer version. The following patch pulls us up to date with the latest stable version of iscsitarget, v1.4.20.1. We were at v1.4.19. Thanks, Leann >From 73acda31864e7c6d53c477912af255bffc7a90fd Mon Sep 17 00:00:00 2001 From: Leann Ogasawara Date: Tue, 25 May 2010 19:31:39 -0700 Subject: [PATCH] UBUNTU: ubuntu: iscsitarget -- version 1.4.20.1 Update iscsitarget to the latest stable version (v1.4.20.1) from sourceforge. ExternalDriver: iscsi_trgt Url: http://sourceforge.net/projects/iscsitarget/files/ Version: 1.4.20.1 Signed-off-by: Leann Ogasawara --- ubuntu/iscsitarget/BOM | 2 +- ubuntu/iscsitarget/block-io.c | 122 +++++---------------- ubuntu/iscsitarget/config.c | 174 ++++++++++++++++++------------ ubuntu/iscsitarget/conn.c | 33 ++++-- ubuntu/iscsitarget/file-io.c | 97 +++-------------- ubuntu/iscsitarget/include/iet_u.h | 38 ++++--- ubuntu/iscsitarget/iotype.h | 13 +++ ubuntu/iscsitarget/iscsi.c | 145 ++++++++++++++++--------- ubuntu/iscsitarget/iscsi.h | 13 ++- ubuntu/iscsitarget/nthread.c | 6 +- ubuntu/iscsitarget/null-io.c | 58 ++++------- ubuntu/iscsitarget/param.c | 2 +- ubuntu/iscsitarget/session.c | 32 ++---- ubuntu/iscsitarget/target.c | 53 ++++++--- ubuntu/iscsitarget/target_disk.c | 63 +++++++---- ubuntu/iscsitarget/ua.c | 12 ++ ubuntu/iscsitarget/volume.c | 211 +++++++++++++++++++++++++++++++----- ubuntu/iscsitarget/wthread.c | 27 +++++- 18 files changed, 644 insertions(+), 457 deletions(-) diff --git a/ubuntu/iscsitarget/BOM b/ubuntu/iscsitarget/BOM index cda1135..0fde30c 100644 --- a/ubuntu/iscsitarget/BOM +++ b/ubuntu/iscsitarget/BOM @@ -1,2 +1,2 @@ Downloaded from: svn://svn.berlios.de/iscsitarget/trunk -Current Version: 1.4.19 +Current Version: 1.4.20.1 diff --git a/ubuntu/iscsitarget/block-io.c b/ubuntu/iscsitarget/block-io.c index 708f101..4de1d20 100644 --- a/ubuntu/iscsitarget/block-io.c +++ b/ubuntu/iscsitarget/block-io.c @@ -86,7 +86,8 @@ blockio_make_request(struct iet_volume *volume, struct tio *tio, int rw) goto out; } - bio->bi_sector = ppos >> volume->blk_shift; + /* bi_sector is ALWAYS in units of 512 bytes */ + bio->bi_sector = ppos >> 9; bio->bi_bdev = bio_data->bdev; bio->bi_end_io = blockio_bio_endio; bio->bi_private = tio_work; @@ -174,77 +175,21 @@ blockio_open_path(struct iet_volume *volume, const char *path) return err; } -static int -set_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 void -gen_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 int -set_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, + 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}, + {opt_path, "path=%s"}, + {opt_ignore, "scsiid=%s"}, + {opt_ignore, "scsisn=%s"}, + {opt_ignore, "type=%s"}, + {opt_ignore, "iomode=%s"}, + {opt_ignore, "blocksize=%s"}, + {opt_err, NULL}, }; static int @@ -262,29 +207,10 @@ parse_blockio_params(struct iet_volume *volume, char *params) int token; if (!*p) continue; + iet_strtolower(p); 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: + case opt_path: if (info->path) { iprintk("Target %s, LUN %u: " "duplicate \"Path\" param\n", @@ -301,7 +227,7 @@ parse_blockio_params(struct iet_volume *volume, char *params) if (err < 0) goto out; break; - case Opt_ignore: + case opt_ignore: break; default: iprintk("Target %s, LUN %u: unknown param %s\n", @@ -315,6 +241,7 @@ parse_blockio_params(struct iet_volume *volume, char *params) volume->target->name, volume->lun); err = -EINVAL; } + out: return err; } @@ -350,22 +277,31 @@ blockio_attach(struct iet_volume *volume, char *args) volume->private = bio_data; - if ((err = parse_blockio_params(volume, args)) < 0) { + err = parse_blockio_params(volume, args); + if (!err) { + /* see Documentation/ABI/testing/sysfs-block */ + unsigned bsz = bdev_logical_block_size(bio_data->bdev); + if (!volume->blk_shift) + volume->blk_shift = ilog2(bsz); + else if (volume->blk_shift < ilog2(bsz)) { + eprintk("Specified block size (%u) smaller than " + "device %s logical block size (%u)\n", + (1 << volume->blk_shift), bio_data->path, bsz); + err = -EINVAL; + } + } + if (err < 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_cnt = bio_data->bdev->bd_inode->i_size >> volume->blk_shift; /* Offer neither write nor read caching */ ClearLURCache(volume); ClearLUWCache(volume); - 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); diff --git a/ubuntu/iscsitarget/config.c b/ubuntu/iscsitarget/config.c index 51331fb..87fa44b 100644 --- a/ubuntu/iscsitarget/config.c +++ b/ubuntu/iscsitarget/config.c @@ -9,6 +9,8 @@ #include "iscsi.h" #include "iscsi_dbg.h" +static DECLARE_MUTEX(ioctl_sem); + struct proc_entries { const char *name; struct file_operations *fops; @@ -60,26 +62,45 @@ err: return -ENOMEM; } -static int get_conn_info(struct iscsi_target *target, unsigned long ptr) +static int get_module_info(unsigned long ptr) { + struct module_info info; int err; + + snprintf(info.version, sizeof(info.version), "%s", IET_VERSION_STRING); + + err = copy_to_user((void *) ptr, &info, sizeof(info)); + if (err) + return -EFAULT; + + return 0; +} + +static int get_conn_info(struct iscsi_target *target, unsigned long ptr) +{ struct iscsi_session *session; - struct conn_info info; struct iscsi_conn *conn; + struct conn_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - return err; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; session = session_lookup(target, info.sid); if (!session) return -ENOENT; + conn = conn_lookup(session, info.cid); + if (!conn) + return -ENOENT; info.cid = conn->cid; info.stat_sn = conn->stat_sn; info.exp_stat_sn = conn->exp_stat_sn; - if (copy_to_user((void *) ptr, &info, sizeof(info))) + err = copy_to_user((void *) ptr, &info, sizeof(info)); + if (err) return -EFAULT; return 0; @@ -87,14 +108,16 @@ static int get_conn_info(struct iscsi_target *target, unsigned long ptr) static int add_conn(struct iscsi_target *target, unsigned long ptr) { - int err; struct iscsi_session *session; struct conn_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - return err; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; - if (!(session = session_lookup(target, info.sid))) + session = session_lookup(target, info.sid); + if (!session) return -ENOENT; return conn_add(session, &info); @@ -102,14 +125,16 @@ static int add_conn(struct iscsi_target *target, unsigned long ptr) static int del_conn(struct iscsi_target *target, unsigned long ptr) { - int err; struct iscsi_session *session; struct conn_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - return err; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; - if (!(session = session_lookup(target, info.sid))) + session = session_lookup(target, info.sid); + if (!session) return -ENOENT; return conn_del(session, &info); @@ -117,22 +142,23 @@ static int del_conn(struct iscsi_target *target, unsigned long ptr) static int get_session_info(struct iscsi_target *target, unsigned long ptr) { - int err; struct iscsi_session *session; struct session_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - return err; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; session = session_lookup(target, info.sid); - if (!session) return -ENOENT; info.exp_cmd_sn = session->exp_cmd_sn; info.max_cmd_sn = session->max_cmd_sn; - if (copy_to_user((void *) ptr, &info, sizeof(info))) + err = copy_to_user((void *) ptr, &info, sizeof(info)); + if (err) return -EFAULT; return 0; @@ -140,78 +166,90 @@ static int get_session_info(struct iscsi_target *target, unsigned long ptr) static int add_session(struct iscsi_target *target, unsigned long ptr) { - int err; struct session_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - return err; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; return session_add(target, &info); } static int del_session(struct iscsi_target *target, unsigned long ptr) { - int err; struct session_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - return err; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; return session_del(target, info.sid); } static int add_volume(struct iscsi_target *target, unsigned long ptr) { - int err; struct volume_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - return err; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; return volume_add(target, &info); } static int del_volume(struct iscsi_target *target, unsigned long ptr) { - int err; struct volume_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - return err; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; return iscsi_volume_del(target, &info); } static int iscsi_param_config(struct iscsi_target *target, unsigned long ptr, int set) { - int err; struct iscsi_param_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) - goto out; + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; - if ((err = iscsi_param_set(target, &info, set)) < 0) - goto out; + err = iscsi_param_set(target, &info, set); + if (err < 0 || set) + return err; - if (!set) - err = copy_to_user((void *) ptr, &info, sizeof(info)); + err = copy_to_user((void *) ptr, &info, sizeof(info)); + if (err) + return -EFAULT; -out: - return err; + return 0; } static int add_target(unsigned long ptr) { - int err; struct target_info info; + int err; - if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0) + err = copy_from_user(&info, (void *) ptr, sizeof(info)); + if (err) + return -EFAULT; + + err = target_add(&info); + if (err < 0) return err; - if (!(err = target_add(&info))) - err = copy_to_user((void *) ptr, &info, sizeof(info)); + err = copy_to_user((void *) ptr, &info, sizeof(info)); + if (err) + return -EFAULT; - return err; + return 0; } static long ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -220,40 +258,39 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg) long err; u32 id; - if ((err = get_user(id, (u32 *) arg)) != 0) - goto done; + err = down_interruptible(&ioctl_sem); + if (err < 0) + return err; - if (cmd == DEL_TARGET) { - err = target_del(id); + if (cmd == GET_MODULE_INFO) { + err = get_module_info(arg); goto done; } - target = target_lookup_by_id(id); + if (cmd == ADD_TARGET) { + err = add_target(arg); + goto done; + } - if (cmd == ADD_TARGET) - if (target) { - err = -EEXIST; - eprintk("Target %u already exist!\n", id); - goto done; - } + err = get_user(id, (u32 *) arg); + if (err < 0) + goto done; - switch (cmd) { - case ADD_TARGET: - assert(!target); - err = add_target(arg); + /* locking handled in target_del */ + if (cmd == DEL_TARGET) { + err = target_del(id); goto done; } + target = target_lookup_by_id(id); if (!target) { - eprintk("can't find the target %u\n", id); - err = -EINVAL; + err = -ENOENT; goto done; } - if ((err = target_lock(target, 1)) < 0) { - eprintk("interrupted %ld %d\n", err, cmd); + err = target_lock(target, 1); + if (err < 0) goto done; - } switch (cmd) { case ADD_VOLUME: @@ -300,17 +337,20 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg) err = -EINVAL; } - if (target) - target_unlock(target); - + target_unlock(target); done: + up(&ioctl_sem); + return err; } static int release(struct inode *i __attribute__((unused)), struct file *f __attribute__((unused))) { + down(&ioctl_sem); target_del_all(); + up(&ioctl_sem); + return 0; } diff --git a/ubuntu/iscsitarget/conn.c b/ubuntu/iscsitarget/conn.c index 5f91e3d..ec6dada 100644 --- a/ubuntu/iscsitarget/conn.c +++ b/ubuntu/iscsitarget/conn.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "iscsi.h" #include "iscsi_dbg.h" @@ -211,22 +212,39 @@ static int iet_conn_alloc(struct iscsi_session *session, struct conn_info *info) void conn_close(struct iscsi_conn *conn) { + struct iscsi_cmnd *cmnd; + struct iscsi_session *session = conn->session; + if (test_and_clear_bit(CONN_ACTIVE, &conn->state)) set_bit(CONN_CLOSING, &conn->state); + spin_lock(&conn->list_lock); + list_for_each_entry(cmnd, &conn->pdu_list, conn_list) { + set_cmnd_tmfabort(cmnd); + if (cmnd->lun) { + ua_establish_for_session(session, cmnd->lun->lun, 0x47, 0x7f); + iscsi_cmnd_set_sense(cmnd, UNIT_ATTENTION, 0x6e, 0x0); + } + } + spin_unlock(&conn->list_lock); + nthread_wakeup(conn->session->target); } int conn_add(struct iscsi_session *session, struct conn_info *info) { struct iscsi_conn *conn; - int err = -EEXIST; + int err; conn = conn_lookup(session, info->cid); if (conn) - return err; + conn_close(conn); - return iet_conn_alloc(session, info); + err = iet_conn_alloc(session, info); + if (!err && conn) + err = -EEXIST; + + return err; } int conn_del(struct iscsi_session *session, struct conn_info *info) @@ -242,12 +260,3 @@ int conn_del(struct iscsi_session *session, struct conn_info *info) return 0; } - -/* target_lock() supposed to be held */ -void conn_del_all(struct iscsi_session *session) -{ - struct iscsi_conn *conn; - - list_for_each_entry(conn, &session->conn_list, list) - conn_close(conn); -} diff --git a/ubuntu/iscsitarget/file-io.c b/ubuntu/iscsitarget/file-io.c index a492ce4..38951a9 100644 --- a/ubuntu/iscsitarget/file-io.c +++ b/ubuntu/iscsitarget/file-io.c @@ -53,9 +53,9 @@ static int fileio_make_request(struct iet_volume *lu, struct tio *tio, int rw) set_fs(get_ds()); if (rw == READ) - ret = do_sync_read(filp, buf, count, &ppos); + ret = vfs_read(filp, buf, count, &ppos); else - ret = do_sync_write(filp, buf, count, &ppos); + ret = vfs_write(filp, buf, count, &ppos); set_fs(oldfs); @@ -82,6 +82,7 @@ static int fileio_sync(struct iet_volume *lu, struct tio *tio) if (tio) { ppos = (loff_t) tio->idx << PAGE_CACHE_SHIFT; + ppos += tio->offset; count = tio->size; } else { ppos = 0; @@ -124,63 +125,18 @@ static int open_path(struct iet_volume *volume, const char *path) return err; } -static int set_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 void gen_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; - - 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 int set_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; -} - enum { - Opt_scsiid, Opt_scsisn, Opt_path, Opt_ignore, Opt_err, + opt_path, opt_ignore, opt_err, }; 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}, + {opt_path, "path=%s"}, + {opt_ignore, "scsiid=%s"}, + {opt_ignore, "scsisn=%s"}, + {opt_ignore, "type=%s"}, + {opt_ignore, "iomode=%s"}, + {opt_ignore, "blocksize=%s"}, + {opt_err, NULL}, }; static int parse_fileio_params(struct iet_volume *volume, char *params) @@ -194,29 +150,10 @@ static int parse_fileio_params(struct iet_volume *volume, char *params) int token; if (!*p) continue; + iet_strtolower(p); 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: + case opt_path: if (info->path) { iprintk("Target %s, LUN %u: " "duplicate \"Path\" param\n", @@ -233,7 +170,7 @@ static int parse_fileio_params(struct iet_volume *volume, char *params) if (err < 0) goto out; break; - case Opt_ignore: + case opt_ignore: break; default: iprintk("Target %s, LUN %u: unknown param %s\n", @@ -285,8 +222,6 @@ static int fileio_attach(struct iet_volume *lu, char *args) } inode = p->filp->f_dentry->d_inode; - gen_scsiid(lu, inode); - if (S_ISREG(inode->i_mode)) ; else if (S_ISBLK(inode->i_mode)) @@ -296,7 +231,9 @@ static int fileio_attach(struct iet_volume *lu, char *args) goto out; } - lu->blk_shift = SECTOR_SIZE_BITS; + if (!lu->blk_shift) + lu->blk_shift = ilog2(IET_DEF_BLOCK_SIZE); + lu->blk_cnt = inode->i_size >> lu->blk_shift; /* we're using the page cache */ diff --git a/ubuntu/iscsitarget/include/iet_u.h b/ubuntu/iscsitarget/include/iet_u.h index 620b3c4..174f0dc 100644 --- a/ubuntu/iscsitarget/include/iet_u.h +++ b/ubuntu/iscsitarget/include/iet_u.h @@ -1,7 +1,7 @@ #ifndef _IET_U_H #define _IET_U_H -#define IET_VERSION_STRING "1.4.19" +#define IET_VERSION_STRING "1.4.20.1" /* The maximum length of 223 bytes in the RFC. */ #define ISCSI_NAME_LEN 256 @@ -9,14 +9,17 @@ #define ISCSI_LISTEN_PORT 3260 -#define VENDOR_ID_LEN 8 -#define SCSI_ID_LEN 24 -#define SCSI_SN_LEN 16 +#define SCSI_ID_LEN 16 +#define SCSI_SN_LEN (SCSI_ID_LEN * 2) #ifndef aligned_u64 #define aligned_u64 unsigned long long __attribute__((aligned(8))) #endif +struct module_info { + char version[128]; +}; + struct target_info { u32 tid; char name[ISCSI_NAME_LEN]; @@ -131,19 +134,18 @@ struct iet_event { #define NETLINK_IET 21 -#define ADD_TARGET _IOW('i', 0, struct target_info) -#define DEL_TARGET _IOW('i', 1, struct target_info) -#define START_TARGET _IO('i', 2) -#define STOP_TARGET _IO('i', 3) -#define ADD_VOLUME _IOW('i', 4, struct volume_info) -#define DEL_VOLUME _IOW('i', 5, struct volume_info) -#define ADD_SESSION _IOW('i', 6, struct session_info) -#define DEL_SESSION _IOW('i', 7, struct session_info) -#define GET_SESSION_INFO _IOWR('i', 8, struct session_info) -#define ADD_CONN _IOW('i', 9, struct conn_info) -#define DEL_CONN _IOW('i', 10, struct conn_info) -#define GET_CONN_INFO _IOWR('i', 11, struct conn_info) -#define ISCSI_PARAM_SET _IOW('i', 12, struct iscsi_param_info) -#define ISCSI_PARAM_GET _IOWR('i', 13, struct iscsi_param_info) +#define GET_MODULE_INFO _IOW('i', 20, struct module_info) +#define ADD_TARGET _IOWR('i', 21, struct target_info) +#define DEL_TARGET _IOW('i', 22, struct target_info) +#define ADD_VOLUME _IOW('i', 24, struct volume_info) +#define DEL_VOLUME _IOW('i', 25, struct volume_info) +#define ADD_SESSION _IOW('i', 26, struct session_info) +#define DEL_SESSION _IOW('i', 27, struct session_info) +#define GET_SESSION_INFO _IOWR('i', 28, struct session_info) +#define ADD_CONN _IOW('i', 29, struct conn_info) +#define DEL_CONN _IOW('i', 30, struct conn_info) +#define GET_CONN_INFO _IOWR('i', 31, struct conn_info) +#define ISCSI_PARAM_SET _IOW('i', 32, struct iscsi_param_info) +#define ISCSI_PARAM_GET _IOWR('i', 33, struct iscsi_param_info) #endif diff --git a/ubuntu/iscsitarget/iotype.h b/ubuntu/iscsitarget/iotype.h index bd7fbd0..db7956a 100644 --- a/ubuntu/iscsitarget/iotype.h +++ b/ubuntu/iscsitarget/iotype.h @@ -3,6 +3,7 @@ * This code is licenced under the GPL. */ +#include #include "iscsi.h" #ifndef __IOTYPE_H__ @@ -26,4 +27,16 @@ extern struct iotype blockio; extern int iotype_init(void); extern void iotype_exit(void); +/* For option parameter parsing. + * This is slightly iet specific: we only tolower() up to the first '='. + * Note that this changes *c _in place_, but our parsing + * routines copy the input to a scratch page before parsing anyways. */ +static inline void iet_strtolower(char *c) +{ + if (!c) + return; + for (; *c && *c != '='; c++) + *c = tolower(*c); +} + #endif diff --git a/ubuntu/iscsitarget/iscsi.c b/ubuntu/iscsitarget/iscsi.c index 4f62b8b..05197f2 100644 --- a/ubuntu/iscsitarget/iscsi.c +++ b/ubuntu/iscsitarget/iscsi.c @@ -345,6 +345,8 @@ void iscsi_cmnd_set_sense(struct iscsi_cmnd *cmnd, u8 sense_key, u8 asc, cmnd->sense_buf[7] = 6; // Additional sense length cmnd->sense_buf[12] = asc; cmnd->sense_buf[13] = ascq; + + /* Call to ACA/UAI handler */ } static struct iscsi_cmnd *create_sense_rsp(struct iscsi_cmnd *req, @@ -534,10 +536,20 @@ static int check_cmd_sn(struct iscsi_cmnd *cmnd) u32 cmd_sn; cmnd->pdu.bhs.sn = cmd_sn = be32_to_cpu(cmnd->pdu.bhs.sn); - dprintk(D_GENERIC, "%d(%d)\n", cmd_sn, session->exp_cmd_sn); - if ((s32)(cmd_sn - session->exp_cmd_sn) >= 0) + + dprintk(D_GENERIC, "cmd_sn(%u) exp_cmd_sn(%u) max_cmd_sn(%u)\n", + cmd_sn, session->exp_cmd_sn, session->max_cmd_sn); + + if (between(cmd_sn, session->exp_cmd_sn, session->max_cmd_sn)) + return 0; + else if (cmnd_immediate(cmnd)) return 0; - eprintk("sequence error (%x,%x)\n", cmd_sn, session->exp_cmd_sn); + + eprintk("sequence error: cmd_sn(%u) exp_cmd_sn(%u) max_cmd_sn(%u)\n", + cmd_sn, session->exp_cmd_sn, session->max_cmd_sn); + + set_cmnd_tmfabort(cmnd); + return -ISCSI_REASON_PROTOCOL_ERROR; } @@ -609,7 +621,8 @@ static int cmnd_insert_hash(struct iscsi_cmnd *cmnd) if (!err) { update_stat_sn(cmnd); err = check_cmd_sn(cmnd); - } + } else if (!cmnd_immediate(cmnd)) + set_cmnd_tmfabort(cmnd); return err; } @@ -826,15 +839,12 @@ static void send_r2t(struct iscsi_cmnd *req) static void scsi_cmnd_exec(struct iscsi_cmnd *cmnd) { - if (cmnd->r2t_length) { - if (!cmnd->is_unsolicited_data) - send_r2t(cmnd); + assert(!cmnd->r2t_length); + + if (cmnd->lun) { + iscsi_scsi_queuecmnd(cmnd); } else { - if (cmnd->lun) { - iscsi_scsi_queuecmnd(cmnd); - } else { - iscsi_device_queue_cmnd(cmnd); - } + iscsi_device_queue_cmnd(cmnd); } } @@ -864,7 +874,7 @@ static int nop_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) } if (cmnd_itt(cmnd) == cpu_to_be32(ISCSI_RESERVED_TAG)) { - if (!(cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE)) + if (!cmnd_immediate(cmnd)) eprintk("%s\n", "initiator bug!"); update_stat_sn(cmnd); err = check_cmd_sn(cmnd); @@ -1093,6 +1103,8 @@ skip_data: return; } +static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd); + static void data_out_end(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) { struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *) &cmnd->pdu.bhs; @@ -1116,8 +1128,7 @@ static void data_out_end(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) if (req->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) { if (req->flags & ISCSI_FLG_FINAL) { scsi_cmnd->is_unsolicited_data = 0; - if (!cmnd_pending(scsi_cmnd)) - scsi_cmnd_exec(scsi_cmnd); + iscsi_session_push_cmnd(scsi_cmnd); } } else { /* TODO : proper error handling */ @@ -1132,7 +1143,7 @@ static void data_out_end(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd) if (scsi_cmnd->r2t_length == 0) assert(list_empty(&scsi_cmnd->pdu_list)); - scsi_cmnd_exec(scsi_cmnd); + iscsi_session_push_cmnd(scsi_cmnd); } out: @@ -1140,35 +1151,64 @@ out: return; } -static int __cmnd_abort(struct iscsi_cmnd *cmnd) +static void __cmnd_abort(struct iscsi_cmnd *cmnd) { + if (cmnd_rxstart(cmnd)) + set_cmnd_tmfabort(cmnd); + if (cmnd_waitio(cmnd)) - return -ISCSI_RESPONSE_UNKNOWN_TASK; + return; if (cmnd->conn->read_cmnd != cmnd) cmnd_release(cmnd, 1); - else if (cmnd_rxstart(cmnd)) - set_cmnd_tmfabort(cmnd); - else - return -ISCSI_RESPONSE_UNKNOWN_TASK; - - return 0; } -static int cmnd_abort(struct iscsi_session *session, u32 itt) +static int cmnd_abort(struct iscsi_session *session, struct iscsi_cmnd *req) { + struct iscsi_task_mgt_hdr *req_hdr = + (struct iscsi_task_mgt_hdr *)&req->pdu.bhs; struct iscsi_cmnd *cmnd; - int err = -ISCSI_RESPONSE_UNKNOWN_TASK; - - if ((cmnd = cmnd_find_hash(session, itt, ISCSI_RESERVED_TAG))) { - eprintk("%x %x %x %u %u %u %u\n", cmnd_itt(cmnd), cmnd_opcode(cmnd), - cmnd->r2t_length, cmnd_scsicode(cmnd), - cmnd_write_size(cmnd), cmnd->is_unsolicited_data, - cmnd->outstanding_r2t); - err = __cmnd_abort(cmnd); + + u32 min_cmd_sn = req_hdr->cmd_sn - session->max_queued_cmnds; + + req_hdr->ref_cmd_sn = be32_to_cpu(req_hdr->ref_cmd_sn); + + dprintk(D_GENERIC, "cmd_sn(%u) ref_cmd_sn(%u) min_cmd_sn(%u) rtt(%x)" + " lun(%d) cid(%u)\n", + req_hdr->cmd_sn, req_hdr->ref_cmd_sn, min_cmd_sn, req_hdr->rtt, + translate_lun(req_hdr->lun), req->conn->cid); + + if (after(req_hdr->ref_cmd_sn, req_hdr->cmd_sn)) + return ISCSI_RESPONSE_FUNCTION_REJECTED; + + if (!(cmnd = cmnd_find_hash(session, req_hdr->rtt, ISCSI_RESERVED_TAG))) { + if (between(req_hdr->ref_cmd_sn, min_cmd_sn, req_hdr->cmd_sn)) + return ISCSI_RESPONSE_FUNCTION_COMPLETE; + else + return ISCSI_RESPONSE_UNKNOWN_TASK; } - return err; + dprintk(D_GENERIC, "itt(%x) opcode(%x) scsicode(%x) lun(%d) cid(%u)\n", + cmnd_itt(cmnd), cmnd_opcode(cmnd), cmnd_scsicode(cmnd), + translate_lun(cmnd_hdr(cmnd)->lun), cmnd->conn->cid); + + if (cmnd_opcode(cmnd) == ISCSI_OP_SCSI_TASK_MGT_MSG) + return ISCSI_RESPONSE_FUNCTION_REJECTED; + + if (translate_lun(cmnd_hdr(cmnd)->lun) != + translate_lun(req_hdr->lun)) + return ISCSI_RESPONSE_FUNCTION_REJECTED; + + if (cmnd->conn && test_bit(CONN_ACTIVE, &cmnd->conn->state)) { + if (cmnd->conn->cid != req->conn->cid) + return ISCSI_RESPONSE_FUNCTION_REJECTED; + } else { + /* Switch cmnd connection allegiance */ + } + + __cmnd_abort(cmnd); + + return ISCSI_RESPONSE_FUNCTION_COMPLETE; } static int target_reset(struct iscsi_cmnd *req, u32 lun, int all) @@ -1187,7 +1227,8 @@ static int target_reset(struct iscsi_cmnd *req, u32 lun, int all) if (all) __cmnd_abort(cmnd); - else if (translate_lun(cmnd_hdr(cmnd)->lun) == lun) + else if (translate_lun(cmnd_hdr(cmnd)->lun) + == lun) __cmnd_abort(cmnd); } } @@ -1214,7 +1255,12 @@ static void task_set_abort(struct iscsi_cmnd *req) list_for_each_entry(conn, &session->conn_list, list) { list_for_each_entry_safe(cmnd, tmp, &conn->pdu_list, conn_list) { - if (cmnd != req) + if (translate_lun(cmnd_hdr(cmnd)->lun) + != translate_lun(cmnd_hdr(req)->lun)) + continue; + + if (before(cmnd_hdr(cmnd)->cmd_sn, + cmnd_hdr(req)->cmd_sn)) __cmnd_abort(cmnd); } } @@ -1274,7 +1320,7 @@ static void execute_task_management(struct iscsi_cmnd *req) struct iscsi_task_mgt_hdr *req_hdr = (struct iscsi_task_mgt_hdr *)&req->pdu.bhs; struct iscsi_task_rsp_hdr *rsp_hdr; u32 lun; - int err, function = req_hdr->function & ISCSI_FUNCTION_MASK; + int function = req_hdr->function & ISCSI_FUNCTION_MASK; rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); rsp_hdr = (struct iscsi_task_rsp_hdr *)&rsp->pdu.bhs; @@ -1299,8 +1345,7 @@ static void execute_task_management(struct iscsi_cmnd *req) switch (function) { case ISCSI_FUNCTION_ABORT_TASK: - if ((err = cmnd_abort(conn->session, req_hdr->rtt)) < 0) - rsp_hdr->response = -err; + rsp_hdr->response = cmnd_abort(conn->session, req); break; case ISCSI_FUNCTION_ABORT_TASK_SET: task_set_abort(req); @@ -1443,7 +1488,7 @@ static void nop_in_tx_end(struct iscsi_cmnd *cmnd) conn->session->target->trgt_param.nop_timeout = t; } - dprintk(D_GENERIC, "NOP-In %p, %x: timer %p\n", cmnd, cmnd_ttt(cmnd), + dprintk(D_GENERIC, "NOP-In %p, %x: timer %p\n", cmnd, cmnd_ttt(cmnd), &cmnd->req->timer); set_cmnd_timer_active(cmnd->req); @@ -1700,10 +1745,16 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd) struct list_head *entry; u32 cmd_sn; + if (cmnd->r2t_length) { + if (!cmnd->is_unsolicited_data) + send_r2t(cmnd); + return; + } + dprintk(D_GENERIC, "%p:%x %u,%u\n", cmnd, cmnd_opcode(cmnd), cmnd->pdu.bhs.sn, session->exp_cmd_sn); - if (cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE) { + if (cmnd_immediate(cmnd)) { iscsi_cmnd_exec(cmnd); return; } @@ -1716,24 +1767,16 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd) if (list_empty(&session->pending_list)) break; + cmnd = list_entry(session->pending_list.next, struct iscsi_cmnd, list); if (cmnd->pdu.bhs.sn != cmd_sn) break; -/* eprintk("find out-of-order %x %u %u\n", */ -/* cmnd_itt(cmnd), cmd_sn, cmnd->pdu.bhs.sn); */ + list_del_init(&cmnd->list); clear_cmnd_pending(cmnd); } } else { -/* eprintk("out-of-order %x %u %u\n", */ -/* cmnd_itt(cmnd), cmd_sn, session->exp_cmd_sn); */ - set_cmnd_pending(cmnd); - if (before(cmd_sn, session->exp_cmd_sn)) /* close the conn */ - eprintk("unexpected cmd_sn (%u,%u)\n", cmd_sn, session->exp_cmd_sn); - - if (after(cmd_sn, session->exp_cmd_sn + session->max_queued_cmnds)) - eprintk("too large cmd_sn (%u,%u)\n", cmd_sn, session->exp_cmd_sn); list_for_each(entry, &session->pending_list) { struct iscsi_cmnd *tmp = list_entry(entry, struct iscsi_cmnd, list); diff --git a/ubuntu/iscsitarget/iscsi.h b/ubuntu/iscsitarget/iscsi.h index 92ce252..e9d37a4 100644 --- a/ubuntu/iscsitarget/iscsi.h +++ b/ubuntu/iscsitarget/iscsi.h @@ -8,6 +8,7 @@ #ifndef __ISCSI_H__ #define __ISCSI_H__ +#include #include #include #include @@ -92,6 +93,8 @@ struct worker_thread_info { struct list_head work_queue; wait_queue_head_t wthread_sleep; + + struct io_context *wthread_ioc; }; struct iscsi_cmnd; @@ -127,7 +130,6 @@ struct iscsi_target { struct worker_thread_info * wthread_info; struct semaphore target_sem; - struct completion *done; }; struct iscsi_queue { @@ -149,7 +151,7 @@ struct iet_volume { struct iscsi_queue queue; u8 scsi_id[SCSI_ID_LEN]; - u8 scsi_sn[SCSI_SN_LEN]; + u8 scsi_sn[SCSI_SN_LEN + 1]; u32 blk_shift; u64 blk_cnt; @@ -336,7 +338,6 @@ extern void send_nop_in(struct iscsi_conn *); extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16); extern int conn_add(struct iscsi_session *, struct conn_info *); extern int conn_del(struct iscsi_session *, struct conn_info *); -extern void conn_del_all(struct iscsi_session *); extern int conn_free(struct iscsi_conn *); extern void conn_close(struct iscsi_conn *); extern void conn_info_show(struct seq_file *, struct iscsi_session *); @@ -377,7 +378,6 @@ extern struct file_operations session_seq_fops; extern struct iscsi_session *session_lookup(struct iscsi_target *, u64); extern int session_add(struct iscsi_target *, struct session_info *); extern int session_del(struct iscsi_target *, u64); -extern void session_del_all(struct iscsi_target *); /* volume.c */ extern struct file_operations volume_seq_fops; @@ -464,8 +464,11 @@ static inline void iscsi_cmnd_set_length(struct iscsi_pdu *pdu) #define cmnd_itt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.itt) #define cmnd_opcode(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OPCODE_MASK) #define cmnd_scsicode(cmnd) cmnd_hdr(cmnd)->scb[0] +#define cmnd_immediate(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE) -#define SECTOR_SIZE_BITS 9 +/* default and maximum scsi level block sizes */ +#define IET_DEF_BLOCK_SIZE 512 +#define IET_MAX_BLOCK_SIZE 4096 enum cmnd_flags { CMND_hashed, diff --git a/ubuntu/iscsitarget/nthread.c b/ubuntu/iscsitarget/nthread.c index ec54ead..52cd69a 100644 --- a/ubuntu/iscsitarget/nthread.c +++ b/ubuntu/iscsitarget/nthread.c @@ -209,6 +209,7 @@ static int recv(struct iscsi_conn *conn) hdigest = conn->hdigest_type & DIGEST_NONE ? 0 : 1; ddigest = conn->ddigest_type & DIGEST_NONE ? 0 : 1; +next_state: switch (conn->read_state) { case RX_INIT_BHS: assert(!cmnd); @@ -270,7 +271,7 @@ static int recv(struct iscsi_conn *conn) return res; if (conn->read_state != RX_END) - return res; + goto next_state; if (conn->read_size) { eprintk("%d %x %d\n", res, cmnd_opcode(cmnd), conn->read_size); @@ -525,6 +526,7 @@ static int send(struct iscsi_conn *conn) ddigest = conn->ddigest_type != DIGEST_NONE ? 1 : 0; +next_state: switch (conn->write_state) { case TX_INIT: assert(!cmnd); @@ -555,7 +557,7 @@ static int send(struct iscsi_conn *conn) return res; if (conn->write_state != TX_END) - return res; + goto next_state; if (conn->write_size) { eprintk("%d %x %u\n", res, cmnd_opcode(cmnd), conn->write_size); diff --git a/ubuntu/iscsitarget/null-io.c b/ubuntu/iscsitarget/null-io.c index cfa5899..f64b18c 100644 --- a/ubuntu/iscsitarget/null-io.c +++ b/ubuntu/iscsitarget/null-io.c @@ -16,41 +16,44 @@ #include "iscsi_dbg.h" #include "iotype.h" -struct nullio_data { - u64 sectors; -}; - enum { - Opt_sectors, Opt_ignore, Opt_err, + opt_blk_cnt, opt_ignore, opt_err, }; static match_table_t tokens = { - {Opt_sectors, "Sectors=%u"}, - {Opt_ignore, "Type=%s"}, - {Opt_err, NULL}, + /* alias for compatibility with existing setups and documentation */ + {opt_blk_cnt, "sectors=%u"}, + /* but actually it is the scsi block count, now that we can + * specify the block size. */ + {opt_blk_cnt, "blocks=%u"}, + {opt_ignore, "scsiid=%s"}, + {opt_ignore, "scsisn=%s"}, + {opt_ignore, "blocksize=%s"}, + {opt_ignore, "type=%s"}, + {opt_err, NULL}, }; static int parse_nullio_params(struct iet_volume *volume, char *params) { int err = 0; char *p, *q; - struct nullio_data *data = volume->private; while ((p = strsep(¶ms, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; int token; if (!*p) continue; + iet_strtolower(p); token = match_token(p, tokens, args); switch (token) { - case Opt_sectors: + case opt_blk_cnt: q = match_strdup(&args[0]); if (!q) return -ENOMEM; - data->sectors = simple_strtoull(q, NULL, 10); + volume->blk_cnt = simple_strtoull(q, NULL, 10); kfree(q); break; - case Opt_ignore: + case opt_ignore: break; default: eprintk("Unknown %s\n", p); @@ -63,35 +66,23 @@ static int parse_nullio_params(struct iet_volume *volume, char *params) static void nullio_detach(struct iet_volume *lu) { - struct nullio_data *p = lu->private; - - kfree(p); - lu->private = NULL; } static int nullio_attach(struct iet_volume *lu, char *args) { int err = 0; - struct nullio_data *p; - - if (lu->private) { - printk("already attached ? %d\n", lu->lun); - return -EBUSY; - } - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - lu->private = p; if ((err = parse_nullio_params(lu, args)) < 0) { eprintk("%d\n", err); goto out; } - lu->blk_shift = SECTOR_SIZE_BITS; - lu->blk_cnt = (p->sectors = p->sectors ? : 1 << 27); /* 64 GB */ + if (!lu->blk_shift) + lu->blk_shift = ilog2(IET_DEF_BLOCK_SIZE); + + /* defaults to 64 GiB */ + if (!lu->blk_cnt) + lu->blk_cnt = 1 << (36 - lu->blk_shift); out: if (err < 0) @@ -99,16 +90,9 @@ out: return err; } -void nullio_show(struct iet_volume *lu, struct seq_file *seq) -{ - struct nullio_data *p = lu->private; - seq_printf(seq, " sectors:%llu\n", p->sectors); -} - struct iotype nullio = { .name = "nullio", .attach = nullio_attach, .detach = nullio_detach, - .show = nullio_show, }; diff --git a/ubuntu/iscsitarget/param.c b/ubuntu/iscsitarget/param.c index 57ad301..482d00c 100644 --- a/ubuntu/iscsitarget/param.c +++ b/ubuntu/iscsitarget/param.c @@ -43,7 +43,7 @@ static void sess_param_check(struct iscsi_param_info *info) { u32 *iparam = info->session_param; - CHECK_PARAM(info, iparam, max_connections, 1, 1); + CHECK_PARAM(info, iparam, max_connections, 1, 65535); CHECK_PARAM(info, iparam, max_recv_data_length, 512, (u32) ((ISCSI_CONN_IOV_MAX - 1) * PAGE_CACHE_SIZE)); CHECK_PARAM(info, iparam, max_xmit_data_length, 512, diff --git a/ubuntu/iscsitarget/session.c b/ubuntu/iscsitarget/session.c index 6365373..a566d8b 100644 --- a/ubuntu/iscsitarget/session.c +++ b/ubuntu/iscsitarget/session.c @@ -124,40 +124,30 @@ int session_add(struct iscsi_target *target, struct session_info *info) int session_del(struct iscsi_target *target, u64 sid) { struct iscsi_session *session; + struct iet_volume *volume; session = session_lookup(target, sid); if (!session) return -ENOENT; if (!list_empty(&session->conn_list)) { - eprintk("%llu still have connections\n", (unsigned long long) session->sid); - return -EBUSY; - } + DECLARE_COMPLETION_ONSTACK(done); + struct iscsi_conn *conn; - return session_free(session); -} - -void session_del_all(struct iscsi_target *target) -{ - DECLARE_COMPLETION_ONSTACK(done); - struct iscsi_session *sess; + session->done = &done; + list_for_each_entry(conn, &session->conn_list, list) + conn_close(conn); - while (!list_empty(&target->session_list)) { - init_completion(&done); - target_lock(target, 0); - sess = list_entry(target->session_list.next, struct - iscsi_session, list); - sess->done = &done; - conn_del_all(sess); target_unlock(target); wait_for_completion(&done); target_lock(target, 0); - session_free(sess); - target_unlock(target); } - if (target->done) - complete(target->done); + list_for_each_entry(volume, &target->volumes, list){ + volume_release(volume, sid, 0); + } + + return session_free(session); } static void iet_session_info_show(struct seq_file *seq, struct iscsi_target *target) diff --git a/ubuntu/iscsitarget/target.c b/ubuntu/iscsitarget/target.c index 15c0715..43326dc 100644 --- a/ubuntu/iscsitarget/target.c +++ b/ubuntu/iscsitarget/target.c @@ -192,21 +192,23 @@ out: int target_add(struct target_info *info) { - int err = -EEXIST; u32 tid = info->tid; + int err; - down(&target_list_sem); + err = down_interruptible(&target_list_sem); + if (err < 0) + return err; if (nr_targets > MAX_NR_TARGETS) { err = -EBUSY; goto out; } - if (__target_lookup_by_name(info->name)) - goto out; - - if (tid && __target_lookup_by_id(tid)) + if (__target_lookup_by_name(info->name) || + (tid && __target_lookup_by_id(tid))) { + err = -EEXIST; goto out; + } if (!tid) { do { @@ -217,7 +219,8 @@ int target_add(struct target_info *info) tid = next_target_id; } - if (!(err = iscsi_target_create(info, tid))) + err = iscsi_target_create(info, tid); + if (!err) nr_targets++; out: up(&target_list_sem); @@ -246,13 +249,24 @@ static void target_destroy(struct iscsi_target *target) } /* @locking: target_list_sem must be locked */ -int __target_del(struct iscsi_target *target) +static int __target_del(struct iscsi_target *target) { + int err; + target_lock(target, 0); if (!list_empty(&target->session_list)) { - target_unlock(target); - return -EBUSY; + struct iscsi_session *session; + + do { + session = list_entry(target->session_list.next, + struct iscsi_session, list); + err = session_del(target, session->sid); + if (err < 0) { + target_unlock(target); + return err; + } + } while (!list_empty(&target->session_list)); } list_del(&target->t_list); @@ -260,13 +274,16 @@ int __target_del(struct iscsi_target *target) target_unlock(target); target_destroy(target); + return 0; } int target_del(u32 id) { struct iscsi_target *target; - int err = down_interruptible(&target_list_sem); + int err; + + err = down_interruptible(&target_list_sem); if (err < 0) return err; @@ -277,15 +294,16 @@ int target_del(u32 id) } err = __target_del(target); - out: +out: up(&target_list_sem); + return err; } void target_del_all(void) { - DECLARE_COMPLETION_ONSTACK(done); struct iscsi_target *target, *tmp; + int err; down(&target_list_sem); @@ -293,11 +311,10 @@ void target_del_all(void) iprintk("Removing all connections, sessions and targets\n"); list_for_each_entry_safe(target, tmp, &target_list, t_list) { - init_completion(&done); - target->done = &done; - session_del_all(target); - wait_for_completion(&done); - __target_del(target); + u32 tid = target->tid; + err =__target_del(target); + if (err) + eprintk("Error deleteing target %u: %d\n", tid, err); } next_target_id = 0; diff --git a/ubuntu/iscsitarget/target_disk.c b/ubuntu/iscsitarget/target_disk.c index 694edb2..1f7693c 100644 --- a/ubuntu/iscsitarget/target_disk.c +++ b/ubuntu/iscsitarget/target_disk.c @@ -193,11 +193,11 @@ static void build_inquiry_response(struct iscsi_cmnd *cmnd) data[7] = 0x02; memset(data + 8, 0x20, 28); memcpy(data + 8, - VENDOR_ID, min_t(size_t, strlen(VENDOR_ID), 8)); + VENDOR_ID, min_t(size_t, strlen(VENDOR_ID), 8)); memcpy(data + 16, - PRODUCT_ID, min_t(size_t, strlen(PRODUCT_ID), 16)); + PRODUCT_ID, min_t(size_t, strlen(PRODUCT_ID), 16)); memcpy(data + 32, - PRODUCT_REV, min_t(size_t, strlen(PRODUCT_REV), 4)); + PRODUCT_REV, min_t(size_t, strlen(PRODUCT_REV), 4)); data[58] = 0x03; data[59] = 0x20; data[60] = 0x09; @@ -217,35 +217,41 @@ static void build_inquiry_response(struct iscsi_cmnd *cmnd) tio_set(tio, 7, 0); err = 0; } else if (scb[2] == 0x80) { - int len = (cmnd->lun && strlen(cmnd->lun->scsi_sn)) ? - SCSI_SN_LEN : 4; + u32 len = 4; + + if (cmnd->lun) { + if (strlen(cmnd->lun->scsi_sn) <= 16) + len = 16; + else + len = SCSI_SN_LEN; + } data[1] = 0x80; data[3] = len; memset(data + 4, 0x20, len); + if (cmnd->lun) { + size_t offset = len - + strlen(cmnd->lun->scsi_sn); + memcpy(data + 4 + offset, cmnd->lun->scsi_sn, + strlen(cmnd->lun->scsi_sn)); + } tio_set(tio, len + 4, 0); err = 0; - - if (len == SCSI_SN_LEN) { - char *p, *q; - - p = data + 4 + len - 1; - q = cmnd->lun->scsi_sn + len - 1; - - for (; len > 0; len--, q--) - if (isascii(*q) && isprint(*q)) - *(p--) = *q; - } } else if (scb[2] == 0x83) { - u32 len = SCSI_ID_LEN * sizeof(u8); + u32 len = SCSI_ID_LEN + 8; data[1] = 0x83; data[3] = len + 4; data[4] = 0x1; data[5] = 0x1; data[7] = len; - if (cmnd->lun) /* We need this ? */ - memcpy(data + 8, cmnd->lun->scsi_id, len); + if (cmnd->lun) { /* We need this ? */ + memset(data + 8, 0x00, 8); + memcpy(data + 8, VENDOR_ID, + min_t(size_t, strlen(VENDOR_ID), 8)); + memcpy(data + 16, cmnd->lun->scsi_id, + SCSI_ID_LEN); + } tio_set(tio, len + 8, 0); err = 0; } @@ -432,9 +438,19 @@ static void build_reserve_response(struct iscsi_cmnd *cmnd) static void build_release_response(struct iscsi_cmnd *cmnd) { - if (volume_release(cmnd->lun, - cmnd->conn->session->sid, 0)) + int ret = volume_release(cmnd->lun, + cmnd->conn->session->sid, 0); + switch (ret) { + case -ENOENT: + /* Logical Unit Not Supported (?) */ + iscsi_cmnd_set_sense(cmnd, ILLEGAL_REQUEST, 0x25, 0x0); + break; + case -EBUSY: cmnd->status = SAM_STAT_RESERVATION_CONFLICT; + break; + default: + break; + } } static void build_reservation_conflict_response(struct iscsi_cmnd *cmnd) @@ -475,8 +491,9 @@ static int disk_check_reservation(struct iscsi_cmnd *cmnd) { struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); - if (is_volume_reserved(cmnd->lun, - cmnd->conn->session->sid)) { + int ret = is_volume_reserved(cmnd->lun, + cmnd->conn->session->sid); + if (ret == -EBUSY) { switch (req->scb[0]) { case INQUIRY: case RELEASE: diff --git a/ubuntu/iscsitarget/ua.c b/ubuntu/iscsitarget/ua.c index db08169..c4ba4c2 100644 --- a/ubuntu/iscsitarget/ua.c +++ b/ubuntu/iscsitarget/ua.c @@ -109,6 +109,7 @@ void ua_establish_for_session(struct iscsi_session *sess, u32 lun, { struct list_head *l = &sess->ua_hash[ua_hashfn(lun)]; struct ua_entry *ua = kmem_cache_alloc(ua_cache, GFP_KERNEL); + struct ua_entry *e; if (!ua) { eprintk("%s", "Failed to alloc ua"); @@ -119,8 +120,19 @@ void ua_establish_for_session(struct iscsi_session *sess, u32 lun, ua->ascq = ascq; ua->lun = lun; ua->session = sess; + INIT_LIST_HEAD(&ua->entry); spin_lock(&sess->ua_hash_lock); + /* One UA per occurrence of an event */ + list_for_each_entry(e, l, entry) { + if (e->session == sess && e->lun == lun && + e->asc == asc && e->ascq == ascq && + e->session->exp_cmd_sn == sess->exp_cmd_sn) { + spin_unlock(&sess->ua_hash_lock); + ua_free(ua); + return; + } + } list_add_tail(&ua->entry, l); spin_unlock(&sess->ua_hash_lock); diff --git a/ubuntu/iscsitarget/volume.c b/ubuntu/iscsitarget/volume.c index ca0d9ca..6abe16b 100644 --- a/ubuntu/iscsitarget/volume.c +++ b/ubuntu/iscsitarget/volume.c @@ -6,6 +6,7 @@ #include #include +#include #include "iscsi.h" #include "iscsi_dbg.h" @@ -23,25 +24,108 @@ struct iet_volume *volume_lookup(struct iscsi_target *target, u32 lun) } enum { - Opt_type, - Opt_iomode, - Opt_err, + opt_type, + opt_iomode, + opt_scsiid, + opt_scsisn, + opt_blk_size, + opt_err, }; static match_table_t tokens = { - {Opt_type, "Type=%s"}, - {Opt_iomode, "IOMode=%s"}, - {Opt_err, NULL}, + {opt_type, "type=%s"}, + {opt_iomode, "iomode=%s"}, + {opt_scsiid, "scsiid=%s"}, + {opt_scsisn, "scsisn=%s"}, + {opt_blk_size, "blocksize=%u"}, + {opt_err, NULL}, }; -static int set_iotype(struct iet_volume *volume, char *params) +static int set_scsiid(struct iet_volume *volume, const char *id) +{ + size_t len; + + if ((len = strlen(id)) > SCSI_ID_LEN) { + eprintk("SCSI ID too long, %zd provided, %u max\n", len, + SCSI_ID_LEN); + return -EINVAL; + } + + memcpy(volume->scsi_id, id, len); + + return 0; +} + +static int set_scsisn(struct iet_volume *volume, const char *sn) +{ + size_t len; + int i; + + if ((len = strlen(sn)) > SCSI_SN_LEN) { + eprintk("SCSI SN too long, %zd provided, %u max\n", len, + SCSI_SN_LEN); + return -EINVAL; + } + + for (i = 0; i < len; i++) { + if (!isascii(*(sn + i)) || !isprint(*(sn + i))) { + eprintk("invalid characters in SCSI SN, %s\n", + "only printable ascii characters allowed!"); + return -EINVAL; + } + } + + memcpy(volume->scsi_sn, sn, len); + + return 0; +} + +/* Generate a MD5 hash of the target IQN and LUN number */ +static void gen_scsiid(struct iet_volume *volume) +{ + struct hash_desc hash; + + hash.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); + hash.flags = 0; + + if (hash.tfm) { + struct scatterlist sg[2]; + unsigned int nbytes = 0; + + sg_init_table(sg, 2); + + sg_set_buf(&sg[0], volume->target->name, + strlen(volume->target->name)); + nbytes += strlen(volume->target->name); + + sg_set_buf(&sg[1], &volume->lun, sizeof(volume->lun)); + nbytes += sizeof(volume->lun); + + crypto_hash_init(&hash); + crypto_hash_update(&hash, sg, nbytes); + crypto_hash_final(&hash, volume->scsi_id); + + crypto_free_hash(hash.tfm); + } else { + /* If no MD5 available set ID to TID and LUN */ + memcpy(volume->scsi_id, &volume->target->tid, + sizeof(volume->target->tid)); + memcpy(volume->scsi_id + sizeof(volume->target->tid), + &volume->lun, sizeof(volume->lun)); + } + +} + +static int parse_volume_params(struct iet_volume *volume, char *params) { int err = 0; + unsigned blk_sz; substring_t args[MAX_OPT_ARGS]; char *p, *argp = NULL, *buf = (char *) get_zeroed_page(GFP_USER); if (!buf) return -ENOMEM; + strncpy(buf, params, PAGE_CACHE_SIZE); while ((p = strsep(&buf, ",")) != NULL) { @@ -49,22 +133,65 @@ static int set_iotype(struct iet_volume *volume, char *params) if (!*p) continue; + iet_strtolower(p); token = match_token(p, tokens, args); switch (token) { - case Opt_type: - if (!(argp = match_strdup(&args[0]))) + case opt_type: + argp = match_strdup(&args[0]); + if (!argp) { err = -ENOMEM; - if (argp && !(volume->iotype = get_iotype(argp))) + break; + } + if (!(volume->iotype = get_iotype(argp))) err = -ENOENT; kfree(argp); break; - case Opt_iomode: - if (!(argp = match_strdup(&args[0]))) + case opt_iomode: + argp = match_strdup(&args[0]); + if (!argp) { err = -ENOMEM; - if (argp && !strcmp(argp, "ro")) + break; + } + if (!strcmp(argp, "ro")) SetLUReadonly(volume); - else if (argp && !strcmp(argp, "wb")) + else if (!strcmp(argp, "wb")) SetLUWCache(volume); + else if (strcmp(argp, "wt")) + err = -EINVAL; + kfree(argp); + break; + case opt_scsiid: + argp = match_strdup(&args[0]); + if (!argp) { + err = -ENOMEM; + break; + } + err = set_scsiid(volume, argp); + kfree(argp); + break; + case opt_scsisn: + argp = match_strdup(&args[0]); + if (!argp) { + err = -ENOMEM; + break; + } + err = set_scsisn(volume, argp); + kfree(argp); + break; + case opt_blk_size: + argp = match_strdup(&args[0]); + if (!argp) { + err = -ENOMEM; + break; + } + blk_sz = simple_strtoull(argp, NULL, 10); + if (is_power_of_2(blk_sz) && + 512 <= blk_sz && blk_sz <= IET_MAX_BLOCK_SIZE) + volume->blk_shift = ilog2(blk_sz); + else { + eprintk("invalid BlockSize=%u\n", blk_sz); + err = -EINVAL; + } kfree(argp); break; default: @@ -115,7 +242,7 @@ int volume_add(struct iscsi_target *target, struct volume_info *info) goto free_args; } - ret = set_iotype(volume, args); + ret = parse_volume_params(volume, args); if (ret < 0) goto free_args; @@ -123,6 +250,17 @@ int volume_add(struct iscsi_target *target, struct volume_info *info) if (ret < 0) goto free_args; + if (!volume->scsi_id[0]) + gen_scsiid(volume); + + if (!volume->scsi_sn[0]) { + int i; + + for (i = 0; i < SCSI_ID_LEN; i++) + snprintf(volume->scsi_sn + (i * 2), 3, "%02x", + volume->scsi_id[i]); + } + INIT_LIST_HEAD(&volume->queue.wait_list); spin_lock_init(&volume->queue.queue_lock); spin_lock_init(&volume->reserve_lock); @@ -193,35 +331,54 @@ void volume_put(struct iet_volume *volume) int volume_reserve(struct iet_volume *volume, u64 sid) { + int err = 0; + if (!volume) return -ENOENT; spin_lock(&volume->reserve_lock); - if (volume->reserve_sid && volume->reserve_sid != sid) { - spin_unlock(&volume->reserve_lock); - return -EBUSY; - } + if (volume->reserve_sid && volume->reserve_sid != sid) + err = -EBUSY; + else + volume->reserve_sid = sid; - volume->reserve_sid = sid; spin_unlock(&volume->reserve_lock); - - return 0; + return err; } int is_volume_reserved(struct iet_volume *volume, u64 sid) { - if (!volume || !volume->reserve_sid || volume->reserve_sid == sid) - return 0; + int err = 0; - return -EBUSY; + if (!volume) + return -ENOENT; + + spin_lock(&volume->reserve_lock); + if (!volume->reserve_sid || volume->reserve_sid == sid) + err = 0; + else + err = -EBUSY; + + spin_unlock(&volume->reserve_lock); + return err; } int volume_release(struct iet_volume *volume, u64 sid, int force) { + int err = 0; + + if (!volume) + return -ENOENT; + + spin_lock(&volume->reserve_lock); + if (force || volume->reserve_sid == sid) volume->reserve_sid = 0; + else + err = -EBUSY; - return 0; + spin_unlock(&volume->reserve_lock); + return err; } static void iet_volume_info_show(struct seq_file *seq, struct iscsi_target *target) @@ -238,6 +395,8 @@ static void iet_volume_info_show(struct seq_file *seq, struct iscsi_target *targ else seq_printf(seq, " iomode:wt"); + seq_printf(seq, " blocks:%llu blocksize:%u", + volume->blk_cnt, 1 << volume->blk_shift); if (volume->iotype->show) volume->iotype->show(volume, seq); else diff --git a/ubuntu/iscsitarget/wthread.c b/ubuntu/iscsitarget/wthread.c index b49ddb7..997a3d6 100644 --- a/ubuntu/iscsitarget/wthread.c +++ b/ubuntu/iscsitarget/wthread.c @@ -67,6 +67,15 @@ static int worker_thread(void *arg) struct iscsi_conn *conn; DECLARE_WAITQUEUE(wait, current); + get_io_context(GFP_KERNEL, -1); + + if (!current->io_context) + eprintk("%s\n", "Failed to get IO context"); + else if (info->wthread_ioc) + copy_io_context(¤t->io_context, &info->wthread_ioc); + else + info->wthread_ioc = current->io_context; + add_wait_queue(&info->wthread_sleep, &wait); __set_current_state(TASK_RUNNING); @@ -74,12 +83,15 @@ static int worker_thread(void *arg) while (!list_empty(&info->work_queue) && (cmnd = get_ready_cmnd(info))) { conn = cmnd->conn; - cmnd_execute(cmnd); + if (cmnd_tmfabort(cmnd)) + cmnd_release(cmnd, 1); + else + cmnd_execute(cmnd); assert(conn); atomic_dec(&conn->nr_busy_cmnds); } - __set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&info->work_queue)) schedule(); @@ -88,6 +100,16 @@ static int worker_thread(void *arg) remove_wait_queue(&info->wthread_sleep, &wait); + if (current->io_context) { + struct io_context *ioc = current->io_context; + + task_lock(current); + current->io_context = NULL; + task_unlock(current); + + put_io_context(ioc); + } + return 0; } @@ -138,6 +160,7 @@ int wthread_init(struct worker_thread_info *info) spin_lock_init(&info->wthread_lock); info->nr_running_wthreads = 0; + info->wthread_ioc = NULL; INIT_LIST_HEAD(&info->work_queue); INIT_LIST_HEAD(&info->wthread_list);