aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2020-02-21 17:29:14 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2020-02-21 17:29:14 +0000
commit76b39a024cd642d677bda6da434f6f73cc80319e (patch)
tree1ee31ec26e55f8045198ccccd0c09bcd2040281b /src
parent2c0eaa5dae9285523e2a1c713369e689a85a4c96 (diff)
downloadsg3_utils-76b39a024cd642d677bda6da434f6f73cc80319e.tar.gz
sgp_dd: support memory-mapped IO via mmap flag; sg_rep_zones: add --num= and --wp options
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@842 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src')
-rw-r--r--src/sg_dd.c18
-rw-r--r--src/sg_rep_zones.c51
-rw-r--r--src/sgm_dd.c22
-rw-r--r--src/sgp_dd.c366
4 files changed, 299 insertions, 158 deletions
diff --git a/src/sg_dd.c b/src/sg_dd.c
index f3782b2d..55de0930 100644
--- a/src/sg_dd.c
+++ b/src/sg_dd.c
@@ -66,7 +66,7 @@
#include "sg_unaligned.h"
#include "sg_pr2serr.h"
-static const char * version_str = "6.09 20200117";
+static const char * version_str = "6.10 20200216";
#define ME "sg_dd: "
@@ -649,7 +649,7 @@ sg_read_low(int sg_fd, uint8_t * buff, int blocks, int64_t from_block,
sg_print_command_len(rdCmd, ifp->cdbsz);
while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
if (res < 0) {
if (ENOMEM == errno)
@@ -1054,7 +1054,7 @@ sg_write(int sg_fd, uint8_t * buff, int blocks, int64_t to_block,
sg_print_command_len(wrCmd, ofp->cdbsz);
while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
if (res < 0) {
if (ENOMEM == errno)
@@ -2061,7 +2061,8 @@ main(int argc, char * argv[])
}
} else {
while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) ||
+ (EBUSY == errno)))
;
if (verbose > 2)
pr2serr("read(unix): count=%d, res=%d\n", blocks * blk_sz,
@@ -2089,7 +2090,8 @@ main(int argc, char * argv[])
if (out2f[0]) {
while (((res = write(out2fd, wrkPos, blocks * blk_sz)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) ||
+ (EBUSY == errno)))
;
if (verbose > 2)
pr2serr("write to of2: count=%d, res=%d\n", blocks * blk_sz,
@@ -2215,7 +2217,8 @@ main(int argc, char * argv[])
out_full += blocks; /* act as if written out without error */
else {
while (((res = write(outfd, wrkPos, blocks * blk_sz)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) ||
+ (EBUSY == errno)))
;
if (verbose > 2)
pr2serr("write(unix): count=%d, res=%d\n", blocks * blk_sz,
@@ -2283,7 +2286,8 @@ main(int argc, char * argv[])
else {
/* ... try writing to extend ofile to length prior to error */
while (((res = write(outfd, zeros_buff, penult_blocks * blk_sz))
- < 0) && ((EINTR == errno) || (EAGAIN == errno)))
+ < 0) && ((EINTR == errno) || (EAGAIN == errno) ||
+ (EBUSY == errno)))
;
if (verbose > 2)
pr2serr("write(unix, sparse after error): count=%d, res=%d\n",
diff --git a/src/sg_rep_zones.c b/src/sg_rep_zones.c
index cf390f19..388c4001 100644
--- a/src/sg_rep_zones.c
+++ b/src/sg_rep_zones.c
@@ -38,7 +38,7 @@
* and decodes the response. Based on zbc-r02.pdf
*/
-static const char * version_str = "1.20 20200122";
+static const char * version_str = "1.21 20200220";
#define MAX_RZONES_BUFF_LEN (1024 * 1024)
#define DEF_RZONES_BUFF_LEN (1024 * 8)
@@ -55,6 +55,7 @@ static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"hex", no_argument, 0, 'H'},
{"maxlen", required_argument, 0, 'm'},
+ {"num", required_argument, 0, 'n'},
{"partial", no_argument, 0, 'p'},
{"raw", no_argument, 0, 'r'},
{"readonly", no_argument, 0, 'R'},
@@ -62,6 +63,7 @@ static struct option long_options[] = {
{"start", required_argument, 0, 's'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
+ {"wp", no_argument, 0, 'w'},
{0, 0, 0, 0},
};
@@ -84,6 +86,8 @@ usage(int h)
" --maxlen=LEN|-m LEN max response length (allocation "
"length in cdb)\n"
" (def: 0 -> 8192 bytes)\n"
+ " --num=NUM|-n NUM number of zones to output (def: 0 -> "
+ "all)\n"
" --partial|-p sets PARTIAL bit in cdb (def: 0 -> "
"zone list\n"
" length not altered by allocation length "
@@ -95,7 +99,8 @@ usage(int h)
" --start=LBA|-s LBA report zones from the LBA (def: 0)\n"
" need not be a zone starting LBA\n"
" --verbose|-v increase verbosity\n"
- " --version|-V print version string and exit\n\n"
+ " --version|-V print version string and exit\n"
+ " --wp|-w output write pointer only\n\n"
"Sends a SCSI REPORT ZONES command and decodes the response. "
"Give\nhelp option twice (e.g. '-hh') to see reporting options "
"enumerated.\n");
@@ -291,10 +296,12 @@ main(int argc, char * argv[])
bool o_readonly = false;
bool verbose_given = false;
bool version_given = false;
+ bool wp_only = false;
int k, res, c, zl_len, len, zones, resid, rlen, zt, zc, same;
int sg_fd = -1;
int do_help = 0;
int do_hex = 0;
+ int do_num = 0;
int maxlen = 0;
int reporting_opt = 0;
int ret = 0;
@@ -310,7 +317,7 @@ main(int argc, char * argv[])
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "hHm:o:prRs:vV", long_options,
+ c = getopt_long(argc, argv, "hHm:n:o:prRs:vVw", long_options,
&option_index);
if (c == -1)
break;
@@ -331,6 +338,13 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
break;
+ case 'n':
+ do_num = sg_get_num(optarg);
+ if (do_num < 0) {
+ pr2serr("argument to '--num' should be zero or more\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
case 'o':
reporting_opt = sg_get_num_nomult(optarg);
if ((reporting_opt < 0) || (reporting_opt > 63)) {
@@ -363,6 +377,9 @@ main(int argc, char * argv[])
case 'V':
version_given = true;
break;
+ case 'w':
+ wp_only = true;
+ break;
default:
pr2serr("unrecognised option code 0x%x ??\n", c);
usage(1);
@@ -464,7 +481,8 @@ main(int argc, char * argv[])
((1 == do_hex) ? 1 : -1));
goto the_end;
}
- printf("Report zones response:\n");
+ if (! wp_only)
+ printf("Report zones response:\n");
if (len < 64) {
pr2serr("Zone length [%d] too short (perhaps after truncation\n)",
len);
@@ -472,16 +490,25 @@ main(int argc, char * argv[])
goto the_end;
}
same = reportZonesBuff[4] & 0xf;
- printf(" Same=%d: %s\n", same, same_desc_arr[same]);
- printf(" Maximum LBA: 0x%" PRIx64 "\n\n",
- sg_get_unaligned_be64(reportZonesBuff + 8));
+ if (! wp_only) {
+ printf(" Same=%d: %s\n", same, same_desc_arr[same]);
+ printf(" Maximum LBA: 0x%" PRIx64 "\n\n",
+ sg_get_unaligned_be64(reportZonesBuff + 8));
+ }
zones = (len - 64) / 64;
+ if (do_num > 0)
+ zones = (zones > do_num) ? do_num : zones;
for (k = 0, bp = reportZonesBuff + 64; k < zones; ++k, bp += 64) {
- printf(" Zone descriptor: %d\n", k);
+ if (! wp_only)
+ printf(" Zone descriptor: %d\n", k);
if (do_hex) {
hex2stdout(bp, len, -1);
continue;
}
+ if (wp_only) {
+ printf("0x%" PRIx64 "\n", sg_get_unaligned_be64(bp + 24));
+ continue;
+ }
zt = bp[0] & 0xf;
zc = (bp[1] >> 4) & 0xf;
printf(" Zone type: %s\n", zone_type_str(zt, b, sizeof(b),
@@ -497,9 +524,11 @@ main(int argc, char * argv[])
printf(" Write pointer LBA: 0x%" PRIx64 "\n",
sg_get_unaligned_be64(bp + 24));
}
- if ((64 + (64 * zones)) < zl_len)
- printf("\n>>> Beware: Zone list truncated, may need another "
- "call\n");
+ if ((do_num == 0) && (! wp_only)) {
+ if ((64 + (64 * zones)) < zl_len)
+ printf("\n>>> Beware: Zone list truncated, may need another "
+ "call\n");
+ }
} else if (SG_LIB_CAT_INVALID_OP == res)
pr2serr("Report zones command not supported\n");
else {
diff --git a/src/sgm_dd.c b/src/sgm_dd.c
index d40f7859..3932242b 100644
--- a/src/sgm_dd.c
+++ b/src/sgm_dd.c
@@ -1,7 +1,7 @@
/* A utility program for copying files. Specialised for "files" that
* represent devices that understand the SCSI command set.
*
- * Copyright (C) 1999 - 2019 D. Gilbert and P. Allworth
+ * Copyright (C) 1999 - 2020 D. Gilbert and P. Allworth
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -69,7 +69,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "1.64 20191226";
+static const char * version_str = "1.65 20200216";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -501,7 +501,7 @@ sg_read(int sg_fd, uint8_t * buff, int blocks, int64_t from_block,
#if 1
while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
sleep(1);
if (res < 0) {
perror(ME "SG_IO error (sg_read)");
@@ -509,7 +509,7 @@ sg_read(int sg_fd, uint8_t * buff, int blocks, int64_t from_block,
}
#else
while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
if (res < 0) {
if (ENOMEM == errno)
@@ -519,7 +519,7 @@ sg_read(int sg_fd, uint8_t * buff, int blocks, int64_t from_block,
}
while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
if (res < 0) {
perror("reading (rd) on sg device, error");
@@ -594,7 +594,7 @@ sg_write(int sg_fd, uint8_t * buff, int blocks, int64_t to_block,
#if 1
while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
sleep(1);
if (res < 0) {
perror(ME "SG_IO error (sg_write)");
@@ -602,7 +602,7 @@ sg_write(int sg_fd, uint8_t * buff, int blocks, int64_t to_block,
}
#else
while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
if (res < 0) {
if (ENOMEM == errno)
@@ -612,7 +612,7 @@ sg_write(int sg_fd, uint8_t * buff, int blocks, int64_t to_block,
}
while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
if (res < 0) {
perror("writing (rd) on sg device, error");
@@ -1326,7 +1326,8 @@ main(int argc, char * argv[])
}
else {
while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) ||
+ (EBUSY == errno)))
;
if (verbose > 2)
pr2serr("read(unix): count=%d, res=%d\n", blocks * blk_sz,
@@ -1380,7 +1381,8 @@ main(int argc, char * argv[])
out_full += blocks; /* act as if written out without error */
else {
while (((res = write(outfd, wrkPos, blocks * blk_sz)) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) ||
+ (EBUSY == errno)))
;
if (verbose > 2)
pr2serr("write(unix): count=%d, res=%d\n", blocks * blk_sz,
diff --git a/src/sgp_dd.c b/src/sgp_dd.c
index d548601a..7f417b96 100644
--- a/src/sgp_dd.c
+++ b/src/sgp_dd.c
@@ -1,7 +1,7 @@
/* A utility program for copying files. Specialised for "files" that
* represent devices that understand the SCSI command set.
*
- * Copyright (C) 1999 - 2019 D. Gilbert and P. Allworth
+ * Copyright (C) 1999 - 2020 D. Gilbert and P. Allworth
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -48,6 +48,7 @@
#include <signal.h>
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>
+#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
@@ -83,7 +84,7 @@
#include "sg_pr2serr.h"
-static const char * version_str = "5.73 20190618";
+static const char * version_str = "5.75 20200219";
#define DEF_BLOCK_SIZE 512
#define DEF_BLOCKS_PER_TRANSFER 128
@@ -119,6 +120,14 @@ static const char * version_str = "5.73 20190618";
#define EBUFF_SZ 768
+#ifndef SG_FLAG_MMAP_IO
+#define SG_FLAG_MMAP_IO 4
+#endif
+
+#define STR_SZ 1024
+#define INOUTF_SZ 512
+
+
struct flags_t {
bool append;
bool coe;
@@ -128,6 +137,7 @@ struct flags_t {
bool dsync;
bool excl;
bool fua;
+ bool mmap;
};
typedef struct request_collection
@@ -157,13 +167,21 @@ typedef struct request_collection
pthread_cond_t out_sync_cv; /* -/ hold writes until "in order" */
int bs;
int bpt;
+ int num_threads;
int dio_incomplete_count; /* -\ */
int sum_of_resids; /* | */
pthread_mutex_t aux_mutex; /* -/ (also serializes some printf()s */
+ bool mmap_active;
int debug;
int dry_run;
} Rq_coll;
+typedef struct thread_arg
+{ /* pointer to this argument passed to thread */
+ int id;
+ Rq_coll * clp;
+} Thread_arg;
+
typedef struct request_element
{ /* one instance per worker thread */
bool wr;
@@ -227,6 +245,7 @@ static int ascending_val = 1;
static pthread_mutex_t strerr_mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_t threads[MAX_NUM_THREADS];
+static Thread_arg thr_arg_a[MAX_NUM_THREADS];
static bool shutting_down = false;
static bool do_sync = false;
@@ -234,8 +253,9 @@ static bool do_time = false;
static Rq_coll rcoll;
static struct timeval start_tm;
static int64_t dd_count = -1;
-static int num_threads = DEF_NUM_THREADS;
static int exit_status = 0;
+static char infn[INOUTF_SZ];
+static char outfn[INOUTF_SZ];
static const char * my_name = "sgp_dd: ";
@@ -412,13 +432,13 @@ usage()
" if file or device to read from (def: stdin)\n"
" iflag comma separated list from: [coe,dio,direct,dpo,"
"dsync,excl,\n"
- " fua, null]\n"
+ " fua,mmap,null]\n"
" of file or device to write to (def: stdout), "
"OFILE of '.'\n"
" treated as /dev/null\n"
" oflag comma separated list from: [append,coe,dio,"
- "direct,dpo,dsync,\n"
- " excl,fua,null]\n"
+ "direct,dpo,\n"
+ " dsync,excl,fua,mmap,null]\n"
" seek block position to start writing to OFILE\n"
" skip block position to start reading from IFILE\n"
" sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE "
@@ -459,6 +479,32 @@ guarded_stop_both(Rq_coll * clp)
guarded_stop_out(clp);
}
+static int
+sgp_mem_mmap(int fd, int res_sz, uint8_t ** mmpp)
+{
+ int t;
+
+ if (ioctl(fd, SG_GET_RESERVED_SIZE, &t) < 0) {
+ perror("SG_GET_RESERVED_SIZE error");
+ return -1;
+ }
+ if (t < (int)sg_get_page_size())
+ t = sg_get_page_size();
+ if (res_sz > t) {
+ if (ioctl(fd, SG_SET_RESERVED_SIZE, &res_sz) < 0) {
+ perror("SG_SET_RESERVED_SIZE error");
+ return -1;
+ }
+ }
+ *mmpp = (uint8_t *)mmap(NULL, res_sz,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (MAP_FAILED == *mmpp) {
+ perror("mmap() failed");
+ return -1;
+ }
+ return 0;
+}
+
/* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */
static int
scsi_read_capacity(int sg_fd, int64_t * num_sect, int * sect_sz)
@@ -567,34 +613,134 @@ cleanup_out(void * v_clp)
pthread_cond_broadcast(&clp->out_sync_cv);
}
+static int
+sg_prepare(int fd, int bs, int bpt)
+{
+ int res, t;
+
+ res = ioctl(fd, SG_GET_VERSION_NUM, &t);
+ if ((res < 0) || (t < 30000)) {
+ pr2serr("%ssg driver prior to 3.x.y\n", my_name);
+ return 1;
+ }
+ t = bs * bpt;
+ res = ioctl(fd, SG_SET_RESERVED_SIZE, &t);
+ if (res < 0)
+ perror("sgp_dd: SG_SET_RESERVED_SIZE error");
+ t = 1;
+ res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t);
+ if (res < 0)
+ perror("sgp_dd: SG_SET_FORCE_PACK_ID error");
+ return 0;
+}
+
+static int
+sg_in_open(const char * fnp, struct flags_t * flagp, int bs, int bpt)
+{
+ int flags = O_RDWR;
+ int fd, err;
+ char ebuff[800];
+
+ if (flagp->direct)
+ flags |= O_DIRECT;
+ if (flagp->excl)
+ flags |= O_EXCL;
+ if (flagp->dsync)
+ flags |= O_SYNC;
+
+ if ((fd = open(fnp, flags)) < 0) {
+ err = errno;
+ snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg "
+ "reading", my_name, fnp);
+ perror(ebuff);
+ return -sg_convert_errno(err);
+ }
+ if (sg_prepare(fd, bs, bpt))
+ return -SG_LIB_FILE_ERROR;
+ return fd;
+}
+
+static int
+sg_out_open(const char * fnp, struct flags_t * flagp, int bs, int bpt)
+{
+ int flags = O_RDWR;
+ int fd, err;
+ char ebuff[800];
+
+ if (flagp->direct)
+ flags |= O_DIRECT;
+ if (flagp->excl)
+ flags |= O_EXCL;
+ if (flagp->dsync)
+ flags |= O_SYNC;
+
+ if ((fd = open(fnp, flags)) < 0) {
+ err = errno;
+ snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg "
+ "writing", my_name, fnp);
+ perror(ebuff);
+ return -sg_convert_errno(err);
+ }
+ if (sg_prepare(fd, bs, bpt))
+ return -SG_LIB_FILE_ERROR;
+ return fd;
+}
+
static void *
-read_write_thread(void * v_clp)
+read_write_thread(void * v_tap)
{
+ Thread_arg * tap;
Rq_coll * clp;
Rq_elem rel;
Rq_elem * rep = &rel;
int sz;
volatile bool stop_after_write = false;
int64_t seek_skip;
- int blocks, status;
+ int blocks, status, id;
- clp = (Rq_coll *)v_clp;
+ tap = (Thread_arg *)v_tap;
+ id = tap->id;
+ clp = tap->clp;
sz = clp->bpt * clp->bs;
seek_skip = clp->seek - clp->skip;
memset(rep, 0, sizeof(Rq_elem));
- rep->buffp = sg_memalign(sz, 0 /* page align */, &rep->alloc_bp, false);
- if (NULL == rep->buffp)
- err_exit(ENOMEM, "out of memory creating user buffers\n");
-
/* Following clp members are constant during lifetime of thread */
rep->bs = clp->bs;
- rep->infd = clp->infd;
- rep->outfd = clp->outfd;
+ if ((clp->num_threads > 1) && clp->mmap_active) {
+ /* sg devices need separate file descriptor */
+ if (clp->in_flags.mmap && (FT_SG == clp->in_type)) {
+ rep->infd = sg_in_open(infn, &clp->in_flags, clp->bs, clp->bpt);
+ if (rep->infd < 0) err_exit(-rep->infd, "error opening infn");
+ } else
+ rep->infd = clp->infd;
+ if (clp->out_flags.mmap && (FT_SG == clp->out_type)) {
+ rep->outfd = sg_out_open(outfn, &clp->out_flags, clp->bs,
+ clp->bpt);
+ if (rep->outfd < 0) err_exit(-rep->outfd, "error opening outfn");
+
+ } else
+ rep->outfd = clp->outfd;
+ } else {
+ rep->infd = clp->infd;
+ rep->outfd = clp->outfd;
+ }
rep->debug = clp->debug;
rep->cdbsz_in = clp->cdbsz_in;
rep->cdbsz_out = clp->cdbsz_out;
rep->in_flags = clp->in_flags;
rep->out_flags = clp->out_flags;
+ if (clp->mmap_active) {
+ int fd = clp->in_flags.mmap ? rep->infd : rep->outfd;
+
+pr2serr("%s: id=%d, fd=%d calling sgp_mem_mmap()\n", __func__, id, fd);
+ status = sgp_mem_mmap(fd, sz, &rep->buffp);
+ if (status) err_exit(status, "sgp_mem_mmap() failed");
+ } else {
+ rep->buffp = sg_memalign(sz, 0 /* page align */, &rep->alloc_bp,
+ false);
+ if (NULL == rep->buffp)
+ err_exit(ENOMEM, "out of memory creating user buffers\n");
+ }
while(1) {
status = pthread_mutex_lock(&clp->in_mutex);
@@ -697,7 +843,7 @@ normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks)
char strerr_buff[STRERR_BUFF_LEN];
/* enters holding in_mutex */
- while (((res = read(clp->infd, rep->buffp, blocks * clp->bs)) < 0) &&
+ while (((res = read(rep->infd, rep->buffp, blocks * clp->bs)) < 0) &&
((EINTR == errno) || (EAGAIN == errno)))
;
if (res < 0) {
@@ -743,7 +889,7 @@ normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks)
char strerr_buff[STRERR_BUFF_LEN];
/* enters holding out_mutex */
- while (((res = write(clp->outfd, rep->buffp, rep->num_blks * clp->bs))
+ while (((res = write(rep->outfd, rep->buffp, rep->num_blks * clp->bs))
< 0) && ((EINTR == errno) || (EAGAIN == errno)))
;
if (res < 0) {
@@ -999,6 +1145,7 @@ sg_start_io(Rq_elem * rep)
bool fua = rep->wr ? rep->out_flags.fua : rep->in_flags.fua;
bool dpo = rep->wr ? rep->out_flags.dpo : rep->in_flags.dpo;
bool dio = rep->wr ? rep->out_flags.dio : rep->in_flags.dio;
+ bool mmap = rep->wr ? rep->out_flags.mmap : rep->in_flags.mmap;
int cdbsz = rep->wr ? rep->cdbsz_out : rep->cdbsz_in;
int res;
@@ -1014,7 +1161,7 @@ sg_start_io(Rq_elem * rep)
hp->cmdp = rep->cmd;
hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
hp->dxfer_len = rep->bs * rep->num_blks;
- hp->dxferp = rep->buffp;
+ hp->dxferp = mmap ? NULL : rep->buffp;
hp->mx_sb_len = sizeof(rep->sb);
hp->sbp = rep->sb;
hp->timeout = DEF_TIMEOUT;
@@ -1023,6 +1170,8 @@ sg_start_io(Rq_elem * rep)
hp->pack_id = (int)rep->pack_id;
if (dio)
hp->flags |= SG_FLAG_DIRECT_IO;
+ if (mmap)
+ hp->flags |= SG_FLAG_MMAP_IO;
if (rep->debug > 8) {
pr2serr("sg_start_io: SCSI %s, blk=%" PRId64 " num_blks=%d\n",
rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
@@ -1031,7 +1180,7 @@ sg_start_io(Rq_elem * rep)
while (((res = write(rep->wr ? rep->outfd : rep->infd, hp,
sizeof(struct sg_io_hdr))) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
if (res < 0) {
if (ENOMEM == errno)
@@ -1063,7 +1212,7 @@ sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp)
while (((res = read(wr ? rep->outfd : rep->infd, &io_hdr,
sizeof(struct sg_io_hdr))) < 0) &&
- ((EINTR == errno) || (EAGAIN == errno)))
+ ((EINTR == errno) || (EAGAIN == errno) || (EBUSY == errno)))
;
if (res < 0) {
perror("finishing io on sg device, error");
@@ -1117,27 +1266,6 @@ sg_finish_io(bool wr, Rq_elem * rep, pthread_mutex_t * a_mutp)
}
static int
-sg_prepare(int fd, int bs, int bpt)
-{
- int res, t;
-
- res = ioctl(fd, SG_GET_VERSION_NUM, &t);
- if ((res < 0) || (t < 30000)) {
- pr2serr("%ssg driver prior to 3.x.y\n", my_name);
- return 1;
- }
- t = bs * bpt;
- res = ioctl(fd, SG_SET_RESERVED_SIZE, &t);
- if (res < 0)
- perror("sgp_dd: SG_SET_RESERVED_SIZE error");
- t = 1;
- res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t);
- if (res < 0)
- perror("sgp_dd: SG_SET_FORCE_PACK_ID error");
- return 0;
-}
-
-static int
process_flags(const char * arg, struct flags_t * fp)
{
char buff[256];
@@ -1171,6 +1299,8 @@ process_flags(const char * arg, struct flags_t * fp)
fp->excl = true;
else if (0 == strcmp(cp, "fua"))
fp->fua = true;
+ else if (0 == strcmp(cp, "mmap"))
+ fp->mmap = true;
else if (0 == strcmp(cp, "null"))
;
else {
@@ -1197,9 +1327,6 @@ num_chs_in_str(const char * s, int slen, int ch)
}
-#define STR_SZ 1024
-#define INOUTF_SZ 512
-
int
main(int argc, char * argv[])
{
@@ -1214,8 +1341,6 @@ main(int argc, char * argv[])
char str[STR_SZ];
char * key;
char * buf;
- char inf[INOUTF_SZ];
- char outf[INOUTF_SZ];
int res, k, err, keylen;
int64_t in_num_sect = 0;
int64_t out_num_sect = 0;
@@ -1233,13 +1358,14 @@ main(int argc, char * argv[])
sigaction(SIGUSR1, &actions, NULL);
#endif
memset(clp, 0, sizeof(*clp));
+ clp->num_threads = DEF_NUM_THREADS;
clp->bpt = DEF_BLOCKS_PER_TRANSFER;
clp->in_type = FT_OTHER;
clp->out_type = FT_OTHER;
clp->cdbsz_in = DEF_SCSI_CDBSZ;
clp->cdbsz_out = DEF_SCSI_CDBSZ;
- inf[0] = '\0';
- outf[0] = '\0';
+ infn[0] = '\0';
+ outfn[0] = '\0';
for (k = 1; k < argc; k++) {
if (argv[k]) {
@@ -1300,12 +1426,12 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
} else if (strcmp(key,"if") == 0) {
- if ('\0' != inf[0]) {
+ if ('\0' != infn[0]) {
pr2serr("Second 'if=' argument??\n");
return SG_LIB_SYNTAX_ERROR;
} else {
- memcpy(inf, buf, INOUTF_SZ);
- inf[INOUTF_SZ - 1] = '\0';
+ memcpy(infn, buf, INOUTF_SZ);
+ infn[INOUTF_SZ - 1] = '\0';
}
} else if (0 == strcmp(key, "iflag")) {
if (process_flags(buf, &clp->in_flags)) {
@@ -1319,12 +1445,12 @@ main(int argc, char * argv[])
return SG_LIB_SYNTAX_ERROR;
}
} else if (strcmp(key,"of") == 0) {
- if ('\0' != outf[0]) {
+ if ('\0' != outfn[0]) {
pr2serr("Second 'of=' argument??\n");
return SG_LIB_SYNTAX_ERROR;
} else {
- memcpy(outf, buf, INOUTF_SZ);
- outf[INOUTF_SZ - 1] = '\0';
+ memcpy(outfn, buf, INOUTF_SZ);
+ outfn[INOUTF_SZ - 1] = '\0';
}
} else if (0 == strcmp(key, "oflag")) {
if (process_flags(buf, &clp->out_flags)) {
@@ -1346,7 +1472,7 @@ main(int argc, char * argv[])
} else if (0 == strcmp(key,"sync"))
do_sync = !! sg_get_num(buf);
else if (0 == strcmp(key,"thr"))
- num_threads = sg_get_num(buf);
+ clp->num_threads = sg_get_num(buf);
else if (0 == strcmp(key,"time"))
do_time = !! sg_get_num(buf);
else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) {
@@ -1436,19 +1562,24 @@ main(int argc, char * argv[])
pr2serr("bpt must be greater than 0\n");
return SG_LIB_SYNTAX_ERROR;
}
+ if (clp->in_flags.mmap && clp->out_flags.mmap) {
+ pr2serr("can only use mmap flag in iflag= or oflag=, not both\n");
+ return SG_LIB_SYNTAX_ERROR;
+ } else if (clp->in_flags.mmap || clp->out_flags.mmap)
+ clp->mmap_active = true;
/* defaulting transfer size to 128*2048 for CD/DVDs is too large
for the block layer in lk 2.6 and results in an EIO on the
SG_IO ioctl. So reduce it in that case. */
if ((clp->bs >= 2048) && (0 == bpt_given))
clp->bpt = DEF_BLOCKS_PER_2048TRANSFER;
- if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) {
+ if ((clp->num_threads < 1) || (clp->num_threads > MAX_NUM_THREADS)) {
pr2serr("too few or too many threads requested\n");
usage();
return SG_LIB_SYNTAX_ERROR;
}
if (clp->debug)
pr2serr("%sif=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%"
- PRId64 "\n", my_name, inf, skip, outf, seek, dd_count);
+ PRId64 "\n", my_name, infn, skip, outfn, seek, dd_count);
install_handler(SIGINT, interrupt_handler);
install_handler(SIGQUIT, interrupt_handler);
@@ -1457,33 +1588,19 @@ main(int argc, char * argv[])
clp->infd = STDIN_FILENO;
clp->outfd = STDOUT_FILENO;
- if (inf[0] && ('-' != inf[0])) {
- clp->in_type = dd_filetype(inf);
+ if (infn[0] && ('-' != infn[0])) {
+ clp->in_type = dd_filetype(infn);
if (FT_ERROR == clp->in_type) {
- pr2serr("%sunable to access %s\n", my_name, inf);
+ pr2serr("%sunable to access %s\n", my_name, infn);
return SG_LIB_FILE_ERROR;
} else if (FT_ST == clp->in_type) {
- pr2serr("%sunable to use scsi tape device %s\n", my_name, inf);
+ pr2serr("%sunable to use scsi tape device %s\n", my_name, infn);
return SG_LIB_FILE_ERROR;
} else if (FT_SG == clp->in_type) {
- flags = O_RDWR;
- if (clp->in_flags.direct)
- flags |= O_DIRECT;
- if (clp->in_flags.excl)
- flags |= O_EXCL;
- if (clp->in_flags.dsync)
- flags |= O_SYNC;
-
- if ((clp->infd = open(inf, flags)) < 0) {
- err = errno;
- snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg "
- "reading", my_name, inf);
- perror(ebuff);
- return sg_convert_errno(err);
- }
- if (sg_prepare(clp->infd, clp->bs, clp->bpt))
- return SG_LIB_FILE_ERROR;
+ clp->infd = sg_in_open(infn, &clp->in_flags, clp->bs, clp->bpt);
+ if (clp->infd < 0)
+ return -clp->infd;
}
else {
flags = O_RDONLY;
@@ -1494,55 +1611,39 @@ main(int argc, char * argv[])
if (clp->in_flags.dsync)
flags |= O_SYNC;
- if ((clp->infd = open(inf, flags)) < 0) {
+ if ((clp->infd = open(infn, flags)) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scould not open %s for reading",
- my_name, inf);
+ my_name, infn);
perror(ebuff);
return sg_convert_errno(err);
}
else if (skip > 0) {
off64_t offset = skip;
- offset *= clp->bs; /* could exceed 32 here! */
+ offset *= clp->bs; /* could exceed 32 bits here! */
if (lseek64(clp->infd, offset, SEEK_SET) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scouldn't skip to required "
- "position on %s", my_name, inf);
+ "position on %s", my_name, infn);
perror(ebuff);
return sg_convert_errno(err);
}
}
}
}
- if (outf[0] && ('-' != outf[0])) {
- clp->out_type = dd_filetype(outf);
+ if (outfn[0] && ('-' != outfn[0])) {
+ clp->out_type = dd_filetype(outfn);
if (FT_ST == clp->out_type) {
- pr2serr("%sunable to use scsi tape device %s\n", my_name, outf);
+ pr2serr("%sunable to use scsi tape device %s\n", my_name, outfn);
return SG_LIB_FILE_ERROR;
- }
- else if (FT_SG == clp->out_type) {
- flags = O_RDWR;
- if (clp->out_flags.direct)
- flags |= O_DIRECT;
- if (clp->out_flags.excl)
- flags |= O_EXCL;
- if (clp->out_flags.dsync)
- flags |= O_SYNC;
-
- if ((clp->outfd = open(outf, flags)) < 0) {
- err = errno;
- snprintf(ebuff, EBUFF_SZ, "%scould not open %s for sg "
- "writing", my_name, outf);
- perror(ebuff);
- return sg_convert_errno(err);
- }
-
- if (sg_prepare(clp->outfd, clp->bs, clp->bpt))
- return SG_LIB_FILE_ERROR;
- }
- else if (FT_DEV_NULL == clp->out_type)
+ } else if (FT_SG == clp->out_type) {
+ clp->outfd = sg_out_open(outfn, &clp->out_flags, clp->bs,
+ clp->bpt);
+ if (clp->outfd < 0)
+ return -clp->outfd;
+ } else if (FT_DEV_NULL == clp->out_type)
clp->outfd = -1; /* don't bother opening */
else {
if (FT_RAW != clp->out_type) {
@@ -1556,19 +1657,19 @@ main(int argc, char * argv[])
if (clp->out_flags.append)
flags |= O_APPEND;
- if ((clp->outfd = open(outf, flags, 0666)) < 0) {
+ if ((clp->outfd = open(outfn, flags, 0666)) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scould not open %s for "
- "writing", my_name, outf);
+ "writing", my_name, outfn);
perror(ebuff);
return sg_convert_errno(err);
}
}
else { /* raw output file */
- if ((clp->outfd = open(outf, O_WRONLY)) < 0) {
+ if ((clp->outfd = open(outfn, O_WRONLY)) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scould not open %s for raw "
- "writing", my_name, outf);
+ "writing", my_name, outfn);
perror(ebuff);
return sg_convert_errno(err);
}
@@ -1580,7 +1681,7 @@ main(int argc, char * argv[])
if (lseek64(clp->outfd, offset, SEEK_SET) < 0) {
err = errno;
snprintf(ebuff, EBUFF_SZ, "%scouldn't seek to required "
- "position on %s", my_name, outf);
+ "position on %s", my_name, outfn);
perror(ebuff);
return sg_convert_errno(err);
}
@@ -1603,22 +1704,22 @@ main(int argc, char * argv[])
}
if (0 != res) {
if (res == SG_LIB_CAT_INVALID_OP)
- pr2serr("read capacity not supported on %s\n", inf);
+ pr2serr("read capacity not supported on %s\n", infn);
else if (res == SG_LIB_CAT_NOT_READY)
- pr2serr("read capacity failed, %s not ready\n", inf);
+ pr2serr("read capacity failed, %s not ready\n", infn);
else
- pr2serr("Unable to read capacity on %s\n", inf);
+ pr2serr("Unable to read capacity on %s\n", infn);
in_num_sect = -1;
}
} else if (FT_BLOCK == clp->in_type) {
if (0 != read_blkdev_capacity(clp->infd, &in_num_sect,
&in_sect_sz)) {
- pr2serr("Unable to read block capacity on %s\n", inf);
+ pr2serr("Unable to read block capacity on %s\n", infn);
in_num_sect = -1;
}
if (clp->bs != in_sect_sz) {
pr2serr("logical block size on %s confusion; bs=%d, from "
- "device=%d\n", inf, clp->bs, in_sect_sz);
+ "device=%d\n", infn, clp->bs, in_sect_sz);
in_num_sect = -1;
}
}
@@ -1635,22 +1736,22 @@ main(int argc, char * argv[])
}
if (0 != res) {
if (res == SG_LIB_CAT_INVALID_OP)
- pr2serr("read capacity not supported on %s\n", outf);
+ pr2serr("read capacity not supported on %s\n", outfn);
else if (res == SG_LIB_CAT_NOT_READY)
- pr2serr("read capacity failed, %s not ready\n", outf);
+ pr2serr("read capacity failed, %s not ready\n", outfn);
else
- pr2serr("Unable to read capacity on %s\n", outf);
+ pr2serr("Unable to read capacity on %s\n", outfn);
out_num_sect = -1;
}
} else if (FT_BLOCK == clp->out_type) {
if (0 != read_blkdev_capacity(clp->outfd, &out_num_sect,
&out_sect_sz)) {
- pr2serr("Unable to read block capacity on %s\n", outf);
+ pr2serr("Unable to read block capacity on %s\n", outfn);
out_num_sect = -1;
}
if (clp->bs != out_sect_sz) {
pr2serr("logical block size on %s confusion: bs=%d, from "
- "device=%d\n", outf, clp->bs, out_sect_sz);
+ "device=%d\n", outfn, clp->bs, out_sect_sz);
out_num_sect = -1;
}
}
@@ -1726,12 +1827,14 @@ main(int argc, char * argv[])
}
/* vvvvvvvvvvv Start worker threads vvvvvvvvvvvvvvvvvvvvvvvv */
- if ((clp->out_rem_count > 0) && (num_threads > 0)) {
+ if ((clp->out_rem_count > 0) && (clp->num_threads > 0)) {
/* Run 1 work thread to shake down infant retryable stuff */
status = pthread_mutex_lock(&clp->out_mutex);
if (0 != status) err_exit(status, "lock out_mutex");
+ thr_arg_a[0].id = 0;
+ thr_arg_a[0].clp = clp;
status = pthread_create(&threads[0], NULL, read_write_thread,
- (void *)clp);
+ (void *)(thr_arg_a + 0));
if (0 != status) err_exit(status, "pthread_create");
if (clp->debug)
pr2serr("Starting worker thread k=0\n");
@@ -1745,19 +1848,22 @@ main(int argc, char * argv[])
if (0 != status) err_exit(status, "unlock out_mutex");
/* now start the rest of the threads */
- for (k = 1; k < num_threads; ++k) {
+ for (k = 1; k < clp->num_threads; ++k) {
+
+ thr_arg_a[k].id = k;
+ thr_arg_a[k].clp = clp;
status = pthread_create(&threads[k], NULL, read_write_thread,
- (void *)clp);
+ (void *)(thr_arg_a + k));
if (0 != status) err_exit(status, "pthread_create");
- if (clp->debug)
+ if (clp->debug > 2)
pr2serr("Starting worker thread k=%d\n", k);
}
/* now wait for worker threads to finish */
- for (k = 0; k < num_threads; ++k) {
+ for (k = 0; k < clp->num_threads; ++k) {
status = pthread_join(threads[k], &vp);
if (0 != status) err_exit(status, "pthread_join");
- if (clp->debug)
+ if (clp->debug > 2)
pr2serr("Worker thread k=%d terminated\n", k);
}
} /* started worker threads and here after they have all exited */
@@ -1767,7 +1873,7 @@ main(int argc, char * argv[])
if (do_sync) {
if (FT_SG == clp->out_type) {
- pr2serr(">> Synchronizing cache on %s\n", outf);
+ pr2serr(">> Synchronizing cache on %s\n", outfn);
res = sg_ll_sync_cache_10(clp->outfd, 0, 0, 0, 0, 0, false, 0);
if (SG_LIB_CAT_UNIT_ATTENTION == res) {
pr2serr("Unit attention(out), continuing\n");