--- //depot/vendor/freebsd/src/sys/compat/ndis/subr_ndis.c 2005/12/16 17:30:18 +++ //depot/projects/smpng/sys/compat/ndis/subr_ndis.c 2006/05/24 21:37:19 @@ -2886,6 +2886,32 @@ return(0); } +struct ndis_checkmodule { + char *afilename; + ndis_fh *fh; +}; + +/* + * See if a single module contains the symbols for a specified file. + */ +static int +NdisCheckModule(linker_file_t lf, void *context) +{ + struct ndis_checkmodule *nc; + caddr_t kldstart, kldend; + + nc = (struct ndis_checkmodule *)context; + if (ndis_find_sym(lf, nc->afilename, "_start", &kldstart)) + return (0); + if (ndis_find_sym(lf, nc->afilename, "_end", &kldend)) + return (0); + nc->fh->nf_vp = lf; + nc->fh->nf_map = NULL; + nc->fh->nf_type = NDIS_FH_TYPE_MODULE; + nc->fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; + return (1); +} + /* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ static void NdisOpenFile(status, filehandle, filelength, filename, highestaddr) @@ -2899,13 +2925,12 @@ char *afilename = NULL; struct thread *td = curthread; struct nameidata nd; - int flags, error; + int flags, error, vfslocked; struct vattr vat; struct vattr *vap = &vat; ndis_fh *fh; char *path; - linker_file_t head, lf; - caddr_t kldstart, kldend; + struct ndis_checkmodule nc; if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) { *status = NDIS_STATUS_RESOURCES; @@ -2943,23 +2968,10 @@ * us since the kernel appears to us as just another module. */ - /* - * This is an evil trick for getting the head of the linked - * file list, which is not exported from kern_linker.o. It - * happens that linker file #1 is always the kernel, and is - * always the first element in the list. - */ - - head = linker_find_file_by_id(1); - for (lf = head; lf != NULL; lf = TAILQ_NEXT(lf, link)) { - if (ndis_find_sym(lf, afilename, "_start", &kldstart)) - continue; - if (ndis_find_sym(lf, afilename, "_end", &kldend)) - continue; - fh->nf_vp = lf; - fh->nf_map = NULL; - fh->nf_type = NDIS_FH_TYPE_MODULE; - *filelength = fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; + nc.afilename = afilename; + nc.fh = fh; + if (linker_file_foreach(NdisCheckModule, &nc)) { + *filelength = fh->nf_maplen; *filehandle = fh; *status = NDIS_STATUS_SUCCESS; return; @@ -2986,21 +2998,19 @@ snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename); - mtx_lock(&Giant); - /* Some threads don't have a current working directory. */ + /* XXX: locking? Which threads don't have these, kthreads maybe? */ if (td->td_proc->p_fd->fd_rdir == NULL) td->td_proc->p_fd->fd_rdir = rootvnode; if (td->td_proc->p_fd->fd_cdir == NULL) td->td_proc->p_fd->fd_cdir = rootvnode; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td); + NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, path, td); flags = FREAD; error = vn_open(&nd, &flags, 0, -1); if (error) { - mtx_unlock(&Giant); *status = NDIS_STATUS_FILE_NOT_FOUND; ExFreePool(fh); printf("NDIS: open file %s failed: %d\n", path, error); @@ -3008,6 +3018,7 @@ free(afilename, M_DEVBUF); return; } + vfslocked = NDHASGIANT(&nd); ExFreePool(path); @@ -3016,7 +3027,7 @@ /* Get the file size. */ VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); VOP_UNLOCK(nd.ni_vp, 0, td); - mtx_unlock(&Giant); + VFS_UNLOCK_GIANT(vfslocked); fh->nf_vp = nd.ni_vp; fh->nf_map = NULL; @@ -3038,7 +3049,8 @@ struct thread *td = curthread; linker_file_t lf; caddr_t kldstart; - int error, resid; + int error, resid, vfslocked; + struct vnode *vp; if (filehandle == NULL) { *status = NDIS_STATUS_FAILURE; @@ -3076,10 +3088,11 @@ return; } - mtx_lock(&Giant); - error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0, + vp = fh->nf_vp; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + error = vn_rdwr(UIO_READ, vp, fh->nf_map, fh->nf_maplen, 0, UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td); - mtx_unlock(&Giant); + VFS_UNLOCK_GIANT(vfslocked); if (error) *status = NDIS_STATUS_FAILURE; @@ -3114,6 +3127,8 @@ { struct thread *td = curthread; ndis_fh *fh; + int vfslocked; + struct vnode *vp; if (filehandle == NULL) return; @@ -3129,9 +3144,10 @@ return; if (fh->nf_type == NDIS_FH_TYPE_VFS) { - mtx_lock(&Giant); - vn_close(fh->nf_vp, FREAD, td->td_ucred, td); - mtx_unlock(&Giant); + vp = fh->nf_vp; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + vn_close(vp, FREAD, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); } fh->nf_vp = NULL; --- //depot/vendor/freebsd/src/sys/compat/ndis/winx32_wrap.S 2005/11/02 18:05:29 +++ //depot/projects/smpng/sys/compat/ndis/winx32_wrap.S 2006/05/24 21:37:19 @@ -32,6 +32,11 @@ * $FreeBSD: src/sys/compat/ndis/winx32_wrap.S,v 1.4 2005/11/02 18:01:04 wpaul Exp $ */ +/* The 'ret' macro doesn't work in this file if GPROF is enabled. */ +#ifdef GPROF +#undef GPROF +#endif + #include /* --- //depot/vendor/freebsd/src/sys/kern/kern_linker.c 2006/03/26 12:22:43 +++ //depot/projects/smpng/sys/kern/kern_linker.c 2006/05/24 21:36:09 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -60,12 +61,27 @@ int kld_debug = 0; #endif +#define KLD_LOCK() do { sx_xlock(&kld_sx); mtx_lock(&Giant); } while (0) +#define KLD_UNLOCK() do { mtx_unlock(&Giant); sx_xunlock(&kld_sx); } while (0) +#define KLD_LOCKED() sx_xlocked(&kld_sx) +#define KLD_LOCK_ASSERT() do { if (!cold) sx_assert(&kld_sx, SX_XLOCKED); } while (0) + /* * static char *linker_search_path(const char *name, struct mod_depend * *verinfo); */ static const char *linker_basename(const char *path); +/* + * Find a currently loaded file given its filename. + */ +static linker_file_t linker_find_file_by_name(const char* _filename); + +/* + * Find a currently loaded file given its file id. + */ +static linker_file_t linker_find_file_by_id(int _fileid); + /* Metadata from the static kernel */ SET_DECLARE(modmetadata_set, struct mod_metadata); @@ -73,7 +89,7 @@ linker_file_t linker_kernel_file; -static struct mtx kld_mtx; /* kernel linker mutex */ +static struct sx kld_sx; /* kernel linker lock */ static linker_class_list_t classes; static linker_file_list_t linker_files; @@ -83,17 +99,15 @@ #define LINKER_GET_NEXT_FILE_ID(a) do { \ linker_file_t lftmp; \ \ + KLD_LOCK_ASSERT(); \ retry: \ - mtx_lock(&kld_mtx); \ TAILQ_FOREACH(lftmp, &linker_files, link) { \ if (next_file_id == lftmp->id) { \ next_file_id++; \ - mtx_unlock(&kld_mtx); \ goto retry; \ } \ } \ (a) = next_file_id; \ - mtx_unlock(&kld_mtx); /* Hold for safe read of id variable */ \ } while(0) @@ -108,8 +122,17 @@ typedef struct modlist *modlist_t; static modlisthead_t found_modules; -static modlist_t modlist_lookup2(const char *name, - struct mod_depend *verinfo); +static int linker_file_add_dependency(linker_file_t file, + linker_file_t dep); +static caddr_t linker_file_lookup_symbol_internal(linker_file_t file, + const char* name, int deps); +static int linker_file_unload_internal(linker_file_t _file, int flags); +static int linker_load_module_internal(const char *kldname, + const char *modname, struct linker_file *parent, + struct mod_depend *verinfo, struct linker_file **lfpp); +static int linker_lookup_set(linker_file_t file, const char *name, + void *firstp, void *lastp, int *countp); +static modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); static char * linker_strdup(const char *str) @@ -125,7 +148,7 @@ linker_init(void *arg) { - mtx_init(&kld_mtx, "kernel linker", NULL, MTX_DEF); + sx_init(&kld_sx, "kernel linker"); TAILQ_INIT(&classes); TAILQ_INIT(&linker_files); } @@ -166,7 +189,7 @@ KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", lf->filename)); - if (linker_file_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) + if (linker_lookup_set(lf, "sysinit_set", &start, &stop, NULL) != 0) return; /* * Perform a bubble sort of the system initialization objects by @@ -208,8 +231,7 @@ KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n", lf->filename)); - if (linker_file_lookup_set(lf, "sysuninit_set", &start, &stop, - NULL) != 0) + if (linker_lookup_set(lf, "sysuninit_set", &start, &stop, NULL) != 0) return; /* @@ -253,7 +275,7 @@ ("linker_file_register_sysctls: registering SYSCTLs for %s\n", lf->filename)); - if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) + if (linker_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) return; for (oidp = start; oidp < stop; oidp++) @@ -268,7 +290,7 @@ KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" " for %s\n", lf->filename)); - if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) + if (linker_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0) return; for (oidp = start; oidp < stop; oidp++) @@ -285,8 +307,8 @@ KLD_DPF(FILE, ("linker_file_register_modules: registering modules" " in %s\n", lf->filename)); - if (linker_file_lookup_set(lf, "modmetadata_set", &start, - &stop, 0) != 0) { + if (linker_lookup_set(lf, "modmetadata_set", &start, &stop, + NULL) != 0) { /* * This fallback should be unnecessary, but if we get booted * from boot2 instead of loader and we are missing our @@ -330,22 +352,23 @@ { linker_class_t lc; linker_file_t lf; - int foundfile, error = 0; + int foundfile, error; /* Refuse to load modules if securelevel raised */ if (securelevel > 0) return (EPERM); + KLD_LOCK_ASSERT(); lf = linker_find_file_by_name(filename); if (lf) { KLD_DPF(FILE, ("linker_load_file: file %s is already loaded," " incrementing refs\n", filename)); *result = lf; lf->refs++; - goto out; + return (0); } - lf = NULL; foundfile = 0; + error = ENOENT; /* * We do not need to protect (lock) classes here because there is @@ -365,15 +388,15 @@ if (lf) { error = linker_file_register_modules(lf); if (error == EEXIST) { - linker_file_unload(lf, LINKER_UNLOAD_FORCE); - goto out; + linker_file_unload_internal(lf, + LINKER_UNLOAD_FORCE); + return (error); } linker_file_register_sysctls(lf); linker_file_sysinit(lf); lf->flags |= LINKER_FILE_LINKED; *result = lf; - error = 0; - goto out; + return (0); } } /* @@ -393,7 +416,6 @@ error = ENOEXEC; } else error = ENOENT; /* Nothing found */ -out: return (error); } @@ -402,67 +424,87 @@ linker_file_t *result) { modlist_t mod; + int error, locked; + locked = KLD_LOCKED(); + if (!locked) + KLD_LOCK(); if ((mod = modlist_lookup2(modname, verinfo)) != NULL) { *result = mod->container; (*result)->refs++; + if (!locked) + KLD_UNLOCK(); return (0); } - return (linker_load_module(NULL, modname, NULL, verinfo, result)); + error = linker_load_module_internal(NULL, modname, NULL, verinfo, + result); + if (!locked) + KLD_UNLOCK(); + return (error); } -linker_file_t +static linker_file_t linker_find_file_by_name(const char *filename) { - linker_file_t lf = 0; + linker_file_t lf; char *koname; koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); - if (koname == NULL) - goto out; sprintf(koname, "%s.ko", filename); - mtx_lock(&kld_mtx); + KLD_LOCK_ASSERT(); TAILQ_FOREACH(lf, &linker_files, link) { if (strcmp(lf->filename, koname) == 0) break; if (strcmp(lf->filename, filename) == 0) break; } - mtx_unlock(&kld_mtx); -out: - if (koname) - free(koname, M_LINKER); + free(koname, M_LINKER); return (lf); } -linker_file_t +static linker_file_t linker_find_file_by_id(int fileid) { - linker_file_t lf = 0; - - mtx_lock(&kld_mtx); + linker_file_t lf; + + KLD_LOCK_ASSERT(); TAILQ_FOREACH(lf, &linker_files, link) if (lf->id == fileid) break; - mtx_unlock(&kld_mtx); return (lf); } +int +linker_file_foreach(linker_predicate_t *predicate, void *context) +{ + linker_file_t lf; + int retval = 0; + + KLD_LOCK(); + TAILQ_FOREACH(lf, &linker_files, link) { + retval = predicate(lf, context); + if (retval != 0) + break; + } + KLD_UNLOCK(); + return (retval); +} + linker_file_t linker_make_file(const char *pathname, linker_class_t lc) { linker_file_t lf; const char *filename; - lf = NULL; + KLD_LOCK_ASSERT(); filename = linker_basename(pathname); KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); if (lf == NULL) - goto out; + return (NULL); lf->refs = 1; lf->userrefs = 0; lf->flags = 0; @@ -472,23 +514,32 @@ lf->deps = NULL; STAILQ_INIT(&lf->common); TAILQ_INIT(&lf->modules); - mtx_lock(&kld_mtx); TAILQ_INSERT_TAIL(&linker_files, lf, link); - mtx_unlock(&kld_mtx); -out: return (lf); } int linker_file_unload(linker_file_t file, int flags) { + int error, locked; + + locked = KLD_LOCKED(); + if (!locked) + KLD_LOCK(); + error = linker_file_unload_internal(file, flags); + if (!locked) + KLD_UNLOCK(); + return (error); +} + +static int +linker_file_unload_internal(linker_file_t file, int flags) +{ module_t mod, next; modlist_t ml, nextml; struct common_symbol *cp; int error, i; - error = 0; - /* Refuse to unload modules if securelevel raised. */ if (securelevel > 0) return (EPERM); @@ -498,6 +549,7 @@ return (error); #endif + KLD_LOCK_ASSERT(); KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); if (file->refs == 1) { KLD_DPF(FILE, ("linker_file_unload: file is unloading," @@ -517,7 +569,7 @@ if ((error = module_unload(mod, flags)) != 0) { KLD_DPF(FILE, ("linker_file_unload: module %p" " vetoes unload\n", mod)); - goto out; + return (error); } else MOD_XLOCK; module_release(mod); @@ -525,9 +577,8 @@ MOD_XUNLOCK; } file->refs--; - if (file->refs > 0) { - goto out; - } + if (file->refs > 0) + return (0); for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) { nextml = TAILQ_NEXT(ml, link); if (ml->container == file) { @@ -544,13 +595,11 @@ linker_file_sysuninit(file); linker_file_unregister_sysctls(file); } - mtx_lock(&kld_mtx); TAILQ_REMOVE(&linker_files, file, link); - mtx_unlock(&kld_mtx); if (file->deps) { for (i = 0; i < file->ndeps; i++) - linker_file_unload(file->deps[i], flags); + linker_file_unload_internal(file->deps[i], flags); free(file->deps, M_LINKER); file->deps = NULL; } @@ -566,15 +615,15 @@ file->filename = NULL; } kobj_delete((kobj_t) file, M_LINKER); -out: - return (error); + return (0); } -int +static int linker_file_add_dependency(linker_file_t file, linker_file_t dep) { linker_file_t *newdeps; + KLD_LOCK_ASSERT(); newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t *), M_LINKER, M_WAITOK | M_ZERO); if (newdeps == NULL) @@ -593,25 +642,60 @@ /* * Locate a linker set and its contents. This is a helper function to avoid - * linker_if.h exposure elsewhere. Note: firstp and lastp are really void *** + * linker_if.h exposure elsewhere. Note: firstp and lastp are really void **. + * The first function is an internal wrapper so we can avoid having lots of + * (void **) casts. */ +static int +linker_lookup_set(linker_file_t file, const char *name, + void *firstp, void *lastp, int *countp) +{ + + KLD_LOCK_ASSERT(); + return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); +} + int linker_file_lookup_set(linker_file_t file, const char *name, void *firstp, void *lastp, int *countp) { + int error, locked; - return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); + locked = KLD_LOCKED(); + if (!locked) + KLD_LOCK(); + error = linker_lookup_set(file, name, firstp, lastp, countp); + if (!locked) + KLD_UNLOCK(); + return (error); } caddr_t linker_file_lookup_symbol(linker_file_t file, const char *name, int deps) { + caddr_t sym; + int locked; + + locked = KLD_LOCKED(); + if (!locked) + KLD_LOCK(); + sym = linker_file_lookup_symbol_internal(file, name, deps); + if (!locked) + KLD_UNLOCK(); + return (sym); +} + +static caddr_t +linker_file_lookup_symbol_internal(linker_file_t file, const char *name, + int deps) +{ c_linker_sym_t sym; linker_symval_t symval; caddr_t address; size_t common_size = 0; int i; + KLD_LOCK_ASSERT(); KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%p, name=%s, deps=%d\n", file, name, deps)); @@ -632,8 +716,8 @@ } if (deps) { for (i = 0; i < file->ndeps; i++) { - address = linker_file_lookup_symbol(file->deps[i], - name, 0); + address = linker_file_lookup_symbol_internal( + file->deps[i], name, 0); if (address) { KLD_DPF(SYM, ("linker_file_lookup_symbol:" " deps value=%p\n", address)); @@ -663,10 +747,6 @@ cp = malloc(sizeof(struct common_symbol) + common_size + strlen(name) + 1, M_LINKER, M_WAITOK | M_ZERO); - if (cp == NULL) { - KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n")); - return (0); - } cp->address = (caddr_t)(cp + 1); cp->name = cp->address + common_size; strcpy(cp->name, name); @@ -688,7 +768,7 @@ * * Note that we do not obey list locking protocols here. We really don't need * DDB to hang because somebody's got the lock held. We'll take the chance - * that the files list is inconsistant instead. + * that the files list is inconsistent instead. */ int @@ -766,13 +846,11 @@ td->td_retval[0] = -1; - mtx_lock(&Giant); - if ((error = securelevel_gt(td->td_ucred, 0)) != 0) - goto out; + return (error); if ((error = suser(td)) != 0) - goto out; + return (error); pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyinstr(uap->file, pathname, MAXPATHLEN, NULL)) != 0) @@ -790,10 +868,11 @@ kldname = NULL; modname = pathname; } - error = linker_load_module(kldname, modname, NULL, NULL, &lf); + + KLD_LOCK(); + error = linker_load_module_internal(kldname, modname, NULL, NULL, &lf); if (error) - goto out; - + goto unlock; #ifdef HWPMC_HOOKS pkm.pm_file = lf->filename; pkm.pm_address = (uintptr_t) lf->address; @@ -801,10 +880,10 @@ #endif lf->userrefs++; td->td_retval[0] = lf->id; +unlock: + KLD_UNLOCK(); out: - if (pathname) - free(pathname, M_TEMP); - mtx_unlock(&Giant); + free(pathname, M_TEMP); return (error); } @@ -820,14 +899,13 @@ linker_file_t lf; int error = 0; - mtx_lock(&Giant); - if ((error = securelevel_gt(td->td_ucred, 0)) != 0) - goto out; + return (error); if ((error = suser(td)) != 0) - goto out; + return (error); + KLD_LOCK(); lf = linker_find_file_by_id(fileid); if (lf) { KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); @@ -838,17 +916,17 @@ printf("kldunload: attempt to unload file that was" " loaded by the kernel\n"); error = EBUSY; - goto out; - } - lf->userrefs--; + } else { #ifdef HWPMC_HOOKS - /* Save data needed by hwpmc(4) before unloading the kld. */ - pkm.pm_address = (uintptr_t) lf->address; - pkm.pm_size = lf->size; + /* Save data needed by hwpmc(4) before unloading. */ + pkm.pm_address = (uintptr_t) lf->address; + pkm.pm_size = lf->size; #endif - error = linker_file_unload(lf, flags); - if (error) - lf->userrefs++; + lf->userrefs--; + error = linker_file_unload_internal(lf, flags); + if (error) + lf->userrefs++; + } } else error = ENOENT; @@ -856,8 +934,7 @@ if (error == 0) PMC_CALL_HOOK(td, PMC_FN_KLD_UNLOAD, (void *) &pkm); #endif -out: - mtx_unlock(&Giant); + KLD_UNLOCK(); return (error); } @@ -901,7 +978,6 @@ return (error); #endif - mtx_lock(&Giant); td->td_retval[0] = -1; pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); @@ -909,15 +985,15 @@ goto out; filename = linker_basename(pathname); + KLD_LOCK(); lf = linker_find_file_by_name(filename); if (lf) td->td_retval[0] = lf->id; else error = ENOENT; + KLD_UNLOCK(); out: - if (pathname) - free(pathname, M_TEMP); - mtx_unlock(&Giant); + free(pathname, M_TEMP); return (error); } @@ -936,15 +1012,12 @@ return (error); #endif - mtx_lock(&Giant); - + KLD_LOCK(); if (uap->fileid == 0) { - mtx_lock(&kld_mtx); if (TAILQ_FIRST(&linker_files)) td->td_retval[0] = TAILQ_FIRST(&linker_files)->id; else td->td_retval[0] = 0; - mtx_unlock(&kld_mtx); goto out; } lf = linker_find_file_by_id(uap->fileid); @@ -956,7 +1029,7 @@ } else error = ENOENT; out: - mtx_unlock(&Giant); + KLD_UNLOCK(); return (error); } @@ -966,10 +1039,18 @@ int kldstat(struct thread *td, struct kldstat_args *uap) { + struct kld_file_stat stat; linker_file_t lf; - int error = 0; - int namelen, version; - struct kld_file_stat *stat; + int error, namelen; + + /* + * Check the version of the user's structure. + */ + error = copyin(uap->stat, &stat, sizeof(struct kld_file_stat)); + if (error) + return (error); + if (stat.version != sizeof(struct kld_file_stat)) + return (EINVAL); #ifdef MAC error = mac_check_kld_stat(td->td_ucred); @@ -977,43 +1058,26 @@ return (error); #endif - mtx_lock(&Giant); - + KLD_LOCK(); lf = linker_find_file_by_id(uap->fileid); if (lf == NULL) { - error = ENOENT; - goto out; + KLD_UNLOCK(); + return (ENOENT); } - stat = uap->stat; - /* - * Check the version of the user's structure. - */ - if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) - goto out; - if (version != sizeof(struct kld_file_stat)) { - error = EINVAL; - goto out; - } namelen = strlen(lf->filename) + 1; if (namelen > MAXPATHLEN) namelen = MAXPATHLEN; - if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0) - goto out; - if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0) - goto out; - if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0) - goto out; - if ((error = copyout(&lf->address, &stat->address, - sizeof(caddr_t))) != 0) - goto out; - if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0) - goto out; + bcopy(lf->filename, &stat.name[0], namelen); + stat.refs = lf->refs; + stat.id = lf->id; + stat.address = lf->address; + stat.size = lf->size; + KLD_UNLOCK(); td->td_retval[0] = 0; -out: - mtx_unlock(&Giant); - return (error); + + return (copyout(&stat, uap->stat, sizeof(struct kld_file_stat))); } /* @@ -1032,7 +1096,7 @@ return (error); #endif - mtx_lock(&Giant); + KLD_LOCK(); lf = linker_find_file_by_id(uap->fileid); if (lf) { MOD_SLOCK; @@ -1044,7 +1108,7 @@ MOD_SUNLOCK; } else error = ENOENT; - mtx_unlock(&Giant); + KLD_UNLOCK(); return (error); } @@ -1067,25 +1131,20 @@ return (error); #endif - mtx_lock(&Giant); - if ((error = copyin(uap->data, &lookup, sizeof(lookup))) != 0) - goto out; + return (error); if (lookup.version != sizeof(lookup) || - uap->cmd != KLDSYM_LOOKUP) { - error = EINVAL; - goto out; - } + uap->cmd != KLDSYM_LOOKUP) + return (EINVAL); symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) goto out; + KLD_LOCK(); if (uap->fileid != 0) { lf = linker_find_file_by_id(uap->fileid); - if (lf == NULL) { + if (lf == NULL) error = ENOENT; - goto out; - } - if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && + else if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { lookup.symvalue = (uintptr_t) symval.value; lookup.symsize = symval.size; @@ -1093,7 +1152,6 @@ } else error = ENOENT; } else { - mtx_lock(&kld_mtx); TAILQ_FOREACH(lf, &linker_files, link) { if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { @@ -1104,14 +1162,12 @@ break; } } - mtx_unlock(&kld_mtx); if (lf == NULL) error = ENOENT; } + KLD_UNLOCK(); out: - if (symstr) - free(symstr, M_TEMP); - mtx_unlock(&Giant); + free(symstr, M_TEMP); return (error); } @@ -1249,7 +1305,7 @@ /* * First get a list of stuff in the kernel. */ - if (linker_file_lookup_set(linker_kernel_file, MDT_SETNAME, &start, + if (linker_lookup_set(linker_kernel_file, MDT_SETNAME, &start, &stop, NULL) == 0) linker_addmodules(linker_kernel_file, start, stop, 1); @@ -1259,8 +1315,7 @@ */ restart: TAILQ_FOREACH(lf, &loaded_files, loaded) { - error = linker_file_lookup_set(lf, MDT_SETNAME, &start, - &stop, NULL); + error = linker_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); /* * First, look to see if we would successfully link with this * stuff. @@ -1310,7 +1365,7 @@ nver) != NULL) { printf("module %s already" " present!\n", modname); - linker_file_unload(lf, + linker_file_unload_internal(lf, LINKER_UNLOAD_FORCE); TAILQ_REMOVE(&loaded_files, lf, loaded); @@ -1337,7 +1392,7 @@ */ TAILQ_FOREACH(lf, &loaded_files, loaded) { printf("KLD file %s is missing dependencies\n", lf->filename); - linker_file_unload(lf, LINKER_UNLOAD_FORCE); + linker_file_unload_internal(lf, LINKER_UNLOAD_FORCE); TAILQ_REMOVE(&loaded_files, lf, loaded); } @@ -1353,8 +1408,7 @@ panic("cannot add dependency"); } lf->userrefs++; /* so we can (try to) kldunload it */ - error = linker_file_lookup_set(lf, MDT_SETNAME, &start, - &stop, NULL); + error = linker_lookup_set(lf, MDT_SETNAME, &start, &stop, NULL); if (!error) { for (mdp = start; mdp < stop; mdp++) { mp = *mdp; @@ -1381,11 +1435,11 @@ if (error) { printf("KLD file %s - could not finalize loading\n", lf->filename); - linker_file_unload(lf, LINKER_UNLOAD_FORCE); + linker_file_unload_internal(lf, LINKER_UNLOAD_FORCE); continue; } linker_file_register_modules(lf); - if (linker_file_lookup_set(lf, "sysinit_set", &si_start, + if (linker_lookup_set(lf, "sysinit_set", &si_start, &si_stop, NULL) == 0) sysinit_add(si_start, si_stop); linker_file_register_sysctls(lf); @@ -1437,7 +1491,7 @@ struct nameidata nd; struct thread *td = curthread; /* XXX */ char *result, **cpp, *sep; - int error, len, extlen, reclen, flags; + int error, len, extlen, reclen, flags, vfslocked; enum vtype type; extlen = 0; @@ -1458,16 +1512,18 @@ * Attempt to open the file, and return the path if * we succeed and it's a regular file. */ - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td); + NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, result, td); flags = FREAD; error = vn_open(&nd, &flags, 0, -1); if (error == 0) { + vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); type = nd.ni_vp->v_type; if (vap) VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); VOP_UNLOCK(nd.ni_vp, 0, td); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); if (type == VREG) return (result); } @@ -1495,6 +1551,7 @@ u_char *hints = NULL; u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; int error, ival, bestver, *intp, reclen, found, flags, clen, blen; + int vfslocked = 0; result = NULL; bestver = found = 0; @@ -1506,11 +1563,12 @@ snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, linker_hintfile); - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td); + NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, pathbuf, td); flags = FREAD; error = vn_open(&nd, &flags, 0, -1); if (error) goto bad; + vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); if (nd.ni_vp->v_type != VREG) goto bad; @@ -1534,6 +1592,7 @@ goto bad; VOP_UNLOCK(nd.ni_vp, 0, td); vn_close(nd.ni_vp, FREAD, cred, td); + VFS_UNLOCK_GIANT(vfslocked); nd.ni_vp = NULL; if (reclen != 0) { printf("can't read %d\n", reclen); @@ -1602,6 +1661,7 @@ if (nd.ni_vp != NULL) { VOP_UNLOCK(nd.ni_vp, 0, td); vn_close(nd.ni_vp, FREAD, cred, td); + VFS_UNLOCK_GIANT(vfslocked); } /* * If nothing found or hints is absent - fallback to the old @@ -1687,53 +1747,61 @@ #ifdef HWPMC_HOOKS +struct hwpmc_context { + int nobjects; + int nmappings; + struct pmckern_map_in *kobase; +}; + +static int +linker_hwpmc_list_object(linker_file_t lf, void *arg) +{ + struct hwpmc_context *hc; + + hc = arg; + + /* If we run out of mappings, fail. */ + if (hc->nobjects >= hc->nmappings) + return (1); + + /* Save the info for this linker file. */ + hc->kobase[hc->nobjects].pm_file = lf->filename; + hc->kobase[hc->nobjects].pm_address = (uintptr_t)lf->address; + hc->nobjects++; + return (0); +} + /* * Inform hwpmc about the set of kernel modules currently loaded. */ void * linker_hwpmc_list_objects(void) { - int nobjects, nmappings; - linker_file_t lf; - struct pmckern_map_in *ko, *kobase; + struct hwpmc_context hc; - nmappings = 15; /* a reasonable default */ + hc.nmappings = 15; /* a reasonable default */ retry: /* allocate nmappings+1 entries */ - MALLOC(kobase, struct pmckern_map_in *, - (nmappings + 1) * sizeof(struct pmckern_map_in), M_LINKER, + MALLOC(hc.kobase, struct pmckern_map_in *, + (hc.nmappings + 1) * sizeof(struct pmckern_map_in), M_LINKER, M_WAITOK | M_ZERO); - nobjects = 0; - mtx_lock(&kld_mtx); - TAILQ_FOREACH(lf, &linker_files, link) - nobjects++; - - KASSERT(nobjects > 0, ("linker_hpwmc_list_objects: no kernel " - "objects?")); - - if (nobjects > nmappings) { - nmappings = nobjects; - FREE(kobase, M_LINKER); - mtx_unlock(&kld_mtx); + hc.nobjects = 0; + if (linker_file_foreach(linker_hwpmc_list_object, &hc) != 0) { + hc.nmappings = hc.nobjects; + FREE(hc.kobase, M_LINKER); goto retry; } - ko = kobase; - TAILQ_FOREACH(lf, &linker_files, link) { - ko->pm_file = lf->filename; - ko->pm_address = (uintptr_t) lf->address; - ko++; - } + KASSERT(hc.nobjects > 0, ("linker_hpwmc_list_objects: no kernel " + "objects?")); /* The last entry of the malloced area comprises of all zeros. */ - KASSERT(ko->pm_file == NULL, + KASSERT(hc.kobase[hc.nobjects].pm_file == NULL, ("linker_hwpmc_list_objects: last object not NULL")); - mtx_unlock(&kld_mtx); - - return ((void *) kobase); + return ((void *)hc.kobase); } #endif @@ -1746,11 +1814,29 @@ struct linker_file *parent, struct mod_depend *verinfo, struct linker_file **lfpp) { + int error, locked; + + locked = KLD_LOCKED(); + if (!locked) + KLD_LOCK(); + error = linker_load_module_internal(kldname, modname, parent, + verinfo, lfpp); + if (!locked) + KLD_UNLOCK(); + return (error); +} + +static int +linker_load_module_internal(const char *kldname, const char *modname, + struct linker_file *parent, struct mod_depend *verinfo, + struct linker_file **lfpp) +{ linker_file_t lfdep; const char *filename; char *pathname; int error; + KLD_LOCK_ASSERT(); if (modname == NULL) { /* * We have to load KLD @@ -1782,17 +1868,15 @@ * provide different versions of the same modules. */ filename = linker_basename(pathname); - if (linker_find_file_by_name(filename)) { + if (linker_find_file_by_name(filename)) error = EEXIST; - goto out; - } - do { + else do { error = linker_load_file(pathname, &lfdep); if (error) break; if (modname && verinfo && modlist_lookup2(modname, verinfo) == NULL) { - linker_file_unload(lfdep, LINKER_UNLOAD_FORCE); + linker_file_unload_internal(lfdep, LINKER_UNLOAD_FORCE); error = ENOENT; break; } @@ -1804,9 +1888,7 @@ if (lfpp) *lfpp = lfdep; } while (0); -out: - if (pathname) - free(pathname, M_LINKER); + free(pathname, M_LINKER); return (error); } @@ -1826,16 +1908,16 @@ int ver, error = 0, count; /* - * All files are dependant on /kernel. + * All files are dependent on /kernel. */ + KLD_LOCK_ASSERT(); if (linker_kernel_file) { linker_kernel_file->refs++; error = linker_file_add_dependency(lf, linker_kernel_file); if (error) return (error); } - if (linker_file_lookup_set(lf, MDT_SETNAME, &start, &stop, - &count) != 0) + if (linker_lookup_set(lf, MDT_SETNAME, &start, &stop, &count) != 0) return (0); for (mdp = start; mdp < stop; mdp++) { mp = *mdp; @@ -1878,7 +1960,8 @@ break; continue; } - error = linker_load_module(NULL, modname, lf, verinfo, NULL); + error = linker_load_module_internal(NULL, modname, lf, verinfo, + NULL); if (error) { printf("KLD %s: depends on %s - not available\n", lf->filename, modname); @@ -1919,16 +2002,16 @@ error = sysctl_wire_old_buffer(req, 0); if (error != 0) return (error); - mtx_lock(&kld_mtx); + KLD_LOCK(); TAILQ_FOREACH(lf, &linker_files, link) { error = LINKER_EACH_FUNCTION_NAME(lf, sysctl_kern_function_list_iterate, req); if (error) { - mtx_unlock(&kld_mtx); + KLD_UNLOCK(); return (error); } } - mtx_unlock(&kld_mtx); + KLD_UNLOCK(); return (SYSCTL_OUT(req, "", 1)); } --- //depot/vendor/freebsd/src/sys/kern/link_elf.c 2005/12/18 04:55:25 +++ //depot/projects/smpng/sys/kern/link_elf.c 2006/03/30 15:48:58 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -556,17 +557,17 @@ int symstrindex; int symcnt; int strcnt; + int vfslocked; - GIANT_REQUIRED; - shdr = NULL; lf = NULL; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); + NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, filename, td); flags = FREAD; error = vn_open(&nd, &flags, 0, -1); if (error) return error; + vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); #ifdef MAC error = mac_check_kld_load(curthread->td_ucred, nd.ni_vp); @@ -758,8 +759,10 @@ #ifdef GPROF /* Update profiling information with the new text segment. */ + mtx_lock(&Giant); kmupetext((uintfptr_t)(mapbase + segs[0]->p_vaddr - base_vaddr + segs[0]->p_memsz)); + mtx_unlock(&Giant); #endif ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); @@ -859,6 +862,7 @@ free(firstpage, M_LINKER); VOP_UNLOCK(nd.ni_vp, 0, td); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); return error; } --- //depot/vendor/freebsd/src/sys/kern/link_elf_obj.c 2005/12/18 04:55:25 +++ //depot/projects/smpng/sys/kern/link_elf_obj.c 2006/03/30 15:48:58 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -393,19 +394,19 @@ int nsym; int pb, rl, ra; int alignmask; - - GIANT_REQUIRED; + int vfslocked; shdr = NULL; lf = NULL; mapsize = 0; hdr = NULL; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); + NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, filename, td); flags = FREAD; error = vn_open(&nd, &flags, 0, -1); if (error) return error; + vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); #ifdef MAC error = mac_check_kld_load(td->td_ucred, nd.ni_vp); @@ -788,6 +789,7 @@ free(hdr, M_LINKER); VOP_UNLOCK(nd.ni_vp, 0, td); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); return error; } --- //depot/vendor/freebsd/src/sys/sys/linker.h 2006/03/26 12:22:43 +++ //depot/projects/smpng/sys/sys/linker.h 2006/04/25 15:46:50 @@ -95,14 +95,14 @@ }; /* - * The "file" for the kernel. + * Function type used when iterating over the list of linker files. */ -extern linker_file_t linker_kernel_file; +typedef int linker_predicate_t(linker_file_t, void *); /* - * Add a new file class to the linker. + * The "file" for the kernel. */ -int linker_add_class(linker_class_t _cls); +extern linker_file_t linker_kernel_file; /* * Load a kernel module. @@ -118,29 +118,16 @@ linker_file_t* _result); /* - * Find a currently loaded file given its filename. - */ -linker_file_t linker_find_file_by_name(const char* _filename); - -/* - * Find a currently loaded file given its file id. - */ -linker_file_t linker_find_file_by_id(int _fileid); - -/* - * Called from a class handler when a file is laoded. - */ -linker_file_t linker_make_file(const char* _filename, linker_class_t _cls); - -/* * Unload a file, freeing up memory. */ int linker_file_unload(linker_file_t _file, int flags); /* - * Add a dependency to a file. + * Iterate over all of the currently loaded linker files calling the + * predicate function while the function returns 0. Returns the value + * returned by the last predicate function. */ -int linker_file_add_dependency(linker_file_t _file, linker_file_t _dep); +int linker_file_foreach(linker_predicate_t *_predicate, void *_context); /* * Lookup a symbol in a file. If deps is TRUE, look in dependencies @@ -158,10 +145,11 @@ void *_start, void *_stop, int *_count); /* - * This routine is responsible for finding dependencies of userland - * initiated kldload(2)'s of files. + * Functions soley for use by the linker class handlers. */ +int linker_add_class(linker_class_t _cls); int linker_load_dependencies(linker_file_t _lf); +linker_file_t linker_make_file(const char* _filename, linker_class_t _cls); /* * DDB Helpers, tuned specifically for ddb/db_kld.c --- //depot/vendor/freebsd/src/sys/sys/sx.h 2006/03/30 15:51:16 +++ //depot/projects/smpng/sys/sys/sx.h 2006/04/14 18:23:32 @@ -76,6 +76,7 @@ SYSUNINIT(name##_sx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE, \ sx_destroy, (sxa)) +#define sx_xlocked(sx) ((sx)->sx_cnt < 0 && (sx)->sx_xholder == curthread) #define sx_slock(sx) _sx_slock((sx), LOCK_FILE, LOCK_LINE) #define sx_xlock(sx) _sx_xlock((sx), LOCK_FILE, LOCK_LINE) #define sx_try_slock(sx) _sx_try_slock((sx), LOCK_FILE, LOCK_LINE) @@ -85,7 +86,7 @@ #define sx_try_upgrade(sx) _sx_try_upgrade((sx), LOCK_FILE, LOCK_LINE) #define sx_downgrade(sx) _sx_downgrade((sx), LOCK_FILE, LOCK_LINE) #define sx_unlock(sx) do { \ - if ((sx)->sx_cnt < 0) \ + if (sx_xlocked(sx)) \ sx_xunlock(sx); \ else \ sx_sunlock(sx); \