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 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
Copyright 1992 - 2003 Kai Makisara
Copyright 1992 - 2004 Kai Makisara
email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
......@@ -17,7 +17,7 @@
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>
......@@ -3846,27 +3846,53 @@ static int st_probe(struct device *dev)
STm->default_compression = ST_DONT_TOUCH;
STm->default_blksize = (-1); /* No forced size */
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++) {
cdev = cdev_alloc();
if (!cdev) {
printk(KERN_ERR
"st: out of memory. Device not attached.\n");
goto out_put_disk;
"st%d: out of memory. Device not attached.\n",
dev_num);
goto out_free_tape;
}
snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%sm%d%s", disk->disk_name,
i, j ? "n" : "");
mode, j ? "n" : "");
cdev->owner = THIS_MODULE;
cdev->ops = &st_fops;
STm->cdevs[j] = cdev;
error = cdev_add(STm->cdevs[j],
MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, i, j)),
error = cdev_add(cdev,
MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, j)),
1);
if (error) {
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,
"device");
......@@ -3884,26 +3910,6 @@ static int st_probe(struct device *dev)
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) {
/* Rewind entry */
devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)),
......@@ -3924,18 +3930,30 @@ static int st_probe(struct device *dev)
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:
put_disk(disk);
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);
}
if (tpnt)
kfree(tpnt);
}
out_buffer_free:
kfree(buffer);
out:
......@@ -3964,6 +3982,8 @@ static int st_remove(struct device *dev)
for (j=0; j < 2; j++) {
sysfs_remove_link(&tpnt->modes[mode].cdevs[j]->kobj,
"device");
cdev_unmap(MKDEV(SCSI_TAPE_MAJOR,
TAPE_MINOR(i, mode, j)), 1);
cdev_del(tpnt->modes[mode].cdevs[j]);
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