patch-1.3.57 linux/fs/devices.c

Next file: linux/fs/exec.c
Previous file: linux/fs/buffer.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.56/linux/fs/devices.c linux/fs/devices.c
@@ -4,8 +4,11 @@
  * (C) 1993 Matthias Urlichs -- collected common code and tables.
  * 
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
  */
 
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/major.h>
 #include <linux/string.h>
@@ -14,6 +17,9 @@
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 #include <linux/errno.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
 
 struct device_struct {
 	const char * name;
@@ -47,19 +53,53 @@
 	}
 	return len;
 }
+/*
+	Return the function table of a device.
+	Load the driver if needed.
+*/
+static struct file_operations * get_fops(
+	unsigned int major,
+	unsigned int maxdev,
+	const char *mangle,		/* String to use to build the module name */
+	struct device_struct tb[])
+{
+	struct file_operations *ret = NULL;
+	if (major < maxdev){
+#ifdef CONFIG_KERNELD
+		/*
+		 * I do get request for device 0. I have no idea why. It happen
+		 * at shutdown time for one. Without the following test, the
+		 * kernel will happily trigger a request_module() which will
+		 * trigger kerneld and modprobe for nothing (since there
+		 * is no device with major number == 0. And furthermore
+		 * it locks the reboot process :-(
+		 *
+		 * Jacques Gelinas (jacques@solucorp.qc.ca)
+		 */
+		if (!tb[major].fops && major != 0) {
+			char name[20];
+			sprintf(name, mangle, major);
+			request_module(name);
+		}
+#endif
+		ret = tb[major].fops;
+	}
+	return ret;
+}
 
+
+/*
+	Return the function table of a device.
+	Load the driver if needed.
+*/
 struct file_operations * get_blkfops(unsigned int major)
 {
-	if (major >= MAX_BLKDEV)
-		return NULL;
-	return blkdevs[major].fops;
+	return get_fops (major,MAX_BLKDEV,"block-major-%d",blkdevs);
 }
 
 struct file_operations * get_chrfops(unsigned int major)
 {
-	if (major >= MAX_CHRDEV)
-		return NULL;
-	return chrdevs[major].fops;
+	return get_fops (major,MAX_CHRDEV,"char-major-%d",chrdevs);
 }
 
 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
@@ -170,17 +210,24 @@
  */
 int blkdev_open(struct inode * inode, struct file * filp)
 {
-	int i;
-
-	i = MAJOR(inode->i_rdev);
-	if (i >= MAX_BLKDEV || !blkdevs[i].fops)
-		return -ENODEV;
-	filp->f_op = blkdevs[i].fops;
-	if (filp->f_op->open)
-		return filp->f_op->open(inode,filp);
-	return 0;
+	int ret = -ENODEV;
+	filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
+	if (filp->f_op != NULL){
+		ret = 0;
+		if (filp->f_op->open != NULL)
+			ret = filp->f_op->open(inode,filp);
+	}	
+	return ret;
 }	
 
+void blkdev_release(struct inode * inode)
+{
+	struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
+	if (fops && fops->release)
+		fops->release(inode,NULL);
+}
+
+
 /*
  * Dummy default file-operations: the only thing this does
  * is contain the open that then fills in the correct operations
@@ -223,15 +270,14 @@
  */
 int chrdev_open(struct inode * inode, struct file * filp)
 {
-	int i;
-
-	i = MAJOR(inode->i_rdev);
-	if (i >= MAX_CHRDEV || !chrdevs[i].fops)
-		return -ENODEV;
-	filp->f_op = chrdevs[i].fops;
-	if (filp->f_op->open)
-		return filp->f_op->open(inode,filp);
-	return 0;
+	int ret = -ENODEV;
+	filp->f_op = get_chrfops(MAJOR(inode->i_rdev));
+	if (filp->f_op != NULL){
+		ret = 0;
+		if (filp->f_op->open != NULL)
+			ret = filp->f_op->open(inode,filp);
+	}
+	return ret;
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this