mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Re: [PATCH 1/3] revert register_chrdev_region change
@ 2003-03-24 19:07 Andries.Brouwer
  2003-03-24 19:10 ` Christoph Hellwig
  2003-03-24 20:55 ` Roman Zippel
  0 siblings, 2 replies; 14+ messages in thread
From: Andries.Brouwer @ 2003-03-24 19:07 UTC (permalink / raw)
  To: Andries.Brouwer, hch; +Cc: akpm, linux-kernel, zippel

> If you look at Roman's patches they don't hinder your dev_t enlargement

Not very much. A little.
And in some ways they are a step back.

> I'm personally not yet completly happy with his interface either
> because he still uses the major/minor split

Yes, it is more elegant to register one or more ranges.
(But ranges of what? Ranges in dev_t space? Or in kdev_t space?
Here you see one reason to wait a little until dev_t/kdev_t
stuff has settled.)
Also, you'll notice that the current simple hash scheme is insufficient
if we want to have subranges that override larger ranges.
But life is easier if we postpone that discussion a bit.

# It would help a lot if you would explain what the next stages are.

- Polish the kernel until a change of the size of dev_t is possible.
- Agree on a new size for dev_t, major, minor.  Make the change.
- Ask Ulrich to update glibc.

On the last part: Ulrich already said that the changes are trivial
and that he is waiting for kernel people to make up their minds on
what dev_t and major and minor are supposed to be.

On the first part: Earlier today I sent a patch on stat.h for a
number of architectures. There are a few more such steps.

Andries

^ permalink raw reply	[flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] revert register_chrdev_region change
@ 2003-03-24 22:40 Andries.Brouwer
  2003-03-24 22:52 ` Roman Zippel
  0 siblings, 1 reply; 14+ messages in thread
From: Andries.Brouwer @ 2003-03-24 22:40 UTC (permalink / raw)
  To: Andries.Brouwer, zippel; +Cc: akpm, hch, linux-kernel

    > > I still don't know what we need ranges or even subranges for.
    > > What problem are you trying to solve?
    > 
    > I mentioned the structure of Al's block device code to you.
    > Haven't you read blk_register_region()?

    I did, have you seen add_disk()? ...
    So which problem requires a complex (sub)ranges solution?

Roman, please. There is no need to invent discussions.
Al wrote certain code. It is not my code. I mentioned
that this code has certain properties.

If you want to know why Al wrote the code he wrote, ask him.

Andries

^ permalink raw reply	[flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] revert register_chrdev_region change
@ 2003-03-24 22:06 Andries.Brouwer
  2003-03-24 22:28 ` Roman Zippel
  0 siblings, 1 reply; 14+ messages in thread
From: Andries.Brouwer @ 2003-03-24 22:06 UTC (permalink / raw)
  To: Andries.Brouwer, zippel; +Cc: akpm, hch, linux-kernel

> I still don't know what we need ranges or even subranges for.
> What problem are you trying to solve?

I mentioned the structure of Al's block device code to you.
Haven't you read blk_register_region()?

Andries


^ permalink raw reply	[flat|nested] 14+ messages in thread
* Re: [PATCH 1/3] revert register_chrdev_region change
@ 2003-03-24 20:34 Andries.Brouwer
  2003-03-24 20:39 ` Christoph Hellwig
  0 siblings, 1 reply; 14+ messages in thread
From: Andries.Brouwer @ 2003-03-24 20:34 UTC (permalink / raw)
  To: Andries.Brouwer, hch; +Cc: akpm, linux-kernel, zippel

    From: Christoph Hellwig <hch@infradead.org>

    > Yes, it is more elegant to register one or more ranges.
    > (But ranges of what? Ranges in dev_t space? Or in kdev_t space?

    In dev_t space.

    I guess basically everyone will disagree with you on making kdev_t
    a different representation.  This will end up as messy as the
    internal/external dev_t stuff on some of the SVR4 ports.

You are the first to say so. I'll think about it.

A. On kdev_t vs. dev_t:
kdev_t gives small and fast code, dev_t needs a conditional
That was my main reason. I suppose you say that dev_t is a cookie
and that the kernel should never want to ask about major and minor,
except perhaps at filesystem interfaces. So the 1000+ invocations
that we have now should all go away. A reasonable point of view.

B. On what is registered:
The main question here is what the documented outside reality is.
Is that phrased in terms of dev_t intervals? Or is that phrased
in terms of (major,minor) pairs?
Until convinced otherwise I will hold that users talk about
(major,minor) pairs. They do ls -l and see major,minor pairs.
They want to do mknod and need a major,minor pair.
So I suppose that the documented reality will give a minor
range for a given major, or give a major range.
Such ranges correspond to kdev_t ranges, not to dev_t ranges.

Of course one can avoid the distinction by decreeing that
majors 0-255 cannot have more than 256 minors.

Andries

^ permalink raw reply	[flat|nested] 14+ messages in thread
* [PATCH 1/3] revert register_chrdev_region change
@ 2003-03-23 23:25 Roman Zippel
  2003-03-24 14:25 ` Andries Brouwer
  0 siblings, 1 reply; 14+ messages in thread
