Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/drivers/base/map.c
0004  *
0005  * (C) Copyright Al Viro 2002,2003
0006  *
0007  * NOTE: data structure needs to be changed.  It works, but for large dev_t
0008  * it will be too slow.  It is isolated, though, so these changes will be
0009  * local to that file.
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include <linux/mutex.h>
0015 #include <linux/kdev_t.h>
0016 #include <linux/kobject.h>
0017 #include <linux/kobj_map.h>
0018 
0019 struct kobj_map {
0020     struct probe {
0021         struct probe *next;
0022         dev_t dev;
0023         unsigned long range;
0024         struct module *owner;
0025         kobj_probe_t *get;
0026         int (*lock)(dev_t, void *);
0027         void *data;
0028     } *probes[255];
0029     struct mutex *lock;
0030 };
0031 
0032 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
0033          struct module *module, kobj_probe_t *probe,
0034          int (*lock)(dev_t, void *), void *data)
0035 {
0036     unsigned int n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
0037     unsigned int index = MAJOR(dev);
0038     unsigned int i;
0039     struct probe *p;
0040 
0041     if (n > 255)
0042         n = 255;
0043 
0044     p = kmalloc_array(n, sizeof(struct probe), GFP_KERNEL);
0045     if (p == NULL)
0046         return -ENOMEM;
0047 
0048     for (i = 0; i < n; i++, p++) {
0049         p->owner = module;
0050         p->get = probe;
0051         p->lock = lock;
0052         p->dev = dev;
0053         p->range = range;
0054         p->data = data;
0055     }
0056     mutex_lock(domain->lock);
0057     for (i = 0, p -= n; i < n; i++, p++, index++) {
0058         struct probe **s = &domain->probes[index % 255];
0059         while (*s && (*s)->range < range)
0060             s = &(*s)->next;
0061         p->next = *s;
0062         *s = p;
0063     }
0064     mutex_unlock(domain->lock);
0065     return 0;
0066 }
0067 
0068 void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
0069 {
0070     unsigned int n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
0071     unsigned int index = MAJOR(dev);
0072     unsigned int i;
0073     struct probe *found = NULL;
0074 
0075     if (n > 255)
0076         n = 255;
0077 
0078     mutex_lock(domain->lock);
0079     for (i = 0; i < n; i++, index++) {
0080         struct probe **s;
0081         for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
0082             struct probe *p = *s;
0083             if (p->dev == dev && p->range == range) {
0084                 *s = p->next;
0085                 if (!found)
0086                     found = p;
0087                 break;
0088             }
0089         }
0090     }
0091     mutex_unlock(domain->lock);
0092     kfree(found);
0093 }
0094 
0095 struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index)
0096 {
0097     struct kobject *kobj;
0098     struct probe *p;
0099     unsigned long best = ~0UL;
0100 
0101 retry:
0102     mutex_lock(domain->lock);
0103     for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) {
0104         struct kobject *(*probe)(dev_t, int *, void *);
0105         struct module *owner;
0106         void *data;
0107 
0108         if (p->dev > dev || p->dev + p->range - 1 < dev)
0109             continue;
0110         if (p->range - 1 >= best)
0111             break;
0112         if (!try_module_get(p->owner))
0113             continue;
0114         owner = p->owner;
0115         data = p->data;
0116         probe = p->get;
0117         best = p->range - 1;
0118         *index = dev - p->dev;
0119         if (p->lock && p->lock(dev, data) < 0) {
0120             module_put(owner);
0121             continue;
0122         }
0123         mutex_unlock(domain->lock);
0124         kobj = probe(dev, index, data);
0125         /* Currently ->owner protects _only_ ->probe() itself. */
0126         module_put(owner);
0127         if (kobj)
0128             return kobj;
0129         goto retry;
0130     }
0131     mutex_unlock(domain->lock);
0132     return NULL;
0133 }
0134 
0135 struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
0136 {
0137     struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
0138     struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
0139     int i;
0140 
0141     if ((p == NULL) || (base == NULL)) {
0142         kfree(p);
0143         kfree(base);
0144         return NULL;
0145     }
0146 
0147     base->dev = 1;
0148     base->range = ~0;
0149     base->get = base_probe;
0150     for (i = 0; i < 255; i++)
0151         p->probes[i] = base;
0152     p->lock = lock;
0153     return p;
0154 }