[PATCH v2] scsi: Add bsg support

Dmitry V. Levin ldv at altlinux.org
Fri Jan 23 18:11:20 UTC 2015


On Fri, Jan 23, 2015 at 04:27:53PM +0100, Bart Van Assche wrote:
> The Linux kernel supports two different versions of the SG_IO API,
> namely v3 and v4. This patch adds support for version 4 of this API.
> At least the sg3_utils package supports version 4 of this API. Version
> 4 of this API is used if /dev/bsg/H:C:I:L is used as device name.
> 
> Signed-off-by: Bart Van Assche <bart.vanassche at sandisk.com>
> ---
>  configure.ac            |   1 +
>  scsi.c                  | 248 ++++++++++++++++++++++++++++++++++++++++--------
>  xlat/bsg_protocol.in    |   1 +
>  xlat/bsg_subprotocol.in |   3 +
>  4 files changed, 211 insertions(+), 42 deletions(-)
>  create mode 100644 xlat/bsg_protocol.in
>  create mode 100644 xlat/bsg_subprotocol.in
> 
> diff --git a/configure.ac b/configure.ac
> index a0b4859..112ea1d 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -225,6 +225,7 @@ AC_CHECK_HEADERS(m4_normalize([
>  	elf.h
>  	inttypes.h
>  	ioctls.h
> +	linux/bsg.h
>  	linux/falloc.h
>  	linux/perf_event.h
>  	linux/ptrace.h
> diff --git a/scsi.c b/scsi.c
> index daf7252..bd2bbb2 100644
> --- a/scsi.c
> +++ b/scsi.c
> @@ -35,8 +35,15 @@
>  
>  #include "xlat/sg_io_dxfer_direction.h"
>  
> +# ifdef HAVE_LINUX_BSG_H
> +#  include <linux/bsg.h>
> +#  include <sys/uio.h>
> +#  include "xlat/bsg_protocol.h"
> +#  include "xlat/bsg_subprotocol.h"
> +# endif
> +
>  static void
> -print_sg_io_buffer(struct tcb *tcp, unsigned char *addr, const unsigned int len)
> +print_sg_io_buffer(struct tcb *tcp, unsigned long addr, const unsigned int len)
>  {
>  	unsigned char *buf = NULL;
>  	unsigned int allocated, i;
> @@ -45,8 +52,8 @@ print_sg_io_buffer(struct tcb *tcp, unsigned char *addr, const unsigned int len)
>  		return;
>  	allocated = (len > max_strlen) ? max_strlen : len;
>  	if ((buf = malloc(allocated)) == NULL ||
> -	    umoven(tcp, (unsigned long) addr, allocated, (char *) buf) < 0) {
> -		tprintf("%p", addr);
> +	    umoven(tcp, addr, allocated, (char *) buf) < 0) {
> +		tprintf("%#lx", addr);
>  		free(buf);
>  		return;
>  	}
> @@ -58,70 +65,227 @@ print_sg_io_buffer(struct tcb *tcp, unsigned char *addr, const unsigned int len)
>  		tprints(", ...");
>  }
>  
> +/* Print up to @len bytes of an iovec */
>  static void
> -print_sg_io_req(struct tcb *tcp, struct sg_io_hdr *sg_io)
> +print_sg_iovec(struct tcb *tcp, unsigned long iovec_addr,
> +	       const unsigned iovec_count, const unsigned len)
>  {
> -	tprintf("{'%c', ", sg_io->interface_id);
> -	printxval(sg_io_dxfer_direction, sg_io->dxfer_direction,
> +	struct iovec *iov;
> +	unsigned allocated, i, r, s;
> +
> +	if (len == 0)
> +		return;
> +	allocated = iovec_count * sizeof(*iov);
> +	iov = malloc(allocated);
> +	if (iov == NULL)
> +		return;
> +	if (umoven(tcp, iovec_addr, allocated, (void *)iov) < 0) {
> +		tprintf("%#lx", iovec_addr);
> +		goto free;
> +	}
> +	r = len;
> +	if (r > max_strlen)
> +		r = max_strlen;
> +	for (i = 0; i < iovec_count; i++) {
> +		s = iov[i].iov_len;
> +		if (s > r)
> +			s = r;
> +		print_sg_io_buffer(tcp, (unsigned long)iov[i].iov_base, s);
> +		r -= s;
> +	}
> +	if (len > max_strlen)
> +		tprints(", ...");
> +
> +free:
> +	free(iov);
> +}

Looks like linux kernel doesn't support this feature yet:

$ git grep -E 'd(in|out)_iovec_count'
include/uapi/linux/bsg.h:	__u32 dout_iovec_count;	/* [i] 0 -> "flat" dout transfer else
include/uapi/linux/bsg.h:	__u32 din_iovec_count;	/* [i] 0 -> "flat" din transfer */

If we have to implement this, the code is going to be as complicated
as tprint_iov_upto(), so I'd rather made the printstr() call in
tprint_iov_upto() parametrized instead.

> +
> +static void
> +print_sg_io_v3_req(struct tcb *tcp, long arg)
> +{
> +	struct sg_io_hdr sg_io;
> +
> +	if (umove(tcp, arg, &sg_io) < 0) {
> +		tprintf("%#lx", arg);
> +		return;
> +	}

There is a "{'%c'" printed already, extra "%#lx" wouldn't look great.

[...]
> +#ifdef HAVE_LINUX_BSG_H
> +static void
> +print_sg_io_v4_req(struct tcb *tcp, long arg)
> +{
[...]
> +}
> +
> +static void
> +print_sg_io_v4_res(struct tcb *tcp, long arg)
> +{
[...]
> +}
> +#endif
> +
> +static void
> +print_sg_io_req(struct tcb *tcp, uint32_t iid, long arg)
> +{
> +	tprintf("{'%c'", iid);
> +
> +	switch (iid) {
> +	case 'S':
> +		print_sg_io_v3_req(tcp, arg);
> +		break;
> +	case 'Q':
> +		print_sg_io_v4_req(tcp, arg);
> +		break;
> +	}
> +
> +}
> +
> +static void
> +print_sg_io_res(struct tcb *tcp, uint32_t iid, long arg)
> +{
> +	switch (iid) {
> +	case 'S':
> +		print_sg_io_v3_res(tcp, arg);
> +		break;
> +	case 'Q':
> +		print_sg_io_v4_res(tcp, arg);
> +		break;
> +	}
> +
> +	tprintf("}");
>  }

print_sg_io_v4_req() and print_sg_io_v4_res() are defined only in
HAVE_LINUX_BSG_H case.

>  int
>  scsi_ioctl(struct tcb *tcp, const unsigned int code, long arg)
>  {
> +	uint32_t iid;
> +
>  	switch (code) {
>  	case SG_IO:
>  		if (entering(tcp)) {
> -			struct sg_io_hdr sg_io;
> -
> -			if (umove(tcp, arg, &sg_io) < 0)
> +			if (umove(tcp, arg, &iid) < 0)
>  				tprintf(", %#lx", arg);
>  			else {
>  				tprints(", ");
> -				print_sg_io_req(tcp, &sg_io);
> +				print_sg_io_req(tcp, iid, arg);
>  			}
>  		}
>  		if (exiting(tcp)) {
> -			struct sg_io_hdr sg_io;
> -
> -			if (!syserror(tcp) && umove(tcp, arg, &sg_io) >= 0)
> -				print_sg_io_res(tcp, &sg_io);
> +			if (!syserror(tcp) && umove(tcp, arg, &iid) >= 0)
> +				print_sg_io_res(tcp, iid, arg);
>  			else
>  				tprints("}");
>  		}

The original code is not OK here: if umove() call failed, there was no
'{' printed on entering, so there is no need to print '}' on exiting.


-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 181 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20150123/7aea98a0/attachment.bin>


More information about the Strace-devel mailing list