From: Roman Zippel @ 2003-03-23 23:25 UTC (permalink / raw)
  To: linux-kernel, aebr, Andrew Morton, Christoph Hellwig

Hi,

This patch removes Andries dev patch, which was unfortunately merged.
It doesn't really help to manage a large number of character devices.
Besides of this the unregister_chrdev() function is buggy (it just
removes a random region).
There is no unregister_chrdev_region function.
Unless kdev_t is 64bit, MAX_CHRDEV is still needed to check the input
argument to register_chrdev().
Dynamic majors have to be allocated from the end of the available number 
space (or from a fixed range) and not at a random number (MAX_PROBE_HASH).

bye, Roman

diff -Nur -X /opt/home/roman/nodiff linux-2.5-dev1/drivers/char/tty_io.c linux-2.5-dev2/drivers/char/tty_io.c
--- linux-2.5-dev1/drivers/char/tty_io.c	2003-03-23 18:08:49.000000000 +0100
+++ linux-2.5-dev2/drivers/char/tty_io.c	2003-03-23 18:20:14.000000000 +0100
@@ -2118,8 +2118,7 @@
 	if (driver->flags & TTY_DRIVER_INSTALLED)
 		return 0;
 
-	error = register_chrdev_region(driver->major, driver->minor_start,
-				       driver->num, driver->name, &tty_fops);
+	error = register_chrdev(driver->major, driver->name, &tty_fops);
 	if (error < 0)
 		return error;
 	else if(driver->major == 0)
diff -Nur -X /opt/home/roman/nodiff linux-2.5-dev1/fs/char_dev.c linux-2.5-dev2/fs/char_dev.c
--- linux-2.5-dev1/fs/char_dev.c	2003-03-23 18:08:54.000000000 +0100
+++ linux-2.5-dev2/fs/char_dev.c	2003-03-23 18:28:37.000000000 +0100
@@ -19,183 +19,122 @@
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
+#include <linux/tty.h>
+
+/* serial module kmod load support */
+struct tty_driver *get_tty_driver(kdev_t device);
+#define is_a_tty_dev(ma)	(ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
+#define need_serial(ma,mi) (get_tty_driver(mk_kdev(ma,mi)) == NULL)
 #endif
 
-#define MAX_PROBE_HASH 255	/* random */
+struct device_struct {
+	const char * name;
+	struct file_operations * fops;
+};
 
 static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED;
+static struct device_struct chrdevs[MAX_CHRDEV];
 
