Commit 545907e6 authored by James Bottomley's avatar James Bottomley

scsi sg: fix smp_call_function() with intrs disabled

From: 	Matthew Wilcox <willy@debian.org>,
	Douglas Gilbert <dougg@torque.net>

  - Fix vmalloc,vfree with intrs disabled
  - bump version number
  - introduce MODULE_VERSION
  - increase over allocation of sg_dev_arr from 6 to 32
parent 11741f8a
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Original driver (sg.c): * Original driver (sg.c):
* Copyright (C) 1992 Lawrence Foard * Copyright (C) 1992 Lawrence Foard
* Version 2 and 3 extensions to driver: * Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2002 Douglas Gilbert * Copyright (C) 1998 - 2004 Douglas Gilbert
* *
* Modified 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support * Modified 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
* *
...@@ -17,27 +17,18 @@ ...@@ -17,27 +17,18 @@
* any later version. * any later version.
* *
*/ */
#include <linux/config.h>
static int sg_version_num = 30530; /* 2 digits for each component */ static int sg_version_num = 30531; /* 2 digits for each component */
#define SG_VERSION_STR "3.5.31"
/* /*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
* the kernel/module needs to be built with CONFIG_SCSI_LOGGING * the kernel/module needs to be built with CONFIG_SCSI_LOGGING
* (otherwise the macros compile to empty statements). * (otherwise the macros compile to empty statements).
* Then before running the program to be debugged enter:
* # echo "scsi log timeout 7" > /proc/scsi/scsi
* This will send copious output to the console and the log which
* is usually /var/log/messages. To turn off debugging enter:
* # echo "scsi log timeout 0" > /proc/scsi/scsi
* The 'timeout' token was chosen because it is relatively unused.
* The token 'hlcomplete' should be used but that triggers too
* much output from the sd device driver. To dump the current
* state of the SCSI mid level data structures enter:
* # echo "scsi dump 1" > /proc/scsi/scsi
* To dump the state of sg's data structures use:
* # cat /proc/scsi/sg/debug
* *
*/ */
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -69,7 +60,7 @@ static int sg_version_num = 30530; /* 2 digits for each component */ ...@@ -69,7 +60,7 @@ static int sg_version_num = 30530; /* 2 digits for each component */
#ifdef CONFIG_SCSI_PROC_FS #ifdef CONFIG_SCSI_PROC_FS
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
static char *sg_version_str = "3.5.30 [20040124]"; static char *sg_version_date = "20040513";
static int sg_proc_init(void); static int sg_proc_init(void);
static void sg_proc_cleanup(void); static void sg_proc_cleanup(void);
...@@ -110,7 +101,7 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF; ...@@ -110,7 +101,7 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF;
#define SG_SECTOR_SZ 512 #define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */ #define SG_DEV_ARR_LUMP 32 /* amount to over allocate sg_dev_arr by */
static int sg_add(struct class_device *); static int sg_add(struct class_device *);
static void sg_remove(struct class_device *); static void sg_remove(struct class_device *);
...@@ -1333,85 +1324,44 @@ static struct class_simple * sg_sysfs_class; ...@@ -1333,85 +1324,44 @@ static struct class_simple * sg_sysfs_class;
static int sg_sysfs_valid = 0; static int sg_sysfs_valid = 0;
static int static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
sg_add(struct class_device *cl_dev)
{ {
struct scsi_device *scsidp = to_scsi_device(cl_dev->dev); Sg_device *sdp;
struct gendisk *disk;
Sg_device *sdp = NULL;
unsigned long iflags; unsigned long iflags;
struct cdev * cdev = NULL; void *old_sg_dev_arr = NULL;
int k, error; int k, error;
disk = alloc_disk(1); sdp = vmalloc(sizeof(Sg_device));
if (!disk) if (!sdp)
return -ENOMEM; return -ENOMEM;
cdev = cdev_alloc();
if (! cdev)
return -ENOMEM;
write_lock_irqsave(&sg_dev_arr_lock, iflags); write_lock_irqsave(&sg_dev_arr_lock, iflags);
if (sg_nr_dev >= sg_dev_max) { /* try to resize */ if (unlikely(sg_nr_dev >= sg_dev_max)) { /* try to resize */
Sg_device **tmp_da; Sg_device **tmp_da;
int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP; int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
tmp_da = (Sg_device **)vmalloc(
tmp_dev_max * sizeof(Sg_device *)); tmp_da = vmalloc(tmp_dev_max * sizeof(Sg_device *));
if (NULL == tmp_da) { if (unlikely(!tmp_da))
printk(KERN_ERR goto expand_failed;
"sg_add: device array cannot be resized\n");
error = -ENOMEM;
goto out;
}
write_lock_irqsave(&sg_dev_arr_lock, iflags); write_lock_irqsave(&sg_dev_arr_lock, iflags);
memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *)); memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
memcpy(tmp_da, sg_dev_arr, memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *));
sg_dev_max * sizeof (Sg_device *)); old_sg_dev_arr = sg_dev_arr;
vfree((char *) sg_dev_arr);
sg_dev_arr = tmp_da; sg_dev_arr = tmp_da;
sg_dev_max = tmp_dev_max; sg_dev_max = tmp_dev_max;
} }
find_empty_slot:
for (k = 0; k < sg_dev_max; k++) for (k = 0; k < sg_dev_max; k++)
if (!sg_dev_arr[k]) if (!sg_dev_arr[k])
break; break;
if (k >= SG_MAX_DEVS) { if (unlikely(k >= SG_MAX_DEVS))
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); goto overflow;
printk(KERN_WARNING
"Unable to attach sg device <%d, %d, %d, %d>"
" type=%d, minor number exceeds %d\n",
scsidp->host->host_no, scsidp->channel, scsidp->id,
scsidp->lun, scsidp->type, SG_MAX_DEVS - 1);
if (NULL != sdp)
vfree((char *) sdp);
error = -ENODEV;
goto out;
}
if (k < sg_dev_max) {
if (NULL == sdp) {
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
sdp = (Sg_device *)vmalloc(sizeof(Sg_device));
write_lock_irqsave(&sg_dev_arr_lock, iflags);
if (!sg_dev_arr[k])
goto find_empty_slot;
}
} else
sdp = NULL;
if (NULL == sdp) {
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
printk(KERN_ERR "sg_add: Sg_device cannot be allocated\n");
error = -ENOMEM;
goto out;
}
SCSI_LOG_TIMEOUT(3, printk("sg_add: dev=%d \n", k));
memset(sdp, 0, sizeof(*sdp)); memset(sdp, 0, sizeof(*sdp));
SCSI_LOG_TIMEOUT(3, printk("sg_alloc: dev=%d \n", k));
sprintf(disk->disk_name, "sg%d", k); sprintf(disk->disk_name, "sg%d", k);
cdev->owner = THIS_MODULE;
cdev->ops = &sg_fops;
disk->major = SCSI_GENERIC_MAJOR;
disk->first_minor = k; disk->first_minor = k;
sdp->disk = disk; sdp->disk = disk;
sdp->device = scsidp; sdp->device = scsidp;
...@@ -1421,6 +1371,55 @@ sg_add(struct class_device *cl_dev) ...@@ -1421,6 +1371,55 @@ sg_add(struct class_device *cl_dev)
sg_nr_dev++; sg_nr_dev++;
sg_dev_arr[k] = sdp; sg_dev_arr[k] = sdp;
write_unlock_irqrestore(&sg_dev_arr_lock, iflags); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
error = k;
out:
if (error < 0)
vfree(sdp);
vfree(old_sg_dev_arr);
return error;
expand_failed:
printk(KERN_ERR "sg_alloc: device array cannot be resized\n");
error = -ENOMEM;
goto out;
overflow:
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
printk(KERN_WARNING
"Unable to attach sg device <%d, %d, %d, %d> type=%d, minor "
"number exceeds %d\n", scsidp->host->host_no, scsidp->channel,
scsidp->id, scsidp->lun, scsidp->type, SG_MAX_DEVS - 1);
error = -ENODEV;
goto out;
}
static int
sg_add(struct class_device *cl_dev)
{
struct scsi_device *scsidp = to_scsi_device(cl_dev->dev);
struct gendisk *disk;
Sg_device *sdp = NULL;
struct cdev * cdev = NULL;
int error, k;
disk = alloc_disk(1);
if (!disk)
return -ENOMEM;
disk->major = SCSI_GENERIC_MAJOR;
error = -ENOMEM;
cdev = cdev_alloc();
if (!cdev)
goto out;
cdev->owner = THIS_MODULE;
cdev->ops = &sg_fops;
error = sg_alloc(disk, scsidp);
if (error < 0)
goto out;
k = error;
sdp = sg_dev_arr[k];
devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k), devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k),
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
...@@ -1543,6 +1542,7 @@ module_param_named(allow_dio, sg_allow_dio, int, 0); ...@@ -1543,6 +1542,7 @@ module_param_named(allow_dio, sg_allow_dio, int, 0);
MODULE_AUTHOR("Douglas Gilbert"); MODULE_AUTHOR("Douglas Gilbert");
MODULE_DESCRIPTION("SCSI generic (sg) driver"); MODULE_DESCRIPTION("SCSI generic (sg) driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(SG_VERSION_STR);
MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
...@@ -2844,7 +2844,8 @@ sg_proc_write_dressz(struct file *filp, const char __user *buffer, ...@@ -2844,7 +2844,8 @@ sg_proc_write_dressz(struct file *filp, const char __user *buffer,
static int sg_proc_seq_show_version(struct seq_file *s, void *v) static int sg_proc_seq_show_version(struct seq_file *s, void *v)
{ {
seq_printf(s, "%d\t%s\n", sg_version_num, sg_version_str); seq_printf(s, "%d\t%s [%s]\n", sg_version_num, SG_VERSION_STR,
sg_version_date);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment