RE: [PATCH 05/10] scsi: use external buffer for command logging

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Original Message-----
> From: Hannes Reinecke [mailto:hare@xxxxxxx]
> Sent: Thursday, 06 November, 2014 2:31 AM
> To: James Bottomley
> Cc: Christoph Hellwig; Ewan Milne; Elliott, Robert (Server Storage);
> linux-scsi@xxxxxxxxxxxxxxx; Hannes Reinecke
> Subject: [PATCH 05/10] scsi: use external buffer for command logging
> 
...
> diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
> index 4f502f9..ed0d10d 100644
> --- a/drivers/scsi/ch.c
> +++ b/drivers/scsi/ch.c
> @@ -195,8 +195,10 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
> int cmd_len,
>   retry:
>  	errno = 0;
>  	if (debug) {
> -		DPRINTK("command: ");
> -		__scsi_print_command(cmd, cmd_len);
> +		char logbuf[SCSI_LOG_BUFSIZE];
> +
> +		__scsi_format_command(logbuf, SCSI_LOG_BUFSIZE, cmd,
> cmd_len);

Use sizeof(logbuf) rather than SCSI_LOG_BUFSIZE to avoid 
the macro name ever mismatching.

> +		DPRINTK("command: %s", logbuf);
>  	}
> 
>  	result = scsi_execute_req(ch->device, cmd, direction, buffer,
...
> diff --git a/drivers/scsi/scsi_logging.c
> b/drivers/scsi/scsi_logging.c
> index dca45fe..d166d12 100644
> --- a/drivers/scsi/scsi_logging.c
> +++ b/drivers/scsi/scsi_logging.c
> @@ -13,10 +13,10 @@
>  #include <scsi/scsi.h>
>  #include <scsi/scsi_cmnd.h>
>  #include <scsi/scsi_device.h>
> +#include <scsi/scsi_eh.h>
>  #include <scsi/scsi_dbg.h>
> 
>  #define SCSI_LOG_SPOOLSIZE 4096
> -#define SCSI_LOG_BUFSIZE 128
> 
>  struct scsi_log_buf {
>  	char buffer[SCSI_LOG_SPOOLSIZE];
> @@ -64,6 +64,21 @@ static void scsi_log_release_buffer(char *bufptr)
>  	preempt_enable();
>  }
> 
> +static size_t scmd_format_header(char *logbuf, size_t logbuf_len,
> +				 struct gendisk *disk, int tag)
> +{
> +	size_t off = 0;
> +
> +	if (disk)
> +		off += scnprintf(logbuf + off, logbuf_len - off,
> +				 "[%s] ", disk->disk_name);
> +
> +	if (tag >= 0)
> +		off += scnprintf(logbuf + off, logbuf_len - off,
> +				 "tag#%d ", tag);

If the first scnprintf consumes the full logbuf_len, then
logbuf_len - off will cause an unsigned wrap (since it's
using size_t types; it'd go negative if it used signed types), 
triggering this from vsnprintf (called by scnprintf):
        if (WARN_ON_ONCE((int) size < 0))
                return 0;

It might be prudent to check that it hasn't gone too far
before calling scnprintf again.

> +	return off;
> +}
> +
>  int sdev_prefix_printk(const char *level, const struct scsi_device
> *sdev,
>  		       const char *name, const char *fmt, ...)
>  {
> @@ -106,13 +121,8 @@ int scmd_printk(const char *level, const struct
> scsi_cmnd *scmd,
>  	logbuf = scsi_log_reserve_buffer(&logbuf_len);
>  	if (!logbuf)
>  		return 0;
> -	if (disk)
> -		off += scnprintf(logbuf + off, logbuf_len - off,
> -				 "[%s] ", disk->disk_name);
> -
> -	if (scmd->request->tag >= 0)
> -		off += scnprintf(logbuf + off, logbuf_len - off,
> -				 "tag#%d ", scmd->request->tag);
> +	off = scmd_format_header(logbuf, logbuf_len, disk,
> +				 scmd->request->tag);
>  	va_start(args, fmt);

Same comment about ensuring off hasn't gone too far.

>  	off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
>  	va_end(args);
> @@ -121,3 +131,121 @@ int scmd_printk(const char *level, const struct
> scsi_cmnd *scmd,
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(scmd_printk);
> +
> +static size_t scsi_format_opcode_name(char *buffer, size_t buf_len,
> +				      const unsigned char *cdbp)
> +{
> +	int sa, cdb0;
> +	const char *cdb_name = NULL, *sa_name = NULL;
> +	size_t off;
> +
> +	cdb0 = cdbp[0];
> +	if (cdb0 == VARIABLE_LENGTH_CMD) {
> +		int len = scsi_varlen_cdb_length(cdbp);
> +
> +		if (len < 10) {
> +			off = scnprintf(buffer, buf_len,
> +					"short variable length command,
> len=%d",
> +					len);
> +			return off;
> +		}
> +		sa = (cdbp[8] << 8) + cdbp[9];
> +	} else
> +		sa = cdbp[1] & 0x1f;
> +
> +	if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) {
> +		if (cdb_name)
> +			off = scnprintf(buffer, buf_len, "%s", cdb_name);
> +		else {
> +			off = scnprintf(buffer, buf_len, "cdb[0]=0x%x",
> cdb0);

Since the service action is printed using "sa=" below,
consider using "op=" or "opcode=" rather than "cdb[0]=".
That might be clearer to readers who don't know the CDB
layout but do have an opcode table handy.


> +			if (cdb0 > VENDOR_SPECIFIC_CDB)

The > should be >= since that define is 0xc0 (which itself
is vendor-specific).

> +				off += scnprintf(buffer + off, buf_len -
> off,
> +						 " (vendor)");
> +			else if (cdb0 > 0x60 && cdb0 < 0x7e)

The > should be >= since 0x60 is reserved.  
The < is correct (0x7e is "extended CDB").


> +				off += scnprintf(buffer + off, buf_len -
> off,
> +						 " (reserved)");
> +		}
> +	} else {
> +		if (sa_name)
> +			off = scnprintf(buffer, buf_len, "%s", sa_name);
> +		else if (cdb_name)
> +			off = scnprintf(buffer, buf_len, "%s, sa=0x%x",
> +					cdb_name, sa);
> +		else
> +			off = scnprintf(buffer, buf_len,
> +					"cdb[0]=0x%x, sa=0x%x", cdb0, sa);
> +	}
> +	return off;
> +}
> +
> +size_t __scsi_format_command(char *logbuf, size_t logbuf_len,
> +			     const unsigned char *cdb, size_t cdb_len)
> +{
> +	int len, k;
> +	size_t off;
> +
> +	off = scsi_format_opcode_name(logbuf, logbuf_len, cdb);
> +	len = scsi_command_size(cdb);
> +	if (cdb_len < len)
> +		len = cdb_len;
> +	/* print out all bytes in cdb */
> +	for (k = 0; k < len; ++k) {
> +		if (off + 3 > logbuf_len)
> +			break;

Might need a check for logbuf_len - off causing an unsigned
wraparound problem before proceeding to scnprintf.


> +		off += scnprintf(logbuf + off, logbuf_len - off,
> +				 " %02x", cdb[k]);
> +	}
> +	return off;
> +}
> +EXPORT_SYMBOL(__scsi_format_command);
> +
> +void scsi_print_command(struct scsi_cmnd *cmd)
> +{
> +	struct gendisk *disk = cmd->request->rq_disk;
> +	int k;
> +	char *logbuf;
> +	size_t off, logbuf_len;
> +
> +	if (cmd->cmnd == NULL)
> +		return;

Using !cmd->cmnd seems more common in SCSI midlayer code.

> +
> +	logbuf = scsi_log_reserve_buffer(&logbuf_len);
> +	if (!logbuf)
> +		return;
> +
> +	off = scmd_format_header(logbuf, logbuf_len, disk, cmd-
> >request->tag);

Repeat the logbuf_len - off wraparound concern.

> +	off += scnprintf(logbuf + off, logbuf_len - off, "CDB: ");

Repeat the logbuf_len - off wraparound concern.

> +	off += scsi_format_opcode_name(logbuf + off, logbuf_len - off,
> +				       cmd->cmnd);
> +	/* print out all bytes in cdb */
> +	if (cmd->cmd_len > 16) {
> +		/* Print opcode in one line and use separate lines for
> CDB */
> +		off += scnprintf(logbuf + off, logbuf_len - off, "\n");
> +		dev_printk(KERN_INFO, &cmd->device->sdev_gendev, logbuf);
> +		scsi_log_release_buffer(logbuf);
> +		for (k = 0; k < cmd->cmd_len; k += 16) {
> +			size_t linelen = min(cmd->cmd_len - k, 16);
> +
> +			logbuf = scsi_log_reserve_buffer(&logbuf_len);
> +			if (!logbuf)
> +				break;
> +			off = scmd_format_header(logbuf, logbuf_len, disk,
> +						 cmd->request->tag);

Repeat the logbuf_len - off wraparound concern.

> +			off += scnprintf(logbuf + off, logbuf_len - off,
> +					 "CDB[%02x]: ", k);

Repeat the logbuf_len - off wraparound concern.

> +			hex_dump_to_buffer(&cmd->cmnd[k], linelen, 16, 1,
> +					   logbuf + off, logbuf_len - off,
> +					   false);
> +			dev_printk(KERN_INFO, &cmd->device->sdev_gendev,
> +				   logbuf);
> +			scsi_log_release_buffer(logbuf);
> +		}
> +	} else {
> +		off += scnprintf(logbuf + off, logbuf_len - off, " ");

Repeat the logbuf_len - off wraparound concern.

> +		hex_dump_to_buffer(cmd->cmnd, cmd->cmd_len, 16, 1,
> +				   logbuf + off, logbuf_len - off, false);
> +		dev_printk(KERN_INFO, &cmd->device->sdev_gendev, logbuf);
> +		scsi_log_release_buffer(logbuf);
> +	}
> +}
> +EXPORT_SYMBOL(scsi_print_command);
> diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
> index fb929fa..4f9fb3c 100644
> --- a/drivers/scsi/sr_ioctl.c
> +++ b/drivers/scsi/sr_ioctl.c
> @@ -188,6 +188,7 @@ int sr_do_ioctl(Scsi_CD *cd, struct
> packet_command *cgc)
>  	struct scsi_sense_hdr sshdr;
>  	int result, err = 0, retries = 0;
>  	struct request_sense *sense = cgc->sense;
> +	char logbuf[SCSI_LOG_BUFSIZE];
> 
>  	SDev = cd->device;
> 
> @@ -257,14 +258,20 @@ int sr_do_ioctl(Scsi_CD *cd, struct
> packet_command *cgc)
>  				/* sense: Invalid command operation code */
>  				err = -EDRIVE_CANT_DO_THIS;
>  #ifdef DEBUG
> -			__scsi_print_command(cgc->cmd, CDROM_PACKET_SIZE);
> +			__scsi_format_command(logbuf, SCSI_LOG_BUFSIZE,
> +					      cgc->cmd, CDROM_PACKET_SIZE);

Use sizeof(logbuf) rather than SCSI_LOG_BUFSIZE to avoid 
the macro name ever mismatching.

> +			sr_printk(KERN_INFO, cd,
> +				  "CDROM (ioctl) invalid command: %s\n",
> +				  logbuf);
>  			scsi_print_sense_hdr(cd->device, cd->cdi.name,
> &sshdr);
>  #endif
>  			break;
>  		default:
> +			__scsi_format_command(logbuf, SCSI_LOG_BUFSIZE,
> +					      cgc->cmd, CDROM_PACKET_SIZE);

Use sizeof(logbuf) rather than SCSI_LOG_BUFSIZE to avoid 
the macro name ever mismatching.

>  			sr_printk(KERN_ERR, cd,
> -				  "CDROM (ioctl) error, command: ");
> -			__scsi_print_command(cgc->cmd, CDROM_PACKET_SIZE);
> +				  "CDROM (ioctl) error, command: %s\n",
> +				  logbuf);
>  			scsi_print_sense_hdr(cd->device, cd->cdi.name,
> &sshdr);
>  			err = -EIO;
>  		}
...

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux