All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] s390 (5/8): tape driver fixes.
@ 2003-10-21 15:08 Martin Schwidefsky
  0 siblings, 0 replies; only message in thread
From: Martin Schwidefsky @ 2003-10-21 15:08 UTC (permalink / raw)
  To: torvalds, linux-kernel

 - Fix device reference counting.
 - Fix online-offline-online cycle.
 - Add module license gpl.

diffstat:
 drivers/s390/char/tape.h       |    3 -
 drivers/s390/char/tape_34xx.c  |    9 +--
 drivers/s390/char/tape_block.c |   18 +++++--
 drivers/s390/char/tape_char.c  |    7 +-
 drivers/s390/char/tape_core.c  |   98 +++++++++++++++++++++--------------------
 5 files changed, 73 insertions(+), 62 deletions(-)

diff -urN linux-2.6/drivers/s390/char/tape.h linux-2.6-s390/drivers/s390/char/tape.h
--- linux-2.6/drivers/s390/char/tape.h	Fri Oct 17 23:43:20 2003
+++ linux-2.6-s390/drivers/s390/char/tape.h	Tue Oct 21 16:37:37 2003
@@ -246,7 +246,8 @@
 extern int tape_generic_remove(struct ccw_device *);
 
 extern struct tape_device *tape_get_device(int devindex);
-extern void tape_put_device(struct tape_device *);
+extern struct tape_device *tape_get_device_reference(struct tape_device *);
+extern struct tape_device *tape_put_device(struct tape_device *);
 
 /* Externals from tape_char.c */
 extern int tapechar_init(void);
diff -urN linux-2.6/drivers/s390/char/tape_34xx.c linux-2.6-s390/drivers/s390/char/tape_34xx.c
--- linux-2.6/drivers/s390/char/tape_34xx.c	Fri Oct 17 23:43:02 2003
+++ linux-2.6-s390/drivers/s390/char/tape_34xx.c	Tue Oct 21 16:37:37 2003
@@ -104,7 +104,7 @@
 			DBF_EVENT(3, "T34XX: internal error: unknown work\n");
 	}
 
-	tape_put_device(p->device);
+	p->device = tape_put_device(p->device);
 	kfree(p);
 }
 
@@ -123,8 +123,7 @@
 	memset(p, 0, sizeof(*p));
 	INIT_WORK(&p->work, tape_34xx_work_handler, p);
 
-	atomic_inc(&device->ref_count);
-	p->device = device;
+	p->device = tape_get_device_reference(device);
 	p->op     = op;
 
 	schedule_work(&p->work);
@@ -1041,7 +1040,7 @@
 {
 	int rc;
 
-	DBF_EVENT(3, "34xx init: $Revision: 1.8 $\n");
+	DBF_EVENT(3, "34xx init: $Revision: 1.9 $\n");
 	/* Register driver for 3480/3490 tapes. */
 	rc = ccw_driver_register(&tape_34xx_driver);
 	if (rc)
@@ -1060,7 +1059,7 @@
 MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);
 MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
 MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape "
-		   "device driver ($Revision: 1.8 $)");
+		   "device driver ($Revision: 1.9 $)");
 MODULE_LICENSE("GPL");
 
 module_init(tape_34xx_init);
diff -urN linux-2.6/drivers/s390/char/tape_block.c linux-2.6-s390/drivers/s390/char/tape_block.c
--- linux-2.6/drivers/s390/char/tape_block.c	Fri Oct 17 23:43:24 2003
+++ linux-2.6-s390/drivers/s390/char/tape_block.c	Tue Oct 21 16:37:37 2003
@@ -214,7 +214,8 @@
 	if (!disk)
 		return -ENOMEM;
 
-	tasklet_init(&d->tasklet, tapeblock_tasklet, (unsigned long)device);
+	tasklet_init(&d->tasklet, tapeblock_tasklet,
+		(unsigned long) tape_get_device_reference(device));
 
 	spin_lock_init(&d->request_queue_lock);
 	q = blk_init_queue(tapeblock_request_fn, &d->request_queue_lock);
@@ -239,7 +240,7 @@
 	disk->major = tapeblock_major;
 	disk->first_minor = device->first_minor;
 	disk->fops = &tapeblock_fops;
-	disk->private_data = device;
+	disk->private_data = tape_get_device_reference(device);
 	disk->queue = q;
 	//set_capacity(disk, size);
 
@@ -262,10 +263,12 @@
 	struct tape_blk_data *d = &device->blk_data;
 
 	del_gendisk(d->disk);
+	d->disk->private_data = tape_put_device(d->disk->private_data);
 	put_disk(d->disk);
 	blk_cleanup_queue(d->request_queue);
 
 	tasklet_kill(&d->tasklet);
