patch-2.4.0-test2 linux/drivers/sound/sound_core.c

Next file: linux/drivers/sound/soundcard.c
Previous file: linux/drivers/sound/sonicvibes.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
@@ -175,9 +175,9 @@
 		sprintf (name_buf, "%s", name);
 	else
 		sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP);
-	s->de = devfs_register (devfs_handle, name_buf, 0,
+	s->de = devfs_register (devfs_handle, name_buf,
 				DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor,
-				S_IFCHR | mode, 0, 0, fops, NULL);
+				S_IFCHR | mode, fops, NULL);
 	return r;
 }
 
@@ -456,6 +456,7 @@
 
 static struct file_operations soundcore_fops=
 {
+	owner:	THIS_MODULE,
 	open:	soundcore_open,
 };
 
@@ -508,12 +509,25 @@
 		s = __look_for_unit(chain, unit);
 	}
 	if (s) {
-		file->f_op=s->unit_fops;
+		/*
+		 * We rely upon the fact that we can't be unloaded while the
+		 * subdriver is there, so if ->open() is successful we can
+		 * safely drop the reference counter and if it is not we can
+		 * revert to old ->f_op. Ugly, indeed, but that's the cost of
+		 * switching ->f_op in the first place.
+		 */
+		int err = 0;
+		struct file_operations *old_fops = file->f_op;
+		file->f_op = fops_get(s->unit_fops);
 		spin_unlock(&sound_loader_lock);
 		if(file->f_op->open)
-			return file->f_op->open(inode,file);
-		else
-			return 0;
+			err = file->f_op->open(inode,file);
+		if (err) {
+			fops_put(file->f_op);
+			file->f_op = fops_get(old_fops);
+		}
+		fops_put(old_fops);
+		return err;
 	}
 	spin_unlock(&sound_loader_lock);
 	return -ENODEV;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)