1 /* 2 * Copyright (c) 2009 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Alex Hornung <ahornung@gmail.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <machine/limits.h> 40 #include <vfs/devfs/devfs.h> 41 42 MALLOC_DECLARE(M_DEVFS); 43 44 static struct devfs_unit_hash *devfs_clone_hash_get(int, cdev_t); 45 #if 0 46 static void devfs_clone_hash_put(struct devfs_unit_hash *); 47 #endif 48 static int devfs_clone_hash_add(struct devfs_unit_hash **, struct devfs_unit_hash *); 49 static struct devfs_unit_hash *devfs_clone_hash_del(struct devfs_unit_hash **, int); 50 51 /* 52 * DEVFS clone hash functions 53 */ 54 55 static struct devfs_unit_hash * 56 devfs_clone_hash_get(int unit_no, cdev_t dev) 57 { 58 struct devfs_unit_hash *hash = (struct devfs_unit_hash *)kmalloc(sizeof(struct devfs_unit_hash), M_DEVFS, M_WAITOK); 59 hash->next = NULL; 60 hash->unit_no = unit_no; 61 hash->dev = dev; 62 63 return hash; 64 } 65 66 67 #if 0 68 69 static void 70 devfs_clone_hash_put(struct devfs_unit_hash *hash) 71 { 72 kfree(hash, M_DEVFS); 73 } 74 75 #endif 76 77 static int 78 devfs_clone_hash_add(struct devfs_unit_hash **devfs_hash_array, struct devfs_unit_hash *hash) 79 { 80 struct devfs_unit_hash **hashp; 81 hashp = &devfs_hash_array[hash->unit_no & 82 DEVFS_UNIT_HMASK]; 83 while (*hashp) { 84 if ((*hashp)->unit_no == 85 hash->unit_no) 86 return(EEXIST); 87 hashp = &(*hashp)->next; 88 } 89 hash->next = NULL; 90 *hashp = hash; 91 return (0); 92 } 93 94 95 static struct devfs_unit_hash * 96 devfs_clone_hash_del(struct devfs_unit_hash **devfs_hash_array, int unit_no) 97 { 98 struct devfs_unit_hash **hashp; 99 struct devfs_unit_hash *hash; 100 hashp = &devfs_hash_array[unit_no & 101 DEVFS_UNIT_HMASK]; 102 hash = *hashp; 103 while ((*hashp)->unit_no != unit_no) { 104 KKASSERT(*hashp != NULL); 105 hashp = &(*hashp)->next; 106 hash = *hashp; 107 } 108 *hashp = hash->next; 109 110 return hash; 111 } 112 113 /* 114 * DEVFS clone bitmap functions 115 */ 116 void 117 devfs_clone_bitmap_init(struct devfs_bitmap *bitmap) 118 { 119 bitmap->bitmap = (unsigned long *)kmalloc(DEVFS_BITMAP_INITIAL_SIZE*sizeof(unsigned long), M_DEVFS, M_WAITOK); 120 bitmap->chunks = DEVFS_BITMAP_INITIAL_SIZE; 121 memset(bitmap->bitmap, ULONG_MAX, DEVFS_BITMAP_INITIAL_SIZE*sizeof(unsigned long)); 122 } 123 124 125 void 126 devfs_clone_bitmap_uninit(struct devfs_bitmap *bitmap) 127 { 128 kfree(bitmap->bitmap, M_DEVFS); 129 } 130 131 132 void 133 devfs_clone_bitmap_resize(struct devfs_bitmap *bitmap, int newchunks) 134 { 135 int oldchunks = bitmap->chunks; 136 bitmap->chunks = newchunks+2; 137 bitmap->bitmap = (unsigned long *)krealloc(bitmap->bitmap, sizeof(unsigned long)*bitmap->chunks, M_DEVFS, M_WAITOK); 138 139 devfs_debug(DEVFS_DEBUG_DEBUG, "%d vs %d (oldchunks=%d)\n", bitmap->bitmap, bitmap->bitmap + oldchunks, oldchunks); 140 memset(bitmap->bitmap + oldchunks, ULONG_MAX, sizeof(unsigned long)*(bitmap->chunks - oldchunks)); 141 } 142 143 144 int 145 devfs_clone_bitmap_fff(struct devfs_bitmap *bitmap) 146 { 147 unsigned long curbitmap; 148 int bit, i; 149 int chunks = bitmap->chunks; 150 151 for (i = 0; i < chunks+1; i++) { 152 if (i == chunks) 153 devfs_clone_bitmap_resize(bitmap, i); 154 curbitmap = bitmap->bitmap[i]; 155 156 if (curbitmap > 0) { 157 curbitmap &= (~curbitmap)+1; 158 for (bit = 1; curbitmap != 1; bit++) 159 curbitmap = (unsigned long)curbitmap >> 1; 160 161 return bit-1 + (i<<3) * sizeof(unsigned long); 162 } 163 } 164 165 /* Should never happen as we dynamically resize as needed */ 166 return -1; 167 } 168 169 170 int 171 devfs_clone_bitmap_chk(struct devfs_bitmap *bitmap, int unit) 172 { 173 int chunk = unit / (sizeof(unsigned long)<<3); 174 unit -= chunk<<3 * sizeof(unsigned long); 175 176 if (chunk >= bitmap->chunks) 177 return 1; 178 179 return !((bitmap->bitmap[chunk]) & (1<<(unit))); 180 } 181 182 183 void 184 devfs_clone_bitmap_set(struct devfs_bitmap *bitmap, int unit) 185 { 186 int chunk = unit / (sizeof(unsigned long)<<3); 187 unit -= chunk<<3 * sizeof(unsigned long); 188 189 if (chunk >= bitmap->chunks) { 190 devfs_clone_bitmap_resize(bitmap, chunk); 191 } 192 193 bitmap->bitmap[chunk] &= ~(1<<unit); 194 } 195 196 197 void 198 devfs_clone_bitmap_rst(struct devfs_bitmap *bitmap, int unit) 199 { 200 int chunk = unit / (sizeof(unsigned long)<<3); 201 unit -= chunk<<3 * sizeof(unsigned long); 202 203 if (chunk >= bitmap->chunks) 204 return; 205 206 bitmap->bitmap[chunk] |= (1<<unit); 207 } 208 209 210 int 211 devfs_clone_bitmap_get(struct devfs_bitmap *bitmap, int limit) 212 { 213 int unit; 214 unit = devfs_clone_bitmap_fff(bitmap); 215 KKASSERT(unit != -1); 216 217 if ((limit > 0) && (unit > limit)) 218 return -1; 219 220 devfs_clone_bitmap_set(bitmap, unit); 221 222 return unit; 223 } 224 225 /* 226 * DEVFS clone helper functions 227 */ 228 229 void 230 devfs_clone_helper_init(struct devfs_clone_helper *helper) 231 { 232 devfs_clone_bitmap_init(&helper->DEVFS_CLONE_BITMAP(generic)); 233 memset(&helper->DEVFS_CLONE_HASHLIST(generic), 0, DEVFS_UNIT_HSIZE*sizeof(void *)); 234 } 235 236 237 void 238 devfs_clone_helper_uninit(struct devfs_clone_helper *helper) 239 { 240 devfs_clone_bitmap_uninit(&helper->DEVFS_CLONE_BITMAP(generic)); 241 //XXX: free all elements in helper->DEVFS_HASHLIST(generic) 242 } 243 244 245 int 246 devfs_clone_helper_insert(struct devfs_clone_helper *helper, cdev_t dev) 247 { 248 struct devfs_unit_hash *hash; 249 int error = 0; 250 int unit_no; 251 252 try_again: 253 unit_no = devfs_clone_bitmap_fff(&helper->DEVFS_CLONE_BITMAP(generic)); 254 255 devfs_clone_bitmap_set(&helper->DEVFS_CLONE_BITMAP(generic), unit_no); 256 hash = devfs_clone_hash_get(unit_no, dev); 257 258 error = devfs_clone_hash_add(helper->DEVFS_CLONE_HASHLIST(generic), hash); 259 KKASSERT(!error); 260 261 if (error) 262 goto try_again; 263 264 dev->si_uminor = unit_no; 265 return unit_no; 266 } 267 268 269 int 270 devfs_clone_helper_remove(struct devfs_clone_helper *helper, int unit_no) 271 { 272 struct devfs_unit_hash *hash; 273 hash = devfs_clone_hash_del(helper->DEVFS_CLONE_HASHLIST(generic), unit_no); 274 devfs_clone_bitmap_rst(&helper->DEVFS_CLONE_BITMAP(generic), unit_no); 275 kfree(hash, M_DEVFS); 276 277 return 0; 278 } 279