summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backup.c39
-rw-r--r--command-list.c8
-rw-r--r--install-from-cwd.c16
-rw-r--r--kernel.c217
-rw-r--r--kernel.h1
-rw-r--r--precompiled.c17
-rw-r--r--version.mk2
7 files changed, 169 insertions, 131 deletions
diff --git a/backup.c b/backup.c
index 3c32f92..60d408f 100644
--- a/backup.c
+++ b/backup.c
@@ -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;
}
diff --git a/kernel.c b/kernel.c
index 1f576ea..08cb1a1 100644
--- a/kernel.c
+++ b/kernel.c
@@ -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;
diff --git a/kernel.h b/kernel.h
index 9bbc37c..1d02b5d 100644
--- a/kernel.h
+++ b/kernel.h
@@ -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;
diff --git a/version.mk b/version.mk
index 22ff29a..753c69c 100644
--- a/version.mk
+++ b/version.mk
@@ -1 +1 @@
-NVIDIA_VERSION = 346.72
+NVIDIA_VERSION = 346.82