Strange memcpy in sanei_scsi.c

Andreas Dilger (adilger@enel.ucalgary.ca)
Tue, 26 Jan 1999 00:23:14 -0700 (MST)

I was looking at whether I could change the code in sanei_scsi.c to use
a dynamically allocated data buffer (SG_BIG_BUFF related), and I came
across something strange in sanei_scsi.c:

In the function sanei_scsi_req_enter(), we do a
memcpy (&req->cdb.data, src, src_size);

but in the function sanei_scsi_req_wait(), there is a call
memcpy (req->dst, req->cdb.data, nread);

which is not properly getting the address of the statically allocated
data buffer when it is doing the memcpy. This should fail miserably,
but is it possible that this part of sanei_scsi_req_wait() function
isn't used very often?

Hope to hear from someone in the know...

Also below is a preliminary patch to allow for dynamic SG_BIG_BUFF under
Linux. It compiles, but has not been tested at all, so YMMV.
The patch quiets one minor compiler warning at the beginning, and also
closes the file descriptor used to read from /proc/sys/kernel/sg-big-buff.
Good luck...

Cheers, Andreas
_______________________________________________
--- sanei_scsi.c.orig Mon Jan 25 22:27:33 1999
+++ sanei_scsi.c Tue Jan 26 00:11:59 1999
@@ -211,11 +211,13 @@
}
*fd_info;

+#if USE != LINUX_INTERFACE
static u_char cdb_sizes[8] =
{
6, 10, 10, 12, 12, 12, 10, 10
};
#define CDB_SIZE(opcode) cdb_sizes[(((opcode) >> 5) & 7)]
+#endif


#if USE == DOMAINOS_INTERFACE
@@ -608,6 +610,7 @@
sanei_scsi_max_request_size = atoi (buf);
DBG (1, "sanei_scsi_open: sanei_scsi_max_request_size=%d bytes\n",
sanei_scsi_max_request_size);
+ close (fd);
}
}
#endif
@@ -1224,11 +1227,10 @@
size_t *dst_len;
void *dst;
struct
- {
- struct sg_header hdr;
- u_int8_t data[SG_BIG_BUFF];
- }
- cdb;
+ {
+ struct sg_header *hdr;
+ u_int8_t *data;
+ } cdb;
struct req *next;
}
*qhead, *qtail, *free_list;
@@ -1244,9 +1246,9 @@
DBG (4, "sanei_scsi.issue: %p\n", req);

ATOMIC (req->running = 1;
- nwritten = write (req->fd, &req->cdb, req->cdb.hdr.pack_len));
+ nwritten = write (req->fd, req->cdb.hdr, req->cdb.hdr->pack_len));

