Print this page
5042 stop using deprecated atomic functions
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ksyms.c
+++ new/usr/src/uts/common/io/ksyms.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26
27 27 /*
28 28 * ksyms driver - exports a single symbol/string table for the kernel
29 29 * by concatenating all the module symbol/string tables.
30 30 */
31 31
32 32 #include <sys/types.h>
33 33 #include <sys/sysmacros.h>
34 34 #include <sys/cmn_err.h>
35 35 #include <sys/uio.h>
36 36 #include <sys/kmem.h>
37 37 #include <sys/cred.h>
38 38 #include <sys/mman.h>
39 39 #include <sys/errno.h>
40 40 #include <sys/stat.h>
41 41 #include <sys/conf.h>
42 42 #include <sys/debug.h>
43 43 #include <sys/kobj.h>
44 44 #include <sys/ksyms.h>
45 45 #include <sys/vmsystm.h>
46 46 #include <vm/seg_vn.h>
47 47 #include <sys/atomic.h>
48 48 #include <sys/compress.h>
49 49 #include <sys/ddi.h>
50 50 #include <sys/sunddi.h>
51 51 #include <sys/list.h>
52 52
53 53 typedef struct ksyms_image {
54 54 caddr_t ksyms_base; /* base address of image */
55 55 size_t ksyms_size; /* size of image */
56 56 } ksyms_image_t;
57 57
58 58 typedef struct ksyms_buflist {
59 59 list_node_t buflist_node;
60 60 char buf[1];
61 61 } ksyms_buflist_t;
62 62
63 63 typedef struct ksyms_buflist_hdr {
64 64 list_t blist;
65 65 int nchunks;
66 66 ksyms_buflist_t *cur;
67 67 size_t curbuf_off;
68 68 } ksyms_buflist_hdr_t;
69 69
70 70 #define BUF_SIZE (PAGESIZE - (size_t)offsetof(ksyms_buflist_t, buf))
71 71
72 72 int nksyms_clones; /* tunable: max clones of this device */
73 73
74 74 static ksyms_image_t *ksyms_clones; /* clone device array */
75 75 static dev_info_t *ksyms_devi;
76 76
77 77 static void
78 78 ksyms_bcopy(const void *srcptr, void *ptr, size_t rsize)
79 79 {
80 80
81 81 size_t sz;
82 82 const char *src = (const char *)srcptr;
83 83 ksyms_buflist_hdr_t *hptr = (ksyms_buflist_hdr_t *)ptr;
84 84
85 85 if (hptr->cur == NULL)
86 86 return;
87 87
88 88 while (rsize) {
89 89 sz = MIN(rsize, (BUF_SIZE - hptr->curbuf_off));
90 90 bcopy(src, (hptr->cur->buf + hptr->curbuf_off), sz);
91 91
92 92 hptr->curbuf_off += sz;
93 93 if (hptr->curbuf_off == BUF_SIZE) {
94 94 hptr->curbuf_off = 0;
95 95 hptr->cur = list_next(&hptr->blist, hptr->cur);
96 96 if (hptr->cur == NULL)
97 97 break;
98 98 }
99 99 src += sz;
100 100 rsize -= sz;
101 101 }
102 102 }
103 103
104 104 static void
105 105 ksyms_buflist_free(ksyms_buflist_hdr_t *hdr)
106 106 {
107 107 ksyms_buflist_t *list;
108 108
109 109 while (list = list_head(&hdr->blist)) {
110 110 list_remove(&hdr->blist, list);
111 111 kmem_free(list, PAGESIZE);
112 112 }
113 113 list_destroy(&hdr->blist);
114 114 hdr->cur = NULL;
115 115 }
116 116
117 117
118 118 /*
119 119 * Allocate 'size'(rounded to BUF_SIZE) bytes in chunks of BUF_SIZE, and
120 120 * add it to the buf list.
121 121 * Returns the total size rounded to BUF_SIZE.
122 122 */
123 123 static size_t
124 124 ksyms_buflist_alloc(ksyms_buflist_hdr_t *hdr, size_t size)
125 125 {
126 126 int chunks, i;
127 127 ksyms_buflist_t *list;
128 128
129 129 chunks = howmany(size, BUF_SIZE);
130 130
131 131 if (hdr->nchunks >= chunks)
132 132 return (hdr->nchunks * BUF_SIZE);
133 133
134 134 /*
135 135 * Allocate chunks - hdr->nchunks buffers and add them to
136 136 * the list.
137 137 */
138 138 for (i = chunks - hdr->nchunks; i > 0; i--) {
139 139
140 140 if ((list = kmem_alloc(PAGESIZE, KM_NOSLEEP)) == NULL)
141 141 break;
142 142
143 143 list_insert_tail(&hdr->blist, list);
144 144 }
145 145
146 146 /*
147 147 * If we are running short of memory, free memory allocated till now
148 148 * and return.
149 149 */
150 150 if (i > 0) {
151 151 ksyms_buflist_free(hdr);
152 152 return (0);
153 153 }
154 154
155 155 hdr->nchunks = chunks;
156 156 hdr->cur = list_head(&hdr->blist);
157 157 hdr->curbuf_off = 0;
158 158
159 159 return (chunks * BUF_SIZE);
160 160 }
161 161
162 162 /*
163 163 * rlen is in multiples of PAGESIZE
164 164 */
165 165 static char *
166 166 ksyms_asmap(struct as *as, size_t rlen)
167 167 {
168 168 char *addr = NULL;
169 169
170 170 as_rangelock(as);
171 171 map_addr(&addr, rlen, 0, 1, 0);
172 172 if (addr == NULL || as_map(as, addr, rlen, segvn_create, zfod_argsp)) {
173 173 as_rangeunlock(as);
174 174 return (NULL);
175 175 }
176 176 as_rangeunlock(as);
177 177 return (addr);
178 178 }
179 179
180 180 static char *
181 181 ksyms_mapin(ksyms_buflist_hdr_t *hdr, size_t size)
182 182 {
183 183 size_t sz, rlen = roundup(size, PAGESIZE);
184 184 struct as *as = curproc->p_as;
185 185 char *addr, *raddr;
186 186 ksyms_buflist_t *list = list_head(&hdr->blist);
187 187
188 188 if ((addr = ksyms_asmap(as, rlen)) == NULL)
189 189 return (NULL);
190 190
191 191 raddr = addr;
192 192 while (size > 0 && list != NULL) {
193 193 sz = MIN(size, BUF_SIZE);
194 194
195 195 if (copyout(list->buf, raddr, sz)) {
196 196 (void) as_unmap(as, addr, rlen);
197 197 return (NULL);
198 198 }
199 199 list = list_next(&hdr->blist, list);
200 200 raddr += sz;
201 201 size -= sz;
202 202 }
203 203 return (addr);
204 204 }
205 205
206 206 /*
207 207 * Copy a snapshot of the kernel symbol table into the user's address space.
208 208 * The symbol table is copied in fragments so that we do not have to
209 209 * do a large kmem_alloc() which could fail/block if the kernel memory is
210 210 * fragmented.
211 211 */
212 212 /* ARGSUSED */
213 213 static int
214 214 ksyms_open(dev_t *devp, int flag, int otyp, struct cred *cred)
215 215 {
216 216 minor_t clone;
217 217 size_t size = 0;
218 218 size_t realsize;
219 219 char *addr;
220 220 void *hptr = NULL;
221 221 ksyms_buflist_hdr_t hdr;
222 222 bzero(&hdr, sizeof (struct ksyms_buflist_hdr));
223 223 list_create(&hdr.blist, PAGESIZE,
224 224 offsetof(ksyms_buflist_t, buflist_node));
225 225
226 226 if (getminor(*devp) != 0)
227 227 return (ENXIO);
228 228
229 229 for (;;) {
230 230 realsize = ksyms_snapshot(ksyms_bcopy, hptr, size);
231 231 if (realsize <= size)
232 232 break;
233 233 size = realsize;
234 234 size = ksyms_buflist_alloc(&hdr, size);
235 235 if (size == 0)
236 236 return (ENOMEM);
237 237 hptr = (void *)&hdr;
238 238 }
239 239
↓ open down ↓ |
239 lines elided |
↑ open up ↑ |
240 240 addr = ksyms_mapin(&hdr, realsize);
241 241 ksyms_buflist_free(&hdr);
242 242 if (addr == NULL)
243 243 return (EOVERFLOW);
244 244
245 245 /*
246 246 * Reserve a clone entry. Note that we don't use clone 0
247 247 * since that's the "real" minor number.
248 248 */
249 249 for (clone = 1; clone < nksyms_clones; clone++) {
250 - if (casptr(&ksyms_clones[clone].ksyms_base, 0, addr) == 0) {
250 + if (atomic_cas_ptr(&ksyms_clones[clone].ksyms_base, 0, addr) ==
251 + 0) {
251 252 ksyms_clones[clone].ksyms_size = realsize;
252 253 *devp = makedevice(getemajor(*devp), clone);
253 254 (void) ddi_prop_update_int(*devp, ksyms_devi,
254 255 "size", realsize);
255 256 modunload_disable();
256 257 return (0);
257 258 }
258 259 }
259 260 cmn_err(CE_NOTE, "ksyms: too many open references");
260 261 (void) as_unmap(curproc->p_as, addr, roundup(realsize, PAGESIZE));
261 262 return (ENXIO);
262 263 }
263 264
264 265 /* ARGSUSED */
265 266 static int
266 267 ksyms_close(dev_t dev, int flag, int otyp, struct cred *cred)
267 268 {
268 269 minor_t clone = getminor(dev);
269 270
270 271 (void) as_unmap(curproc->p_as, ksyms_clones[clone].ksyms_base,
271 272 roundup(ksyms_clones[clone].ksyms_size, PAGESIZE));
272 273 ksyms_clones[clone].ksyms_base = 0;
273 274 modunload_enable();
274 275 (void) ddi_prop_remove(dev, ksyms_devi, "size");
275 276 return (0);
276 277 }
277 278
278 279 static int
279 280 ksyms_symtbl_copy(ksyms_image_t *kip, struct uio *uio, size_t len)
280 281 {
281 282 char *buf;
282 283 int error = 0;
283 284 caddr_t base;
284 285 off_t off = uio->uio_offset;
285 286 size_t size;
286 287
287 288 /*
288 289 * The symbol table is stored in the user address space,
289 290 * so we have to copy it into the kernel first,
290 291 * then copy it back out to the specified user address.
291 292 */
292 293 buf = kmem_alloc(PAGESIZE, KM_SLEEP);
293 294 base = kip->ksyms_base + off;
294 295 while (len) {
295 296 size = MIN(PAGESIZE, len);
296 297 if (copyin(base, buf, size))
297 298 error = EFAULT;
298 299 else
299 300 error = uiomove(buf, size, UIO_READ, uio);
300 301
301 302 if (error)
302 303 break;
303 304
304 305 len -= size;
305 306 base += size;
306 307 }
307 308 kmem_free(buf, PAGESIZE);
308 309 return (error);
309 310 }
310 311
311 312 /* ARGSUSED */
312 313 static int
313 314 ksyms_read(dev_t dev, struct uio *uio, struct cred *cred)
314 315 {
315 316 ksyms_image_t *kip = &ksyms_clones[getminor(dev)];
316 317 off_t off = uio->uio_offset;
317 318 size_t len = uio->uio_resid;
318 319
319 320 if (off < 0 || off > kip->ksyms_size)
320 321 return (EFAULT);
321 322
322 323 if (len > kip->ksyms_size - off)
323 324 len = kip->ksyms_size - off;
324 325
325 326 if (len == 0)
326 327 return (0);
327 328
328 329 return (ksyms_symtbl_copy(kip, uio, len));
329 330 }
330 331
331 332 /* ARGSUSED */
332 333 static int
333 334 ksyms_segmap(dev_t dev, off_t off, struct as *as, caddr_t *addrp, off_t len,
334 335 uint_t prot, uint_t maxprot, uint_t flags, struct cred *cred)
335 336 {
336 337 ksyms_image_t *kip = &ksyms_clones[getminor(dev)];
337 338 int error = 0;
338 339 char *addr = NULL;
339 340 size_t rlen = 0;
340 341 struct iovec aiov;
341 342 struct uio auio;
342 343
343 344 if (flags & MAP_FIXED)
344 345 return (ENOTSUP);
345 346
346 347 if (off < 0 || len <= 0 || off > kip->ksyms_size ||
347 348 len > kip->ksyms_size - off)
348 349 return (EINVAL);
349 350
350 351 rlen = roundup(len, PAGESIZE);
351 352 if ((addr = ksyms_asmap(as, rlen)) == NULL)
352 353 return (EOVERFLOW);
353 354
354 355 aiov.iov_base = addr;
355 356 aiov.iov_len = len;
356 357 auio.uio_offset = off;
357 358 auio.uio_iov = &aiov;
358 359 auio.uio_iovcnt = 1;
359 360 auio.uio_resid = len;
360 361 auio.uio_segflg = UIO_USERSPACE;
361 362 auio.uio_llimit = MAXOFFSET_T;
362 363 auio.uio_fmode = FREAD;
363 364 auio.uio_extflg = UIO_COPY_CACHED;
364 365
365 366 error = ksyms_symtbl_copy(kip, &auio, len);
366 367
367 368 if (error)
368 369 (void) as_unmap(as, addr, rlen);
369 370 else
370 371 *addrp = addr;
371 372 return (error);
372 373 }
373 374
374 375 /* ARGSUSED */
375 376 static int
376 377 ksyms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
377 378 {
378 379 switch (infocmd) {
379 380 case DDI_INFO_DEVT2DEVINFO:
380 381 *result = ksyms_devi;
381 382 return (DDI_SUCCESS);
382 383 case DDI_INFO_DEVT2INSTANCE:
383 384 *result = 0;
384 385 return (DDI_SUCCESS);
385 386 }
386 387 return (DDI_FAILURE);
387 388 }
388 389
389 390 static int
390 391 ksyms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
391 392 {
392 393 if (cmd != DDI_ATTACH)
393 394 return (DDI_FAILURE);
394 395 if (ddi_create_minor_node(devi, "ksyms", S_IFCHR, 0, DDI_PSEUDO, NULL)
395 396 == DDI_FAILURE) {
396 397 ddi_remove_minor_node(devi, NULL);
397 398 return (DDI_FAILURE);
398 399 }
399 400 ksyms_devi = devi;
400 401 return (DDI_SUCCESS);
401 402 }
402 403
403 404 static int
404 405 ksyms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
405 406 {
406 407 if (cmd != DDI_DETACH)
407 408 return (DDI_FAILURE);
408 409 ddi_remove_minor_node(devi, NULL);
409 410 return (DDI_SUCCESS);
410 411 }
411 412
412 413 static struct cb_ops ksyms_cb_ops = {
413 414 ksyms_open, /* open */
414 415 ksyms_close, /* close */
415 416 nodev, /* strategy */
416 417 nodev, /* print */
417 418 nodev, /* dump */
418 419 ksyms_read, /* read */
419 420 nodev, /* write */
420 421 nodev, /* ioctl */
421 422 nodev, /* devmap */
422 423 nodev, /* mmap */
423 424 ksyms_segmap, /* segmap */
424 425 nochpoll, /* poll */
425 426 ddi_prop_op, /* prop_op */
426 427 0, /* streamtab */
427 428 D_NEW | D_MP /* Driver compatibility flag */
428 429 };
429 430
430 431 static struct dev_ops ksyms_ops = {
431 432 DEVO_REV, /* devo_rev, */
432 433 0, /* refcnt */
433 434 ksyms_info, /* info */
434 435 nulldev, /* identify */
435 436 nulldev, /* probe */
436 437 ksyms_attach, /* attach */
437 438 ksyms_detach, /* detach */
438 439 nodev, /* reset */
439 440 &ksyms_cb_ops, /* driver operations */
440 441 (struct bus_ops *)0, /* no bus operations */
441 442 NULL, /* power */
442 443 ddi_quiesce_not_needed, /* quiesce */
443 444 };
444 445
445 446 static struct modldrv modldrv = {
446 447 &mod_driverops, "kernel symbols driver", &ksyms_ops,
447 448 };
448 449
449 450 static struct modlinkage modlinkage = {
450 451 MODREV_1, { (void *)&modldrv }
451 452 };
452 453
453 454 int
454 455 _init(void)
455 456 {
456 457 int error;
457 458
458 459 if (nksyms_clones == 0)
459 460 nksyms_clones = maxusers + 50;
460 461
461 462 ksyms_clones = kmem_zalloc(nksyms_clones *
462 463 sizeof (ksyms_image_t), KM_SLEEP);
463 464
464 465 if ((error = mod_install(&modlinkage)) != 0)
465 466 kmem_free(ksyms_clones, nksyms_clones * sizeof (ksyms_image_t));
466 467
467 468 return (error);
468 469 }
469 470
470 471 int
471 472 _fini(void)
472 473 {
473 474 int error;
474 475
475 476 if ((error = mod_remove(&modlinkage)) == 0)
476 477 kmem_free(ksyms_clones, nksyms_clones * sizeof (ksyms_image_t));
477 478 return (error);
478 479 }
479 480
480 481 int
481 482 _info(struct modinfo *modinfop)
482 483 {
483 484 return (mod_info(&modlinkage, modinfop));
484 485 }
↓ open down ↓ |
224 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX