Linus, patch below adds the missing half of kdev_t -
for block devices we already have a unique pointer (struct block_device *,
inode->i_bdev) and that adds a similar animal for character devices.
        That is, it adds a new structure (struct char_device) and a cache
indexed by dev_t. init_special_inode() sets ->i_cdev to corresponding
element of cache (creating it if needed).
        Result: ->i_cdev is shared by all inodes of given character device
(i.e. if we need per-device objects we can put them there), we can use
stuct char_device * as ID for character devices, we can (in 2.5) get
rid of i_rdev - it's covered by ->i_bdev and ->i_cdev now.
        Patch is pretty straightforward - cache handling is lifted from
fs/block_device, the rest is trivial.
        Please, consider applying.
                                                        Al

diff -urN S5-pre4/fs/Makefile S5-pre4-cdev/fs/Makefile
--- S5-pre4/fs/Makefile Thu May  3 17:13:26 2001
+++ S5-pre4-cdev/fs/Makefile    Tue May 22 09:12:11 2001
@@ -11,8 +11,8 @@
 mod-subdirs := nls
 
 obj-y :=       open.o read_write.o devices.o file_table.o buffer.o \
-               super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
-               ioctl.o readdir.o select.o fifo.o locks.o \
+               super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
+               fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
                dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
                filesystems.o
 
diff -urN S5-pre4/fs/block_dev.c S5-pre4-cdev/fs/block_dev.c
--- S5-pre4/fs/block_dev.c      Sat May 19 22:46:35 2001
+++ S5-pre4-cdev/fs/block_dev.c Tue May 22 08:34:44 2001
@@ -392,7 +392,7 @@
        }
 }
 
