Commit 53e978e8 authored by Kai Mäkisara's avatar Kai Mäkisara Committed by James Bottomley

[PATCH] SCSI tape cdev fixes for 2.6.2-rc1

The patch at the end of this message fixes the following problems:

- cdev allocation moved outside st_dev_arr_lock, prevents the debugging
error messages reported by Mike and Mike
- cdev_unmap() added before cdev_del(), prevents oops (and kernel data
corruption) in case someone tries to use a device after removing the
module
- better error handling for failures in cdev allocation

As far as I am concerned, the patch is tested but testing by others might
be useful :-)
parent 76c403c4
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale. Michael Schaefer, J"org Weule, and Eric Youngdale.
Copyright 1992 - 2003 Kai Makisara Copyright 1992 - 2004 Kai Makisara
email Kai.Makisara@kolumbus.fi email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809 Some small formal changes - aeb, 950809
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/ */
static char *verstr = "20031228"; static char *verstr = "20040122";
#include <linux/module.h> #include <linux/module.h>
...@@ -3846,27 +3846,53 @@ static int st_probe(struct device *dev) ...@@ -3846,27 +3846,53 @@ static int st_probe(struct device *dev)
STm->default_compression = ST_DONT_TOUCH; STm->default_compression = ST_DONT_TOUCH;
STm->default_blksize = (-1); /* No forced size */ STm->default_blksize = (-1); /* No forced size */
STm->default_density = (-1); /* No forced density */ STm->default_density = (-1); /* No forced density */
}
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STps = &(tpnt->ps[i]);
STps->rw = ST_IDLE;
STps->eof = ST_NOEOF;
STps->at_sm = 0;
STps->last_block_valid = FALSE;
STps->drv_block = (-1);
STps->drv_file = (-1);
}
tpnt->current_mode = 0;
tpnt->modes[0].defined = TRUE;
tpnt->density_changed = tpnt->compression_changed =
tpnt->blksize_changed = FALSE;
init_MUTEX(&tpnt->lock);
st_nr_dev++;
write_unlock(&st_dev_arr_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
STm = &(tpnt->modes[mode]);
for (j=0; j < 2; j++) { for (j=0; j < 2; j++) {
cdev = cdev_alloc(); cdev = cdev_alloc();
if (!cdev) { if (!cdev) {
printk(KERN_ERR printk(KERN_ERR
"st: out of memory. Device not attached.\n"); "st%d: out of memory. Device not attached.\n",
goto out_put_disk; dev_num);
goto out_free_tape;
} }
snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%sm%d%s", disk->disk_name, snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%sm%d%s", disk->disk_name,
i, j ? "n" : ""); mode, j ? "n" : "");
cdev->owner = THIS_MODULE; cdev->owner = THIS_MODULE;
cdev->ops = &st_fops; cdev->ops = &st_fops;
STm->cdevs[j] = cdev;
error = cdev_add(STm->cdevs[j], error = cdev_add(cdev,
MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, i, j)), MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, j)),
1); 1);
if (error) { if (error) {
printk(KERN_ERR "st%d: Can't add %s-rewind mode %d\n", printk(KERN_ERR "st%d: Can't add %s-rewind mode %d\n",
dev_num, j ? "non" : "auto", i); dev_num, j ? "non" : "auto", mode);
printk(KERN_ERR "st%d: Device not attached.\n", dev_num);
goto out_free_tape;
} }
STm->cdevs[j] = cdev;
error = sysfs_create_link(&STm->cdevs[j]->kobj, &SDp->sdev_gendev.kobj, error = sysfs_create_link(&STm->cdevs[j]->kobj, &SDp->sdev_gendev.kobj,
"device"); "device");
...@@ -3884,35 +3910,15 @@ static int st_probe(struct device *dev) ...@@ -3884,35 +3910,15 @@ static int st_probe(struct device *dev)
dev_num); dev_num);
} }
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STps = &(tpnt->ps[i]);
STps->rw = ST_IDLE;
STps->eof = ST_NOEOF;
STps->at_sm = 0;
STps->last_block_valid = FALSE;
STps->drv_block = (-1);
STps->drv_file = (-1);
}
tpnt->current_mode = 0;
tpnt->modes[0].defined = TRUE;
tpnt->density_changed = tpnt->compression_changed =
tpnt->blksize_changed = FALSE;
init_MUTEX(&tpnt->lock);
st_nr_dev++;
write_unlock(&st_dev_arr_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) { for (mode = 0; mode < ST_NBR_MODES; ++mode) {
/* Rewind entry */ /* Rewind entry */
devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)), devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)),
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
"%s/mt%s", SDp->devfs_name, st_formats[mode]); "%s/mt%s", SDp->devfs_name, st_formats[mode]);
/* No-rewind entry */ /* No-rewind entry */
devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128), devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128),
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
"%s/mt%sn", SDp->devfs_name, st_formats[mode]); "%s/mt%sn", SDp->devfs_name, st_formats[mode]);
} }
disk->number = devfs_register_tape(SDp->devfs_name); disk->number = devfs_register_tape(SDp->devfs_name);
...@@ -3924,18 +3930,30 @@ static int st_probe(struct device *dev) ...@@ -3924,18 +3930,30 @@ static int st_probe(struct device *dev)
return 0; return 0;
out_free_tape:
for (mode=0; mode < ST_NBR_MODES; mode++) {
STm = &(tpnt->modes[mode]);
for (j=0; j < 2; j++) {
if (STm->cdevs[j]) {
if (cdev == STm->cdevs[j])
cdev = NULL;
sysfs_remove_link(&STm->cdevs[j]->kobj, "device");
cdev_unmap(MKDEV(SCSI_TAPE_MAJOR,
TAPE_MINOR(dev_num, mode, j)), 1);
cdev_del(STm->cdevs[j]);
}
}
}
if (cdev)
kobject_put(&cdev->kobj);
write_lock(&st_dev_arr_lock);
scsi_tapes[dev_num] = NULL;
st_nr_dev--;
write_unlock(&st_dev_arr_lock);
out_put_disk: out_put_disk:
put_disk(disk); put_disk(disk);
if (tpnt) { if (tpnt)
for (i=0; i < ST_NBR_MODES; i++) {
STm = &(tpnt->modes[i]);
if (STm->cdevs[0])
kobject_put(&STm->cdevs[0]->kobj);
if (STm->cdevs[1])
kobject_put(&STm->cdevs[1]->kobj);
}
kfree(tpnt); kfree(tpnt);
}
out_buffer_free: out_buffer_free:
kfree(buffer); kfree(buffer);
out: out:
...@@ -3964,6 +3982,8 @@ static int st_remove(struct device *dev) ...@@ -3964,6 +3982,8 @@ static int st_remove(struct device *dev)
for (j=0; j < 2; j++) { for (j=0; j < 2; j++) {
sysfs_remove_link(&tpnt->modes[mode].cdevs[j]->kobj, sysfs_remove_link(&tpnt->modes[mode].cdevs[j]->kobj,
"device"); "device");
cdev_unmap(MKDEV(SCSI_TAPE_MAJOR,
TAPE_MINOR(i, mode, j)), 1);
cdev_del(tpnt->modes[mode].cdevs[j]); cdev_del(tpnt->modes[mode].cdevs[j]);
tpnt->modes[mode].cdevs[j] = NULL; tpnt->modes[mode].cdevs[j] = NULL;
} }
......
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