-static struct char_device_struct {
-	struct char_device_struct *next;
-	unsigned int major;
-	unsigned int baseminor;
-	int minorct;
-	const char *name;
-	struct file_operations *fops;
-} *chrdevs[MAX_PROBE_HASH];
-
-/* index in the above */
-static inline int major_to_index(int major)
-{
-	return major % MAX_PROBE_HASH;
-}
-
-/* get char device names in somewhat random order */
 int get_chrdev_list(char *page)
 {
-	struct char_device_struct *cd;
-	int i, len;
+	int i;
+	int len;
 
 	len = sprintf(page, "Character devices:\n");
-
 	read_lock(&chrdevs_lock);
-	for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
-		for (cd = chrdevs[i]; cd; cd = cd->next)
+	for (i = 0; i < MAX_CHRDEV ; i++) {
+		if (chrdevs[i].fops) {
 			len += sprintf(page+len, "%3d %s\n",
-				       cd->major, cd->name);
-	}
-	read_unlock(&chrdevs_lock);
-
-	return len;
-}
-
-/*
- * Return the function table of a device, if present.
- * Increment the reference count of module in question.
- */
-static struct file_operations *
-lookup_chrfops(unsigned int major, unsigned int minor)
-{
-	struct char_device_struct *cd;
-	struct file_operations *ret = NULL;
-	int i;
-
-	i = major_to_index(major);
-
-	read_lock(&chrdevs_lock);
-	for (cd = chrdevs[i]; cd; cd = cd->next) {
-		if (major == cd->major &&
-		    minor - cd->baseminor < cd->minorct) {
-			ret = fops_get(cd->fops);
-			break;
+				       i, chrdevs[i].name);
 		}
 	}
 	read_unlock(&chrdevs_lock);
-
-	return ret;
+	return len;
 }
 
 /*
- * Return the function table of a device, if present.
- * Load the driver if needed.
- * Increment the reference count of module in question.
+ *	Return the function table of a device.
+ *	Load the driver if needed.
+ *	Increment the reference count of module in question.
  */
 static struct file_operations *
 get_chrfops(unsigned int major, unsigned int minor)
 {
-	struct file_operations *ret = NULL;
+	struct file_operations *ret;
 
-	if (!major)
+	if (!major || major >= MAX_CHRDEV)
 		return NULL;
 
-	ret = lookup_chrfops(major, minor);
-
+	read_lock(&chrdevs_lock);
+	ret = fops_get(chrdevs[major].fops);
+	read_unlock(&chrdevs_lock);
 #ifdef CONFIG_KMOD
+	if (ret && is_a_tty_dev(major)) {
+		lock_kernel();
+		if (need_serial(major,minor)) {
+			/* Force request_module anyway, but what for? */
+			/* The reason is that we may have a driver for
+			   /dev/tty1 already, but need one for /dev/ttyS1. */
+			fops_put(ret);
+			ret = NULL;
+		}
+		unlock_kernel();
+	}
 	if (!ret) {
-		char name[32];
+		char name[20];
 		sprintf(name, "char-major-%d", major);
 		request_module(name);
 
 		read_lock(&chrdevs_lock);
-		ret = lookup_chrfops(major, minor);
+		ret = fops_get(chrdevs[major].fops);
 		read_unlock(&chrdevs_lock);
 	}
 #endif
 	return ret;
 }
 
-/*
- * Register a single major with a specified minor range
- */
-int register_chrdev_region(unsigned int major, unsigned int baseminor,
-			   int minorct, const char *name,
-			   struct file_operations *fops)
+int register_chrdev(unsigned int major, const char *name,
+		    struct file_operations *fops)
 {
-	struct char_device_struct *cd, **cp;
-	int ret = 0;
-	int i;
-
-	/* temporary */
 	if (major == 0) {
-		read_lock(&chrdevs_lock);
-		for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--)
-			if (chrdevs[i] == NULL)
-				break;
-		read_unlock(&chrdevs_lock);
-
-		if (i == 0)
-			return -EBUSY;
-		ret = major = i;
-	}
-
-	cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL);
-	if (cd == NULL)
-		return -ENOMEM;
-
-	cd->major = major;
-	cd->baseminor = baseminor;
-	cd->minorct = minorct;
-	cd->name = name;
-	cd->fops = fops;
-
-	i = major_to_index(major);
-
+		write_lock(&chrdevs_lock);
+		for (major = MAX_CHRDEV-1; major > 0; major--) {
+			if (chrdevs[major].fops == NULL) {
+				chrdevs[major].name = name;
+				chrdevs[major].fops = fops;
+				write_unlock(&chrdevs_lock);
+				return major;
+			}
+		}
+		write_unlock(&chrdevs_lock);
+		return -EBUSY;
+	}
+	if (major >= MAX_CHRDEV)
+		return -EINVAL;
 	write_lock(&chrdevs_lock);
-	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
-		if ((*cp)->major > major ||
-		    ((*cp)->major == major && (*cp)->baseminor >= baseminor))
-			break;
-	if (*cp && (*cp)->major == major &&
-	    (*cp)->baseminor < baseminor + minorct) {
-		ret = -EBUSY;
-	} else {
-		cd->next = *cp;
-		*cp = cd;
+	if (chrdevs[major].fops && chrdevs[major].fops != fops) {
+		write_unlock(&chrdevs_lock);
+		return -EBUSY;
 	}
+	chrdevs[major].name = name;
+	chrdevs[major].fops = fops;
 	write_unlock(&chrdevs_lock);
-
-	return ret;
+	return 0;
 }
 
