diff options
-rw-r--r-- | backup.c | 39 | ||||
-rw-r--r-- | command-list.c | 8 | ||||
-rw-r--r-- | install-from-cwd.c | 16 | ||||
-rw-r--r-- | kernel.c | 217 | ||||
-rw-r--r-- | kernel.h | 1 | ||||
-rw-r--r-- | precompiled.c | 17 | ||||
-rw-r--r-- | version.mk | 2 |
7 files changed, 169 insertions, 131 deletions
@@ -40,6 +40,7 @@ #include "files.h" #include "crc.h" #include "misc.h" +#include "kernel.h" #define BACKUP_DIRECTORY "/var/lib/nvidia" #define BACKUP_LOG (BACKUP_DIRECTORY "/log") @@ -626,11 +627,10 @@ static int rmdir_recursive(Options *op) static void unload_nvidia_module(Options *op, const char *suffix) { - char *cmd; - - cmd = nvstrcat(op->utils[RMMOD], " ", RMMOD_MODULE_NAME, suffix, NULL); - run_command(op, cmd, NULL, FALSE, 0, TRUE); - nvfree(cmd); + char *name; + name = nvstrcat(RMMOD_MODULE_NAME, suffix, NULL); + rmmod_kernel_module(op, name); + nvfree(name); } @@ -1434,34 +1434,7 @@ int run_existing_uninstaller(Options *op) ui_log(op, "Uninstalling the previous installation with %s.", uninstaller); - if (!op->no_kernel_module && !op->kernel_name) { - /* - * Attempt to run the uninstaller with the --skip-module-unload - * option first. If that fails, fall back to running it without - * that option. - * - * We don't want the uninstaller to unload the module because this - * instance of the installer already unloaded the old module and - * loaded the new one. - */ - char *uninstall_skip_unload_cmd = - nvstrcat(uninstall_cmd, " --skip-module-unload", NULL); - ret = run_command(op, uninstall_skip_unload_cmd, NULL, FALSE, 0, TRUE); - nvfree(uninstall_skip_unload_cmd); - } else { - /* - * If installing the kernel module was skipped or we're - * building/installing for a different kernel, then the new kernel - * module wasn't automatically loaded and we should unload whichever - * one is loaded now. - */ - ret = 1; - } - - if (ret) { - /* Try again without --skip-module-unload */ - ret = run_command(op, uninstall_cmd, &data, FALSE, 0, TRUE); - } + ret = run_command(op, uninstall_cmd, &data, FALSE, 0, TRUE); nvfree(uninstall_cmd); diff --git a/command-list.c b/command-list.c index a35c7a6..d65440c 100644 --- a/command-list.c +++ b/command-list.c @@ -248,8 +248,16 @@ CommandList *build_command_list(Options *op, Package *p) * stop recursing into any "nvidia-cg-toolkit" * directory to prevent libGL.so.1 from being deleted * (see bug 843595). + * + * Also, do not recurse into "source" or "build" directories, pretty + * much ever. This is because distros (for example, Fedora Core 21) + * have started putting links to kernel source and build trees in + * other locations, including /usr/lib/modules/`uname -r`/kernel. + * (See bug 1646361). */ static const NoRecursionDirectory skipdirs[] = { + { -1, "source" }, + { -1, "build" }, { -1, "nvidia-cg-toolkit" }, { 0, NULL } }; diff --git a/install-from-cwd.c b/install-from-cwd.c index 64fc6d4..669136f 100644 --- a/install-from-cwd.c +++ b/install-from-cwd.c @@ -308,20 +308,12 @@ int install_from_cwd(Options *op) if (op->dkms && !dkms_install_module(op, p->version, get_kernel_name(op))) goto failed; - /* Make sure the RM is loaded */ + /* + * Leave the RM loaded in case an X server with OutputClass-based driver + * matching is being used. + */ if (!op->no_kernel_module || op->dkms) { - /* - * If a kernel module was installed the normal way, it should have been - * left loaded by test_kernel_module(). However, older versions of - * nvidia-uninstall don't honor the --skip-module-unload option, so - * uninstalling a previous driver may have unloaded the module that - * test_kernel_module() loaded. Just in case that happened, modprobe it - * again here. - * - * When installing the module via DKMS, the module is not loaded to - * begin with. - */ if (!load_kernel_module(op, p)) goto failed; } @@ -51,7 +51,6 @@ static char *default_kernel_source_path(Options *op); static char *find_module_substring(char *string, const char *substring); static int check_for_loaded_kernel_module(Options *op, const char *); static void check_for_warning_messages(Options *op); -static int rmmod_kernel_module(Options *op, const char *); static PrecompiledInfo *download_updated_kernel_interface(Options*, Package*, const char*, char* const*); @@ -72,6 +71,8 @@ static void close_libkmod(void); static int run_conftest(Options *op, Package *p, const char *args, char **result); static void replace_zero(char* filename, int i); +static void load_kernel_module_quiet(Options *op, const char *module_name); +static void modprobe_remove_kernel_module_quiet(Options *op, const char *name); /* libkmod handle and function pointers */ static void *libkmod = NULL; @@ -1262,17 +1263,76 @@ static void close_libkmod(void) +#define PRINTK_LOGLEVEL_KERN_ALERT 1 + +/* + * Attempt to set the printk loglevel, first using the /proc/sys interface, + * and falling back to the deprecated sysctl if that fails. Pass the previous + * loglevel back to the caller and return TRUE on success, or FALSE on failure. + */ +static int set_loglevel(int level, int *old_level) +{ + FILE *fp; + int loglevel_set = FALSE; + + fp = fopen("/proc/sys/kernel/printk", "r+"); + if (fp) { + if (!old_level || fscanf(fp, "%d ", old_level) == 1) { + char *strlevel = nvasprintf("%d", level); + + fseek(fp, 0, SEEK_SET); + if (fwrite(strlevel, strlen(strlevel), 1, fp) == 1) { + loglevel_set = TRUE; + } + + nvfree(strlevel); + } + fclose(fp); + } + + if (!loglevel_set) { + /* + * Explicitly initialize the value of len, even though it looks like the + * syscall should do that, since in practice it doesn't always actually + * set the value of the pointed-to length parameter. + */ + size_t len = sizeof(int); + int name[] = { CTL_KERN, KERN_PRINTK }; + + if (!old_level || + sysctl(name, ARRAY_LEN(name), old_level, &len, NULL, 0) == 0) { + if (sysctl(name, ARRAY_LEN(name), NULL, 0, &level, len) == 0) { + loglevel_set = TRUE; + } + } + } + + return loglevel_set; +} + + /* * do_insmod() - load the kernel module using libkmod if available; fall back * to insmod otherwise. Returns the result of kmod_module_insert_module() if * available, or of insmod otherwise. Pass the result of module loading up * through the data argument, regardless of whether we used libkmod or insmod. */ -static int do_insmod(Options *op, const char *module, char **data) +static int do_insmod(Options *op, const char *module, char **data, + const char *module_opts) { - int ret = 0, libkmod_failed = FALSE; + int ret = 0, libkmod_failed = FALSE, old_loglevel, loglevel_set; + *data = NULL; + /* + * Temporarily disable most console messages to keep the curses + * interface from being clobbered when the module is loaded. + * Save the original console loglevel to allow restoring it once + * we're done. + */ + + loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel); + if (init_libkmod()) { struct kmod_ctx *ctx = NULL; struct kmod_module *mod = NULL; @@ -1290,7 +1350,7 @@ static int do_insmod(Options *op, const char *module, char **data) goto kmod_done; } - ret = lkmod_module_insert_module(mod, 0, ""); + ret = lkmod_module_insert_module(mod, 0, module_opts); if (ret < 0) { /* insmod ignores > 0 return codes of kmod_module_insert_module(), * so we should do it too. On failure, strdup() the error string to @@ -1318,7 +1378,7 @@ kmod_done: /* Fall back to insmod */ - cmd = nvstrcat(op->utils[INSMOD], " ", module, NULL); + cmd = nvstrcat(op->utils[INSMOD], " ", module, " ", module_opts, NULL); /* only output the result of the test if in expert mode */ @@ -1328,6 +1388,10 @@ kmod_done: close_libkmod(); + if (loglevel_set) { + set_loglevel(old_loglevel, NULL); + } + return ret; } /* do_insmod() */ @@ -1454,17 +1518,16 @@ static int ignore_load_error(Options *op, Package *p, /* * test_kernel_module() - attempt to insmod the kernel modules and then rmmod - * nvidia-uvm. Return TRUE if the insmod succeeded, or FALSE otherwise. + * them. Return TRUE if the insmod succeeded, or FALSE otherwise. */ int test_kernel_module(Options *op, Package *p) { char *cmd = NULL, *data = NULL, *module_path; - int old_loglevel = 0, new_loglevel = 0; - int fd, ret, name[] = { CTL_KERN, KERN_PRINTK }, i; - size_t len = sizeof(int); + 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. @@ -1473,34 +1536,12 @@ int test_kernel_module(Options *op, Package *p) if (op->kernel_name) return TRUE; /* - * Temporarily disable most console messages to keep the curses - * interface from being clobbered when the module is loaded. - * Save the original console loglevel to allow restoring it once - * we're done. - */ - fd = open("/proc/sys/kernel/printk", O_RDWR); - if (fd >= 0) { - if (read(fd, &old_loglevel, 1) == 1) { - new_loglevel = '2'; /* KERN_CRIT */ - lseek(fd, 0, SEEK_SET); - write(fd, &new_loglevel, 1); - } - } else { - if (!sysctl(name, 2, &old_loglevel, &len, NULL, 0)) { - new_loglevel = 2; /* KERN_CRIT */ - sysctl(name, 2, NULL, 0, &new_loglevel, len); - } - } - - /* * Attempt to load modules that nvidia.ko might depend on. Silently ignore * failures: if nvidia.ko doesn't depend on the module that failed, the test * load below will succeed and it doesn't matter that the load here failed. */ for (i = 0; i < ARRAY_LEN(depmods); i++) { - cmd = nvstrcat(op->utils[MODPROBE], " -q ", depmods[i], NULL); - run_command(op, cmd, NULL, FALSE, 0, TRUE); - nvfree(cmd); + load_kernel_module_quiet(op, depmods[i]); } if (op->multiple_kernel_modules) { @@ -1508,7 +1549,7 @@ int test_kernel_module(Options *op, Package *p) module_path = nvstrcat(p->kernel_module_build_directory, "/", p->kernel_frontend_module_filename, NULL); - ret = do_insmod(op, module_path, &data); + ret = do_insmod(op, module_path, &data, ""); nvfree(module_path); if (ret != 0) { @@ -1527,7 +1568,10 @@ int test_kernel_module(Options *op, Package *p) module_path = nvstrcat(p->kernel_module_build_directory, "/", p->kernel_module_filename, NULL); - ret = do_insmod(op, module_path, &data); + ret = do_insmod(op, module_path, &data, + "NVreg_DeviceFileUID=0 NVreg_DeviceFileGID=0 " + "NVreg_DeviceFileMode=0 NVreg_ModifyDeviceFiles=0"); + nvfree(module_path); if (ret != 0) { @@ -1537,7 +1581,7 @@ int test_kernel_module(Options *op, Package *p) 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, &data, ""); nvfree(module_path); if (ret != 0) { @@ -1563,20 +1607,19 @@ int test_kernel_module(Options *op, Package *p) check_for_warning_messages(op); /* - * attempt to unload the UVM kernel module, but don't abort if this fails: + * 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). - * - * The nvidia module is left loaded in case an X server with - * OutputClass-based driver matching is being used. UVM is unloaded to make - * it easier to roll back to older versions of the driver whose installers - * didn't know how to unload the nvidia-uvm module. */ if (op->install_uvm) { - cmd = nvstrcat(op->utils[RMMOD], " ", p->uvm_kernel_module_name, NULL); - run_command(op, cmd, NULL, FALSE, 0, TRUE); - nvfree(cmd); + 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); } ret = TRUE; @@ -1598,25 +1641,12 @@ test_exit: nvfree(cmd); nvfree(data); - if (fd >= 0) { - if (new_loglevel != 0) { - lseek(fd, 0, SEEK_SET); - write(fd, &old_loglevel, 1); - } - close(fd); - } else { - if (new_loglevel != 0) { - sysctl(name, 2, NULL, 0, &old_loglevel, len); - } - } - /* * Unload dependencies that might have been loaded earlier. */ + for (i = 0; i < ARRAY_LEN(depmods); i++) { - cmd = nvstrcat(op->utils[MODPROBE], " -qr ", depmods[i], NULL); - run_command(op, cmd, NULL, FALSE, 0, TRUE); - nvfree(cmd); + modprobe_remove_kernel_module_quiet(op, depmods[i]); } return ret; @@ -1626,27 +1656,42 @@ test_exit: /* - * load_kernel_module() - modprobe the kernel module + * modprobe_helper() - run modprobe; used internally by other functions. + * + * module_name: the name of the kernel module to modprobe + * quiet: load/unload the kernel module silently if TRUE + * unload: remove a kernel module instead of loading it if TRUE + * (Note: unlike `rmmod`, `modprobe -r` handles dependencies. */ -int load_kernel_module(Options *op, Package *p) +static int modprobe_helper(Options *op, const char *module_name, + int quiet, int unload) { char *cmd, *data; - int len, ret; + int ret, old_loglevel, loglevel_set; - len = strlen(op->utils[MODPROBE]) + strlen(p->kernel_module_name) + 2; + cmd = nvstrcat(op->utils[MODPROBE], + quiet ? " -q" : "", + unload ? " -r" : "", + " ", module_name, + NULL); - cmd = (char *) nvalloc(len); - - snprintf(cmd, len, "%s %s", op->utils[MODPROBE], p->kernel_module_name); + loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel); ret = run_command(op, cmd, &data, FALSE, 0, TRUE); - if (ret != 0) { + if (loglevel_set) { + set_loglevel(old_loglevel, NULL); + } + + if (!quiet && ret != 0) { if (op->expert) { - ui_error(op, "Unable to load the kernel module: '%s'", data); + ui_error(op, "Unable to %s the kernel module: '%s'", + unload ? "unload" : "load", + data); } else { - ui_error(op, "Unable to load the kernel module."); + ui_error(op, "Unable to %s the kernel module.", + unload ? "unload" : "load"); } ret = FALSE; } else { @@ -1660,6 +1705,20 @@ int load_kernel_module(Options *op, Package *p) } /* load_kernel_module() */ +int load_kernel_module(Options *op, Package *p) +{ + return modprobe_helper(op, p->kernel_module_name, FALSE, FALSE); +} + +static void load_kernel_module_quiet(Options *op, const char *module_name) +{ + modprobe_helper(op, module_name, TRUE, FALSE); +} + +static void modprobe_remove_kernel_module_quiet(Options *op, const char *name) +{ + modprobe_helper(op, name, TRUE, TRUE); +} /* @@ -2254,22 +2313,24 @@ static int check_for_loaded_kernel_module(Options *op, const char *module_name) /* - * rmmod_kernel_module() - run `rmmod nvidia` + * rmmod_kernel_module() - run `rmmod $module_name` */ -static int rmmod_kernel_module(Options *op, const char *module_name) +int rmmod_kernel_module(Options *op, const char *module_name) { - int len, ret; + int ret, old_loglevel, loglevel_set; char *cmd; - len = strlen(op->utils[RMMOD]) + strlen(module_name) + 2; - - cmd = (char *) nvalloc(len); - - snprintf(cmd, len, "%s %s", op->utils[RMMOD], module_name); + cmd = nvstrcat(op->utils[RMMOD], " ", module_name, NULL); + + loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel); ret = run_command(op, cmd, NULL, FALSE, 0, TRUE); - + + if (loglevel_set) { + set_loglevel(old_loglevel, NULL); + } + free(cmd); return ret ? FALSE : TRUE; @@ -49,6 +49,7 @@ KernelConfigOptionStatus test_kernel_config_option (Options*, Package*, 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 diff --git a/precompiled.c b/precompiled.c index 50d6183..08ba107 100644 --- a/precompiled.c +++ b/precompiled.c @@ -234,10 +234,11 @@ PrecompiledInfo *get_precompiled_info(Options *op, } offset += val; - /* check if this precompiled kernel interface is the right driver - version */ + /* fail if the version could not be read, or if a package version was + specified and the read version does not match it */ - if (!version || !package_version || strcmp(version, package_version) != 0) { + if (!version || + (package_version && strcmp(version, package_version) != 0)) { goto done; } @@ -955,10 +956,12 @@ const char **precompiled_file_attribute_names(uint32 attribute_mask) ret = nvalloc((max_file_attribute_names + 1) * sizeof(char *)); for (i = 0; i < max_file_attribute_names; i++) { - if (i >= ARRAY_LEN(file_attribute_names)) { - ret[attr++] = unknown_attribute; - } else if (attribute_mask & (1 << i)) { - ret[attr++] = file_attribute_names[i]; + if (attribute_mask & (1 << i)) { + if (i >= ARRAY_LEN(file_attribute_names)) { + ret[attr++] = unknown_attribute; + } else { + ret[attr++] = file_attribute_names[i]; + } } } ret[attr] = NULL; @@ -1 +1 @@ -NVIDIA_VERSION = 346.72 +NVIDIA_VERSION = 346.82 |