+	tape_put_device(device);
 }
 
 /*
@@ -301,9 +304,9 @@
 static int
 tapeblock_open(struct inode *inode, struct file *filp)
 {
-	struct gendisk *disk = inode->i_bdev->bd_disk;
-	struct tape_device *device = disk->private_data;
-	int rc;
+	struct gendisk *	disk;
+	struct tape_device *	device;
+	int			rc;
 
 	/*
 	 * FIXME: this new tapeblock_open function is from 2.5.69.
@@ -311,6 +314,9 @@
 	 * pointer from disk->private_data. It is stored in 
 	 * tapeblock_setup_device but WITHOUT proper ref-counting.
 	 */
+	disk   = inode->i_bdev->bd_disk;
+	device = tape_get_device_reference(disk->private_data);
+
 	rc = tape_open(device);
 	if (rc)
 		goto put_device;
@@ -341,8 +347,8 @@
 	struct gendisk *disk = inode->i_bdev->bd_disk;
 	struct tape_device *device = disk->private_data;
 
-	tape_release(device);
 	tape_unassign(device);
+	tape_release(device);
 	tape_put_device(device);
 
 	return 0;
diff -urN linux-2.6/drivers/s390/char/tape_char.c linux-2.6-s390/drivers/s390/char/tape_char.c
--- linux-2.6/drivers/s390/char/tape_char.c	Fri Oct 17 23:43:24 2003
+++ linux-2.6-s390/drivers/s390/char/tape_char.c	Tue Oct 21 16:37:37 2003
@@ -267,8 +267,9 @@
 {
 	struct tape_device *device;
 
-	device = (struct tape_device *) filp->private_data;
 	DBF_EVENT(6, "TCHAR:release: %x\n", iminor(inode));
+	device = (struct tape_device *) filp->private_data;
+
 #if 0
 	// FIXME: this is broken. Either MTWEOF/MTWEOF/MTBSR is done
 	// EVERYTIME the user switches from write to something different
@@ -287,9 +288,9 @@
 		device->char_data.idal_buf = NULL;
 	}
 	device->char_data.block_size = 0;
-	tape_release(device);
 	tape_unassign(device);
-	tape_put_device(device);
+	tape_release(device);
+	filp->private_data = tape_put_device(device);
 	return 0;
 }
 
diff -urN linux-2.6/drivers/s390/char/tape_core.c linux-2.6-s390/drivers/s390/char/tape_core.c
--- linux-2.6/drivers/s390/char/tape_core.c	Fri Oct 17 23:42:57 2003
+++ linux-2.6-s390/drivers/s390/char/tape_core.c	Tue Oct 21 16:37:37 2003
@@ -36,11 +36,6 @@
 static rwlock_t tape_device_lock = RW_LOCK_UNLOCKED;
 
 /*
- * Wait queue for tape_delete_device waits.
- */
-static DECLARE_WAIT_QUEUE_HEAD(tape_delete_wq);
-
-/*
  * Pointer to debug area.
  */
 debug_info_t *tape_dbf_area = NULL;
@@ -258,7 +253,7 @@
 			__tape_halt_io(device, request);
 		list_del(&request->list);
 		/* Decrease ref_count for removed request. */
-		tape_put_device(device);
+		request->device = tape_put_device(device);
 		request->rc = -EIO;
 		if (request->callback != NULL)
 			request->callback(request, request->callback_data);
@@ -269,6 +264,9 @@
 	tapechar_cleanup_device(device);
 	device->discipline->cleanup_device(device);
 	tape_remove_minor(device);
+
+	/* FIXME: This should be more something like TS_OFFLINE */
+	device->tape_state = TS_INIT;
 }
 
 /*
@@ -301,17 +299,50 @@
 	device->tape_state = TS_INIT;
 	device->medium_state = MS_UNKNOWN;
 	*device->modeset_byte = 0;
+	atomic_set(&device->ref_count, 1);
+
 	return device;
 }
 
 /*
- * Free memory of a device structure.
+ * Get a reference to an existing device structure. This will automatically
+ * increment the reference count.
  */
