diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2015-08-03 10:02:16 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2015-08-03 10:02:16 -0700 |
commit | 34f4c891167075210bba38ea063c771347ca55f6 (patch) | |
tree | cee1d74b36498030cd185c4d52505a4fdc54c136 | |
parent | 93549f66b29cbbc5d88de96ca74e8623d5251899 (diff) |
355.06355.06
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | backup.c | 30 | ||||
-rw-r--r-- | command-list.c | 65 | ||||
-rw-r--r-- | common-utils/nvgetopt.c | 35 | ||||
-rw-r--r-- | conflicting-kernel-modules.c | 38 | ||||
-rw-r--r-- | conflicting-kernel-modules.h | 26 | ||||
-rw-r--r-- | dist-files.mk | 2 | ||||
-rw-r--r-- | files.c | 283 | ||||
-rw-r--r-- | files.h | 5 | ||||
-rw-r--r-- | install-from-cwd.c | 337 | ||||
-rw-r--r-- | kernel.c | 1156 | ||||
-rw-r--r-- | kernel.h | 19 | ||||
-rw-r--r-- | manifest.c | 124 | ||||
-rw-r--r-- | misc.c | 4 | ||||
-rw-r--r-- | nvidia-installer.c | 28 | ||||
-rw-r--r-- | nvidia-installer.h | 51 | ||||
-rw-r--r-- | option_table.h | 18 | ||||
-rwxr-xr-x | rtld_test_Linux-armv7l-gnueabi | bin | 3892 -> 2808 bytes | |||
-rwxr-xr-x | rtld_test_Linux-armv7l-gnueabihf | bin | 5540 -> 2820 bytes | |||
-rwxr-xr-x | rtld_test_Linux-x86 | bin | 3056 -> 2668 bytes | |||
-rwxr-xr-x | rtld_test_Linux-x86_64 | bin | 4688 -> 3800 bytes | |||
-rw-r--r-- | version.mk | 2 |
22 files changed, 1164 insertions, 1061 deletions
@@ -308,7 +308,7 @@ tls_test: tls_test.c # nvidia-installer to simplify x86-64 builds. rebuild_rtld_test: rtld_test.c $(CONFIG_H) - $(call quiet_cmd,LINK) $(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) -o $(RTLD_TEST) -lGL $< + $(call quiet_cmd,LINK) $(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) -o $(RTLD_TEST) -lGL -lEGL $< $(call quiet_cmd,STRIP_CMD) $(RTLD_TEST) # dummy rule to override implicit rule that builds dls_test from @@ -41,13 +41,12 @@ #include "crc.h" #include "misc.h" #include "kernel.h" +#include "conflicting-kernel-modules.h" #define BACKUP_DIRECTORY "/var/lib/nvidia" #define BACKUP_LOG (BACKUP_DIRECTORY "/log") #define BACKUP_MKDIR_LOG (BACKUP_DIRECTORY "/dirs") -#define RMMOD_MODULE_NAME "nvidia" - @@ -623,18 +622,6 @@ static int rmdir_recursive(Options *op) -/* unload_nvidia_module() - unload nvidia${suffix}.ko, ignoring failures. */ - -static void unload_nvidia_module(Options *op, const char *suffix) -{ - char *name; - name = nvstrcat(RMMOD_MODULE_NAME, suffix, NULL); - rmmod_kernel_module(op, name); - nvfree(name); -} - - - /* * do_uninstall() - this function uninstalls a previously installed * driver, by parsing the BACKUP_LOG file. @@ -840,20 +827,9 @@ static int do_uninstall(Options *op, const char *version) * module might not have existed at all. */ - unload_nvidia_module(op, "-uvm"); - - unload_nvidia_module(op, ""); - - for (i = 0; i < NV_MAX_MODULE_INSTANCES; i++) { - char num[5]; - memset(num, 0, sizeof(num)); - snprintf(num, sizeof(num), "%d", i); - num[sizeof(num) - 1] = '\0'; - - unload_nvidia_module(op, num); + for (i = 0; i < num_conflicting_kernel_modules; i++) { + rmmod_kernel_module(op, conflicting_kernel_modules[i]); } - - unload_nvidia_module(op, "-frontend"); } run_distro_hook(op, "post-uninstall"); diff --git a/command-list.c b/command-list.c index d65440c..7dc5933 100644 --- a/command-list.c +++ b/command-list.c @@ -43,13 +43,12 @@ #include "files.h" #include "kernel.h" #include "manifest.h" +#include "conflicting-kernel-modules.h" static void free_file_list(FileList* l); -static void find_conflicting_kernel_modules(Options *op, - Package *p, - FileList *l); +static void find_conflicting_kernel_modules(Options *op, FileList *l); static void find_existing_files(Package *p, FileList *l, PackageEntryFileTypeList *file_type_list); @@ -207,8 +206,9 @@ CommandList *build_command_list(Options *op, Package *p) /* find any possibly conflicting modules and/or libraries */ - if (!op->no_kernel_module || op->dkms) - find_conflicting_kernel_modules(op, p, l); + if (!op->no_kernel_module || op->dkms) { + find_conflicting_kernel_modules(op, l); + } /* check the conflicting file list for any installed kernel modules */ @@ -377,14 +377,6 @@ CommandList *build_command_list(Options *op, Package *p) } } - /* find any commands we should run */ - - for (i = 0; i < p->num_entries; i++) { - if (p->entries[i].type == FILE_TYPE_KERNEL_MODULE_CMD) { - add_command(c, RUN_CMD, p->entries[i].file, NULL, 0); - } - } - /* * if "--no-abi-note" was requested, scan for any OpenGL * libraries, and run the following command on them: @@ -625,13 +617,13 @@ int execute_command_list(Options *op, CommandList *c, * modules under the kernel module installation prefix. */ -static void find_conflicting_kernel_modules(Options *op, - Package *p, FileList *l) +static void find_conflicting_kernel_modules(Options *op, FileList *l) { - int i = 0, n = 0; - ConflictingFileInfo files[2]; + int i = 0; + ConflictingFileInfo *files; char *paths[3]; char *tmp = get_kernel_name(op); + char **filenames; /* Don't descend into the "build" or "source" directories; these won't * contain modules, and may be symlinks back to an actual source tree. */ @@ -641,9 +633,6 @@ static void find_conflicting_kernel_modules(Options *op, { 0, NULL } }; - memset(files, 0, sizeof(files)); - files[1].name = NULL; - files[1].len = 0; if (op->kernel_module_installation_path) { paths[i++] = op->kernel_module_installation_path; } @@ -653,18 +642,25 @@ static void find_conflicting_kernel_modules(Options *op, } paths[i] = NULL; - + + /* Build the list of conflicting kernel modules */ + + files = nvalloc((num_conflicting_kernel_modules + 1) * sizeof(files[0])); + filenames = nvalloc(num_conflicting_kernel_modules * sizeof(filenames[0])); + + for (i = 0; i < num_conflicting_kernel_modules; i++) { + filenames[i] = nvstrcat(conflicting_kernel_modules[i], ".ko", NULL); + files[i].name = filenames[i]; + files[i].len = strlen(filenames[i]); + } + for (i = 0; paths[i]; i++) { - for (n = 0; p->bad_module_filenames[n]; n++) { - /* - * Recursively search for this conflicting kernel module - * relative to the current prefix. - */ - files[0].name = p->bad_module_filenames[n]; - files[0].len = strlen(files[0].name); + /* + * Recursively search for the conflicting kernel modules + * relative to the current prefix. + */ - find_conflicting_files(op, paths[i], files, l, skipdirs); - } + find_conflicting_files(op, paths[i], files, l, skipdirs); } /* free any paths we nvstrcat()'d above */ @@ -673,7 +669,14 @@ static void find_conflicting_kernel_modules(Options *op, nvfree(paths[i]); } -} /* find_conflicting_kernel_modules() */ + /* free the kernel module names */ + + for (i = 0; i < num_conflicting_kernel_modules; i++) { + nvfree(filenames[i]); + } + nvfree(filenames); + nvfree(files); +} diff --git a/common-utils/nvgetopt.c b/common-utils/nvgetopt.c index 1716495..286aee8 100644 --- a/common-utils/nvgetopt.c +++ b/common-utils/nvgetopt.c @@ -205,6 +205,41 @@ int nvgetopt(int argc, } } + /* + * If we still didn't find a match, maybe this is a short option + * with its argument value concatenated (e.g., "-j8"). For now, + * limit this to short options with integer argument values. + */ + if (!o && intval) { + + /* Is the string after the first character an integer? */ + int appendedInteger = NVGETOPT_FALSE; + if ((name[0] != '\0') && (name[1] != '\0')) { + char *endptr; + strtol(name + 1, &endptr, 0); + if (*endptr == '\0') { + /* + * The only characters after the first character are + * parsable by strtol(3). + */ + appendedInteger = NVGETOPT_TRUE; + } + } + + if (appendedInteger) { + for (i = 0; options[i].name; i++) { + if ((options[i].flags & NVGETOPT_INTEGER_ARGUMENT) == 0) { + continue; + } + if (options[i].val == name[0]) { + o = &options[i]; + argument = name + 1; + break; + } + } + } + } + /* if we didn't find an option, return */ if (!o) { diff --git a/conflicting-kernel-modules.c b/conflicting-kernel-modules.c new file mode 100644 index 0000000..74c33eb --- /dev/null +++ b/conflicting-kernel-modules.c @@ -0,0 +1,38 @@ +/* + * nvidia-installer: A tool for installing NVIDIA software packages on + * Unix and Linux systems. + * + * Copyright (C) 2015 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses>. + */ + +#include "common-utils.h" + +/* + * A list of kernel modules that will conflict with this driver installation. + * The list should be maintained in reverse dependency order; i.e., it should + * be possible to unload kernel modules one at a time, in the order that they + * appear in this list. + */ + +const char * const conflicting_kernel_modules[] = { + "nvidia-uvm", + "nvidia-modeset", + "nvidia", + "nvidia0", "nvidia1", "nvidia2", "nvidia3", + "nvidia4", "nvidia5", "nvidia6", "nvidia7", + "nvidia-frontend", +}; + +const int num_conflicting_kernel_modules = ARRAY_LEN(conflicting_kernel_modules); diff --git a/conflicting-kernel-modules.h b/conflicting-kernel-modules.h new file mode 100644 index 0000000..892a5a6 --- /dev/null +++ b/conflicting-kernel-modules.h @@ -0,0 +1,26 @@ +/* + * nvidia-installer: A tool for installing NVIDIA software packages on + * Unix and Linux systems. + * + * Copyright (C) 2015 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses>. + */ + +#ifndef __CONFLICTING_KERNEL_MODULES_H__ +#define __CONFLICTING_KERNEL_MODULES_H__ + +extern const char * const conflicting_kernel_modules[]; +extern const int num_conflicting_kernel_modules; + +#endif diff --git a/dist-files.mk b/dist-files.mk index c4b104f..3be998b 100644 --- a/dist-files.mk +++ b/dist-files.mk @@ -44,6 +44,7 @@ SRC += update.c SRC += user-interface.c SRC += sanity.c SRC += manifest.c +SRC += conflicting-kernel-modules.c DIST_FILES := $(SRC) @@ -63,6 +64,7 @@ DIST_FILES += snarf.h DIST_FILES += update.h DIST_FILES += user-interface.h DIST_FILES += manifest.h +DIST_FILES += conflicting-kernel-modules.h DIST_FILES += COPYING DIST_FILES += README @@ -480,6 +480,116 @@ void select_tls_class(Options *op, Package *p) #endif /* NV_TLS_TEST */ } /* select_tls_class() */ +/* + * check_libGLX_indirect_target() - Helper function for + * check_libGLX_indirect_links. + * + * Checks to see if the installer should install (or overwrite) a + * libGLX_indirect.so.0 symlink. + * + * (path) should be the path to where the symlink would be installed. + */ +static int check_libGLX_indirect_target(Options *op, const char *path) +{ + char *target = NULL; + char *base = NULL; + char *ext = NULL; + struct stat stat_buf; + int ret; + + if (lstat(path, &stat_buf) != 0) { + // If the file doesn't exist, then we should create it. + return TRUE; + } + + if (!S_ISLNK(stat_buf.st_mode)) { + // The file is not a symlink. Leave it alone. + return FALSE; + } + + if (stat(path, &stat_buf) != 0) { + // If we can't resolve the link, then overwrite it. + return TRUE; + } + + // Resolve the symlink. + target = get_resolved_symlink_target(op, path); + while (target != NULL) { + // Follow any more symlinks. The fact that the stat call above + // succeeded means that the link is valid. + char *nextTarget = NULL; + if (lstat(target, &stat_buf) != 0) { + free(target); + target = NULL; + break; + } + + if (!S_ISLNK(stat_buf.st_mode)) { + break; + } + + nextTarget = get_resolved_symlink_target(op, target); + free(target); + target = nextTarget; + } + if (target == NULL) { + // This should never happen. + ui_error(op, "Unable to resolve symbolic link \"%s\"\n", path); + return FALSE; + } + + // Find the basename of the link target. + base = basename(target); + // Strip off the extension. + ext = strchr(base, '.'); + if (ext != NULL) { + *ext = '\0'; + } + + // Finally, see if the resulting name is "libGLX_indirect". If it is, then + // we'll assume that the existing file is a dedicated indirect rendering + // library. Otherwise, we'll assume that it's a link to another vendor + // library. + if (strcmp(base, "libGLX_indirect") == 0) { + ret = FALSE; + } else { + ret = TRUE; + } + free(target); + return ret; +} + +/* + * check_libGLX_indirect_links() - Finds the entries for the + * "libGLX_indirect.so.0" symlinks, and figures out whether to install them. + */ +static void check_libGLX_indirect_links(Options *op, Package *p) +{ + int i; + + if (op->install_libglx_indirect == NV_OPTIONAL_BOOL_TRUE) { + // The user specified that we should install the symlink. + return; + } + + // Find the entries for libGLX_indirect.so.0, and decide whether or not to + // keep them. + for (i = 0; i < p->num_entries; i++) { + if (p->entries[i].dst != NULL && p->entries[i].type == FILE_TYPE_OPENGL_SYMLINK) { + if (strcmp(p->entries[i].name, "libGLX_indirect.so.0") == 0) { + int overwrite = FALSE; + if (op->install_libglx_indirect == NV_OPTIONAL_BOOL_DEFAULT) { + if (check_libGLX_indirect_target(op, p->entries[i].dst)) { + overwrite = TRUE; + } + } + if (!overwrite) { + invalidate_package_entry(&(p->entries[i])); + } + } + } + } +} /* * set_destinations() - given the Options and Package structures, @@ -499,32 +609,20 @@ int set_destinations(Options *op, Package *p) op->kernel_module_src_dir = nvstrcat("nvidia-", p->version, NULL); } - op->uvm_module_src_dir = nvstrcat(op->kernel_module_src_dir, "/" UVM_SUBDIR, - NULL); - for (i = 0; i < p->num_entries; i++) { switch (p->entries[i].type) { - case FILE_TYPE_KERNEL_MODULE_CMD: - /* we don't install kernel module commands */ - p->entries[i].dst = NULL; - continue; - case FILE_TYPE_KERNEL_MODULE_SRC: - case FILE_TYPE_UVM_MODULE_SRC: + case FILE_TYPE_DKMS_CONF: if (op->no_kernel_module_source) { /* Don't install kernel module source files if requested. */ p->entries[i].dst = NULL; continue; } prefix = op->kernel_module_src_prefix; - if (p->entries[i].type == FILE_TYPE_UVM_MODULE_SRC) { - dir = op->uvm_module_src_dir; - } else { - dir = op->kernel_module_src_dir; - } - path = ""; + dir = op->kernel_module_src_dir; + path = p->entries[i].path; break; case FILE_TYPE_OPENGL_LIB: @@ -775,6 +873,8 @@ int set_destinations(Options *op, Package *p) } #endif /* NV_X86_64 */ } + + check_libGLX_indirect_links(op, p); return TRUE; @@ -1031,11 +1131,11 @@ int get_prefixes (Options *op) */ static void add_kernel_module_helper(Options *op, Package *p, - const char *filename, const char *dir) + const char *filename) { char *file, *name, *dst; - file = nvstrcat(dir, "/", filename, NULL); + file = nvstrcat(p->kernel_module_build_directory, "/", filename, NULL); name = strrchr(file, '/'); @@ -1066,43 +1166,20 @@ static void add_kernel_module_helper(Options *op, Package *p, * to the package list for installation. */ -int add_kernel_modules_to_package(Options *op, Package *p) +void add_kernel_modules_to_package(Options *op, Package *p) { int i; - if (op->multiple_kernel_modules) { - add_kernel_module_helper(op, p, p->kernel_frontend_module_filename, - p->kernel_module_build_directory); - } - - for (i = 0; i < op->num_kernel_modules; i++) { - - char *tmp, *name; - - name = nvstrdup(p->kernel_module_filename); - - tmp = strrchr(name, '0'); - if (tmp) *tmp = *tmp + i; - - add_kernel_module_helper(op, p, name, p->kernel_module_build_directory); - - nvfree(name); + for (i = 0; i < p->num_kernel_modules; i++) { + add_kernel_module_helper(op, p, p->kernel_modules[i].module_filename); } - - if (op->install_uvm) { - add_kernel_module_helper(op, p, p->uvm_kernel_module_filename, - p->uvm_module_build_directory); - } - - return TRUE; - -} /* add_kernel_module_to_package() */ +} /* * Invalidate each package entry that is not type - * FILE_TYPE_KERNEL_MODULE{,_CMD,_SRC}. + * FILE_TYPE_KERNEL_MODULE{,_SRC} or FILE_TYPE_DKMS_CONF. */ void remove_non_kernel_module_files_from_package(Options *op, Package *p) @@ -1111,8 +1188,8 @@ void remove_non_kernel_module_files_from_package(Options *op, Package *p) for (i = 0; i < p->num_entries; i++) { if ((p->entries[i].type != FILE_TYPE_KERNEL_MODULE) && - (p->entries[i].type != FILE_TYPE_KERNEL_MODULE_CMD) && - (p->entries[i].type != FILE_TYPE_KERNEL_MODULE_SRC)) { + (p->entries[i].type != FILE_TYPE_KERNEL_MODULE_SRC) && + (p->entries[i].type != FILE_TYPE_DKMS_CONF)) { invalidate_package_entry(&(p->entries[i])); } } @@ -1592,8 +1669,8 @@ int check_for_existing_rpms(Options *op) /* - * copy_directory_contents() - copy the contents of directory src to - * directory dst. This only copies files; subdirectories are ignored. + * copy_directory_contents() - recursively copy the contents of directory src to + * directory dst. Special files are ignored. */ int copy_directory_contents(Options *op, const char *src, const char *dst) @@ -1612,22 +1689,24 @@ int copy_directory_contents(Options *op, const char *src, const char *dst) struct stat stat_buf; char *srcfile, *dstfile; int ret; - + if (((strcmp(ent->d_name, ".")) == 0) || ((strcmp(ent->d_name, "..")) == 0)) continue; - + srcfile = nvstrcat(src, "/", ent->d_name, NULL); + dstfile = nvstrcat(dst, "/", ent->d_name, NULL); - /* only copy regular files */ + ret = (stat(srcfile, &stat_buf) != -1); - if ((stat(srcfile, &stat_buf) == -1) || !(S_ISREG(stat_buf.st_mode))) { - nvfree(srcfile); - continue; + if (ret) { + /* recurse into subdirectories */ + if (S_ISDIR(stat_buf.st_mode)) { + ret = mkdir_recursive(op, dstfile, stat_buf.st_mode, FALSE) && + copy_directory_contents(op, srcfile, dstfile); + } else if (S_ISREG(stat_buf.st_mode)) { + ret = copy_file(op, srcfile, dstfile, stat_buf.st_mode); + } } - - dstfile = nvstrcat(dst, "/", ent->d_name, NULL); - - ret = copy_file(op, srcfile, dstfile, stat_buf.st_mode); nvfree(srcfile); nvfree(dstfile); @@ -1644,13 +1723,13 @@ int copy_directory_contents(Options *op, const char *src, const char *dst) if (closedir(dir) != 0) { ui_error(op, "Failure while closing directory '%s' (%s).", src, strerror(errno)); - + return FALSE; } - + return status; - -} /* copy_directory_contents() */ + +} @@ -2098,6 +2177,84 @@ void process_dot_desktop_files(Options *op, Package *p) } /* process_dot_desktop_files() */ + +/* + * process_dkms_conf() - copy dkms.conf to a temporary file and perform + * some substitutions. Then, add the new file to the package list. + */ + +void process_dkms_conf(Options *op, Package *p) +{ + int i; + char *tmpfile; + + char *tokens[6] = { "__VERSION_STRING", "__DKMS_MODULES", "__JOBS", + "__EXCLUDE_MODULES", "will be generated", NULL }; + char *replacements[6] = { p->version, NULL, NULL, + p->excluded_kernel_modules, + "was generated", NULL }; + + int package_num_entries = p->num_entries; + + replacements[1] = nvstrdup(""); + replacements[2] = nvasprintf("%d", op->concurrency_level); + + /* Build the list of kernel modules to be installed */ + for (i = 0; i < p->num_kernel_modules; i++) { + char *old_modules = replacements[1]; + char *index = nvasprintf("%d", i); + + replacements[1] = nvstrcat(old_modules, + "BUILT_MODULE_NAME[", index, "]=\"", + p->kernel_modules[i].module_name, "\"\n", + "DEST_MODULE_LOCATION[", index, "]=", + "\"/kernel/drivers/video\"\n", NULL); + + nvfree(index); + nvfree(old_modules); + } + + for (i = 0; i < package_num_entries; i++) { + if ((p->entries[i].type == FILE_TYPE_DKMS_CONF)) { + + /* invalidate the template file */ + + invalidate_package_entry(&(p->entries[i])); + + tmpfile = process_template_file(op, &p->entries[i], tokens, + replacements); + if (tmpfile != NULL) { + /* add this new file to the package */ + + /* + * XXX 'name' is the basename (non-directory part) of + * the file to be installed; normally, 'name' just + * points into 'file', but in this case 'file' is + * mkstemp(3)-generated, so doesn't have the same + * basename; instead, we just strdup the name from the + * template package entry; yes, 'name' will get leaked + */ + + add_package_entry(p, + tmpfile, + nvstrdup(p->entries[i].path), + nvstrdup(p->entries[i].name), + NULL, /* target */ + NULL, /* dst */ + FILE_TYPE_DKMS_CONF, + p->entries[i].tls_class, + p->entries[i].compat_arch, + p->entries[i].mode); + } + } + } + + nvfree(replacements[2]); + nvfree(replacements[1]); + +} + + /* * set_security_context() - set the security context of the file to 'shlib_t' * Returns TRUE on success or if SELinux is disabled, FALSE otherwise @@ -23,8 +23,6 @@ #include "nvidia-installer.h" #include "precompiled.h" -#define UVM_SUBDIR "uvm" - int remove_directory(Options *op, const char *victim); int touch_directory(Options *op, const char *victim); int copy_file(Options *op, const char *srcfile, @@ -35,7 +33,7 @@ void select_tls_class(Options *op, Package *p); /* XXX move? */ int set_destinations(Options *op, Package *p); /* XXX move? */ int get_license_acceptance(Options *op); /* XXX move? */ int get_prefixes(Options *op); /* XXX move? */ -int add_kernel_modules_to_package(Options *op, Package *p); +void add_kernel_modules_to_package(Options *op, Package *p); void remove_non_kernel_module_files_from_package(Options *op, Package *p); void remove_opengl_files_from_package(Options *op, Package *p); int mode_string_to_mode(Options *op, char *s, mode_t *mode); @@ -62,6 +60,7 @@ char *process_template_file(Options *op, PackageEntry *pe, char **tokens, char **replacements); void process_libGL_la_files(Options *op, Package *p); void process_dot_desktop_files(Options *op, Package *p); +void process_dkms_conf(Options *op, Package *p); int set_security_context(Options *op, const char *filename); void get_default_prefixes_and_paths(Options *op); void get_compat32_path(Options *op); diff --git a/install-from-cwd.c b/install-from-cwd.c index a6388da..18d7df1 100644 --- a/install-from-cwd.c +++ b/install-from-cwd.c @@ -111,7 +111,7 @@ int install_from_cwd(Options *op) /* make sure the kernel module is unloaded */ - if (!check_for_unloaded_kernel_module(op, p)) goto failed; + if (!check_for_unloaded_kernel_module(op)) goto failed; /* ask the user to accept the license */ @@ -314,7 +314,9 @@ int install_from_cwd(Options *op) */ if (!op->no_kernel_module || op->dkms) { - if (!load_kernel_module(op, p)) goto failed; + if (!load_kernel_module(op, p->kernel_modules[0].module_name)) { + goto failed; + } } /* run the distro postinstall script */ @@ -419,49 +421,7 @@ static int install_kernel_modules(Options *op, Package *p) { PrecompiledInfo *precompiled_info; - /* Append the UVM dkms.conf fragment to RM's dkms.conf when installing UVM */ - - if (op->install_uvm) { - FILE *dkmsconf, *uvmdkmsconf; - char *tmppath; - - tmppath = nvstrcat(p->kernel_module_build_directory, "/dkms.conf", NULL); - dkmsconf = fopen(tmppath, "a"); - nvfree(tmppath); - - tmppath = nvstrcat(p->uvm_module_build_directory, - "/dkms.conf.fragment", NULL); - uvmdkmsconf = fopen(tmppath, "r"); - nvfree (tmppath); - - if (dkmsconf && uvmdkmsconf) { - char byte; - - while (fread(&byte, 1, 1, uvmdkmsconf)) { - if (!fwrite(&byte, 1, 1, dkmsconf)) { - goto dkmscatfailed; - } - } - - if (ferror(uvmdkmsconf)) { - goto dkmscatfailed; - } - - } else { -dkmscatfailed: - ui_warn(op, "Failed to add build commands for the NVIDIA Unified " - "Memory kernel module to the dkms.conf file: DKMS will " - "not be able to build the NVIDIA Unified Memory kernel " - "module."); - } - - if (dkmsconf) { - fclose(dkmsconf); - } - if (uvmdkmsconf) { - fclose(uvmdkmsconf); - } - } + process_dkms_conf(op,p); /* Offer the DKMS option if DKMS exists and the kernel module sources * will be installed somewhere. Don't offer DKMS as an option if module @@ -528,8 +488,8 @@ dkmscatfailed: */ for (i = 0; i < precompiled_info->num_files; i++) { - if (!link_kernel_module(op, p, p->kernel_module_build_directory, - &(precompiled_info->files[i]))) { + if (!unpack_kernel_modules(op, p, p->kernel_module_build_directory, + &(precompiled_info->files[i]))) { precompiled_success = FALSE; goto precompiled_done; } @@ -579,7 +539,7 @@ precompiled_done: /* add the kernel modules to the list of things to install */ - if (!add_kernel_modules_to_package(op, p)) return FALSE; + add_kernel_modules_to_package(op, p); return TRUE; } @@ -595,7 +555,6 @@ int add_this_kernel(Options *op) { Package *p; PrecompiledFileInfo *fileInfos; - int num_expected_files = 1; /* parse the manifest */ @@ -609,22 +568,14 @@ int add_this_kernel(Options *op) if (!determine_kernel_source_path(op, p)) goto failed; - if (op->multiple_kernel_modules) { - num_expected_files += op->num_kernel_modules; - } - - if (op->install_uvm) { - num_expected_files += 1; - } - /* build the precompiled files */ - if (num_expected_files != build_kernel_interface(op, p, &fileInfos)) + if (p->num_kernel_modules != build_kernel_interfaces(op, p, &fileInfos)) goto failed; /* pack the precompiled files */ - if (!pack_precompiled_files(op, p, num_expected_files, fileInfos)) + if (!pack_precompiled_files(op, p, p->num_kernel_modules, fileInfos)) goto failed; free_package(p); @@ -650,6 +601,7 @@ static void add_conflicting_file(Package *p, int *index, const char *file) p->conflicting_files = nvrealloc(p->conflicting_files, sizeof(ConflictingFileInfo) * (*index+1)); + memset(&p->conflicting_files[*index], 0, sizeof(ConflictingFileInfo)); p->conflicting_files[*index].name = file; @@ -686,6 +638,100 @@ static void add_conflicting_file(Package *p, int *index, const char *file) } +/* + * Returns TRUE if the given module has a separate interface, FALSE otherwise. + */ +static int has_separate_interface_file(char *name) { + int i; + + static const char* no_interface_modules[] = { + "nvidia-uvm", + }; + + for (i = 0; i < ARRAY_LEN(no_interface_modules); i++) { + if (strcmp(no_interface_modules[i],name) == 0) { + return FALSE; + } + } + + return TRUE; +}; + + +/* + * Populate the module info records for optional records with information + * that can be used in e.g. error messages. + */ +static void populate_optional_module_info(KernelModuleInfo *module) +{ + int i; + + static struct { + const char *name; + char * const dependee; + char * const disable_option; + } optional_modules[] = { + { "nvidia-uvm", "CUDA", "no-unified-memory" }, + }; + + for (i = 0; i < ARRAY_LEN(optional_modules); i++) { + if (strcmp(optional_modules[i].name, module->module_name) == 0) { + module->is_optional = TRUE; + module->optional_module_dependee = optional_modules[i].dependee; + module->disable_option = optional_modules[i].disable_option; + return; + } + } +} + + +/* + * Return a string with 'suffix' appended to the original source string, after + * replacing "nvidia" with "nv" at the beginning of the original source string. + */ +static char *nvidia_to_nv(const char *name, const char *suffix) { + if (strncmp("nvidia", name, strlen("nvidia")) != 0) { + return NULL; + } + + return nvstrcat("nv", name + strlen("nvidia"), suffix, NULL); +} + + +/* + * Iterate over the list of kernel modules from the manifest file; generate + * and store module information records for each module in the Package. + */ +static int parse_kernel_modules_list(Package *p, char *list) { + char *name; + + p->num_kernel_modules = 0; /* in case this gets called more than once */ + + for (name = strtok(list, " "); name; name = strtok(NULL, " ")) { + KernelModuleInfo *module; + p->kernel_modules = nvrealloc(p->kernel_modules, + (p->num_kernel_modules + 1) * + sizeof(p->kernel_modules[0])); + module = p->kernel_modules + p->num_kernel_modules; + memset(module, 0, sizeof(*module)); + + module->module_name = nvstrdup(name); + module->module_filename = nvstrcat(name, ".ko", NULL); + module->has_separate_interface_file = has_separate_interface_file(name); + if (module->has_separate_interface_file) { + char *core_binary = nvidia_to_nv(name, "-kernel.o_binary"); + module->interface_filename = nvidia_to_nv(name, "-linux.o"); + module->core_object_name = nvstrcat(name, "/", core_binary, NULL); + nvfree(core_binary); + } + populate_optional_module_info(module); + + p->num_kernel_modules++; + } + + return p->num_kernel_modules; +} + /* * parse_manifest() - open and read the .manifest file in the current @@ -714,13 +760,14 @@ static void add_conflicting_file(Package *p, int *index, const char *file) * - certain file types have an architecture * - certain file types have a second flag * - certain file types will have a path + * - file types which inherit their paths will have a path depth * - symbolic links will name the target of the link */ static Package *parse_manifest (Options *op) { - char *buf, *c, *tmpstr, *module_suffix = "", *interface_suffix = ""; - int n, line; + char *buf, *c, *tmpstr; + int line; int fd, ret, len = 0; struct stat stat_buf; Package *p; @@ -763,74 +810,32 @@ static Package *parse_manifest (Options *op) line++; nvfree(get_next_line(ptr, &ptr, manifest, len)); - /* the fourth line is the kernel module name */ + /* the fourth line is the list of kernel modules. */ line++; tmpstr = get_next_line(ptr, &ptr, manifest, len); - if (!tmpstr) goto invalid_manifest_file; - - if (op->multiple_kernel_modules) { - module_suffix = "0"; - interface_suffix = "-0"; + if (parse_kernel_modules_list(p, tmpstr) == 0) { + goto invalid_manifest_file; } - - p->kernel_module_name = nvstrcat(tmpstr, module_suffix, NULL); - p->kernel_module_filename = nvstrcat(p->kernel_module_name, ".ko", NULL); - p->kernel_interface_filename = nvstrcat("nv-linux", interface_suffix, ".o", NULL); - - p->kernel_frontend_module_name = nvstrcat(tmpstr, "-frontend", NULL); - p->kernel_frontend_module_filename = nvstrcat(p->kernel_frontend_module_name, - ".ko", NULL); - p->kernel_frontend_interface_filename = "nv-linux-frontend.o"; - - p->uvm_kernel_module_name = nvstrcat(tmpstr, "-uvm", NULL); - p->uvm_kernel_module_filename = nvstrcat(p->uvm_kernel_module_name, ".ko", - NULL); - p->uvm_interface_filename = "nv-linux-uvm.o"; - nvfree(tmpstr); /* - * the fifth line is a whitespace-separated list of kernel modules - * to be unloaded before installing the new kernel module + * set the default value of excluded_kernel_modules to an empty, heap + * allocated string so that it can be freed and won't prematurely end + * an nvstrcat()ed string when unset. */ - line++; - tmpstr = get_next_line(ptr, &ptr, manifest, len); - if (!tmpstr) goto invalid_manifest_file; + p->excluded_kernel_modules = nvstrdup(""); - p->bad_modules = NULL; - c = tmpstr; - n = 0; - - do { - n++; - p->bad_modules = (char **) - nvrealloc(p->bad_modules, n * sizeof(char *)); - p->bad_modules[n-1] = read_next_word(c, &c); - } while (p->bad_modules[n-1]); - /* - * the sixth line is a whitespace-separated list of kernel module - * filenames to be uninstalled before installing the new kernel - * module + * ignore the fifth and sixth lines */ line++; - tmpstr = get_next_line(ptr, &ptr, manifest, len); - if (!tmpstr) goto invalid_manifest_file; + nvfree(get_next_line(ptr, &ptr, manifest, len)); + line++; + nvfree(get_next_line(ptr, &ptr, manifest, len)); - p->bad_module_filenames = NULL; - c = tmpstr; - n = 0; - - do { - n++; - p->bad_module_filenames = (char **) - nvrealloc(p->bad_module_filenames, n * sizeof(char *)); - p->bad_module_filenames[n-1] = read_next_word(c, &c); - } while (p->bad_module_filenames[n-1]); - /* the seventh line is the kernel module build directory */ line++; @@ -838,9 +843,6 @@ static Package *parse_manifest (Options *op) if (!p->kernel_module_build_directory) goto invalid_manifest_file; remove_trailing_slashes(p->kernel_module_build_directory); - p->uvm_module_build_directory = nvstrcat(p->kernel_module_build_directory, - "/" UVM_SUBDIR, NULL); - /* * the eigth line is the directory containing precompiled kernel * interfaces @@ -907,9 +909,6 @@ static Package *parse_manifest (Options *op) /* Track whether certain file types were packaged */ switch (entry.type) { - case FILE_TYPE_UVM_MODULE_SRC: - op->uvm_files_packaged = TRUE; - break; case FILE_TYPE_XMODULE_SHARED_LIB: op->x_files_packaged = TRUE; break; @@ -964,11 +963,45 @@ static Package *parse_manifest (Options *op) } } - /* libs and documentation have a path field */ + /* some file types have a path field, or inherit their paths */ if (entry.caps.has_path) { entry.path = read_next_word(c, &c); if (!entry.path) goto invalid_manifest_file; + } else if (entry.caps.inherit_path) { + int i; + char *path, *depth, *slash; + const char * const depth_marker = "INHERIT_PATH_DEPTH:"; + + depth = read_next_word(c, &c); + if (!depth || + strncmp(depth, depth_marker, strlen(depth_marker)) != 0) { + goto invalid_manifest_file; + } + entry.inherit_path_depth = atoi(depth + strlen(depth_marker)); + nvfree(depth); + + /* Remove the file component from the packaged filename */ + path = entry.path = nvstrdup(entry.file); + slash = strrchr(path, '/'); + if (slash == NULL) { + goto invalid_manifest_file; + } + slash[1] = '\0'; + + /* Strip leading directory components from the path */ + for (i = 0; i < entry.inherit_path_depth; i++) { + slash = strchr(entry.path, '/'); + + if (slash == NULL) { + goto invalid_manifest_file; + } + + entry.path = slash + 1; + } + + entry.path = nvstrdup(entry.path); + nvfree(path); } else { entry.path = NULL; } @@ -1132,29 +1165,18 @@ static void free_package(Package *p) nvfree(p->description); nvfree(p->version); - nvfree(p->kernel_module_filename); - nvfree(p->kernel_interface_filename); - nvfree(p->kernel_module_name); - - if (p->bad_modules) { - for (i = 0; p->bad_modules[i]; i++) { - nvfree(p->bad_modules[i]); - } - nvfree((char *) p->bad_modules); - } - - if (p->bad_module_filenames) { - for (i = 0; p->bad_module_filenames[i]; i++) { - nvfree(p->bad_module_filenames[i]); - } - nvfree((char *) p->bad_module_filenames); - } nvfree(p->kernel_module_build_directory); - nvfree(p->uvm_module_build_directory); - + nvfree(p->precompiled_kernel_interface_directory); - + + for (i = 0; i < p->num_kernel_modules; i++) { + free_kernel_module_info(p->kernel_modules[i]); + } + nvfree(p->kernel_modules); + + nvfree(p->excluded_kernel_modules); + for (i = 0; i < p->num_entries; i++) { nvfree(p->entries[i].file); nvfree(p->entries[i].path); @@ -1169,11 +1191,6 @@ static void free_package(Package *p) nvfree((char *) p->entries); - nvfree(p->kernel_frontend_module_filename); - nvfree(p->kernel_frontend_module_name); - nvfree(p->uvm_kernel_module_name); - nvfree(p->uvm_kernel_module_filename); - nvfree((char *) p); } /* free_package() */ @@ -1307,7 +1324,8 @@ static int assisted_module_signing(Options *op, Package *p) "plan to generate a new key pair with " "nvidia-installer."; - guess = guess_module_signing_hash(op, p); + guess = guess_module_signing_hash(op, + p->kernel_module_build_directory); if (guess == NULL) { warn = no_guess; @@ -1405,30 +1423,9 @@ generate_done: /* Now that we have keys (user-supplied or installer-generated), * sign the kernel module/s which we built earlier. */ - for (i = 0; i < op->num_kernel_modules; i++) { - char module_instance_str[5]; - memset(module_instance_str, 0, sizeof(module_instance_str)); - - if (op->multiple_kernel_modules) { - snprintf(module_instance_str, sizeof(module_instance_str), "%d", i); - } - + for (i = 0; i < p->num_kernel_modules; i++) { if (!sign_kernel_module(op, p->kernel_module_build_directory, - module_instance_str, TRUE)) { - return FALSE; - } - } - - if (op->multiple_kernel_modules) { - if (!sign_kernel_module(op, p->kernel_module_build_directory, - "-frontend", TRUE)) { - return FALSE; - } - } - - if (op->install_uvm) { - if (!sign_kernel_module(op, p->uvm_module_build_directory, "-uvm", - TRUE)) { + p->kernel_modules[i].module_filename, TRUE)) { return FALSE; } } @@ -43,6 +43,7 @@ #include "precompiled.h" #include "snarf.h" #include "crc.h" +#include "conflicting-kernel-modules.h" /* local prototypes */ @@ -54,9 +55,9 @@ static void check_for_warning_messages(Options *op); static PrecompiledInfo *download_updated_kernel_interface(Options*, Package*, const char*, char* const*); -static int fbdev_check(Options *op, Package *p); -static int xen_check(Options *op, Package *p); -static int preempt_rt_check(Options *op, Package *p); +static int sanity_check(Options *op, const char *dir, + const char *sanity_check_name, + const char *conftest_name); static PrecompiledInfo *scan_dir(Options *op, Package *p, const char *directory_name, @@ -68,9 +69,10 @@ static char *convert_include_path_to_source_path(const char *inc); static char *get_machine_arch(Options *op); static int init_libkmod(void); static void close_libkmod(void); -static int run_conftest(Options *op, Package *p, const char *args, +static int run_conftest(Options *op, const char *dir, const char *args, char **result); -static void replace_zero(char* filename, int i); +static int run_make(Options *op, Package *p, char *dir, const char *target, + char **vars, const char *status, int lines); static void load_kernel_module_quiet(Options *op, const char *module_name); static void modprobe_remove_kernel_module_quiet(Options *op, const char *name); @@ -83,7 +85,6 @@ static int (*lkmod_module_new_from_path)(struct kmod_ctx*, const char*, struct kmod_module**) = NULL; static int (*lkmod_module_insert_module)(struct kmod_module*, unsigned int, const char*) = NULL; -static void free_search_filelist(char **); /* * Message text that is used by several error messages. @@ -170,28 +171,33 @@ int determine_kernel_module_installation_path(Options *op) * the result back to the caller. Returns TRUE on success, or FALSE on failure. */ -static int run_conftest(Options *op, Package *p, const char *args, char **result) +static int run_conftest(Options *op, const char *dir, const char *args, + char **result) { char *cmd, *arch; int ret; - if (result) + if (result) { *result = NULL; + } arch = get_machine_arch(op); - if (!arch) + if (!arch) { return FALSE; + } - cmd = nvstrcat("sh \"", p->kernel_module_build_directory, - "/conftest.sh\" \"", op->utils[CC], "\" \"", op->utils[CC], - "\" \"", arch, "\" \"", op->kernel_source_path, "\" \"", - op->kernel_output_path, "\" ", args, NULL); + cmd = nvstrcat("sh \"", dir, "/conftest.sh\" \"", + op->utils[CC], "\" \"", + op->utils[CC], "\" \"", + arch, "\" \"", + op->kernel_source_path, "\" \"", + op->kernel_output_path, "\" ", + args, NULL); ret = run_command(op, cmd, result, FALSE, 0, TRUE); nvfree(cmd); return ret == 0; - } /* run_conftest() */ @@ -295,7 +301,8 @@ int determine_kernel_source_path(Options *op, Package *p) if (!determine_kernel_output_path(op)) return FALSE; - ret = run_conftest(op, p, "get_uname", &result); + ret = run_conftest(op, p->kernel_module_build_directory, "get_uname", + &result); if (!ret) { ui_error(op, "Unable to determine the version of the kernel " @@ -501,54 +508,45 @@ static int attach_signature(Options *op, Package *p, /* - * Look for the presence of char '0' in filename and replace - * it with the integer value passed as input. This is used - * especially for multiple kernel module builds. - */ - -static void replace_zero(char *filename, int i) -{ - char *name; - - if (i < 0 || i > 9) return; - - name = strrchr(filename, '0'); - if (name) *name = *name + i; -} - - -/* - * link_kernel_module() - link the prebuilt kernel interface against - * the binary-only core of the kernel module. This results in a - * complete kernel module, ready for installation. + * unpack_kernel_modules() - unpack the precompiled file bundle, and link any + * prebuilt kernel interface against their respective binary-only core object + * files. This results in a complete kernel module, ready for installation. * + * e.g.: ld -r -o nvidia.ko nv-linux.o nvidia/nv-kernel.o_binary * - * ld -r -o nvidia.o nv-linux.o nv-kernel.o + * If the precompiled file is a complete kernel module instead of an interface + * file, no additional action is needed after unpacking. */ -int link_kernel_module(Options *op, Package *p, const char *build_directory, - const PrecompiledFileInfo *fileInfo) +int unpack_kernel_modules(Options *op, Package *p, const char *build_directory, + const PrecompiledFileInfo *fileInfo) { char *cmd, *result; int ret; uint32 attrmask; - if (fileInfo->type != PRECOMPILED_FILE_TYPE_INTERFACE) { + if (fileInfo->type != PRECOMPILED_FILE_TYPE_INTERFACE && + fileInfo->type != PRECOMPILED_FILE_TYPE_MODULE) { ui_error(op, "The file does not appear to be a valid precompiled " - "kernel interface."); + "kernel interface or module."); return FALSE; } ret = precompiled_file_unpack(op, fileInfo, build_directory); if (!ret) { - ui_error(op, "Failed to unpack the precompiled interface."); + ui_error(op, "Failed to unpack the precompiled file."); return FALSE; + } else if (fileInfo->type == PRECOMPILED_FILE_TYPE_MODULE) { + ui_log(op, "Kernel module unpacked successfully."); + return TRUE; } - cmd = nvstrcat("cd ", build_directory, "/", fileInfo->target_directory, + cmd = nvstrcat("cd ", build_directory, "; ", op->utils[LD], " ", LD_OPTIONS, " -o ", fileInfo->linked_module_name, " ", - fileInfo->name, " ", fileInfo->core_object_name, NULL); + fileInfo->target_directory, "/", fileInfo->name, " ", + fileInfo->target_directory, "/", fileInfo->core_object_name, + NULL); ret = run_command(op, cmd, &result, TRUE, 0, TRUE); @@ -571,215 +569,129 @@ int link_kernel_module(Options *op, Package *p, const char *build_directory, return TRUE; -} /* link_kernel_module() */ - - - -static int build_kernel_module_helper(Options *op, const char *dir, - const char *module, int num_instances) -{ - int ret; - char *instances = NULL, *cmd, *tmp, *concurrency; - - tmp = op->multiple_kernel_modules && num_instances ? - nvasprintf("%d", num_instances) : NULL; - instances = nvstrcat(" NV_BUILD_MODULE_INSTANCES=", tmp, NULL); - nvfree(tmp); - - concurrency = nvasprintf(" -j%d ", op->concurrency_level); - - tmp = nvasprintf("Building %s kernel module:", module); - ui_status_begin(op, tmp, "Building"); - nvfree(tmp); - - cmd = nvstrcat("cd ", dir, "; ", op->utils[MAKE], " module", - " SYSSRC=", op->kernel_source_path, - " SYSOUT=", op->kernel_output_path, concurrency, - instances, NULL); - nvfree(instances); - nvfree(concurrency); - - ret = run_command(op, cmd, NULL, TRUE, 25, TRUE); - - nvfree(cmd); - - if (ret != 0) { - ui_status_end(op, "Error."); - ui_error(op, "Unable to build the %s kernel module.", module); - /* XXX need more descriptive error message */ - - return FALSE; - } - - ui_status_end(op, "done."); - - return TRUE; } -static int check_file(Options *op, const char *dir, const char *filename, - const char *modname) +static int check_file(Options *op, const char *dir, const char *modname) { int ret; char *path; - path = nvstrcat(dir, "/", filename, NULL); + path = nvstrcat(dir, "/", modname, ".ko", NULL); ret = access(path, F_OK); nvfree(path); if (ret == -1) { - ui_error(op, "The NVIDIA %s module was not created.", modname); + ui_error(op, "The %s kernel module was not created.", modname); } return ret != -1; } + /* - * Determine the kernel include directory, - * copy the kernel module source files into a temporary directory, and - * compile nvidia.o. + * Build the kernel modules that part of this package. */ int build_kernel_modules(Options *op, Package *p) { - char *result, *cmd; - int ret; - - /* - * touch all the files in the build directory to avoid make time - * skew messages - */ - - touch_directory(op, p->kernel_module_build_directory); - - if (!fbdev_check(op, p)) return FALSE; - if (!xen_check(op, p)) return FALSE; - if (!preempt_rt_check(op, p)) return FALSE; - - ui_log(op, "Cleaning kernel module build directory."); - - cmd = nvstrcat("cd ", p->kernel_module_build_directory, "; ", - op->utils[MAKE], " clean", NULL); - - ret = run_command(op, cmd, &result, TRUE, 0, TRUE); - free(result); - free(cmd); - - ret = build_kernel_module_helper(op, p->kernel_module_build_directory, - "NVIDIA", op->num_kernel_modules); - - if (!ret) { - return FALSE; - } - - /* check that the frontend file actually exists */ - if (op->multiple_kernel_modules) { - if (!check_file(op, p->kernel_module_build_directory, - p->kernel_frontend_module_filename, "frontend")) { - return FALSE; - } - } - - /* check that the file actually exists */ - if (!check_file(op, p->kernel_module_build_directory, - p->kernel_module_filename, "kernel")) { - return FALSE; - } - - /* - * Build the UVM kernel module. The build directory from the previous kernel - * module build must not be cleaned first, as the UVM kernel module will - * depend on the Module.symvers file produced by that build. - */ + return build_kernel_interfaces(op, p, NULL); +} - if (op->install_uvm) { - ret = build_kernel_module_helper(op, p->uvm_module_build_directory, - "Unified Memory", 0); - ret = ret && check_file(op, p->uvm_module_build_directory, - p->uvm_kernel_module_filename, "Unified Memory"); +/* + * Run the module_signing_script with three or four arguments. + * Return TRUE on success. + */ +static int try_sign_file(Options *op, const char *file, int num_args) +{ + char *cmd; + const char *arg_1; + int ret; - if (!ret) { - ui_error(op, "The Unified Memory kernel module failed to build. " - "This kernel module is required for the proper operation " - "of CUDA. If you do not need to use CUDA, you can try to " - "install this driver package again with the " - "'--no-unified-memory' option."); - return FALSE; - } + switch (num_args) { + case 3: arg_1 = ""; break; + case 4: arg_1 = op->module_signing_hash; break; + default: return FALSE; } - ui_log(op, "Kernel module compilation complete."); + cmd = nvstrcat("\"", op->module_signing_script, "\" ", + arg_1, " \"", + op->module_signing_secret_key, "\" \"", + op->module_signing_public_key, "\" \"", + file, "\"", NULL); + ret = run_command(op, cmd, NULL, TRUE, 1, TRUE); + nvfree(cmd); - return TRUE; + return ret == 0; } - - /* - * sign_kernel_module() - sign the kernel module. The caller is responsible + * sign_kernel_module() - sign a kernel module. The caller is responsible * for ensuring that the kernel module is already built successfully and that * op->module_signing_{secret,public}_key are set. */ int sign_kernel_module(Options *op, const char *build_directory, - const char *module_suffix, int status) { - char *cmd, *mod_sign_cmd, *mod_sign_hash; - int ret, success; - char *build_module_instances_parameter, *concurrency; - - /* if module_signing_script isn't set, then set mod_sign_cmd below to end - * the nvstrcat() that builds cmd early. */ - mod_sign_cmd = op->module_signing_script ? - nvstrcat(" mod_sign_cmd=", op->module_signing_script, NULL) : - NULL; - - mod_sign_hash = op->module_signing_hash ? - nvstrcat(" CONFIG_MODULE_SIG_HASH=", - op->module_signing_hash, NULL) : - NULL; + const char *module_filename, int status) { + char *file; + int success; + static int num_args = 3; + + /* Lazily set the default value for module_signing_script. */ + + if (!op->module_signing_script) { + op->module_signing_script = nvstrcat(op->kernel_source_path, + "/scripts/sign-file", NULL); + } if (status) { ui_status_begin(op, "Signing kernel module:", "Signing"); } - if (op->multiple_kernel_modules) { - build_module_instances_parameter = - nvasprintf(" NV_BUILD_MODULE_INSTANCES=%d", - NV_MAX_MODULE_INSTANCES); - } - else { - build_module_instances_parameter = nvstrdup(""); - } + file = nvstrcat(build_directory, "/", module_filename, NULL); - concurrency = nvasprintf(" -j%d ", op->concurrency_level); - cmd = nvstrcat("cd ", build_directory, "; ", op->utils[MAKE], " module-sign" - " SYSSRC=", op->kernel_source_path, - " SYSOUT=", op->kernel_output_path, - " MODSECKEY=", op->module_signing_secret_key, - " MODPUBKEY=", op->module_signing_public_key, - " BUILD_MODULES_LIST=\"nvidia", module_suffix, "\" ", - build_module_instances_parameter, - mod_sign_cmd ? mod_sign_cmd : "", - mod_sign_hash ? mod_sign_hash : "", concurrency, NULL); - nvfree(concurrency); + try_sign: - ret = run_command(op, cmd, NULL, TRUE, 20 /* XXX */, TRUE); - success = ret == 0; + success = try_sign_file(op, file, num_args); - nvfree(mod_sign_hash); - nvfree(mod_sign_cmd); - nvfree(cmd); - nvfree(build_module_instances_parameter); + /* If sign-file failed to run with three arguments, try running it with + * four arguments on all subsequent signing attempts. */ + + if (num_args == 3 && !success) { + num_args = 4; + + /* The four-arg version of sign-file needs a hash. */ + + if (!op->module_signing_hash) { + op->module_signing_hash = guess_module_signing_hash(op, + build_directory); + } + + if (op->module_signing_hash) { + goto try_sign; + } else { + ui_error(op, "The installer was unable to sign %s without " + "specifying a hash algorithm on the command line to %s, " + "and was also unable to automatically detect the hash. " + "If you need to sign the NVIDIA kernel modules, please " + "try again and set the '--module-signing-hash' option on " + "the installer's command line.", + file, op->module_signing_script); + } + } + + nvfree(file); if (status) { ui_status_end(op, success ? "done." : "Failed to sign kernel module."); } else { ui_log(op, success ? "Signed kernel module." : "Module signing failed"); } + op->kernel_module_signed = success; return success; -} /* sign_kernel_module */ +} @@ -791,7 +703,6 @@ int sign_kernel_module(Options *op, const char *build_directory, static int create_detached_signature(Options *op, Package *p, const char *build_dir, PrecompiledFileInfo *fileInfo, - const char *module_suffix, const char *module_filename) { int ret, command_ret; @@ -801,7 +712,7 @@ static int create_detached_signature(Options *op, Package *p, ui_status_begin(op, "Creating a detached signature for the linked " "kernel module:", "Linking module"); - ret = link_kernel_module(op, p, build_dir, fileInfo); + ret = unpack_kernel_modules(op, p, build_dir, fileInfo); if (!ret) { ui_error(op, "Failed to link a kernel module for signing."); @@ -825,7 +736,7 @@ static int create_detached_signature(Options *op, Package *p, ui_status_update(op, .50, "Signing linked module"); - ret = sign_kernel_module(op, target_dir, module_suffix, FALSE); + ret = sign_kernel_module(op, target_dir, module_filename, FALSE); if (!ret) { error = "Failed to sign the linked kernel module."; @@ -857,95 +768,34 @@ done: nvfree(module_path); nvfree(target_dir); return ret; -} /* create_detached_signature() */ - - -/* - * build_kernel_interface_file() - build the kernel interface(s). - * Returns true if the build was successful, or false on error. - * - * This is done by copying the sources to a temporary working - * directory and building the kernel interface in that directory. - */ - -static int build_kernel_interface_file(Options *op, const char *tmpdir, - PrecompiledFileInfo *fileInfo, - const char *kernel_interface_filename) -{ - char *cmd; - char *kernel_interface, *build_module_instances_parameter = NULL; - char *concurrency; - int ret; - - if (op->multiple_kernel_modules) { - build_module_instances_parameter = - nvasprintf(" NV_BUILD_MODULE_INSTANCES=%d", NV_MAX_MODULE_INSTANCES); - } - - concurrency = nvasprintf(" -j%d ", op->concurrency_level); - - cmd = nvstrcat("cd ", tmpdir, "; ", op->utils[MAKE], " ", - kernel_interface_filename, - " SYSSRC=", op->kernel_source_path, - " SYSOUT=", op->kernel_output_path, concurrency, - build_module_instances_parameter, NULL); - - nvfree(build_module_instances_parameter); - nvfree(concurrency); - - ret = run_command(op, cmd, NULL, TRUE, 25 /* XXX */, TRUE); - - free(cmd); - - if (ret != 0) { - ui_status_end(op, "Error."); - ui_error(op, "Unable to build the NVIDIA kernel module interface."); - /* XXX need more descriptive error message */ - return FALSE; - } - - /* check that the file exists */ - - kernel_interface = nvstrcat(tmpdir, "/", - kernel_interface_filename, NULL); - ret = access(kernel_interface, F_OK); - nvfree(kernel_interface); - - if (ret == -1) { - ui_status_end(op, "Error."); - ui_error(op, "The NVIDIA kernel module interface was not created."); - return FALSE; - } - - return TRUE; } + /* * pack_kernel_interface() - Store the input built interfaces in the * PrecompiledFileInfo array. * * Returns true if the packing was successful, or false on error. */ - static int pack_kernel_interface(Options *op, Package *p, const char *build_dir, PrecompiledFileInfo *fileInfo, - const char *module_suffix, const char *kernel_interface, const char *module_filename, - const char *core_file, - const char *target_directory) + const char *core_file) { int command_ret; + char *file_path = nvstrcat(build_dir, "/", kernel_interface, NULL); - command_ret = precompiled_read_interface(fileInfo, kernel_interface, + command_ret = precompiled_read_interface(fileInfo, file_path, module_filename, - core_file, target_directory); + core_file, "."); + + nvfree(file_path); if (command_ret) { if (op->module_signing_secret_key && op->module_signing_public_key) { if (!create_detached_signature(op, p, build_dir, fileInfo, - module_suffix, module_filename)) { return FALSE; } @@ -957,104 +807,110 @@ static int pack_kernel_interface(Options *op, Package *p, } +static void handle_optional_module_failure(Options *op, + KernelModuleInfo module, + ui_message_func msg_func, + const char *action) { + if (module.is_optional) { + msg_func(op, "The %s kernel module failed to %s. This kernel module " + "is required for the proper operation of %s. If you do not " + "need to use %s, you can try to install this driver package " + "again with the '--%s' option.", + module.module_name, action, module.optional_module_dependee, + module.optional_module_dependee, module.disable_option); + } +} -static int build_and_pack_interface(Options *op, Package *p, const char *tmpdir, - const char *subdir, - PrecompiledFileInfo *fileInfo, - const char *interface, const char *module, - const char *suffix, const char *core) -{ - int ret; - char *filename = NULL; - char *dir = NULL; - - ui_status_begin(op, "Building kernel module interface: ", "Building %s", - interface); - dir = nvstrcat(tmpdir, "/", subdir, NULL); - ret = build_kernel_interface_file(op, dir, fileInfo, interface); +static int pack_kernel_module(Options *op, + const char *build_dir, + PrecompiledFileInfo *fileInfo, + const char *module_filename) +{ + int command_ret; + char *file_path = nvstrcat(build_dir, "/", module_filename, NULL); - if (!ret) { - goto done; + if (op->module_signing_secret_key && op->module_signing_public_key) { + if (sign_kernel_module(op, build_dir, module_filename, FALSE)) { + fileInfo->attributes |= PRECOMPILED_ATTR(EMBEDDED_SIGNATURE); + } else { + ui_error(op, "Failed to sign precompiled kernel module %s!", + module_filename); + return FALSE; + } } - ui_status_end(op, "done."); + command_ret = precompiled_read_module(fileInfo, file_path, ""); - ui_log(op, "Kernel module interface compilation complete."); + nvfree(file_path); - filename = nvstrcat(dir, "/", interface, NULL); - - /* add the kernel interface to the list of files to be packaged */ - ret = pack_kernel_interface(op, p, tmpdir, fileInfo, suffix, filename, - module, core, subdir); - -done: - nvfree(dir); - nvfree(filename); + if (command_ret) { + return TRUE; + } - return ret; + return FALSE; } + /* - * build_kernel_interface() - build the kernel interface(s), and store any - * built interfaces in a newly allocated PrecompiledFileInfo array. Return - * the number of packaged interface files, or 0 on error. + * build_kernel_interfaces() - build the kernel modules and interfaces, and + * store any precompiled files in a newly allocated PrecompiledFileInfo array. + * Return the number of packaged files, or 0 on error. * - * The tmpdir created to build the kernel interface is removed before exit. + * If fileInfos is NULL, stop after building the kernel modules and do not + * build the interfaces. * - * For multi-RM, the frontend module interface should be compiled and - * packaged too. - * - * XXX this and build_kernel_module() should be merged. + * When building interfaces, copy everything into a temporary directory and + * work out of the tmpdir. For kernel module only builds, operate within + * p->kernel_module_build_directory, as later packaging steps will look for + * the built files there. If a tmpdir is created, it is removed before exit. */ -int build_kernel_interface(Options *op, Package *p, - PrecompiledFileInfo ** fileInfos) +int build_kernel_interfaces(Options *op, Package *p, + PrecompiledFileInfo ** fileInfos) { - char *tmpdir = NULL; - int files_packaged = 0, i; - int num_files = 1, ret = FALSE; - char *uvmdir = NULL; - - *fileInfos = NULL; - - /* create a temporary directory */ - - tmpdir = make_tmpdir(op); + char *tmpdir = NULL, *builddir; + int ret, files_packaged = 0, i; + + struct { + const char *sanity_check_name; + const char *conftest_name; + } sanity_checks[] = { + { "rivafb", "rivafb_sanity_check" }, + { "nvidiafb", "nvidiafb_sanity_check" }, + { "Xen", "xen_sanity_check" }, + { "PREEMPT_RT", "preempt_rt_sanity_check" }, + }; - if (!tmpdir) { - ui_error(op, "Unable to create a temporary build directory."); - return FALSE; + if (fileInfos) { + *fileInfos = NULL; } - - /* copy the kernel module sources to it */ - - ui_log(op, "Copying kernel module sources to temporary directory."); - if (!copy_directory_contents - (op, p->kernel_module_build_directory, tmpdir)) { - ui_error(op, "Unable to copy the kernel module sources to temporary " - "directory '%s'.", tmpdir); - goto failed; - } + /* create a temporary directory if we will be packing interfaces */ - uvmdir = nvstrcat(tmpdir, "/" UVM_SUBDIR, NULL); + if (fileInfos) { + tmpdir = make_tmpdir(op); + builddir = tmpdir; - if (op->install_uvm) { - if (!mkdir_recursive(op, uvmdir, 0655, FALSE)) { - ui_error(op, "Unable to create a temporary subdirectory for the " - "Unified Memory kernel module build."); - goto failed; + if (!tmpdir) { + ui_error(op, "Unable to create a temporary build directory."); + goto done; } - if (!copy_directory_contents(op, - p->uvm_module_build_directory, uvmdir)) { - ui_error(op, "Unable to copy the Unified Memory kernel module " - "sources to temporary directory '%s'.", uvmdir); - goto failed; + /* copy the kernel module sources to it */ + + ui_log(op, "Copying kernel module sources to temporary directory."); + + if (!copy_directory_contents + (op, p->kernel_module_build_directory, tmpdir)) { + ui_error(op, "Unable to copy the kernel module sources to temporary " + "directory '%s'.", tmpdir); + goto done; } + } else { + builddir = p->kernel_module_build_directory; } /* @@ -1062,81 +918,76 @@ int build_kernel_interface(Options *op, Package *p, * skew error messages */ - touch_directory(op, p->kernel_module_build_directory); - - if (op->multiple_kernel_modules) { - num_files = op->num_kernel_modules; - } - - *fileInfos = nvalloc(sizeof(PrecompiledFileInfo) * (num_files + 2)); - - for (i = 0; i < num_files; i++) { - char *kernel_module_filename; - char *kernel_interface_filename; - char *module_instance_str = NULL; - - if (op->multiple_kernel_modules) { - module_instance_str = nvasprintf("%d", i); - } else { - module_instance_str = nvstrdup(""); + /* run sanity checks */ + for (i = 0; i < ARRAY_LEN(sanity_checks); i++) { + if (!sanity_check(op, builddir, + sanity_checks[i].sanity_check_name, + sanity_checks[i].conftest_name)) { + return FALSE; } + } - kernel_interface_filename = nvstrdup(p->kernel_interface_filename); - replace_zero(kernel_interface_filename, i); - - kernel_module_filename = nvstrdup(p->kernel_module_filename); - replace_zero(kernel_module_filename, i); - - ret = build_and_pack_interface(op, p, tmpdir, "", *fileInfos + i, - kernel_interface_filename, - kernel_module_filename, - module_instance_str, "nv-kernel.o"); - - if (!ret) { - goto interface_done; + ui_log(op, "Cleaning kernel module build directory."); + run_make(op, p, builddir, "clean", NULL, NULL, 0); + ret = run_make(op, p, builddir, "", NULL, "Building kernel modules", 25); + + /* Test to make sure that all kernel modules were built. */ + for (i = 0; i < p->num_kernel_modules; i++) { + if (!check_file(op, builddir, p->kernel_modules[i].module_name)) { + handle_optional_module_failure(op, + p->kernel_modules[i], ui_error, + "build"); + goto done; } + } -interface_done: - - nvfree(kernel_interface_filename); - nvfree(kernel_module_filename); - nvfree(module_instance_str); - - if (!ret) - goto failed; - - files_packaged++; + /* + * Now check the status of the overall build: it may have failed, despite + * having produced all expected kernel modules. + */ + if (!ret) { + goto done; } - if (op->multiple_kernel_modules) { - ret = build_and_pack_interface(op, p, tmpdir, "", *fileInfos + num_files, - p->kernel_frontend_interface_filename, - p->kernel_frontend_module_filename, - "-frontend", ""); - if (!ret) { - goto failed; - } + ui_log(op, "Kernel module compilation complete."); - files_packaged++; + /* + * If we're not building interfaces, return the number of built modules + * instead of the number of packaged interfaces. + */ + if (fileInfos == NULL) { + /* If we've made it this far, all the modules were built. */ + files_packaged = p->num_kernel_modules; + goto done; } - if (op->install_uvm) { - ret = build_and_pack_interface(op, p, tmpdir, UVM_SUBDIR, - *fileInfos + files_packaged, - p->uvm_interface_filename, - p->uvm_kernel_module_filename, "-uvm", ""); + *fileInfos = nvalloc(sizeof(PrecompiledFileInfo) * + (p->num_kernel_modules + 1)); - if (!ret) { - goto failed; - } + for (files_packaged = 0; + files_packaged < p->num_kernel_modules; + files_packaged++) { + PrecompiledFileInfo *fileInfo = *fileInfos + files_packaged; + KernelModuleInfo *module = p->kernel_modules + files_packaged; - files_packaged++; + if (module->has_separate_interface_file) { + if (!(run_make(op, p, tmpdir, module->interface_filename, + NULL, NULL, 0) && + pack_kernel_interface(op, p, tmpdir, fileInfo, + module->interface_filename, + module->module_filename, + module->core_object_name))) { + goto done; + } + } else if (!pack_kernel_module(op, tmpdir, fileInfo, + module->module_filename)) { + goto done; + } } -failed: - nvfree(uvmdir); +done: - if (files_packaged == 0) { + if (files_packaged == 0 && fileInfos) { nvfree(*fileInfos); *fileInfos = NULL; } @@ -1147,8 +998,7 @@ failed: } return files_packaged; - -} /* build_kernel_interface() */ +} @@ -1503,17 +1353,31 @@ static int ignore_load_error(Options *op, Package *p, /* + * attempt to unload all kernel modules, but don't abort if this fails: the + * kernel may not have been configured with support for module unloading + * (Linux 2.6). + */ + +static void unload_kernel_modules(Options *op, Package *p) { + int i; + + for (i = p->num_kernel_modules - 1; i >= 0; i--) { + rmmod_kernel_module(op, p->kernel_modules[i].module_name); + } +} + + +/* * test_kernel_module() - attempt to insmod the kernel modules and then rmmod * them. Return TRUE if the insmod succeeded, or FALSE otherwise. */ int test_kernel_modules(Options *op, Package *p) { - char *cmd = NULL, *data = NULL, *module_path; + char *cmd = NULL, *data = NULL; int ret, i; const char *depmods[] = { "i2c-core", "drm" }; - /* * If we're building/installing for a different kernel, then we * can't test the module now. @@ -1530,56 +1394,44 @@ int test_kernel_modules(Options *op, Package *p) load_kernel_module_quiet(op, depmods[i]); } - if (op->multiple_kernel_modules) { - /* Load nvidia-frontend.ko */ - - module_path = nvstrcat(p->kernel_module_build_directory, "/", - p->kernel_frontend_module_filename, NULL); - ret = do_insmod(op, module_path, &data, ""); - nvfree(module_path); - - if (ret != 0) { - ret = ignore_load_error(op, p, p->kernel_frontend_module_filename, - data, ret); - goto test_exit; - } - - nvfree(data); - } - - /* - * Load nvidia0.ko while building multiple kernel modules or - * load nvidia.ko for non-multiple-kernel-module/simple builds. + /* + * Attempt to load each kernel module one at a time. The order of the list + * in the package manifest is set such that loading modules in that order + * should satisfy any dependencies that exist between modules. */ - module_path = nvstrcat(p->kernel_module_build_directory, "/", - p->kernel_module_filename, NULL); - ret = do_insmod(op, module_path, &data, - "NVreg_DeviceFileUID=0 NVreg_DeviceFileGID=0 " - "NVreg_DeviceFileMode=0 NVreg_ModifyDeviceFiles=0"); - - nvfree(module_path); + for (i = 0; i < p->num_kernel_modules; i++) { + int module_success = FALSE; + char *cmd_output; + char *module_path = nvstrcat(p->kernel_module_build_directory, "/", + p->kernel_modules[i].module_filename, + NULL); + const char *module_opts = ""; + + if (strcmp(p->kernel_modules[i].module_name, "nvidia") == 0) { + module_opts = "NVreg_DeviceFileUID=0 NVreg_DeviceFileGID=0 " + "NVreg_DeviceFileMode=0 NVreg_ModifyDeviceFiles=0"; + } - if (ret != 0) { - ret = ignore_load_error(op, p, p->kernel_module_filename, data, ret); - goto test_exit; - } - if (op->install_uvm) { - module_path = nvstrcat(p->uvm_module_build_directory, "/", - p->uvm_kernel_module_filename, NULL); - ret = do_insmod(op, module_path, &data, ""); + ret = do_insmod(op, module_path, &cmd_output, module_opts); nvfree(module_path); - if (ret != 0) { - ret = ignore_load_error(op, p, p->uvm_kernel_module_filename, data, - ret); + if (ret == 0) { + module_success = TRUE; + } else { + ret = ignore_load_error(op, p, p->kernel_modules[i].module_filename, + cmd_output, ret); if (ret) { - ui_warn(op, "The NVIDIA Unified Memory module failed to load, " - "and the load failure was ignored. This module is " - "required in order for the CUDA driver to function; if " - "the load failure cannot be resolved, then this system " - "will be unable to run CUDA applications."); + op->load_error_ignored = TRUE; + handle_optional_module_failure(op, + p->kernel_modules[i], ui_warn, + "load"); } + } + + nvfree(cmd_output); + + if (!module_success) { goto test_exit; } } @@ -1592,27 +1444,11 @@ int test_kernel_modules(Options *op, Package *p) check_for_warning_messages(op); - /* - * attempt to unload the kernel modules, but don't abort if this fails: - * the kernel may not have been configured with support for module unloading - * (Linux 2.6). - */ - - if (op->install_uvm) { - rmmod_kernel_module(op, p->uvm_kernel_module_name); - } - - rmmod_kernel_module(op, p->kernel_module_name); - - if (op->multiple_kernel_modules) { - rmmod_kernel_module(op, p->kernel_frontend_module_name); - } + unload_kernel_modules(op, p); ret = TRUE; test_exit: - nvfree(data); - /* * display/log the last few lines of the kernel ring buffer * to provide further details in case of a load failure or @@ -1652,8 +1488,12 @@ test_exit: static int modprobe_helper(Options *op, const char *module_name, int quiet, int unload) { + int ret = 0, old_loglevel, loglevel_set; char *cmd, *data; - int ret, old_loglevel, loglevel_set; + + if (op->load_error_ignored) { + return TRUE; + } cmd = nvstrcat(op->utils[MODPROBE], quiet ? " -q" : "", @@ -1662,37 +1502,31 @@ static int modprobe_helper(Options *op, const char *module_name, NULL); loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel); - + ret = run_command(op, cmd, &data, FALSE, 0, TRUE); if (loglevel_set) { set_loglevel(old_loglevel, NULL); } + nvfree(cmd); + if (!quiet && ret != 0) { - if (op->expert) { - ui_error(op, "Unable to %s the kernel module: '%s'", - unload ? "unload" : "load", - data); - } else { - ui_error(op, "Unable to %s the kernel module.", - unload ? "unload" : "load"); - } - ret = FALSE; - } else { - ret = TRUE; + char *expert_detail = nvstrcat(": '", data, "'", NULL); + ui_error(op, "Unable to %s the '%s' kernel module%s", + unload ? "unload" : "load", module_name, + op->expert? expert_detail : "."); + nvfree(expert_detail); } - nvfree(cmd); nvfree(data); - - return ret; -} /* load_kernel_module() */ + return ret == 0; +} -int load_kernel_module(Options *op, Package *p) +int load_kernel_module(Options *op, const char *module_name) { - return modprobe_helper(op, p->kernel_module_name, FALSE, FALSE); + return modprobe_helper(op, module_name, FALSE, FALSE); } static void load_kernel_module_quiet(Options *op, const char *module_name) @@ -1705,6 +1539,24 @@ static void modprobe_remove_kernel_module_quiet(Options *op, const char *name) modprobe_helper(op, name, TRUE, TRUE); } +/* + * Attempt to load all kernel modules that are part of the Package. Returns + * the number of successfully loaded kernel modules. + */ +int load_kernel_modules(Options *op, Package *p) +{ + int i; + + for (i = 0; i < p->num_kernel_modules; i++) { + if (!load_kernel_module(op, p->kernel_modules[i].module_name)) { + break; + } + } + + return i; +} + + /* * check_for_unloaded_kernel_module() - test if any of the "bad" @@ -1712,11 +1564,11 @@ static void modprobe_remove_kernel_module_quiet(Options *op, const char *name) * we can't unload it, then report an error and return FALSE; */ -int check_for_unloaded_kernel_module(Options *op, Package *p) +int check_for_unloaded_kernel_module(Options *op) { - int n = 0; + int n; int loaded = FALSE; - unsigned int bits = 0; + unsigned long long int bits = 0; /* * We can skip this check if we are installing for a non-running @@ -1741,30 +1593,27 @@ int check_for_unloaded_kernel_module(Options *op, Package *p) return TRUE; } - while (p->bad_modules[n]) { - if (check_for_loaded_kernel_module(op, p->bad_modules[n])) { + for (n = 0; n < num_conflicting_kernel_modules; n++) { + if (check_for_loaded_kernel_module(op, conflicting_kernel_modules[n])) { loaded = TRUE; bits |= (1 << n); } - n++; } if (!loaded) return TRUE; /* one or more kernel modules is loaded... try to unload them */ - n = 0; - while (p->bad_modules[n]) { + for (n = 0; n < num_conflicting_kernel_modules; n++) { if (!(bits & (1 << n))) { - n++; continue; } - rmmod_kernel_module(op, p->bad_modules[n]); + rmmod_kernel_module(op, conflicting_kernel_modules[n]); /* check again */ - if (check_for_loaded_kernel_module(op, p->bad_modules[n])) { + if (check_for_loaded_kernel_module(op, conflicting_kernel_modules[n])) { ui_error(op, "An NVIDIA kernel module '%s' appears to already " "be loaded in your kernel. This may be because it is " "in use (for example, by an X server, a CUDA program, " @@ -1778,11 +1627,10 @@ int check_for_unloaded_kernel_module(Options *op, Package *p) "error may have occured that has corrupted an NVIDIA " "kernel module's usage count, for which the simplest " "remedy is to reboot your computer.", - p->bad_modules[n]); + conflicting_kernel_modules[n]); return FALSE; } - n++; } return TRUE; @@ -1791,44 +1639,6 @@ int check_for_unloaded_kernel_module(Options *op, Package *p) /* - * add_file_to_search_filelist() - Add file to build a list - * of files expected to be unpacked. - */ - -static void add_file_to_search_filelist(char **search_filelist, char *filename) -{ - int index = 0; - - while(search_filelist[index]) { - index++; - } - - if (index == SEARCH_FILELIST_MAX_ENTRIES) - return; - - search_filelist[index] = nvstrdup(filename); - -} /* add_file_to_search_filelist() */ - - -/* - * free_search_filelist() - frees the list of files expected - * to unpack - */ - -static void free_search_filelist(char **search_filelist) -{ - int index = 0; - - while (search_filelist[index]) { - free(search_filelist[index]); - index++; - } - -} /*free_search_filelist() */ - - -/* * find_precompiled_kernel_interface() - do assorted black magic to * determine if the given package contains a precompiled kernel interface * for the kernel on this system. @@ -1841,8 +1651,8 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p) { char *proc_version_string, *tmp; PrecompiledInfo *info = NULL; - char *search_filelist[SEARCH_FILELIST_MAX_ENTRIES+1]; - int index; + char **search_filelist = NULL; + int i; /* allow the user to completely skip this search */ @@ -1862,19 +1672,14 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p) if (!mkdir_recursive(op, p->kernel_module_build_directory, 0755, FALSE)) goto done; - memset(search_filelist, 0, sizeof(search_filelist)); + search_filelist = nvalloc(p->num_kernel_modules * sizeof(char*)); - if (op->multiple_kernel_modules) { - add_file_to_search_filelist(search_filelist, - p->kernel_frontend_interface_filename); - } - - for (index = 0; index < op->num_kernel_modules; index++) { - char *tmp; - tmp = nvstrdup(p->kernel_interface_filename); - replace_zero(tmp, index); - add_file_to_search_filelist(search_filelist, tmp); - free(tmp); + for (i = 0; i < p->num_kernel_modules; i++) { + if (p->kernel_modules[i].has_separate_interface_file) { + search_filelist[i] = p->kernel_modules[i].interface_filename; + } else { + search_filelist[i] = p->kernel_modules[i].module_filename; + } } /* @@ -1926,13 +1731,10 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p) "found at '%s'; this means that the installer will need " "to compile a kernel interface for your kernel.", op->precompiled_kernel_interfaces_url); - free_search_filelist(search_filelist); goto done; } } - free_search_filelist(search_filelist); - /* If we found one, ask expert users if they really want to use it */ if (info && op->expert) { @@ -1953,6 +1755,8 @@ PrecompiledInfo *find_precompiled_kernel_interface(Options *op, Package *p) done: + nvfree(search_filelist); + nvfree(proc_version_string); if (!info && op->expert) { @@ -2006,7 +1810,8 @@ KernelConfigOptionStatus test_kernel_config_option(Options* op, Package *p, char *conftest_cmd; conftest_cmd = nvstrcat("test_configuration_option ", option, NULL); - ret = run_conftest(op, p, conftest_cmd, NULL); + ret = run_conftest(op, p->kernel_module_build_directory, conftest_cmd, + NULL); nvfree(conftest_cmd); return ret ? KERNEL_CONFIG_OPTION_DEFINED : @@ -2023,11 +1828,12 @@ KernelConfigOptionStatus test_kernel_config_option(Options* op, Package *p, * signing kernel modules, or NULL if it can't be determined. */ -char *guess_module_signing_hash(Options *op, Package *p) +char *guess_module_signing_hash(Options *op, const char *build_directory) { char *ret; - if (run_conftest(op, p, "guess_module_signing_hash", &ret)) { + if (run_conftest(op, build_directory, + "guess_module_signing_hash", &ret)) { return ret; } @@ -2525,7 +2331,8 @@ int check_cc_version(Options *op, Package *p) dummyop.kernel_source_path = "DUMMY_SOURCE_PATH"; dummyop.kernel_output_path = "DUMMY_OUTPUT_PATH"; - ret = run_conftest(&dummyop, p, "cc_version_check just_msg", &result); + ret = run_conftest(&dummyop, p->kernel_module_build_directory, + "cc_version_check just_msg", &result); if (ret) return TRUE; @@ -2546,100 +2353,30 @@ int check_cc_version(Options *op, Package *p) /* - * fbdev_check() - run the rivafb_sanity_check and the nvidiafb_sanity_check - * conftests; if either test fails, print the error message from the test - * and abort the driver installation. + * sanity_check() - run the given sanity check conftest; if the test fails, + * print the error message from the test. Return the status from the test. */ -static int fbdev_check(Options *op, Package *p) +static int sanity_check(Options *op, const char *dir, + const char *sanity_check_name, + const char *conftest_name) { - char *result; + char *result, *conftest_args; int ret; - - ui_log(op, "Performing rivafb check."); - - ret = run_conftest(op, p,"rivafb_sanity_check just_msg", &result); - - if (!ret) { - if (result) - ui_error(op, "%s", result); - nvfree(result); - return FALSE; - } + ui_log(op, "Performing %s check.", sanity_check_name); - ui_log(op, "Performing nvidiafb check."); - - ret = run_conftest(op, p,"nvidiafb_sanity_check just_msg", &result); - - if (!ret) { - if (result) - ui_error(op, "%s", result); - nvfree(result); + conftest_args = nvstrcat(conftest_name, " just_msg", NULL); + ret = run_conftest(op, dir, conftest_args, &result); + nvfree(conftest_args); - return FALSE; + if (!ret && result) { + ui_error(op, "%s", result); } - return TRUE; - -} /* fbdev_check() */ - - - -/* - * xen_check() - run the xen_sanity_check conftest; if this test fails, print - * the test's error message and abort the driver installation. - */ - -static int xen_check(Options *op, Package *p) -{ - char *result; - int ret; - - ui_log(op, "Performing Xen check."); - - ret = run_conftest(op, p,"xen_sanity_check just_msg", &result); - - if (!ret) { - if (result) - ui_error(op, "%s", result); - nvfree(result); - - return FALSE; - } - - return TRUE; - -} /* xen_check() */ - - - -/* - * preempt_rt_check() - run the preempt_rt_sanity_check conftest; if this - * test fails, print the test's error message and abort the driver - * installation. - */ - -static int preempt_rt_check(Options *op, Package *p) -{ - char *result; - int ret; - - ui_log(op, "Performing PREEMPT_RT check."); - - ret = run_conftest(op, p, "preempt_rt_sanity_check just_msg", &result); - - if (!ret) { - if (result) - ui_error(op, "%s", result); - nvfree(result); - - return FALSE; - } - - return TRUE; - -} /* preempt_rt_check() */ + nvfree(result); + return ret; +} @@ -2786,3 +2523,132 @@ char *get_machine_arch(Options *op) } } /* get_machine_arch() */ + +/* + * Run `make` with the specified target and make variables. The variables + * are given in the form of a NULL-terminated array of alternating key + * and value strings, e.g. { "KEY1", "value1", "KEY2", "value2", NULL }. + * If a 'status' string is given, then a ui_status progress bar is shown + * using 'status' as the initial message, expecting 'lines' lines of output + * from the make command. + */ +static int run_make(Options *op, Package *p, char *dir, const char *target, + char **vars, const char *status, int lines) { + char *cmd, *concurrency, *data = NULL; + int i = 0, ret; + + concurrency = nvasprintf(" -j%d ", op->concurrency_level); + + cmd = nvstrcat("cd ", dir, "; ", + op->utils[MAKE], " -k", concurrency, target, + " NV_EXCLUDE_KERNEL_MODULES=\"", + p->excluded_kernel_modules, "\"", + " SYSSRC=\"", op->kernel_source_path, "\"", + " SYSOUT=\"", op->kernel_output_path, "\"", + NULL); + nvfree(concurrency); + + if (vars) { + while (vars[i] && vars[i+1]) { + char *old_cmd = cmd; + + cmd = nvstrcat(old_cmd, " ", vars[i], "=\"", vars[i+1], "\"", NULL); + nvfree(old_cmd); + i += 2; + } + } + + if (status) { + ui_status_begin(op, status, ""); + } + + ret = (run_command(op, cmd, &data, TRUE, status ? lines : 0, TRUE) == 0); + + if (status) { + if (ret) { + ui_status_end(op, "done."); + } else { + ui_status_end(op, "Error."); + } + } + + if (!ret) { + char *status_extra; + + if (status) { + status_extra = nvasprintf(" while performing the step: \"%s\"", + status); + } else { + status_extra = nvstrdup(""); + } + + ui_error(op, "An error occurred%s. See " DEFAULT_LOG_FILE_NAME + " for details.", status_extra); + ui_log(op, "The command `%s` failed with the following output:\n\n%s", + cmd, data); + nvfree(status_extra); + } + + nvfree(cmd); + nvfree(data); + + return ret; +} + + +/* + * Remove any instances of kernel module 'module' from the kernel modules + * list in the package. + */ +int remove_kernel_module_from_package(Package *p, const char *module) +{ + int i, found = 0; + + for (i = 0; i < p->num_kernel_modules; i++) { + if (found) { + p->kernel_modules[i - found] = p->kernel_modules[i]; + } + + if (strcmp(p->kernel_modules[i].module_name, module) == 0) { + free_kernel_module_info(p->kernel_modules[i]); + found++; + } + } + + if (found) { + char *old_exclude_list; + + p->num_kernel_modules -= found; + old_exclude_list = p->excluded_kernel_modules; + p->excluded_kernel_modules = nvstrcat(module, " ", old_exclude_list, + NULL); + nvfree(old_exclude_list); + } + + return found; +} + + +void free_kernel_module_info(KernelModuleInfo info) +{ + nvfree(info.module_name); + nvfree(info.module_filename); + if (info.has_separate_interface_file) { + nvfree(info.interface_filename); + nvfree(info.core_object_name); + } +} + + +int package_includes_kernel_module(const Package *p, const char *module) +{ + int i; + + for (i = 0; i < p->num_kernel_modules; i++) { + if (strcmp(p->kernel_modules[i].module_name, module) == 0) { + return TRUE; + } + } + + return FALSE; +} @@ -32,26 +32,29 @@ typedef enum { int determine_kernel_module_installation_path (Options*); int determine_kernel_source_path (Options*, Package*); int determine_kernel_output_path (Options*); -int link_kernel_module (Options*, Package*, +int unpack_kernel_modules (Options*, Package*, const char *, const PrecompiledFileInfo *); int check_cc_version (Options*, Package*); int build_kernel_modules (Options*, Package*); -int build_kernel_interface (Options*, Package*, +int build_kernel_interfaces (Options*, Package*, PrecompiledFileInfo **); int test_kernel_modules (Options*, Package*); -int load_kernel_module (Options*, Package*); -int check_for_unloaded_kernel_module (Options*, Package*); +int load_kernel_module (Options*, const char*); +int load_kernel_modules (Options*, Package*); +int check_for_unloaded_kernel_module (Options*); PrecompiledInfo *find_precompiled_kernel_interface (Options*, Package*); char *get_kernel_name (Options*); KernelConfigOptionStatus test_kernel_config_option (Options*, Package*, const char*); int sign_kernel_module (Options*, const char*, const char*, int); -char *guess_module_signing_hash (Options*, Package*); -int rmmod_kernel_module (Options*, const char*); - -#define SEARCH_FILELIST_MAX_ENTRIES 32 +char *guess_module_signing_hash (Options*, const char*); +int remove_kernel_module_from_package (Package*, const char*); +void free_kernel_module_info (KernelModuleInfo); +int package_includes_kernel_module (const Package*, + const char *); +int rmmod_kernel_module (Options*, const char *); #ifndef ENOKEY #define ENOKEY 126 /* Required key not available */ @@ -33,7 +33,8 @@ _is_shared_lib, \ _is_opengl, \ _is_temporary, \ - _is_wrapper) \ + _is_wrapper, \ + _inherit_path) \ #_name , FILE_TYPE_ ## _name , \ { \ .has_arch = _has_arch, \ @@ -45,6 +46,7 @@ .is_opengl = _is_opengl, \ .is_temporary = _is_temporary, \ .is_wrapper = _is_wrapper, \ + .inherit_path = _inherit_path, \ } /* @@ -58,65 +60,65 @@ static const struct { } packageEntryFileTypeTable[] = { /* - * is_wrapper ---------------------------------------+ - * is_temporary ------------------------------------+ | - * is_opengl ---------------------------------+ | | - * is_shared_lib ------------------------------+ | | | - * is_symlink ---------------------------+ | | | | - * has_path ------------------------+ | | | | | - * installable ---------------------+ | | | | | | - * has_tls_class ------------------+ | | | | | | | - * has_arch ---------------+ | | | | | | | | - * | | | | | | | | | + * inherit_path ------------------------------------------+ + * is_wrapper ---------------------------------------+ | + * is_temporary ------------------------------------+ | | + * is_opengl ---------------------------------+ | | | + * is_shared_lib ------------------------------+ | | | | + * is_symlink ---------------------------+ | | | | | + * has_path ------------------------+ | | | | | | + * installable ---------------------+ | | | | | | | + * has_tls_class ------------------+ | | | | | | | | + * has_arch ---------------+ | | | | | | | | | + * | | | | | | | | | | */ - { ENTRY(KERNEL_MODULE_SRC, F, F, T, F, F, F, F, F, F) }, - { ENTRY(KERNEL_MODULE_CMD, F, F, F, F, F, F, F, F, F) }, - { ENTRY(KERNEL_MODULE, F, F, T, F, F, F, F, F, F) }, - { ENTRY(OPENGL_HEADER, F, F, T, T, F, F, T, F, F) }, - { ENTRY(CUDA_ICD, F, F, T, F, F, F, F, F, F) }, - { ENTRY(OPENGL_LIB, T, F, T, F, F, T, T, F, F) }, - { ENTRY(CUDA_LIB, T, F, T, T, F, T, F, F, F) }, - { ENTRY(OPENCL_LIB, T, F, T, T, F, T, F, F, F) }, - { ENTRY(OPENCL_WRAPPER_LIB, T, F, T, T, F, T, F, F, T) }, - { ENTRY(OPENCL_LIB_SYMLINK, T, F, F, T, T, F, F, F, F) }, - { ENTRY(OPENCL_WRAPPER_SYMLINK, T, F, F, T, T, F, F, F, T) }, - { ENTRY(LIBGL_LA, T, F, T, F, F, F, T, T, F) }, - { ENTRY(TLS_LIB, T, T, T, T, F, T, T, F, F) }, - { ENTRY(UTILITY_LIB, T, F, T, F, F, T, F, F, F) }, - { ENTRY(DOCUMENTATION, F, F, T, T, F, F, F, F, F) }, - { ENTRY(APPLICATION_PROFILE, F, F, T, T, F, F, F, F, F) }, - { ENTRY(MANPAGE, F, F, T, T, F, F, F, F, F) }, - { ENTRY(EXPLICIT_PATH, F, F, T, T, F, F, F, F, F) }, - { ENTRY(OPENGL_SYMLINK, T, F, F, F, T, F, T, F, F) }, - { ENTRY(CUDA_SYMLINK, T, F, F, T, T, F, F, F, F) }, - { ENTRY(TLS_SYMLINK, T, T, F, T, T, F, T, F, F) }, - { ENTRY(UTILITY_LIB_SYMLINK, T, F, F, F, T, F, F, F, F) }, - { ENTRY(INSTALLER_BINARY, F, F, T, F, F, F, F, F, F) }, - { ENTRY(UTILITY_BINARY, F, F, T, F, F, F, F, F, F) }, - { ENTRY(UTILITY_BIN_SYMLINK, F, F, F, F, T, F, F, F, F) }, - { ENTRY(DOT_DESKTOP, F, F, T, T, F, F, F, T, F) }, - { ENTRY(XMODULE_SHARED_LIB, F, F, T, T, F, T, F, F, F) }, - { ENTRY(XMODULE_SYMLINK, F, F, F, T, T, F, F, F, F) }, - { ENTRY(GLX_MODULE_SHARED_LIB, F, F, T, T, F, T, T, F, F) }, - { ENTRY(GLX_MODULE_SYMLINK, F, F, F, T, T, F, T, F, F) }, - { ENTRY(XMODULE_NEWSYM, F, F, F, T, T, F, F, F, F) }, - { ENTRY(VDPAU_LIB, T, F, T, T, F, T, F, F, F) }, - { ENTRY(VDPAU_WRAPPER_LIB, T, F, T, T, F, T, F, F, T) }, - { ENTRY(VDPAU_SYMLINK, T, F, F, T, T, F, F, F, F) }, - { ENTRY(VDPAU_WRAPPER_SYMLINK, T, F, F, T, T, F, F, F, T) }, - { ENTRY(NVCUVID_LIB, T, F, T, F, F, T, F, F, F) }, - { ENTRY(NVCUVID_LIB_SYMLINK, T, F, F, F, T, F, F, F, F) }, - { ENTRY(ENCODEAPI_LIB, T, F, T, F, F, T, F, F, F) }, - { ENTRY(ENCODEAPI_LIB_SYMLINK, T, F, F, F, T, F, F, F, F) }, - { ENTRY(VGX_LIB, F, F, T, F, F, T, F, F, F) }, - { ENTRY(VGX_LIB_SYMLINK, F, F, F, F, T, F, F, F, F) }, - { ENTRY(NVIDIA_MODPROBE, F, F, T, T, F, F, F, F, F) }, - { ENTRY(NVIDIA_MODPROBE_MANPAGE,F, F, T, T, F, F, F, F, F) }, - { ENTRY(MODULE_SIGNING_KEY, F, F, T, F, F, F, F, T, F) }, - { ENTRY(NVIFR_LIB, T, F, T, F, F, T, F, F, F) }, - { ENTRY(NVIFR_LIB_SYMLINK, T, F, F, F, T, F, F, F, F) }, - { ENTRY(UVM_MODULE_SRC, F, F, T, F, F, F, F, F, F) }, - { ENTRY(XORG_OUTPUTCLASS_CONFIG,F, F, T, F, F, F, F, F, F) }, + { ENTRY(KERNEL_MODULE_SRC, F, F, T, F, F, F, F, F, F, T) }, + { ENTRY(KERNEL_MODULE, F, F, T, F, F, F, F, F, F, F) }, + { ENTRY(OPENGL_HEADER, F, F, T, T, F, F, T, F, F, F) }, + { ENTRY(CUDA_ICD, F, F, T, F, F, F, F, F, F, F) }, + { ENTRY(OPENGL_LIB, T, F, T, F, F, T, T, F, F, F) }, + { ENTRY(CUDA_LIB, T, F, T, T, F, T, F, F, F, F) }, + { ENTRY(OPENCL_LIB, T, F, T, T, F, T, F, F, F, F) }, + { ENTRY(OPENCL_WRAPPER_LIB, T, F, T, T, F, T, F, F, T, F) }, + { ENTRY(OPENCL_LIB_SYMLINK, T, F, F, T, T, F, F, F, F, F) }, + { ENTRY(OPENCL_WRAPPER_SYMLINK, T, F, F, T, T, F, F, F, T, F) }, + { ENTRY(LIBGL_LA, T, F, T, F, F, F, T, T, F, F) }, + { ENTRY(TLS_LIB, T, T, T, T, F, T, T, F, F, F) }, + { ENTRY(UTILITY_LIB, T, F, T, F, F, T, F, F, F, F) }, + { ENTRY(DOCUMENTATION, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(APPLICATION_PROFILE, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(MANPAGE, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(EXPLICIT_PATH, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(OPENGL_SYMLINK, T, F, F, F, T, F, T, F, F, F) }, + { ENTRY(CUDA_SYMLINK, T, F, F, T, T, F, F, F, F, F) }, + { ENTRY(TLS_SYMLINK, T, T, F, T, T, F, T, F, F, F) }, + { ENTRY(UTILITY_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F) }, + { ENTRY(INSTALLER_BINARY, F, F, T, F, F, F, F, F, F, F) }, + { ENTRY(UTILITY_BINARY, F, F, T, F, F, F, F, F, F, F) }, + { ENTRY(UTILITY_BIN_SYMLINK, F, F, F, F, T, F, F, F, F, F) }, + { ENTRY(DOT_DESKTOP, F, F, T, T, F, F, F, T, F, F) }, + { ENTRY(XMODULE_SHARED_LIB, F, F, T, T, F, T, F, F, F, F) }, + { ENTRY(XMODULE_SYMLINK, F, F, F, T, T, F, F, F, F, F) }, + { ENTRY(GLX_MODULE_SHARED_LIB, F, F, T, T, F, T, T, F, F, F) }, + { ENTRY(GLX_MODULE_SYMLINK, F, F, F, T, T, F, T, F, F, F) }, + { ENTRY(XMODULE_NEWSYM, F, F, F, T, T, F, F, F, F, F) }, + { ENTRY(VDPAU_LIB, T, F, T, T, F, T, F, F, F, F) }, + { ENTRY(VDPAU_WRAPPER_LIB, T, F, T, T, F, T, F, F, T, F) }, + { ENTRY(VDPAU_SYMLINK, T, F, F, T, T, F, F, F, F, F) }, + { ENTRY(VDPAU_WRAPPER_SYMLINK, T, F, F, T, T, F, F, F, T, F) }, + { ENTRY(NVCUVID_LIB, T, F, T, F, F, T, F, F, F, F) }, + { ENTRY(NVCUVID_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F) }, + { ENTRY(ENCODEAPI_LIB, T, F, T, F, F, T, F, F, F, F) }, + { ENTRY(ENCODEAPI_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F) }, + { ENTRY(VGX_LIB, F, F, T, F, F, T, F, F, F, F) }, + { ENTRY(VGX_LIB_SYMLINK, F, F, F, F, T, F, F, F, F, F) }, + { ENTRY(NVIDIA_MODPROBE, F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(NVIDIA_MODPROBE_MANPAGE,F, F, T, T, F, F, F, F, F, F) }, + { ENTRY(MODULE_SIGNING_KEY, F, F, T, F, F, F, F, T, F, F) }, + { ENTRY(NVIFR_LIB, T, F, T, F, F, T, F, F, F, F) }, + { ENTRY(NVIFR_LIB_SYMLINK, T, F, F, F, T, F, F, F, F, F) }, + { ENTRY(XORG_OUTPUTCLASS_CONFIG,F, F, T, F, F, F, F, F, F, F) }, + { ENTRY(DKMS_CONF ,F, F, T, F, F, F, F, T, F, T) }, }; /* @@ -128,7 +130,7 @@ PackageEntryFileCapabilities get_file_type_capabilities( ) { int i; - PackageEntryFileCapabilities nullCaps = { F, F, F, F, F, F, F, F, F }; + PackageEntryFileCapabilities nullCaps = { F, F, F, F, F, F, F, F, F, F }; for (i = 0; i < ARRAY_LEN(packageEntryFileTypeTable); i++) { if (type == packageEntryFileTypeTable[i].type) { @@ -182,7 +184,7 @@ void get_installable_file_type_list( } if (((type == FILE_TYPE_KERNEL_MODULE_SRC) || - (type == FILE_TYPE_UVM_MODULE_SRC)) && + (type == FILE_TYPE_DKMS_CONF)) && op->no_kernel_module_source) { continue; } @@ -1248,7 +1248,7 @@ void should_install_uvm(Options *op, Package *p) { /* if the package does not include UVM, it can't be installed. */ - if (!op->uvm_files_packaged) { + if (!package_includes_kernel_module(p, "nvidia-uvm")) { op->install_uvm = FALSE; return; } @@ -1266,6 +1266,8 @@ void should_install_uvm(Options *op, Package *p) ui_warn(op, "The NVIDIA Unified Memory kernel module will not be " "installed. As a result, CUDA applications will not be able to " "run with this installation of the NVIDIA driver."); + + remove_kernel_module_from_package(p, "nvidia-uvm"); } } diff --git a/nvidia-installer.c b/nvidia-installer.c index 94300f1..92176a9 100644 --- a/nvidia-installer.c +++ b/nvidia-installer.c @@ -145,9 +145,9 @@ static Options *load_default_options(void) op->dkms = FALSE; op->install_vdpau_wrapper = NV_OPTIONAL_BOOL_DEFAULT; op->check_for_alternate_installs = TRUE; - op->num_kernel_modules = 1; op->install_uvm = TRUE; op->install_compat32_libs = NV_OPTIONAL_BOOL_DEFAULT; + op->install_libglx_indirect = NV_OPTIONAL_BOOL_DEFAULT; return op; @@ -361,7 +361,7 @@ static void parse_commandline(int argc, char *argv[], Options *op) case NO_RPMS_OPTION: op->no_rpms = TRUE; break; - case NO_RECURSION_OPTION: + case 'r': op->no_recursion = TRUE; break; case FORCE_SELINUX_OPTION: @@ -430,28 +430,18 @@ static void parse_commandline(int argc, char *argv[], Options *op) op->install_vdpau_wrapper = boolval ? NV_OPTIONAL_BOOL_TRUE : NV_OPTIONAL_BOOL_FALSE; break; - case MULTIPLE_KERNEL_MODULES_OPTION: - if (intval < 0) { - nv_error_msg("Invalid parameter for '--multiple-kernel-modules'"); - goto fail; - } - op->multiple_kernel_modules = TRUE; - /* Unified Memory is incompatible with multiple kernel modules */ - op->install_uvm = FALSE; - - if (intval > NV_MAX_MODULE_INSTANCES) { - op->num_kernel_modules = NV_MAX_MODULE_INSTANCES; - } - else { - op->num_kernel_modules = intval; - } - break; case NO_UVM_OPTION: op->install_uvm = FALSE; break; case NO_CHECK_FOR_ALTERNATE_INSTALLS_OPTION: op->check_for_alternate_installs = FALSE; break; + case FORCE_LIBGLX_INDIRECT: + op->install_libglx_indirect = NV_OPTIONAL_BOOL_TRUE; + break; + case NO_LIBGLX_INDIRECT: + op->install_libglx_indirect = NV_OPTIONAL_BOOL_FALSE; + break; default: goto fail; } @@ -644,7 +634,7 @@ int main(int argc, char *argv[]) done: ui_close(op); - + nvfree((void*)op); return (ret ? 0 : 1); diff --git a/nvidia-installer.h b/nvidia-installer.h index eed02a7..0252174 100644 --- a/nvidia-installer.h +++ b/nvidia-installer.h @@ -151,13 +151,12 @@ typedef struct __options { int no_kernel_module_source; int dkms; int check_for_alternate_installs; - int multiple_kernel_modules; - int num_kernel_modules; int install_uvm; - int uvm_files_packaged; int compat32_files_packaged; int x_files_packaged; int concurrency_level; + int load_error_ignored; + int install_libglx_indirect; NVOptionalBool install_vdpau_wrapper; NVOptionalBool install_compat32_libs; @@ -200,8 +199,7 @@ typedef struct __options { char *kernel_module_src_prefix; char *kernel_module_src_dir; char *utils[MAX_UTILS]; - char *uvm_module_src_dir; - + char *proc_mount_point; char *ui_str; char *log_file_name; @@ -238,7 +236,6 @@ typedef struct __options { typedef enum { FILE_TYPE_NONE, FILE_TYPE_KERNEL_MODULE_SRC, - FILE_TYPE_KERNEL_MODULE_CMD, FILE_TYPE_OPENGL_HEADER, FILE_TYPE_OPENGL_LIB, FILE_TYPE_DOCUMENTATION, @@ -283,8 +280,8 @@ typedef enum { FILE_TYPE_MODULE_SIGNING_KEY, FILE_TYPE_NVIFR_LIB, FILE_TYPE_NVIFR_LIB_SYMLINK, - FILE_TYPE_UVM_MODULE_SRC, FILE_TYPE_XORG_OUTPUTCLASS_CONFIG, + FILE_TYPE_DKMS_CONF, FILE_TYPE_MAX } PackageEntryFileType; @@ -310,6 +307,7 @@ typedef struct { unsigned int is_opengl : 1; unsigned int is_temporary : 1; unsigned int is_wrapper : 1; + unsigned int inherit_path : 1; } PackageEntryFileCapabilities; /* @@ -320,6 +318,7 @@ typedef struct { uint8_t types[FILE_TYPE_MAX]; } PackageEntryFileTypeList; + typedef struct __package_entry { char *file; /* @@ -356,6 +355,7 @@ typedef struct __package_entry { PackageEntryFileType type; PackageEntryFileTlsClass tls_class; PackageEntryFileCompatArch compat_arch; + int inherit_path_depth; mode_t mode; @@ -389,29 +389,38 @@ typedef struct { } ConflictingFileInfo; +/* + * KernelModuleInfo: store information about a kernel module that is useful + * for building the module or identifying it or its component objects. + */ +typedef struct { + char *module_name; /* e.g. "nvidia" */ + char *module_filename; /* e.g. "nvidia.ko" */ + int has_separate_interface_file; /* e.g. FALSE for "nvidia-uvm" */ + char *interface_filename; /* e.g. "nv-linux.o" */ + char *core_object_name; /* e.g. "nv-kernel.o" */ + int is_optional; /* e.g. TRUE for "nvidia-uvm" */ + char *optional_module_dependee; /* e.g. "CUDA" for "nvidia-uvm" */ + char *disable_option; /* e.g. "--no-unified-memory" */ +} KernelModuleInfo; + + typedef struct __package { char *description; char *version; - char *kernel_module_filename; - char *kernel_interface_filename; - char *kernel_module_name; - char **bad_modules; - char **bad_module_filenames; char *kernel_module_build_directory; - char *uvm_module_build_directory; char *precompiled_kernel_interface_directory; - char *kernel_frontend_module_filename; - char *kernel_frontend_module_name; - char *kernel_frontend_interface_filename; - char *uvm_kernel_module_name; - char *uvm_kernel_module_filename; - char *uvm_interface_filename; - + PackageEntry *entries; /* array of filename/checksum/bytesize entries */ int num_entries; ConflictingFileInfo *conflicting_files; + + KernelModuleInfo *kernel_modules; + int num_kernel_modules; + char *excluded_kernel_modules; + } Package; @@ -502,8 +511,6 @@ typedef struct __package { #define NUM_TIMES_QUESTIONS_ASKED 3 -#define NV_MAX_MODULE_INSTANCES 8 - #define LD_OPTIONS "-d -r" #define NVIDIA_VERSION_PROC_FILE "/proc/driver/nvidia/version" diff --git a/option_table.h b/option_table.h index c9c5c60..6096697 100644 --- a/option_table.h +++ b/option_table.h @@ -65,7 +65,6 @@ enum { NO_RPMS_OPTION, X_PREFIX_OPTION, KERNEL_OUTPUT_PATH_OPTION, - NO_RECURSION_OPTION, FORCE_TLS_COMPAT32_OPTION, COMPAT32_CHROOT_OPTION, COMPAT32_PREFIX_OPTION, @@ -95,10 +94,11 @@ enum { MODULE_SIGNING_X509_HASH_OPTION, INSTALL_VDPAU_WRAPPER_OPTION, NO_CHECK_FOR_ALTERNATE_INSTALLS_OPTION, - MULTIPLE_KERNEL_MODULES_OPTION, NO_UVM_OPTION, INSTALL_COMPAT32_LIBS_OPTION, X_SYSCONFIG_PATH_OPTION, + FORCE_LIBGLX_INDIRECT, + NO_LIBGLX_INDIRECT, }; static const NVGetoptOption __options[] = { @@ -444,7 +444,7 @@ static const NVGetoptOption __options[] = { "This option instructs the installer to not attempt to access the " "network." }, - { "no-recursion", NO_RECURSION_OPTION, 0, NULL, + { "no-recursion", 'r', 0, NULL, "Normally, nvidia-installer will recursively search for " "potentially conflicting libraries under the default OpenGL " "and X server installation locations. With this option set, " @@ -640,12 +640,6 @@ static const NVGetoptOption __options[] = { "nvidia-installer. Setting this option skips the check for alternate " "driver installations." }, - { "multiple-kernel-modules", MULTIPLE_KERNEL_MODULES_OPTION, - NVGETOPT_INTEGER_ARGUMENT, NULL, - "Build and install multiple NVIDIA kernel modules. The maximum number " - "of NVIDIA kernel modules that may be built is 8. '--multiple-kernel-" - "modules' implies '--no-unified-memory'." }, - { "no-unified-memory", NO_UVM_OPTION, 0, NULL, "Do not install the NVIDIA Unified Memory kernel module. This kernel " "module is required for CUDA on 64-bit systems, and if it is not " @@ -660,6 +654,12 @@ static const NVGetoptOption __options[] = { "be set to the number of detected CPUs, or to '1', if nvidia-installer " "fails to detect the number of CPUs." }, + { "force-libglx-indirect", FORCE_LIBGLX_INDIRECT, 0, NULL, + "If the package includes a libglvnd-based OpenGL library, then always " + "install a libGLX_indirect.so.0 symlink, overwriting one if it exists." }, + { "no-libglx-indirect", NO_LIBGLX_INDIRECT, 0, NULL, + "Do not install a libGLX_indirect.so.0 symlink." }, + /* Orphaned options: These options were in the long_options table in * nvidia-installer.c but not in the help. */ { "debug", 'd', 0, NULL,NULL }, diff --git a/rtld_test_Linux-armv7l-gnueabi b/rtld_test_Linux-armv7l-gnueabi Binary files differindex 604a02a..9afef55 100755 --- a/rtld_test_Linux-armv7l-gnueabi +++ b/rtld_test_Linux-armv7l-gnueabi diff --git a/rtld_test_Linux-armv7l-gnueabihf b/rtld_test_Linux-armv7l-gnueabihf Binary files differindex be0eadb..221965d 100755 --- a/rtld_test_Linux-armv7l-gnueabihf +++ b/rtld_test_Linux-armv7l-gnueabihf diff --git a/rtld_test_Linux-x86 b/rtld_test_Linux-x86 Binary files differindex b60ea47..290b8c0 100755 --- a/rtld_test_Linux-x86 +++ b/rtld_test_Linux-x86 diff --git a/rtld_test_Linux-x86_64 b/rtld_test_Linux-x86_64 Binary files differindex be5e874..037cf90 100755 --- a/rtld_test_Linux-x86_64 +++ b/rtld_test_Linux-x86_64 @@ -1 +1 @@ -NVIDIA_VERSION = 352.30 +NVIDIA_VERSION = 355.06 |