kern_module.c (841c0c7ec75bef3c9920cd811270f9f84791ee04) | kern_module.c (cea6c86c11f5264ab880e5d253986982d5644dd0) |
---|---|
1/*- 2 * Copyright (c) 1997 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 8 unchanged lines hidden (view full) --- 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. | 1/*- 2 * Copyright (c) 1997 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 8 unchanged lines hidden (view full) --- 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. |
25 * 26 * $Id$ |
|
25 */ 26 | 27 */ 28 |
27#include "opt_compat.h" 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 | |
32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/systm.h> | 29#include <sys/param.h> 30#include <sys/kernel.h> 31#include <sys/systm.h> |
35#include <sys/eventhandler.h> | 32#include <sys/sysctl.h> 33#include <sys/queue.h> 34#include <sys/libkern.h> |
36#include <sys/malloc.h> 37#include <sys/sysproto.h> 38#include <sys/sysent.h> | 35#include <sys/malloc.h> 36#include <sys/sysproto.h> 37#include <sys/sysent.h> |
39#include <sys/proc.h> 40#include <sys/lock.h> 41#include <sys/mutex.h> 42#include <sys/reboot.h> 43#include <sys/sx.h> | |
44#include <sys/module.h> 45#include <sys/linker.h> 46 | 38#include <sys/module.h> 39#include <sys/linker.h> 40 |
47static MALLOC_DEFINE(M_MODULE, "module", "module data structures"); | 41#define M_MODULE M_TEMP /* XXX */ |
48 49typedef TAILQ_HEAD(, module) modulelist_t; 50struct module { | 42 43typedef TAILQ_HEAD(, module) modulelist_t; 44struct module { |
51 TAILQ_ENTRY(module) link; /* chain together all modules */ 52 TAILQ_ENTRY(module) flink; /* all modules in a file */ 53 struct linker_file *file; /* file which contains this module */ 54 int refs; /* reference count */ 55 int id; /* unique id number */ 56 char *name; /* module name */ 57 modeventhand_t handler; /* event handler */ 58 void *arg; /* argument for handler */ 59 modspecific_t data; /* module specific data */ | 45 TAILQ_ENTRY(module) link; /* chain together all modules */ 46 TAILQ_ENTRY(module) flink; /* all modules in a file */ 47 struct linker_file* file; /* file which contains this module */ 48 int refs; /* reference count */ 49 int id; /* unique id number */ 50 char *name; /* module name */ 51 modeventhand_t handler; /* event handler */ 52 void *arg; /* argument for handler */ |
60}; 61 | 53}; 54 |
62#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) | 55#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) |
63 64static modulelist_t modules; | 56 57static modulelist_t modules; |
65struct sx modules_sx; | |
66static int nextid = 1; | 58static int nextid = 1; |
67static void module_shutdown(void *, int); | |
68 | 59 |
69static int 70modevent_nop(module_t mod, int what, void *arg) 71{ | 60static void module_shutdown(int, void*); |
72 | 61 |
73 switch(what) { 74 case MOD_LOAD: 75 return (0); 76 case MOD_UNLOAD: 77 return (EBUSY); 78 default: 79 return (EOPNOTSUPP); 80 } 81} 82 | |
83static void | 62static void |
84module_init(void *arg) | 63module_init(void* arg) |
85{ | 64{ |
86 87 sx_init(&modules_sx, "module subsystem sx lock"); 88 TAILQ_INIT(&modules); 89 EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL, 90 SHUTDOWN_PRI_DEFAULT); | 65 TAILQ_INIT(&modules); 66 at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC); |
91} 92 | 67} 68 |
93SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); | 69SYSINIT(module, SI_SUB_KMEM, SI_ORDER_ANY, module_init, 0); |
94 95static void | 70 71static void |
96module_shutdown(void *arg1, int arg2) | 72module_shutdown(int arg1, void* arg2) |
97{ | 73{ |
98 module_t mod; | 74 module_t mod; 75 int error; |
99 | 76 |
100 if (arg2 & RB_NOSYNC) 101 return; 102 mtx_lock(&Giant); 103 MOD_SLOCK; 104 TAILQ_FOREACH(mod, &modules, link) 105 MOD_EVENT(mod, MOD_SHUTDOWN); 106 MOD_SUNLOCK; 107 mtx_unlock(&Giant); | 77 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) 78 MOD_EVENT(mod, MOD_SHUTDOWN); |
108} 109 110void | 79} 80 81void |
111module_register_init(const void *arg) | 82module_register_static(void *arg) |
112{ | 83{ |
113 const moduledata_t *data = (const moduledata_t *)arg; 114 int error; 115 module_t mod; | 84 moduledata_t* data = (moduledata_t*) arg; 85 int error; |
116 | 86 |
117 mtx_lock(&Giant); 118 MOD_SLOCK; 119 mod = module_lookupbyname(data->name); 120 if (mod == NULL) 121 panic("module_register_init: module named %s not found\n", 122 data->name); 123 MOD_SUNLOCK; 124 error = MOD_EVENT(mod, MOD_LOAD); 125 if (error) { 126 MOD_EVENT(mod, MOD_UNLOAD); 127 MOD_XLOCK; 128 module_release(mod); 129 MOD_XUNLOCK; 130 printf("module_register_init: MOD_LOAD (%s, %p, %p) error" 131 " %d\n", data->name, (void *)data->evhand, data->priv, 132 error); 133 } else { 134 MOD_XLOCK; 135 if (mod->file) { 136 /* 137 * Once a module is succesfully loaded, move 138 * it to the head of the module list for this 139 * linker file. This resorts the list so that 140 * when the kernel linker iterates over the 141 * modules to unload them, it will unload them 142 * in the reverse order they were loaded. 143 */ 144 TAILQ_REMOVE(&mod->file->modules, mod, flink); 145 TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink); 146 } 147 MOD_XUNLOCK; 148 } 149 mtx_unlock(&Giant); | 87 if (error = module_register(data->name, data->evhand, data->priv)) 88 printf("module_register_static: module_register(%s, %x, %x) returned %d", 89 data->name, data->evhand, data->priv, error); |
150} 151 152int | 90} 91 92int |
153module_register(const moduledata_t *data, linker_file_t container) | 93module_register(const char* name, modeventhand_t handler, void* arg) |
154{ | 94{ |
155 size_t namelen; 156 module_t newmod; | 95 size_t namelen; 96 module_t newmod; 97 int error; |
157 | 98 |
158 MOD_XLOCK; 159 newmod = module_lookupbyname(data->name); 160 if (newmod != NULL) { 161 MOD_XUNLOCK; 162 printf("module_register: module %s already exists!\n", 163 data->name); 164 return (EEXIST); 165 } 166 namelen = strlen(data->name) + 1; 167 newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); 168 if (newmod == NULL) { 169 MOD_XUNLOCK; 170 return (ENOMEM); 171 } 172 newmod->refs = 1; 173 newmod->id = nextid++; 174 newmod->name = (char *)(newmod + 1); 175 strcpy(newmod->name, data->name); 176 newmod->handler = data->evhand ? data->evhand : modevent_nop; 177 newmod->arg = data->priv; 178 bzero(&newmod->data, sizeof(newmod->data)); 179 TAILQ_INSERT_TAIL(&modules, newmod, link); | 99 namelen = strlen(name) + 1; 100 newmod = (module_t) malloc(sizeof(struct module) + namelen, 101 M_MODULE, M_WAITOK); 102 if (newmod == 0) 103 return ENOMEM; |
180 | 104 |
181 if (container) 182 TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 183 newmod->file = container; 184 MOD_XUNLOCK; 185 return (0); | 105 newmod->refs = 1; 106 newmod->id = nextid++; 107 newmod->name = (char *) (newmod + 1); 108 strcpy(newmod->name, name); 109 newmod->handler = handler; 110 newmod->arg = arg; 111 TAILQ_INSERT_TAIL(&modules, newmod, link); 112 113 if (linker_current_file) { 114 TAILQ_INSERT_TAIL(&linker_current_file->modules, newmod, flink); 115 newmod->file = linker_current_file; 116 } else 117 newmod->file = 0; 118 119 if (error = MOD_EVENT(newmod, MOD_LOAD)) { 120 module_release(newmod); 121 return error; 122 } 123 124 return 0; |
186} 187 188void 189module_reference(module_t mod) 190{ | 125} 126 127void 128module_reference(module_t mod) 129{ |
130 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); |
|
191 | 131 |
192 MOD_XLOCK_ASSERT; 193 194 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 195 mod->refs++; | 132 mod->refs++; |
196} 197 198void 199module_release(module_t mod) 200{ | 133} 134 135void 136module_release(module_t mod) 137{ |
138 if (mod->refs <= 0) 139 panic("module_release: bad reference count"); |
|
201 | 140 |
202 MOD_XLOCK_ASSERT; | 141 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); |
203 | 142 |
204 if (mod->refs <= 0) 205 panic("module_release: bad reference count"); 206 207 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 208 209 mod->refs--; 210 if (mod->refs == 0) { 211 TAILQ_REMOVE(&modules, mod, link); 212 if (mod->file) 213 TAILQ_REMOVE(&mod->file->modules, mod, flink); 214 free(mod, M_MODULE); | 143 mod->refs--; 144 if (mod->refs == 0) { 145 TAILQ_REMOVE(&modules, mod, link); 146 if (mod->file) { 147 TAILQ_REMOVE(&mod->file->modules, mod, flink); |
215 } | 148 } |
149 free(mod, M_MODULE); 150 } |
|
216} 217 218module_t | 151} 152 153module_t |
219module_lookupbyname(const char *name) | 154module_lookupbyname(const char* name) |
220{ | 155{ |
221 module_t mod; 222 int err; | 156 module_t mod; |
223 | 157 |
224 MOD_LOCK_ASSERT; | 158 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 159 if (!strcmp(mod->name, name)) 160 return mod; 161 } |
225 | 162 |
226 TAILQ_FOREACH(mod, &modules, link) { 227 err = strcmp(mod->name, name); 228 if (err == 0) 229 return (mod); 230 } 231 return (NULL); | 163 return 0; |
232} 233 234module_t 235module_lookupbyid(int modid) 236{ | 164} 165 166module_t 167module_lookupbyid(int modid) 168{ |
237 module_t mod; | 169 module_t mod; |
238 | 170 |
239 MOD_LOCK_ASSERT; | 171 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 172 if (mod->id == modid) 173 return mod; 174 } |
240 | 175 |
241 TAILQ_FOREACH(mod, &modules, link) 242 if (mod->id == modid) 243 return(mod); 244 return (NULL); | 176 return 0; |
245} 246 247int | 177} 178 179int |
248module_quiesce(module_t mod) 249{ 250 int error; 251 252 mtx_lock(&Giant); 253 error = MOD_EVENT(mod, MOD_QUIESCE); 254 mtx_unlock(&Giant); 255 if (error == EOPNOTSUPP || error == EINVAL) 256 error = 0; 257 return (error); 258} 259 260int | |
261module_unload(module_t mod) 262{ | 180module_unload(module_t mod) 181{ |
263 int error; 264 265 mtx_lock(&Giant); 266 error = MOD_EVENT(mod, MOD_UNLOAD); 267 mtx_unlock(&Giant); 268 return (error); | 182 return MOD_EVENT(mod, MOD_UNLOAD); |
269} 270 271int 272module_getid(module_t mod) 273{ | 183} 184 185int 186module_getid(module_t mod) 187{ |
274 275 MOD_LOCK_ASSERT; 276 return (mod->id); | 188 return mod->id; |
277} 278 279module_t 280module_getfnext(module_t mod) 281{ | 189} 190 191module_t 192module_getfnext(module_t mod) 193{ |
282 283 MOD_LOCK_ASSERT; 284 return (TAILQ_NEXT(mod, flink)); | 194 return TAILQ_NEXT(mod, flink); |
285} 286 | 195} 196 |
287const char * 288module_getname(module_t mod) 289{ 290 291 MOD_LOCK_ASSERT; 292 return (mod->name); 293} 294 295void 296module_setspecific(module_t mod, modspecific_t *datap) 297{ 298 299 MOD_XLOCK_ASSERT; 300 mod->data = *datap; 301} 302 303linker_file_t 304module_file(module_t mod) 305{ 306 307 return (mod->file); 308} 309 | |
310/* 311 * Syscalls. 312 */ 313int | 197/* 198 * Syscalls. 199 */ 200int |
314modnext(struct thread *td, struct modnext_args *uap) | 201modnext(struct proc* p, struct modnext_args* uap, int* retval) |
315{ | 202{ |
316 module_t mod; 317 int error = 0; | 203 module_t mod; |
318 | 204 |
319 td->td_retval[0] = -1; | 205 *retval = -1; 206 if (SCARG(uap, modid) == 0) { 207 mod = TAILQ_FIRST(&modules); 208 if (mod) { 209 *retval = mod->id; 210 return 0; 211 } else 212 return ENOENT; 213 } |
320 | 214 |
321 MOD_SLOCK; 322 if (uap->modid == 0) { 323 mod = TAILQ_FIRST(&modules); 324 if (mod) 325 td->td_retval[0] = mod->id; 326 else 327 error = ENOENT; 328 goto done2; 329 } 330 mod = module_lookupbyid(uap->modid); 331 if (mod == NULL) { 332 error = ENOENT; 333 goto done2; 334 } 335 if (TAILQ_NEXT(mod, link)) 336 td->td_retval[0] = TAILQ_NEXT(mod, link)->id; 337 else 338 td->td_retval[0] = 0; 339done2: 340 MOD_SUNLOCK; 341 return (error); 342} | 215 mod = module_lookupbyid(SCARG(uap, modid)); 216 if (!mod) 217 return ENOENT; |
343 | 218 |
344int 345modfnext(struct thread *td, struct modfnext_args *uap) 346{ 347 module_t mod; 348 int error; 349 350 td->td_retval[0] = -1; 351 352 MOD_SLOCK; 353 mod = module_lookupbyid(uap->modid); 354 if (mod == NULL) { 355 error = ENOENT; 356 } else { 357 error = 0; 358 if (TAILQ_NEXT(mod, flink)) 359 td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; 360 else 361 td->td_retval[0] = 0; 362 } 363 MOD_SUNLOCK; 364 return (error); | 219 if (TAILQ_NEXT(mod, link)) 220 *retval = TAILQ_NEXT(mod, link)->id; 221 else 222 *retval = 0; 223 return 0; |
365} 366 | 224} 225 |
367struct module_stat_v1 { 368 int version; /* set to sizeof(struct module_stat) */ 369 char name[MAXMODNAME]; 370 int refs; 371 int id; 372}; 373 | |
374int | 226int |
375modstat(struct thread *td, struct modstat_args *uap) | 227modfnext(struct proc* p, struct modfnext_args* uap, int* retval) |
376{ | 228{ |
377 module_t mod; 378 modspecific_t data; 379 int error = 0; 380 int id, namelen, refs, version; 381 struct module_stat *stat; 382 char *name; | 229 module_t mod; |
383 | 230 |
384 MOD_SLOCK; 385 mod = module_lookupbyid(uap->modid); 386 if (mod == NULL) { 387 MOD_SUNLOCK; 388 return (ENOENT); 389 } 390 id = mod->id; 391 refs = mod->refs; 392 name = mod->name; 393 data = mod->data; 394 MOD_SUNLOCK; 395 stat = uap->stat; | 231 *retval = -1; |
396 | 232 |
397 /* 398 * Check the version of the user's structure. 399 */ 400 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 401 return (error); 402 if (version != sizeof(struct module_stat_v1) 403 && version != sizeof(struct module_stat)) 404 return (EINVAL); 405 namelen = strlen(mod->name) + 1; 406 if (namelen > MAXMODNAME) 407 namelen = MAXMODNAME; 408 if ((error = copyout(name, &stat->name[0], namelen)) != 0) 409 return (error); | 233 mod = module_lookupbyid(SCARG(uap, modid)); 234 if (!mod) 235 return ENOENT; |
410 | 236 |
411 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0) 412 return (error); 413 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0) 414 return (error); 415 416 /* 417 * >v1 stat includes module data. 418 */ 419 if (version == sizeof(struct module_stat)) 420 if ((error = copyout(&data, &stat->data, 421 sizeof(data))) != 0) 422 return (error); 423 td->td_retval[0] = 0; 424 return (error); | 237 if (TAILQ_NEXT(mod, flink)) 238 *retval = TAILQ_NEXT(mod, flink)->id; 239 else 240 *retval = 0; 241 return 0; |
425} 426 427int | 242} 243 244int |
428modfind(struct thread *td, struct modfind_args *uap) | 245modstat(struct proc* p, struct modstat_args* uap, int* retval) |
429{ | 246{ |
430 int error = 0; 431 char name[MAXMODNAME]; 432 module_t mod; | 247 module_t mod; 248 int error = 0; 249 int namelen; 250 int version; 251 struct module_stat* stat; |
433 | 252 |
434 if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0) 435 return (error); | 253 mod = module_lookupbyid(SCARG(uap, modid)); 254 if (!mod) 255 return ENOENT; |
436 | 256 |
437 MOD_SLOCK; 438 mod = module_lookupbyname(name); 439 if (mod == NULL) 440 error = ENOENT; 441 else 442 td->td_retval[0] = module_getid(mod); 443 MOD_SUNLOCK; 444 return (error); 445} | 257 stat = SCARG(uap, stat); |
446 | 258 |
447MODULE_VERSION(kernel, __FreeBSD_version); | 259 /* 260 * Check the version of the user's structure. 261 */ 262 if (error = copyin(&stat->version, &version, sizeof(version))) 263 goto out; 264 if (version != sizeof(struct module_stat)) { 265 error = EINVAL; 266 goto out; 267 } |
448 | 268 |
449#ifdef COMPAT_FREEBSD32 450#include <sys/mount.h> 451#include <sys/socket.h> 452#include <compat/freebsd32/freebsd32_util.h> 453#include <compat/freebsd32/freebsd32.h> 454#include <compat/freebsd32/freebsd32_proto.h> | 269 namelen = strlen(mod->name) + 1; 270 if (namelen > MAXMODNAME) 271 namelen = MAXMODNAME; 272 if (error = copyout(mod->name, &stat->name[0], namelen)) 273 goto out; |
455 | 274 |
456typedef union modspecific32 { 457 int intval; 458 u_int32_t uintval; 459 int longval; 460 u_int32_t ulongval; 461} modspecific32_t; | 275 if (error = copyout(&mod->refs, &stat->refs, sizeof(int))) 276 goto out; 277 if (error = copyout(&mod->id, &stat->id, sizeof(int))) 278 goto out; |
462 | 279 |
463struct module_stat32 { 464 int version; 465 char name[MAXMODNAME]; 466 int refs; 467 int id; 468 modspecific32_t data; 469}; | 280 *retval = 0; |
470 | 281 |
282out: 283 return error; 284} 285 |
|
471int | 286int |
472freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap) | 287modfind(struct proc* p, struct modfind_args* uap, int* retval) |
473{ | 288{ |
474 module_t mod; 475 modspecific32_t data32; 476 int error = 0; 477 int id, namelen, refs, version; 478 struct module_stat32 *stat32; 479 char *name; | 289 int error = 0; 290 char name[MAXMODNAME]; 291 module_t mod; |
480 | 292 |
481 MOD_SLOCK; 482 mod = module_lookupbyid(uap->modid); 483 if (mod == NULL) { 484 MOD_SUNLOCK; 485 return (ENOENT); 486 } | 293 if (error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) 294 goto out; |
487 | 295 |
488 id = mod->id; 489 refs = mod->refs; 490 name = mod->name; 491 CP(mod->data, data32, intval); 492 CP(mod->data, data32, uintval); 493 CP(mod->data, data32, longval); 494 CP(mod->data, data32, ulongval); 495 MOD_SUNLOCK; 496 stat32 = uap->stat; | 296 mod = module_lookupbyname(name); 297 if (!mod) 298 error = ENOENT; 299 else 300 *retval = mod->id; |
497 | 301 |
498 if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0) 499 return (error); 500 if (version != sizeof(struct module_stat_v1) 501 && version != sizeof(struct module_stat32)) 502 return (EINVAL); 503 namelen = strlen(mod->name) + 1; 504 if (namelen > MAXMODNAME) 505 namelen = MAXMODNAME; 506 if ((error = copyout(name, &stat32->name[0], namelen)) != 0) 507 return (error); 508 509 if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0) 510 return (error); 511 if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0) 512 return (error); 513 514 /* 515 * >v1 stat includes module data. 516 */ 517 if (version == sizeof(struct module_stat32)) 518 if ((error = copyout(&data32, &stat32->data, 519 sizeof(data32))) != 0) 520 return (error); 521 td->td_retval[0] = 0; 522 return (error); | 302out: 303 return error; |
523} | 304} |
524#endif | |