-static void
-tape_free_device(struct tape_device *device)
+struct tape_device *
+tape_get_device_reference(struct tape_device *device)
+{
+	DBF_EVENT(4, "tape_get_device_reference(%p) = %i\n", device,
+		atomic_inc_return(&device->ref_count));
+
+	return device;
+}
+
+/*
+ * Decrease the reference counter of a devices structure. If the
+ * reference counter reaches zero free the device structure.
+ * The function returns a NULL pointer to be used by the caller
+ * for clearing reference pointers.
+ */
+struct tape_device *
+tape_put_device(struct tape_device *device)
 {
-	kfree(device->modeset_byte);
-	kfree(device);
+	int remain;
+
+	remain = atomic_dec_return(&device->ref_count);
+	if (remain > 0) {
+		DBF_EVENT(4, "tape_put_device(%p) -> %i\n", device, remain);
+	} else {
+		if (remain < 0) {
+			DBF_EVENT(4, "put device without reference\n");
+			PRINT_ERR("put device without reference\n");
+		} else {
+			DBF_EVENT(4, "tape_free_device(%p)\n", device);
+			kfree(device->modeset_byte);
+			kfree(device);
+		}
+	}
+
+	return NULL;			
 }
 
 /*
@@ -326,8 +357,7 @@
 	read_lock(&tape_device_lock);
 	list_for_each_entry(tmp, &tape_device_list, node) {
 		if (tmp->first_minor * TAPE_MINORS_PER_DEV == devindex) {
-			device = tmp;
-			atomic_inc(&device->ref_count);
+			device = tape_get_device_reference(tmp);
 			break;
 		}
 	}
@@ -336,25 +366,6 @@
 }
 
 /*
- * Decrease the reference counter of a devices structure. If the
- * reference counter reaches zero free the device structure and
- * wake up sleepers.
- */
-void
-tape_put_device(struct tape_device *device)
-{
-	if (atomic_dec_return(&device->ref_count) > 0)
-		return;
-	/*
-	 * Reference counter dropped to zero. This means
-	 * that the device is deleted and the last user
-	 * of the device structure is gone. That is what
-	 * tape_delete_device is waiting for. Do a wake up.
-	 */
-	wake_up(&tape_delete_wq);
-}
-
-/*
  * Driverfs tape probe function.
  */
 int
@@ -367,7 +378,6 @@
 	if (IS_ERR(device))
 		return -ENODEV;
 	PRINT_INFO("tape device %s found\n", bus_id);
-	atomic_inc(&device->ref_count);
 	cdev->dev.driver_data = device;
 	device->cdev = cdev;
 	cdev->handler = tape_do_irq;
@@ -383,14 +393,8 @@
 int
 tape_generic_remove(struct ccw_device *cdev)
 {
-	struct tape_device *device;
-
-	device = cdev->dev.driver_data;
-	cdev->dev.driver_data = NULL;
-	if (device != NULL) {
-		tape_put_device(device);
-		wait_event(tape_delete_wq, atomic_read(&device->ref_count) == 0);
-		tape_free_device(device);
+	if (cdev->dev.driver_data != NULL) {
+		cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data);
 	}
 	return 0;
 }
@@ -446,8 +450,7 @@
 tape_free_request (struct tape_request * request)
 {
 	if (request->device != NULL) {
-		tape_put_device(request->device);
-		request->device = NULL;
+		request->device = tape_put_device(request->device);
 	}
 	if (request->cpdata != NULL)
 		kfree(request->cpdata);
@@ -518,8 +521,7 @@
 		return -ENODEV;
 
 	/* Increase use count of device for the added request. */
-	atomic_inc(&device->ref_count);
-	request->device = device;
+	request->device = tape_get_device_reference(device);
 
 	if (list_empty(&device->req_queue)) {
 		/* No other requests are on the queue. Start this one. */
@@ -905,7 +907,7 @@
 {
 	tape_dbf_area = debug_register ( "tape", 1, 2, 3*sizeof(long));
 	debug_register_view(tape_dbf_area, &debug_sprintf_view);
-	DBF_EVENT(3, "tape init: ($Revision: 1.26 $)\n");
+	DBF_EVENT(3, "tape init: ($Revision: 1.29 $)\n");
 	tape_proc_init();
 	tapechar_init ();
 	tapeblock_init ();
@@ -930,7 +932,8 @@
 MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and "
 	      "Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)");
 MODULE_DESCRIPTION("Linux on zSeries channel attached "
-		   "tape device driver ($Revision: 1.26 $)");
+		   "tape device driver ($Revision: 1.29 $)");
+MODULE_LICENSE("GPL");
 
 module_init(tape_init);
 module_exit(tape_exit);
@@ -941,6 +944,7 @@
 EXPORT_SYMBOL(tape_generic_probe);
 EXPORT_SYMBOL(tape_enable_device);
 EXPORT_SYMBOL(tape_put_device);
+EXPORT_SYMBOL(tape_get_device_reference);
 EXPORT_SYMBOL(tape_state_verbose);
 EXPORT_SYMBOL(tape_op_verbose);
 EXPORT_SYMBOL(tape_state_set);

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-10-21 15:10 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-10-21 15:08 [PATCH] s390 (5/8): tape driver fixes Martin Schwidefsky

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.