RE: [PATCH 01/10] scsi: Use real functions for logging

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

 




> -----Original Message-----
> From: Hannes Reinecke [mailto:hare@xxxxxxx]
> Sent: Tuesday, 04 November, 2014 2:07 AM
...
> diff --git a/drivers/scsi/scsi_logging.c
> b/drivers/scsi/scsi_logging.c
...
> @@ -0,0 +1,119 @@
> +/*
> + * scsi_logging.c
> + *
> + * Copyright (C) 2014 SUSE Linux Products GmbH
> + * Copyright (C) 2014 Hannes Reinecke <hare@xxxxxxx>
> + *
> + * This file is released under the GPLv2
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/atomic.h>
> +
> +#include <scsi/scsi.h>
> +#include <scsi/scsi_cmnd.h>
> +#include <scsi/scsi_device.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];
> +	unsigned long map;
> +};
> +
> +static DEFINE_PER_CPU(struct scsi_log_buf, scsi_format_log);
> +
> +static char *scsi_log_reserve_buffer(size_t *len)
> +{
> +	struct scsi_log_buf *buf;
> +	unsigned long map_bits = SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE;
> +	unsigned long idx = 0;
> +
> +	WARN_ON(map_bits > BITS_PER_LONG);

Since SCSI_LOG_SPOOLSIZE, SCSI_LOG_BUFSIZE, and BITS_PER_LONG
are constants, that can be a compile-time check.

> +	preempt_disable();
> +	buf = this_cpu_ptr(&scsi_format_log);
> +	idx = find_first_zero_bit(&buf->map, map_bits);

If this fails to find a bit, it returns map_bits.
This could result in the next test_and_set_bit call 
accessing an address that is outside the bounds of
buf->map.

A safety check seems prudent before the test_and_set_bit:
	if (likely(idx < map_bits))

> +	while (test_and_set_bit(idx, &buf->map)) {
> +		idx = find_next_zero_bit(&buf->map, map_bits, idx);
> +		if (idx >= map_bits) {
> +			break;
> +		}

scripts/checkpatch.pl -f doesn't like the {} on that.

> +	}
> +	if (WARN_ON(idx >= map_bits)) {
> +		preempt_enable();
> +		return NULL;
> +	}
> +	*len = SCSI_LOG_BUFSIZE;
> +	return buf->buffer + idx * SCSI_LOG_BUFSIZE;
> +}
> +
> +static void scsi_log_release_buffer(char *bufptr)
> +{
> +	struct scsi_log_buf *buf;
> +	unsigned long idx;
> +	int ret;
> +
> +	buf = this_cpu_ptr(&scsi_format_log);
> +	if (bufptr < buf->buffer + SCSI_LOG_SPOOLSIZE) {

Should that also check that bufptr > buf->buffer?

> +		idx = (bufptr - buf->buffer) / SCSI_LOG_BUFSIZE;
> +		ret = test_and_clear_bit(idx, &buf->map);
> +		WARN_ON(!ret);
> +	}
> +	preempt_enable();
> +}
> +
> +int sdev_prefix_printk(const char *level, const struct scsi_device
> *sdev,
> +		       const char *name, const char *fmt, ...)
> +{
> +	va_list args;
> +	char *logbuf;
> +	size_t off = 0, logbuf_len;
> +	int ret;
> +
> +	if (!sdev)
> +		return 0;
> +
> +	logbuf = scsi_log_reserve_buffer(&logbuf_len);
> +	if (!logbuf)
> +		return 0;
> +
> +	if (name)
> +		off += scnprintf(logbuf + off, logbuf_len - off,
> +				 "[%s] ", name);
> +	va_start(args, fmt);
> +	off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
> +	va_end(args);
> +	ret = dev_printk(level, &sdev->sdev_gendev, "%s", logbuf);
> +	scsi_log_release_buffer(logbuf);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sdev_prefix_printk);
> +
> +int scmd_printk(const char *level, const struct scsi_cmnd *scmd,
> +		const char *fmt, ...)
> +{
> +	struct gendisk *disk = scmd->request->rq_disk;
> +	va_list args;
> +	char *logbuf;
> +	size_t off = 0, logbuf_len;
> +	int ret;
> +
> +	if (!scmd || scmd->cmnd == NULL)
> +		return 0;

!scmd->cmnd seems more common in neighboring code.

> +
> +	logbuf = scsi_log_reserve_buffer(&logbuf_len);
> +	if (!logbuf)
> +		return 0;
> +	if (disk)
> +		off += scnprintf(logbuf + off, logbuf_len - off,
> +				 "[%s] ", disk->disk_name);
> +	va_start(args, fmt);
> +	off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
> +	va_end(args);
> +	ret = dev_printk(level, &scmd->device->sdev_gendev, "%s",
> logbuf);
> +	scsi_log_release_buffer(logbuf);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(scmd_printk);
...

dev_printk is EXPORT_SYMBOL.  The former macro versions of 
sdev_printk and scmd_printk just called dev_printk, and not
being symbols, did not change that.

So, I think these function versions should use EXPORT_SYMBOL, so 
the hated binary drivers can still call them.


---
Rob Elliott    HP Server Storage



--
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