linux-bk/fs/char_dev.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/block_dev.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 */
   6
   7#include <linux/config.h>
   8#include <linux/init.h>
   9#include <linux/fs.h>
  10#include <linux/slab.h>
  11
  12#define HASH_BITS       6
  13#define HASH_SIZE       (1UL << HASH_BITS)
  14#define HASH_MASK       (HASH_SIZE-1)
  15static struct list_head cdev_hashtable[HASH_SIZE];
  16static spinlock_t cdev_lock = SPIN_LOCK_UNLOCKED;
  17static kmem_cache_t * cdev_cachep;
  18
  19#define alloc_cdev() \
  20         ((struct char_device *) kmem_cache_alloc(cdev_cachep, SLAB_KERNEL))
  21#define destroy_cdev(cdev) kmem_cache_free(cdev_cachep, (cdev))
  22
  23static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
  24{
  25        struct char_device * cdev = (struct char_device *) foo;
  26
  27        if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
  28            SLAB_CTOR_CONSTRUCTOR)
  29        {
  30                memset(cdev, 0, sizeof(*cdev));
  31                sema_init(&cdev->sem, 1);
  32        }
  33}
  34
  35void __init cdev_cache_init(void)
  36{
  37        int i;
  38        struct list_head *head = cdev_hashtable;
  39
  40        i = HASH_SIZE;
  41        do {
  42                INIT_LIST_HEAD(head);
  43                head++;
  44                i--;
  45        } while (i);
  46
  47        cdev_cachep = kmem_cache_create("cdev_cache",
  48                                         sizeof(struct char_device),
  49                                         0, SLAB_HWCACHE_ALIGN, init_once,
  50                                         NULL);
  51        if (!cdev_cachep)
  52                panic("Cannot create cdev_cache SLAB cache");
  53}
  54
  55/*
  56 * Most likely _very_ bad one - but then it's hardly critical for small
  57 * /dev and can be fixed when somebody will need really large one.
  58 */
  59static inline unsigned long hash(dev_t dev)
  60{
  61        unsigned long tmp = dev;
  62        tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
  63        return tmp & HASH_MASK;
  64}
  65
  66static struct char_device *cdfind(dev_t dev, struct list_head *head)
  67{
  68        struct list_head *p;
  69        struct char_device *cdev;
  70        list_for_each(p, head) {
  71                cdev = list_entry(p, struct char_device, hash);
  72                if (cdev->dev != dev)
  73                        continue;
  74                atomic_inc(&cdev->count);
  75                return cdev;
  76        }
  77        return NULL;
  78}
  79
  80struct char_device *cdget(dev_t dev)
  81{
  82        struct list_head * head = cdev_hashtable + hash(dev);
  83        struct char_device *cdev, *new_cdev;
  84        spin_lock(&cdev_lock);
  85        cdev = cdfind(dev, head);
  86        spin_unlock(&cdev_lock);
  87        if (cdev)
  88                return cdev;
  89        new_cdev = alloc_cdev();
  90        if (!new_cdev)
  91                return NULL;
  92        atomic_set(&new_cdev->count,1);
  93        new_cdev->dev = dev;
  94        spin_lock(&cdev_lock);
  95        cdev = cdfind(dev, head);
  96        if (!cdev) {
  97                list_add(&new_cdev->hash, head);
  98                spin_unlock(&cdev_lock);
  99                return new_cdev;
 100        }
 101        spin_unlock(&cdev_lock);
 102        destroy_cdev(new_cdev);
 103        return cdev;
 104}
 105
 106void cdput(struct char_device *cdev)
 107{
 108        if (atomic_dec_and_lock(&cdev->count, &cdev_lock)) {
 109                list_del(&cdev->hash);
 110                spin_unlock(&cdev_lock);
 111                destroy_cdev(cdev);
 112        }
 113}
 114
 115
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.