-void __init bdev_init(void)
+void __init bdev_cache_init(void)
 {
        int i;
        struct list_head *head = bdev_hashtable;
diff -urN S5-pre4/fs/char_dev.c S5-pre4-cdev/fs/char_dev.c
--- S5-pre4/fs/char_dev.c       Wed Dec 31 19:00:00 1969
+++ S5-pre4-cdev/fs/char_dev.c  Tue May 22 10:03:10 2001
@@ -0,0 +1,114 @@
+/*
+ *  linux/fs/block_dev.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#define HASH_BITS      6
+#define HASH_SIZE      (1UL << HASH_BITS)
+#define HASH_MASK      (HASH_SIZE-1)
+static struct list_head cdev_hashtable[HASH_SIZE];
+static spinlock_t cdev_lock = SPIN_LOCK_UNLOCKED;
+static kmem_cache_t * cdev_cachep;
+
+#define alloc_cdev() \
+        ((struct char_device *) kmem_cache_alloc(cdev_cachep, SLAB_KERNEL))
+#define destroy_cdev(cdev) kmem_cache_free(cdev_cachep, (cdev))
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+       struct char_device * cdev = (struct char_device *) foo;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+           SLAB_CTOR_CONSTRUCTOR)
+       {
+               memset(cdev, 0, sizeof(*cdev));
+               sema_init(&cdev->sem, 1);
+       }
+}
+
+void __init cdev_cache_init(void)
+{
+       int i;
+       struct list_head *head = cdev_hashtable;
+
+       i = HASH_SIZE;
+       do {
+               INIT_LIST_HEAD(head);
+               head++;
+               i--;
+       } while (i);
+
+       cdev_cachep = kmem_cache_create("cdev_cache",
+                                        sizeof(struct char_device),
+                                        0, SLAB_HWCACHE_ALIGN, init_once,
+                                        NULL);
+       if (!cdev_cachep)
+               panic("Cannot create cdev_cache SLAB cache");
+}
+
+/*
+ * Most likely _very_ bad one - but then it's hardly critical for small
+ * /dev and can be fixed when somebody will need really large one.
+ */
+static inline unsigned long hash(dev_t dev)
+{
+       unsigned long tmp = dev;
+       tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+       return tmp & HASH_MASK;
+}
+
+static struct char_device *cdfind(dev_t dev, struct list_head *head)
+{
+       struct list_head *p;
+       struct char_device *cdev;
+       for (p=head->next; p!=head; p=p->next) {
+               cdev = list_entry(p, struct char_device, hash);
+               if (cdev->dev != dev)
+                       continue;
+               atomic_inc(&cdev->count);
+               return cdev;
+       }
+       return NULL;
+}
+
+struct char_device *cdget(dev_t dev)
+{
+       struct list_head * head = cdev_hashtable + hash(dev);
+       struct char_device *cdev, *new_cdev;
+       spin_lock(&cdev_lock);
+       cdev = cdfind(dev, head);
+       spin_unlock(&cdev_lock);
+       if (cdev)
+               return cdev;
+       new_cdev = alloc_cdev();
+       if (!new_cdev)
+               return NULL;
+       atomic_set(&new_cdev->count,1);
+       new_cdev->dev = dev;
+       spin_lock(&cdev_lock);
+       cdev = cdfind(dev, head);
+       if (!cdev) {
+               list_add(&new_cdev->hash, head);
+               spin_unlock(&cdev_lock);
+               return new_cdev;
+       }
+       spin_unlock(&cdev_lock);
+       destroy_cdev(new_cdev);
+       return cdev;
+}
+
+void cdput(struct char_device *cdev)
+{
+       if (atomic_dec_and_test(&cdev->count)) {
+               spin_lock(&cdev_lock);
+               list_del(&cdev->hash);
+               spin_unlock(&cdev_lock);
+               destroy_cdev(cdev);
+       }
+}
+
diff -urN S5-pre4/fs/dcache.c S5-pre4-cdev/fs/dcache.c
--- S5-pre4/fs/dcache.c Sat Apr 28 02:12:56 2001
+++ S5-pre4-cdev/fs/dcache.c    Tue May 22 09:22:43 2001
@@ -1250,6 +1250,9 @@
 kmem_cache_t *bh_cachep;
 EXPORT_SYMBOL(bh_cachep);
 
+extern void bdev_cache_init(void);
+extern void cdev_cache_init(void);
+
 void __init vfs_caches_init(unsigned long mempages)
 {
        bh_cachep = kmem_cache_create("buffer_head",
@@ -1279,4 +1282,7 @@
 #endif
 
        dcache_init(mempages);
+       inode_init(mempages);
+       bdev_cache_init();
+       cdev_cache_init();
 }
diff -urN S5-pre4/fs/devfs/base.c S5-pre4-cdev/fs/devfs/base.c
--- S5-pre4/fs/devfs/base.c     Sat May 19 22:46:35 2001
+++ S5-pre4-cdev/fs/devfs/base.c        Tue May 22 08:51:03 2001
@@ -2256,6 +2256,7 @@
     {
        inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
                               de->u.fcb.u.device.minor);
+       inode->i_cdev = cdget (kdev_t_to_nr(inode->i_rdev));
     }
     else if ( S_ISBLK (de->inode.mode) )
     {
diff -urN S5-pre4/fs/devices.c S5-pre4-cdev/fs/devices.c
--- S5-pre4/fs/devices.c        Fri Feb 16 19:00:19 2001
+++ S5-pre4-cdev/fs/devices.c   Tue May 22 08:31:04 2001
@@ -203,6 +203,7 @@
        if (S_ISCHR(mode)) {
                inode->i_fop = &def_chr_fops;
                inode->i_rdev = to_kdev_t(rdev);
+               inode->i_cdev = cdget(rdev);
        } else if (S_ISBLK(mode)) {
                inode->i_fop = &def_blk_fops;
                inode->i_rdev = to_kdev_t(rdev);
diff -urN S5-pre4/fs/inode.c S5-pre4-cdev/fs/inode.c
--- S5-pre4/fs/inode.c  Sat May 19 22:46:35 2001
+++ S5-pre4-cdev/fs/inode.c     Mon May 21 22:49:48 2001
@@ -497,6 +497,10 @@
                bdput(inode->i_bdev);
                inode->i_bdev = NULL;
        }
+       if (inode->i_cdev) {
+               cdput(inode->i_cdev);
+               inode->i_cdev = NULL;
+       }
        inode->i_state = I_CLEAR;
 }
 
@@ -750,6 +754,7 @@
        memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
        inode->i_pipe = NULL;
        inode->i_bdev = NULL;
+       inode->i_cdev = NULL;
        inode->i_data.a_ops = &empty_aops;
        inode->i_data.host = inode;
        inode->i_data.gfp_mask = GFP_HIGHUSER;
diff -urN S5-pre4/include/linux/fs.h S5-pre4-cdev/include/linux/fs.h
--- S5-pre4/include/linux/fs.h  Sat May 19 22:46:36 2001
+++ S5-pre4-cdev/include/linux/fs.h     Tue May 22 09:14:25 2001
@@ -384,6 +384,14 @@
        int                     gfp_mask;       /* how to allocate the pages */
 };
 