- if (nwritten != req->cdb.hdr.pack_len)
+ if (nwritten != req->cdb.hdr->pack_len)
{
DBG (1, "sanei_scsi.issue: bad write (errno=%s)\n",
strerror (errno));
@@ -1270,7 +1272,7 @@
for (req = qhead; req; req = next_req)
{
if (req->running && !req->done)
- read (req->fd, &req->cdb, req->cdb.hdr.reply_len);
+ read (req->fd, req->cdb.hdr, req->cdb.hdr->reply_len);
next_req = req->next;

req->next = free_list;
@@ -1293,13 +1295,34 @@
}
else
{
- req = malloc (sizeof (*req));
- if (!req)
+ req = (struct req *) malloc (sizeof (struct req));
+ if (req == NULL)
{
- DBG (1, "sanei_scsi_req_enter: failed to malloc %lu bytes\n",
- (u_long) sizeof (*req));
+ DBG (1, "sanei_scsi_req_enter: failed to malloc %lu bytes for req\n",
+ (u_long) sizeof (struct req));
return SANE_STATUS_NO_MEM;
}
+
+ /* Allocate enough space for both the header and the buffer (whatever
+ * the kernel max buffer size is currently configured as), to ensure they
+ * are contiguous, but then set the .data pointer separately, so we can
+ * access the data directly. It appears, from the read and write calls
+ * to the SCSI device that the .hdr and .data segments must be contiguous.
+ * If that isn't the case, we don't have to be so convoluted.
+ * Make sure we only free .hdr and not .data (if freeing is ever done)!
+ */
+ req->cdb.hdr = (struct sg_header *) malloc (sizeof (struct sg_header) +
+ sanei_scsi_max_request_size);
+ if (req->cdb.hdr == NULL)
+ {
+ DBG (1, "sanei_scsi_req_enter: failed to malloc %lu bytes for cdb\n",
+ (u_long) (sizeof (struct sg_header) +
+ sanei_scsi_max_request_size));
+ free (req);
+ return SANE_STATUS_NO_MEM;
+ }
+ else
+ req->cdb.data = (u_int8_t *) (req->cdb.hdr + sizeof (struct sg_header));
}
req->fd = fd;
req->running = 0;
@@ -1307,11 +1330,11 @@
req->status = SANE_STATUS_GOOD;
req->dst = dst;
req->dst_len = dst_size;
- memset (&req->cdb.hdr, 0, sizeof (req->cdb.hdr));
- req->cdb.hdr.pack_id = pack_id++;
- req->cdb.hdr.pack_len = src_size + sizeof (req->cdb.hdr);
- req->cdb.hdr.reply_len = (dst_size ? *dst_size : 0) + sizeof (req->cdb.hdr);
- memcpy (&req->cdb.data, src, src_size);
+ memset (req->cdb.hdr, 0, sizeof (struct sg_header));
+ req->cdb.hdr->pack_id = pack_id++;
+ req->cdb.hdr->pack_len = src_size + sizeof (struct sg_header);
+ req->cdb.hdr->reply_len = (dst_size ? *dst_size : 0) + sizeof (struct sg_header);
+ memcpy (req->cdb.data, src, src_size);

req->next = 0;
ATOMIC (if (qtail)
@@ -1355,7 +1378,7 @@
select (req->fd + 1, &readable, 0, 0, 0);

/* now atomically read result and set DONE: */
- ATOMIC (nread = read (req->fd, &req->cdb, req->cdb.hdr.reply_len);
+ ATOMIC (nread = read (req->fd, req->cdb.hdr, req->cdb.hdr->reply_len);
req->done = 1);

/* Now issue next command asap, if any. We can't do this
@@ -1373,25 +1396,25 @@
}
else
{
- nread -= sizeof (req->cdb.hdr);
+ nread -= sizeof (struct sg_header);

/* check for errors, but let the sense_handler decide.... */
- if ((req->cdb.hdr.result != 0) ||
- ((req->cdb.hdr.sense_buffer[0] & 0x7f) != 0))
+ if ((req->cdb.hdr->result != 0) ||
+ ((req->cdb.hdr->sense_buffer[0] & 0x7f) != 0))
{
SANEI_SCSI_Sense_Handler handler
= fd_info[req->fd].sense_handler;
void *arg = fd_info[req->fd].sense_handler_arg;

DBG (1, "sanei_scsi_req_wait: SCSI command complained: %s\n",
- strerror (req->cdb.hdr.result));
+ strerror (req->cdb.hdr->result));

- if (req->cdb.hdr.result == EBUSY)
+ if (req->cdb.hdr->result == EBUSY)
status = SANE_STATUS_DEVICE_BUSY;
else if (handler)
/* sense handler should return SANE_STATUS_GOOD if it
decided all was ok afterall */
- status = (*handler) (req->fd, req->cdb.hdr.sense_buffer, arg);
+ status = (*handler) (req->fd, req->cdb.hdr->sense_buffer, arg);
else
status = SANE_STATUS_IO_ERROR;
}
________________________

-- 
Andreas Dilger  University of Calgary \ "If a man ate a pound of pasta and
                Micronet Research Group \ a pound of antipasto, would they
Dept of Electrical & Computer Engineering \  cancel out, leaving him still
<http://www-mddsp.enel.ucalgary.ca/People/adilger/>    hungry?" -- Dogbert

--
Source code, list archive, and docs: http://www.mostang.com/sane/
To unsubscribe: echo unsubscribe sane-devel | mail majordomo@mostang.com