-int register_chrdev(unsigned int major, const char *name,
-		    struct file_operations *fops)
-{
-	return register_chrdev_region(major, 0, 256, name, fops);
-}
-
-/* todo: make void - error printk here */
 int unregister_chrdev(unsigned int major, const char * name)
 {
-	struct char_device_struct *cd, **cp;
-	int ret = 0;
-	int i;
-
-	i = major_to_index(major);
-
+	if (major >= MAX_CHRDEV)
+		return -EINVAL;
 	write_lock(&chrdevs_lock);
-	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
-		if ((*cp)->major == major)
-			break;
-	if (!*cp || strcmp((*cp)->name, name))
-		ret = -EINVAL;
-	else {
-		cd = *cp;
-		*cp = cd->next;
-		kfree(cd);
+	if (!chrdevs[major].fops || strcmp(chrdevs[major].name, name)) {
+		write_unlock(&chrdevs_lock);
+		return -EINVAL;
 	}
+	chrdevs[major].name = NULL;
+	chrdevs[major].fops = NULL;
 	write_unlock(&chrdevs_lock);
-
-	return ret;
+	return 0;
 }
 
 /*
@@ -229,20 +168,10 @@
 const char *cdevname(kdev_t dev)
 {
 	static char buffer[40];
-	const char *name = "unknown-char";
-	unsigned int major = major(dev);
-	unsigned int minor = minor(dev);
-	int i = major_to_index(major);
-	struct char_device_struct *cd;
-
-	read_lock(&chrdevs_lock);
-	for (cd = chrdevs[i]; cd; cd = cd->next)
-		if (cd->major == major)
-			break;
-	if (cd)
-		name = cd->name;
-	sprintf(buffer, "%s(%d,%d)", name, major, minor);
-	read_unlock(&chrdevs_lock);
+	const char * name = chrdevs[major(dev)].name;
 
+	if (!name)
+		name = "unknown-char";
+	sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev));
 	return buffer;
 }
diff -Nur -X /opt/home/roman/nodiff linux-2.5-dev1/fs/inode.c linux-2.5-dev2/fs/inode.c
--- linux-2.5-dev1/fs/inode.c	2003-03-23 18:08:54.000000000 +0100
+++ linux-2.5-dev2/fs/inode.c	2003-03-23 18:20:14.000000000 +0100
@@ -145,7 +145,7 @@
 		mapping->assoc_mapping = NULL;
 		mapping->backing_dev_info = &default_backing_dev_info;
 		if (sb->s_bdev)
-			mapping->backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
+			inode->i_data.backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
 		memset(&inode->u, 0, sizeof(inode->u));
 		inode->i_mapping = mapping;
 	}
diff -Nur -X /opt/home/roman/nodiff linux-2.5-dev1/include/linux/fs.h linux-2.5-dev2/include/linux/fs.h
--- linux-2.5-dev1/include/linux/fs.h	2003-03-23 18:08:55.000000000 +0100
+++ linux-2.5-dev2/include/linux/fs.h	2003-03-23 18:20:14.000000000 +0100
@@ -1055,10 +1055,7 @@
 extern void blk_run_queues(void);
 
 /* fs/char_dev.c */
-extern int register_chrdev_region(unsigned int, unsigned int, int,
-				  const char *, struct file_operations *);
-extern int register_chrdev(unsigned int, const char *,
-			   struct file_operations *);
+extern int register_chrdev(unsigned int, const char *, struct file_operations *);
 extern int unregister_chrdev(unsigned int, const char *);
 extern int chrdev_open(struct inode *, struct file *);
 
diff -Nur -X /opt/home/roman/nodiff linux-2.5-dev1/include/linux/major.h linux-2.5-dev2/include/linux/major.h
--- linux-2.5-dev1/include/linux/major.h	2003-03-23 22:19:03.000000000 +0100
+++ linux-2.5-dev2/include/linux/major.h	2003-03-23 18:22:44.000000000 +0100
@@ -160,6 +160,13 @@
 #define IBM_FS3270_MAJOR	228
 
 /*
+ * Important: Don't change this to 256.  Major number 255 is and must be
+ * reserved for future expansion into a larger dev_t space.
+ */
+#define MAX_CHRDEV		255
+#define MAX_BLKDEV		255
+
+/*
  * Tests for SCSI devices.
  */
 


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2003-03-24 22:41 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-03-24 19:07 [PATCH 1/3] revert register_chrdev_region change Andries.Brouwer
2003-03-24 19:10 ` Christoph Hellwig
2003-03-24 20:55 ` Roman Zippel
  -- strict thread matches above, loose matches on Subject: below --
2003-03-24 22:40 Andries.Brouwer
2003-03-24 22:52 ` Roman Zippel
2003-03-24 22:06 Andries.Brouwer
2003-03-24 22:28 ` Roman Zippel
2003-03-24 20:34 Andries.Brouwer
2003-03-24 20:39 ` Christoph Hellwig
2003-03-23 23:25 Roman Zippel
2003-03-24 14:25 ` Andries Brouwer
2003-03-24 14:43   ` Roman Zippel
2003-03-24 15:04   ` Christoph Hellwig
2003-03-24 16:09     ` Roman Zippel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®