1// SPDX-License-Identifier: GPL-2.0 2/* 3 * linux/drivers/base/map.c 4 * 5 * (C) Copyright Al Viro 2002,2003 6 * 7 * NOTE: data structure needs to be changed. It works, but for large dev_t 8 * it will be too slow. It is isolated, though, so these changes will be 9 * local to that file. 10 */ 11 12#include <linux/module.h> 13#include <linux/slab.h> 14#include <linux/mutex.h> 15#include <linux/kdev_t.h> 16#include <linux/kobject.h> 17#include <linux/kobj_map.h> 18 19struct kobj_map { 20 struct probe { 21 struct probe *next; 22 dev_t dev; 23 unsigned long range; 24 struct module *owner; 25 kobj_probe_t *get; 26 int (*lock)(dev_t, void *); 27 void *data; 28 } *probes[255]; 29 struct mutex *lock; 30}; 31 32int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range, 33 struct module *module, kobj_probe_t *probe, 34 int (*lock)(dev_t, void *), void *data) 35{ 36 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; 37 unsigned index = MAJOR(dev); 38 unsigned i; 39 struct probe *p; 40 41 if (n > 255) 42 n = 255; 43 44 p = kmalloc_array(n, sizeof(struct probe), GFP_KERNEL); 45 if (p == NULL) 46 return -ENOMEM; 47 48 for (i = 0; i < n; i++, p++) { 49 p->owner = module; 50 p->get = probe; 51 p->lock = lock; 52 p->dev = dev; 53 p->range = range; 54 p->data = data; 55 } 56 mutex_lock(domain->lock); 57 for (i = 0, p -= n; i < n; i++, p++, index++) { 58 struct probe **s = &domain->probes[index % 255]; 59 while (*s && (*s)->range < range) 60 s = &(*s)->next; 61 p->next = *s; 62 *s = p; 63 } 64 mutex_unlock(domain->lock); 65 return 0; 66} 67 68void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range) 69{ 70 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; 71 unsigned index = MAJOR(dev); 72 unsigned i; 73 struct probe *found = NULL; 74 75 if (n > 255) 76 n = 255; 77 78 mutex_lock(domain->lock); 79 for (i = 0; i < n; i++, index++) { 80 struct probe **s; 81 for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) { 82 struct probe *p = *s; 83 if (p->dev == dev && p->range == range) { 84 *s = p->next; 85 if (!found) 86 found = p; 87 break; 88 } 89 } 90 } 91 mutex_unlock(domain->lock); 92 kfree(found); 93} 94 95void kobj_delete(struct kobj_map *domain, dev_t dev, unsigned long range, 96 kobj_probe_t *probe) 97{ 98 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; 99 unsigned index = MAJOR(dev); 100 unsigned i; 101 struct probe *found = NULL; 102 103 if (n > 255) 104 n = 255; 105 106 mutex_lock(domain->lock); 107 for (i = 0; i < n; i++, index++) { 108 struct probe **s; 109 for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) { 110 struct probe *p = *s; 111 if (p->dev == dev && p->range == range && p->get == probe) { 112 *s = p->next; 113 if (!found) 114 found = p; 115 break; 116 } 117 } 118 } 119 mutex_unlock(domain->lock); 120 kfree(found); 121} 122 123struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index) 124{ 125 struct kobject *kobj; 126 struct probe *p; 127 unsigned long best = ~0UL; 128 129retry: 130 mutex_lock(domain->lock); 131 for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) { 132 struct kobject *(*probe)(dev_t, int *, void *); 133 struct module *owner; 134 void *data; 135 136 if (p->dev > dev || p->dev + p->range - 1 < dev) 137 continue; 138 if (p->range - 1 >= best) 139 break; 140 if (!try_module_get(p->owner)) 141 continue; 142 owner = p->owner; 143 data = p->data; 144 probe = p->get; 145 best = p->range - 1; 146 *index = dev - p->dev; 147 if (p->lock && p->lock(dev, data) < 0) { 148 module_put(owner); 149 continue; 150 } 151 mutex_unlock(domain->lock); 152 kobj = probe(dev, index, data); 153 /* Currently ->owner protects _only_ ->probe() itself. */ 154 module_put(owner); 155 if (kobj) 156 return kobj; 157 goto retry; 158 } 159 mutex_unlock(domain->lock); 160 return NULL; 161} 162 163struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock) 164{ 165 struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL); 166 struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL); 167 int i; 168 169 if ((p == NULL) || (base == NULL)) { 170 kfree(p); 171 kfree(base); 172 return NULL; 173 } 174 175 base->dev = 1; 176 base->range = ~0; 177 base->get = base_probe; 178 for (i = 0; i < 255; i++) 179 p->probes[i] = base; 180 p->lock = lock; 181 return p; 182} 183