|
|
1.1 ! root 1: /* ! 2: * kern_lkm.c ! 3: * ! 4: * functions and pseudo-device for loadable kernel modules ! 5: * ! 6: * 05 Jun 93 Terry Lambert Release cleanup ! 7: * 10 Feb 93 Terry Lambert Original ! 8: * ! 9: * Copyright (c) 1992 Terrence R. Lambert. ! 10: * All rights reserved. ! 11: * ! 12: * Redistribution and use in source and binary forms, with or without ! 13: * modification, are permitted provided that the following conditions ! 14: * are met: ! 15: * 1. Redistributions of source code must retain the above copyright ! 16: * notice, this list of conditions and the following disclaimer. ! 17: * 2. Redistributions in binary form must reproduce the above copyright ! 18: * notice, this list of conditions and the following disclaimer in the ! 19: * documentation and/or other materials provided with the distribution. ! 20: * 3. All advertising materials mentioning features or use of this software ! 21: * must display the following acknowledgement: ! 22: * This product includes software developed by Terrence R. Lambert. ! 23: * 4. The name Terrence R. Lambert may not be used to endorse or promote ! 24: * products derived from this software without specific prior written ! 25: * permission. ! 26: * ! 27: * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY ! 28: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 29: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 30: * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE ! 31: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 32: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 33: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 34: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 35: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 36: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 37: * SUCH DAMAGE. ! 38: * ! 39: * kern_lkm.c,v 1.3.2.1 1993/07/22 13:01:55 cgd Exp ! 40: */ ! 41: ! 42: #include "param.h" ! 43: #include "systm.h" ! 44: #include "ioctl.h" ! 45: #include "tty.h" ! 46: #include "conf.h" ! 47: #include "file.h" ! 48: #include "proc.h" ! 49: #include "uio.h" ! 50: #include "kernel.h" ! 51: #include "vnode.h" ! 52: #include "malloc.h" ! 53: #include "vm/vm.h" ! 54: #include "vm/vm_param.h" ! 55: #include "vm/vm_kern.h" ! 56: #include "mount.h" ! 57: #include "exec.h" ! 58: #include "lkm.h" ! 59: ! 60: #define PAGESIZE 1024 /* kmem_alloc() allocation quantum*/ ! 61: ! 62: #define LKM_ALLOC 0x01 ! 63: #define LKM_WANT 0x02 ! 64: ! 65: ! 66: #define LKMS_IDLE 0x00 ! 67: #define LKMS_RESERVED 0x01 ! 68: #define LKMS_LOADING 0x02 ! 69: #define LKMS_LOADED 0x04 ! 70: #define LKMS_UNLOADING 0x08 ! 71: ! 72: static int lkm_v = 0; ! 73: static int lkm_state = LKMS_IDLE; ! 74: ! 75: #ifndef MAXLKMS ! 76: #define MAXLKMS 20 ! 77: #endif ! 78: ! 79: static struct lkm_table lkmods[ MAXLKMS]; /* table of loaded modules*/ ! 80: static struct lkm_table *curp; /* global for in-progress ops*/ ! 81: ! 82: /*ARGSUSED*/ ! 83: lkmopen( dev, flag, devtype, p) ! 84: dev_t dev; ! 85: int flag; ! 86: int devtype; ! 87: struct proc *p; ! 88: { ! 89: int error; ! 90: ! 91: if( minor( dev) != 0) ! 92: return( ENXIO); /* bad minor #*/ ! 93: ! 94: /* ! 95: * Use of the loadable kernel module device must be exclusive; we ! 96: * may try to remove this restriction later, but it's really no ! 97: * hardship. ! 98: */ ! 99: while( lkm_v & LKM_ALLOC) { ! 100: if( flag & FNONBLOCK) /* don't hang*/ ! 101: return( EBUSY); ! 102: lkm_v |= LKM_WANT; ! 103: /* ! 104: * Sleep pending unlock; we use tsleep() to allow ! 105: * an alarm out of the open. ! 106: */ ! 107: if( error = tsleep( (caddr_t)&lkm_v, TTIPRI|PCATCH, "LKM", 0)) ! 108: return( error); /* leave LKM_WANT set -- no problem*/ ! 109: } ! 110: lkm_v |= LKM_ALLOC; ! 111: ! 112: return( 0); /* pseudo-device open*/ ! 113: } ! 114: ! 115: ! 116: /* ! 117: * l k m u n r e s e r v e ! 118: * ! 119: * Unreserve the memory associated with the current loaded module; done on ! 120: * a coerced close of the lkm device (close on premature exit of modload) ! 121: * or explicitly by modload as a result of a link failure. ! 122: */ ! 123: static int ! 124: lkmunreserve() ! 125: { ! 126: if( lkm_state == LKMS_IDLE) ! 127: return; ! 128: ! 129: /* ! 130: * Actually unreserve the memory ! 131: */ ! 132: kmem_free( kmem_map, curp->area, curp->size);/**/ ! 133: ! 134: lkm_state = LKMS_IDLE; ! 135: } ! 136: ! 137: ! 138: lkmclose( dev, flag, mode, p) ! 139: dev_t dev; ! 140: int flag; ! 141: int mode; ! 142: struct proc *p; ! 143: { ! 144: if( !( lkm_v & LKM_ALLOC)) { ! 145: #ifdef DEBUG ! 146: printf( "LKM: close before open!\n"); ! 147: #endif /* DEBUG*/ ! 148: return( EBADF); ! 149: } ! 150: ! 151: /* do this before waking the herd...*/ ! 152: if( !curp->used) { ! 153: /* ! 154: * If we close before setting used, we have aborted ! 155: * by way of error or by way of close-on-exit from ! 156: * a premature exit of "modload". ! 157: */ ! 158: lkmunreserve(); /* coerce state to LKM_IDLE*/ ! 159: } ! 160: ! 161: lkm_v &= ~LKM_ALLOC; ! 162: wakeup( (caddr_t)&lkm_v); /* thundering herd "problem" here*/ ! 163: ! 164: return( 0); /* pseudo-device closed*/ ! 165: } ! 166: ! 167: ! 168: /*ARGSUSED*/ ! 169: lkmioctl( dev, cmd, data, flag) ! 170: dev_t dev; ! 171: int cmd; ! 172: caddr_t data; ! 173: int flag; ! 174: { ! 175: int err = 0; ! 176: int i; ! 177: struct lmc_resrv *resrvp; ! 178: struct lmc_loadbuf *loadbufp; ! 179: struct lmc_unload *unloadp; ! 180: struct lmc_stat *statp; ! 181: int (*funcp)(); ! 182: char istr[ MAXLKMNAME]; ! 183: ! 184: switch( cmd) { ! 185: case LMRESERV: /* reserve pages for a module*/ ! 186: if ((flag & FWRITE) == 0) /* only allow this if writing */ ! 187: return EPERM; ! 188: ! 189: resrvp = (struct lmc_resrv *)data; ! 190: ! 191: /* ! 192: * Find a free slot. ! 193: */ ! 194: for( i = 0; i < MAXLKMS; i++) { ! 195: if( !lkmods[ i].used) ! 196: break; ! 197: } ! 198: if( i == MAXLKMS) { ! 199: err = ENOMEM; /* no slots available*/ ! 200: break; ! 201: } ! 202: curp = &lkmods[ i]; ! 203: curp->id = i; /* self reference slot offset*/ ! 204: ! 205: resrvp->slot = i; /* return slot*/ ! 206: ! 207: /* ! 208: * Get memory for module ! 209: */ ! 210: curp->size = resrvp->size; ! 211: ! 212: curp->area = (char *)kmem_alloc( kmem_map, curp->size);/**/ ! 213: ! 214: curp->offset = 0; /* load offset*/ ! 215: ! 216: resrvp->addr = (unsigned long)curp->area; /* ret kernel addr*/ ! 217: ! 218: #ifdef DEBUG ! 219: printf( "LKM: LMRESERV (actual = 0x%08x)\n", curp->area); ! 220: printf( "LKM: LMRESERV (adjusted = 0x%08x)\n", ! 221: trunc_page(curp->area)); ! 222: #endif /* DEBUG*/ ! 223: lkm_state = LKMS_RESERVED; ! 224: break; ! 225: ! 226: case LMLOADBUF: /* Copy in; stateful, follows LMRESERV*/ ! 227: if ((flag & FWRITE) == 0) /* only allow this if writing */ ! 228: return EPERM; ! 229: ! 230: loadbufp = (struct lmc_loadbuf *)data; ! 231: if( lkm_state != LKMS_RESERVED && lkm_state != LKMS_LOADING) { ! 232: err = ENOMEM; ! 233: break; ! 234: } ! 235: ! 236: /* account for odd size (non-page multiple) copyin*/ ! 237: i = MIN( curp->size - curp->offset, MODIOBUF); ! 238: ! 239: /* copy in buffer full of data*/ ! 240: if( err = copyin( (caddr_t)loadbufp->data, (caddr_t)curp->area + curp->offset, i)) ! 241: break; ! 242: ! 243: if( ( curp->offset + i) < curp->size) { ! 244: lkm_state = LKMS_LOADING; ! 245: #ifdef DEBUG ! 246: printf( "LKM: LMLOADBUF (loading @ %d of %d, i = %d)\n", ! 247: curp->offset, curp->size, i); ! 248: #endif /* DEBUG*/ ! 249: } else { ! 250: lkm_state = LKMS_LOADED; ! 251: #ifdef DEBUG ! 252: printf( "LKM: LMLOADBUF (loaded)\n"); ! 253: #endif /* DEBUG*/ ! 254: } ! 255: curp->offset += MODIOBUF; ! 256: break; ! 257: ! 258: case LMUNRESRV: /* discard reserved pages for a module*/ ! 259: if ((flag & FWRITE) == 0) /* only allow this if writing */ ! 260: return EPERM; ! 261: ! 262: lkmunreserve(); /* coerce state to LKM_IDLE*/ ! 263: #ifdef DEBUG ! 264: printf( "LKM: LMUNRESERV\n"); ! 265: #endif /* DEBUG*/ ! 266: break; ! 267: ! 268: case LMREADY: /* module loaded: call entry*/ ! 269: if ((flag & FWRITE) == 0) /* only allow this if writing */ ! 270: return EPERM; ! 271: ! 272: if( lkm_state != LKMS_LOADED) { ! 273: ! 274: #ifdef DEBUG ! 275: printf( "lkm_state is %02x\n", lkm_state); ! 276: #endif /* DEBUG*/ ! 277: err = ENXIO; ! 278: break; ! 279: } ! 280: ! 281: curp->entry = (int (*)()) (*((int *) ( data))); ! 282: ! 283: /* call entry(load)... (assigns "private" portion)*/ ! 284: if( err = (*(curp->entry))( curp, LKM_E_LOAD, LKM_VERSION)) { ! 285: /* ! 286: * Module may refuse loading or may have a ! 287: * version mismatch... ! 288: */ ! 289: lkm_state = LKMS_UNLOADING; /* for lkmunreserve*/ ! 290: lkmunreserve(); /* free memory*/ ! 291: curp->used = 0; /* free slot*/ ! 292: break; ! 293: } ! 294: ! 295: curp->used = 1; ! 296: #ifdef DEBUG ! 297: printf( "LKM: LMREADY\n"); ! 298: #endif /* DEBUG*/ ! 299: lkm_state = LKMS_IDLE; ! 300: break; ! 301: ! 302: case LMUNLOAD: /* unload a module*/ ! 303: if ((flag & FWRITE) == 0) /* only allow this if writing */ ! 304: return EPERM; ! 305: ! 306: unloadp = (struct lmc_unload *)data; ! 307: ! 308: if( ( i = unloadp->id) == -1) { /* unload by name*/ ! 309: /* ! 310: * Copy name and lookup id from all loaded ! 311: * modules. ! 312: */ ! 313: copystr( unloadp->name, istr, MAXLKMNAME-1, NULL); ! 314: /* ! 315: * look up id... ! 316: */ ! 317: for( i = 0; i < MAXLKMS; i++) { ! 318: if( !lkmods[ i].used) ! 319: continue; ! 320: if( !strcmp( istr, ! 321: lkmods[ i].private.lkm_any->lkm_name)) ! 322: break; ! 323: } ! 324: } ! 325: ! 326: /* ! 327: * Range check the value; on failure, return EINVAL ! 328: */ ! 329: if( i < 0 || i >= MAXLKMS) { ! 330: err = EINVAL; ! 331: break; ! 332: } ! 333: ! 334: curp = &lkmods[ i]; ! 335: ! 336: /* call entry(unload)*/ ! 337: if( (*(curp->entry))( curp, LKM_E_UNLOAD, LKM_VERSION)) { ! 338: err = EBUSY; ! 339: break; ! 340: } ! 341: ! 342: lkm_state = LKMS_UNLOADING; /* non-idle for lkmunreserve*/ ! 343: lkmunreserve(); /* free memory*/ ! 344: curp->used = 0; /* free slot*/ ! 345: break; ! 346: ! 347: case LMSTAT: /* stat a module by id/name*/ ! 348: /* allow readers and writers to stat */ ! 349: ! 350: statp = (struct lmc_stat *)data; ! 351: ! 352: if( ( i = statp->id) == -1) { /* stat by name*/ ! 353: /* ! 354: * Copy name and lookup id from all loaded ! 355: * modules. ! 356: */ ! 357: copystr( statp->name, istr, MAXLKMNAME-1, NULL); ! 358: /* ! 359: * look up id... ! 360: */ ! 361: for( i = 0; i < MAXLKMS; i++) { ! 362: if( !lkmods[ i].used) ! 363: continue; ! 364: if( !strcmp( istr, ! 365: lkmods[ i].private.lkm_any->lkm_name)) ! 366: break; ! 367: } ! 368: ! 369: if( i == MAXLKMS) { /* Not found*/ ! 370: err = ENOENT; ! 371: break; ! 372: } ! 373: } ! 374: ! 375: /* ! 376: * Range check the value; on failure, return EINVAL ! 377: */ ! 378: if( i < 0 || i >= MAXLKMS) { ! 379: err = EINVAL; ! 380: break; ! 381: } ! 382: ! 383: curp = &lkmods[ i]; ! 384: ! 385: if( !curp->used) { /* Not found*/ ! 386: err = ENOENT; ! 387: break; ! 388: } ! 389: ! 390: /* ! 391: * Copy out stat information for this module... ! 392: */ ! 393: statp->id = curp->id; ! 394: statp->offset = curp->private.lkm_any->lkm_offset; ! 395: statp->type = curp->private.lkm_any->lkm_type; ! 396: statp->area = curp->area; ! 397: statp->size = curp->size / PAGESIZE; ! 398: statp->private = (unsigned long)curp->private.lkm_any; ! 399: statp->ver = curp->private.lkm_any->lkm_ver; ! 400: copystr( curp->private.lkm_any->lkm_name, ! 401: statp->name, ! 402: MAXLKMNAME - 2, ! 403: NULL); ! 404: ! 405: break; ! 406: ! 407: default: /* bad ioctl()...*/ ! 408: err = ENOTTY; ! 409: break; ! 410: } ! 411: ! 412: return (err); ! 413: } ! 414: ! 415: ! 416: /*********************************************************************/ ! 417: ! 418: ! 419: /* ! 420: * l k m n o s y s ! 421: * ! 422: * Acts like "nosys" but can be identified in sysent for dynamic call ! 423: * number assignment for a limited number of calls. ! 424: * ! 425: * Place holder for system call slots reserved for loadable modules. ! 426: */ ! 427: lkmnosys() ! 428: { ! 429: return( nosys()); ! 430: } ! 431: ! 432: /* ! 433: * l k m e n o d e v ! 434: * ! 435: * Acts like "enodev", but can be identified in cdevsw and bdevsw for ! 436: * dynamic driver major number assignment for a limited number of ! 437: * drivers. ! 438: * ! 439: * Place holder for device switch slots reserved for loadable modules. ! 440: */ ! 441: int ! 442: lkmenodev() ! 443: { ! 444: return( enodev()); ! 445: } ! 446: ! 447: /*********************************************************************/ ! 448: ! 449: ! 450: int ! 451: lkmexists( lkmtp) ! 452: struct lkm_table *lkmtp; ! 453: { ! 454: int i; ! 455: ! 456: /* ! 457: * see if name exists... ! 458: */ ! 459: for( i = 0; i < MAXLKMS; i++) { ! 460: /* ! 461: * An unused module and the one we are testing are not ! 462: * considered. ! 463: */ ! 464: if( !lkmods[ i].used || &lkmods[ i] == lkmtp) ! 465: continue; ! 466: if( !strcmp( lkmtp->private.lkm_any->lkm_name, ! 467: lkmods[ i].private.lkm_any->lkm_name)) ! 468: return( 1); /* already loaded...*/ ! 469: } ! 470: ! 471: return( 0); /* module not loaded...*/ ! 472: } ! 473: ! 474: ! 475: /* ! 476: * For the loadable system call described by the structure pointed to ! 477: * by lkmtp, load/unload/stat it depending on the cmd requested. ! 478: */ ! 479: static int ! 480: _lkm_syscall( lkmtp, cmd) ! 481: struct lkm_table *lkmtp; ! 482: int cmd; ! 483: { ! 484: struct lkm_syscall *args = lkmtp->private.lkm_syscall; ! 485: int i; ! 486: int err = 0; ! 487: extern int nsysent; /* init_sysent.c*/ ! 488: ! 489: switch( cmd) { ! 490: case LKM_E_LOAD: ! 491: /* don't load twice!*/ ! 492: if( lkmexists( lkmtp)) ! 493: return( EEXIST); ! 494: if( ( i = args->lkm_offset) == -1) { /* auto*/ ! 495: /* ! 496: * Search the table looking for a slot... ! 497: */ ! 498: for( i = 0; i < nsysent; i++) ! 499: if( sysent[ i].sy_call == lkmnosys) ! 500: break; /* found it!*/ ! 501: /* out of allocable slots?*/ ! 502: if( i == nsysent) { ! 503: err = ENFILE; ! 504: break; ! 505: } ! 506: } else { /* assign*/ ! 507: if( i < 0 || i >= nsysent) { ! 508: err = EINVAL; ! 509: break; ! 510: } ! 511: } ! 512: ! 513: /* save old*/ ! 514: bcopy( &sysent[ i], &(args->lkm_oldent), sizeof( struct sysent)); ! 515: ! 516: /* replace with new*/ ! 517: bcopy( args->lkm_sysent, &sysent[ i], sizeof( struct sysent)); ! 518: ! 519: /* done!*/ ! 520: args->lkm_offset = i; /* slot in sysent[]*/ ! 521: ! 522: break; ! 523: ! 524: case LKM_E_UNLOAD: ! 525: /* current slot...*/ ! 526: i = args->lkm_offset; ! 527: ! 528: /* replace current slot contents with old contents*/ ! 529: bcopy( &(args->lkm_oldent), &sysent[ i], sizeof( struct sysent)); ! 530: ! 531: break; ! 532: ! 533: case LKM_E_STAT: /* no special handling...*/ ! 534: break; ! 535: } ! 536: ! 537: return( err); ! 538: } ! 539: ! 540: ! 541: /* ! 542: * For the loadable virtual file system described by the structure pointed ! 543: * to by lkmtp, load/unload/stat it depending on the cmd requested. ! 544: */ ! 545: static int ! 546: _lkm_vfs( lkmtp, cmd) ! 547: struct lkm_table *lkmtp; ! 548: int cmd; ! 549: { ! 550: struct lkm_vfs *args = lkmtp->private.lkm_vfs; ! 551: int i; ! 552: int err = 0; ! 553: ! 554: switch( cmd) { ! 555: case LKM_E_LOAD: ! 556: /* don't load twice!*/ ! 557: if( lkmexists( lkmtp)) ! 558: return( EEXIST); ! 559: /* ! 560: * Currently, the VFS and mount code in 386BSD is malformed; ! 561: * this means that the per volume file system identifier is ! 562: * the index into the table rather than the name; this means ! 563: * that only the file systems already known to 386BSD are ! 564: * allowable, since all others don't have fixed offsets. ! 565: * Interestingly, Dell UNIX has this same bug with their VFS ! 566: * implementation, but generic AT&T SVR4 does not. ! 567: * ! 568: * I will correct the VFS code when I get a chance. ! 569: */ ! 570: i = args->lkm_offset; ! 571: if( i < 0 || i > MOUNT_MAXTYPE) { ! 572: err = EINVAL; ! 573: break; ! 574: } ! 575: ! 576: if( vfssw[ i] != (struct vfsops *)0) { ! 577: err = EEXIST; ! 578: break; ! 579: } ! 580: ! 581: /* ! 582: * Set up file system ! 583: */ ! 584: vfssw[ i] = args->lkm_vfsops; ! 585: ! 586: /* ! 587: * Call init function for this VFS... ! 588: */ ! 589: ( *(vfssw[ i]->vfs_init))( args->lkm_flags); ! 590: ! 591: /* done!*/ ! 592: args->lkm_offset = i; /* slot in sysent[]*/ ! 593: ! 594: break; ! 595: ! 596: case LKM_E_UNLOAD: ! 597: /* current slot...*/ ! 598: i = args->lkm_offset; ! 599: ! 600: /* replace current slot contents with old contents*/ ! 601: vfssw[ i] = (struct vfsops *)0; ! 602: ! 603: break; ! 604: ! 605: case LKM_E_STAT: /* no special handling...*/ ! 606: break; ! 607: } ! 608: ! 609: return( err); ! 610: } ! 611: ! 612: ! 613: /* ! 614: * For the loadable device driver described by the structure pointed to ! 615: * by lkmtp, load/unload/stat it depending on the cmd requested. ! 616: */ ! 617: static int ! 618: _lkm_dev( lkmtp, cmd) ! 619: struct lkm_table *lkmtp; ! 620: int cmd; ! 621: { ! 622: struct lkm_dev *args = lkmtp->private.lkm_dev; ! 623: int i; ! 624: int err = 0; ! 625: extern int nblkdev; /* i386/i386/conf.c*/ ! 626: extern int nchrdev; /* i386/i386/conf.c*/ ! 627: ! 628: switch( cmd) { ! 629: case LKM_E_LOAD: ! 630: /* don't load twice!*/ ! 631: if( lkmexists( lkmtp)) ! 632: return( EEXIST); ! 633: switch( args->lkm_devtype) { ! 634: case LM_DT_BLOCK: ! 635: if( ( i = args->lkm_offset) == -1) { /* auto*/ ! 636: /* ! 637: * Search the table looking for a slot... ! 638: */ ! 639: for( i = 0; i < nblkdev; i++) ! 640: if( bdevsw[ i].d_open == lkmenodev) ! 641: break; /* found it!*/ ! 642: /* out of allocable slots?*/ ! 643: if( i == nblkdev) { ! 644: err = ENFILE; ! 645: break; ! 646: } ! 647: } else { /* assign*/ ! 648: if( i < 0 || i >= nblkdev) { ! 649: err = EINVAL; ! 650: break; ! 651: } ! 652: } ! 653: ! 654: /* save old*/ ! 655: bcopy( &bdevsw[ i], &(args->lkm_olddev.bdev), sizeof( struct bdevsw)); ! 656: ! 657: /* replace with new*/ ! 658: bcopy( args->lkm_dev.bdev, &bdevsw[ i], sizeof( struct bdevsw)); ! 659: ! 660: /* done!*/ ! 661: args->lkm_offset = i; /* slot in bdevsw[]*/ ! 662: break; ! 663: ! 664: case LM_DT_CHAR: ! 665: if( ( i = args->lkm_offset) == -1) { /* auto*/ ! 666: /* ! 667: * Search the table looking for a slot... ! 668: */ ! 669: for( i = 0; i < nchrdev; i++) ! 670: if( cdevsw[ i].d_open == lkmenodev) ! 671: break; /* found it!*/ ! 672: /* out of allocable slots?*/ ! 673: if( i == nchrdev) { ! 674: err = ENFILE; ! 675: break; ! 676: } ! 677: } else { /* assign*/ ! 678: if( i < 0 || i >= nchrdev) { ! 679: err = EINVAL; ! 680: break; ! 681: } ! 682: } ! 683: ! 684: /* save old*/ ! 685: bcopy( &cdevsw[ i], &(args->lkm_olddev.cdev), sizeof( struct cdevsw)); ! 686: ! 687: /* replace with new*/ ! 688: bcopy( args->lkm_dev.cdev, &cdevsw[ i], sizeof( struct cdevsw)); ! 689: ! 690: /* done!*/ ! 691: args->lkm_offset = i; /* slot in cdevsw[]*/ ! 692: ! 693: break; ! 694: ! 695: default: ! 696: err = ENODEV; ! 697: break; ! 698: } ! 699: break; ! 700: ! 701: case LKM_E_UNLOAD: ! 702: /* current slot...*/ ! 703: i = args->lkm_offset; ! 704: ! 705: switch( args->lkm_devtype) { ! 706: case LM_DT_BLOCK: ! 707: /* replace current slot contents with old contents*/ ! 708: bcopy( &(args->lkm_olddev.bdev), &bdevsw[ i], sizeof( struct bdevsw)); ! 709: break; ! 710: ! 711: case LM_DT_CHAR: ! 712: /* replace current slot contents with old contents*/ ! 713: bcopy( &(args->lkm_olddev.cdev), &cdevsw[ i], sizeof( struct cdevsw)); ! 714: break; ! 715: ! 716: default: ! 717: err = ENODEV; ! 718: break; ! 719: } ! 720: break; ! 721: ! 722: case LKM_E_STAT: /* no special handling...*/ ! 723: break; ! 724: } ! 725: ! 726: return( err); ! 727: } ! 728: ! 729: ! 730: #ifdef STREAMS ! 731: /* ! 732: * For the loadable streams module described by the structure pointed to ! 733: * by lkmtp, load/unload/stat it depending on the cmd requested. ! 734: */ ! 735: static int ! 736: _lkm_strmod( lkmtp, cmd) ! 737: struct lkm_table *lkmtp; ! 738: int cmd; ! 739: { ! 740: struct lkm_strmod *args = lkmtp->private.lkm_strmod; ! 741: int i; ! 742: int err = 0; ! 743: ! 744: switch( cmd) { ! 745: case LKM_E_LOAD: ! 746: /* don't load twice!*/ ! 747: if( lkmexists( lkmtp)) ! 748: return( EEXIST); ! 749: break; ! 750: ! 751: case LKM_E_UNLOAD: ! 752: break; ! 753: ! 754: case LKM_E_STAT: /* no special handling...*/ ! 755: break; ! 756: } ! 757: ! 758: return( err); ! 759: } ! 760: #endif /* STREAMS*/ ! 761: ! 762: #ifdef LKM_EXEC /* XXX NOTDEF YET!!! - cgd */ ! 763: /* ! 764: * For the loadable execution class described by the structure pointed to ! 765: * by lkmtp, load/unload/stat it depending on the cmd requested. ! 766: */ ! 767: static int ! 768: _lkm_exec( lkmtp, cmd) ! 769: struct lkm_table *lkmtp; ! 770: int cmd; ! 771: { ! 772: struct lkm_exec *args = lkmtp->private.lkm_exec; ! 773: int i; ! 774: int err = 0; ! 775: ! 776: switch( cmd) { ! 777: case LKM_E_LOAD: ! 778: /* don't load twice!*/ ! 779: if( lkmexists( lkmtp)) ! 780: return( EEXIST); ! 781: if( ( i = args->lkm_offset) == -1) { /* auto*/ ! 782: /* ! 783: * Search the table looking for a slot... ! 784: */ ! 785: for( i = 0; i < nexecs; i++) ! 786: if( execsw[ i].m_size == 0) ! 787: break; /* found it!*/ ! 788: /* out of allocable slots?*/ ! 789: if( i == nexecs) { ! 790: err = ENFILE; ! 791: break; ! 792: } ! 793: } else { /* assign*/ ! 794: if( i < 0 || i >= nexecs) { ! 795: err = EINVAL; ! 796: break; ! 797: } ! 798: } ! 799: ! 800: /* save old*/ ! 801: bcopy( &execsw[ i], &(args->lkm_oldexec), sizeof( struct execsw)); ! 802: ! 803: /* replace with new*/ ! 804: bcopy( args->lkm_exec, &execsw[ i], sizeof( struct execsw)); ! 805: ! 806: /* done!*/ ! 807: args->lkm_offset = i; /* slot in execsw[]*/ ! 808: ! 809: break; ! 810: ! 811: case LKM_E_UNLOAD: ! 812: /* current slot...*/ ! 813: i = args->lkm_offset; ! 814: ! 815: /* replace current slot contents with old contents*/ ! 816: bcopy( &execsw[ i], &(args->lkm_oldexec), sizeof( struct execsw)); ! 817: ! 818: break; ! 819: ! 820: case LKM_E_STAT: /* no special handling...*/ ! 821: break; ! 822: } ! 823: ! 824: return( err); ! 825: } ! 826: #endif /* LKM_EXEC */ ! 827: ! 828: /* ! 829: * This code handles the per-module type "wiring-in" of loadable modules ! 830: * into existing kernel tables. For "LM_MISC" modules, wiring and unwiring ! 831: * is assumed to be done in their entry routines internal to the module ! 832: * itself. ! 833: */ ! 834: lkmdispatch( lkmtp, cmd) ! 835: struct lkm_table *lkmtp; ! 836: int cmd; ! 837: { ! 838: int err = 0; /* default = success*/ ! 839: ! 840: switch( lkmtp->private.lkm_any->lkm_type) { ! 841: case LM_SYSCALL: ! 842: err = _lkm_syscall( lkmtp, cmd); ! 843: break; ! 844: ! 845: case LM_VFS: ! 846: err = _lkm_vfs( lkmtp, cmd); ! 847: break; ! 848: ! 849: case LM_DEV: ! 850: { ! 851: struct lkm_dev *args = lkmtp->private.lkm_dev; ! 852: } ! 853: break; ! 854: ! 855: #ifdef STREAMS ! 856: case LM_STRMOD: ! 857: { ! 858: struct lkm_strmod *args = lkmtp->private.lkm_strmod; ! 859: } ! 860: break; ! 861: ! 862: #endif /* STREAMS*/ ! 863: ! 864: #ifdef LKM_EXEC ! 865: case LM_EXEC: ! 866: err = _lkm_exec( lkmtp, cmd); ! 867: break; ! 868: #endif /* LKM_EXEC */ ! 869: ! 870: case LM_MISC: /* ignore content -- no "misc-specific" procedure*/ ! 871: break; ! 872: ! 873: default: ! 874: err = ENXIO; /* unknown type*/ ! 875: break; ! 876: } ! 877: ! 878: return( err); ! 879: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.