+struct char_device {
+       struct list_head        hash;
+       atomic_t                count;
+       dev_t                   dev;
+       atomic_t                openers;
+       struct semaphore        sem;
+};
+
 struct block_device {
        struct list_head        bd_hash;
        atomic_t                bd_count;
@@ -426,8 +434,10 @@
        struct address_space    *i_mapping;
        struct address_space    i_data; 
        struct dquot            *i_dquot[MAXQUOTAS];
+       /* These three should probably be a union */
        struct pipe_inode_info  *i_pipe;
        struct block_device     *i_bdev;
+       struct char_device      *i_cdev;
 
        unsigned long           i_dnotify_mask; /* Directory notify events */
        struct dnotify_struct   *i_dnotify; /* for directory notifications */
@@ -982,6 +992,8 @@
 extern int unregister_blkdev(unsigned int, const char *);
 extern struct block_device *bdget(dev_t);
 extern void bdput(struct block_device *);
+extern struct char_device *cdget(dev_t);
+extern void cdput(struct char_device *);
 extern int blkdev_open(struct inode *, struct file *);
 extern struct file_operations def_blk_fops;
 extern struct file_operations def_fifo_fops;
diff -urN S5-pre4/init/main.c S5-pre4-cdev/init/main.c
--- S5-pre4/init/main.c Sat May 19 22:46:36 2001
+++ S5-pre4-cdev/init/main.c    Tue May 22 08:34:09 2001
@@ -93,7 +93,6 @@
 extern void ppc_init(void);
 extern void sysctl_init(void);
 extern void signals_init(void);
-extern void bdev_init(void);
 extern int init_pcmcia_ds(void);
 extern void net_notifier_init(void);
 
@@ -569,8 +568,6 @@
        ccwcache_init();
 #endif
        signals_init();
-       bdev_init();
-       inode_init(mempages);
 #ifdef CONFIG_PROC_FS
        proc_root_init();
 #endif
diff -urN S5-pre4/kernel/ksyms.c S5-pre4-cdev/kernel/ksyms.c
--- S5-pre4/kernel/ksyms.c      Sat May 19 22:46:37 2001
+++ S5-pre4-cdev/kernel/ksyms.c Tue May 22 09:06:47 2001
@@ -186,6 +186,8 @@
 EXPORT_SYMBOL(notify_change);
 EXPORT_SYMBOL(set_blocksize);
 EXPORT_SYMBOL(getblk);
+EXPORT_SYMBOL(cdget);
+EXPORT_SYMBOL(cdput);
 EXPORT_SYMBOL(bdget);
 EXPORT_SYMBOL(bdput);
 EXPORT_SYMBOL(bread);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to