568 lines
15 KiB
Diff
568 lines
15 KiB
Diff
--- a/src/nvidia-modprobe-utils.c 2020-09-18 18:11:57.042187266 +0800
|
|
+++ b/src/nvidia-modprobe-utils.c 2020-09-18 18:25:49.318472815 +0800
|
|
@@ -1,3 +1,29 @@
|
|
+/*
|
|
+ * Copyright (c) 2013, NVIDIA CORPORATION.
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person
|
|
+ * obtaining a copy of this software and associated documentation
|
|
+ * files (the "Software"), to deal in the Software without
|
|
+ * restriction, including without limitation the rights to use, copy,
|
|
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
+ * of the Software, and to permit persons to whom the Software is
|
|
+ * furnished to do so, subject to the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be
|
|
+ * included in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
+ * SOFTWARE.
|
|
+ *
|
|
+ * This file provides utility functions on Linux for loading the
|
|
+ * NVIDIA kernel module and creating NVIDIA device files.
|
|
+ */
|
|
|
|
#if defined(NV_LINUX)
|
|
|
|
@@ -27,9 +53,6 @@
|
|
#define NV_NVIDIA_MODULE_NAME "nvidia"
|
|
#define NV_PROC_REGISTRY_PATH "/proc/driver/nvidia/params"
|
|
|
|
-#define NV_NMODULE_NVIDIA_MODULE_NAME "nvidia%d"
|
|
-#define NV_NMODULE_PROC_REGISTRY_PATH "/proc/driver/nvidia/%d/params"
|
|
-
|
|
#define NV_UVM_MODULE_NAME "nvidia-uvm"
|
|
#define NV_UVM_DEVICE_NAME "/dev/nvidia-uvm"
|
|
#define NV_UVM_TOOLS_DEVICE_NAME "/dev/nvidia-uvm-tools"
|
|
@@ -41,12 +64,16 @@
|
|
#define NV_NVLINK_MODULE_NAME "nvidia-nvlink"
|
|
#define NV_NVLINK_PROC_PERM_PATH "/proc/driver/nvidia-nvlink/permissions"
|
|
|
|
+#define NV_NVSWITCH_MODULE_NAME "nvidia-nvswitch"
|
|
+#define NV_NVSWITCH_PROC_PERM_PATH "/proc/driver/nvidia-nvswitch/permissions"
|
|
+
|
|
#define NV_DEVICE_FILE_MODE_MASK (S_IRWXU|S_IRWXG|S_IRWXO)
|
|
#define NV_DEVICE_FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
|
|
#define NV_DEVICE_FILE_UID 0
|
|
#define NV_DEVICE_FILE_GID 0
|
|
|
|
-#define NV_MAKE_DEVICE(x,y) ((dev_t)((x) << 8 | (y)))
|
|
+#define NV_MAKE_DEVICE(major, minor) \
|
|
+ ((dev_t)((minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12)))
|
|
|
|
#define NV_MAJOR_DEVICE_NUMBER 195
|
|
|
|
@@ -55,84 +82,6 @@
|
|
#define NV_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
|
/*
|
|
- * Construct the nvidia kernel module name based on the input
|
|
- * module instance provided. If an error occurs, the null
|
|
- * terminator will be written to nv_module_name[0].
|
|
- */
|
|
-static __inline__ void assign_nvidia_kernel_module_name
|
|
-(
|
|
- char nv_module_name[NV_MAX_MODULE_NAME_SIZE],
|
|
- int module_instance
|
|
-)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- if (is_multi_module(module_instance))
|
|
- {
|
|
- ret = snprintf(nv_module_name, NV_MAX_MODULE_NAME_SIZE,
|
|
- NV_NMODULE_NVIDIA_MODULE_NAME, module_instance);
|
|
- }
|
|
- else
|
|
- {
|
|
- ret = snprintf(nv_module_name, NV_MAX_MODULE_NAME_SIZE,
|
|
- NV_NVIDIA_MODULE_NAME);
|
|
- }
|
|
-
|
|
- if (ret <= 0)
|
|
- {
|
|
- goto fail;
|
|
- }
|
|
-
|
|
- nv_module_name[NV_MAX_MODULE_NAME_SIZE - 1] = '\0';
|
|
-
|
|
- return;
|
|
-
|
|
-fail:
|
|
-
|
|
- nv_module_name[0] = '\0';
|
|
-}
|
|
-
|
|
-
|
|
-/*
|
|
- * Construct the proc registry path name based on the input
|
|
- * module instance provided. If an error occurs, the null
|
|
- * terminator will be written to proc_path[0].
|
|
- */
|
|
-static __inline__ void assign_proc_registry_path
|
|
-(
|
|
- char proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE],
|
|
- int module_instance
|
|
-)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- if (is_multi_module(module_instance))
|
|
- {
|
|
- ret = snprintf(proc_path, NV_MAX_PROC_REGISTRY_PATH_SIZE,
|
|
- NV_NMODULE_PROC_REGISTRY_PATH, module_instance);
|
|
- }
|
|
- else
|
|
- {
|
|
- ret = snprintf(proc_path, NV_MAX_PROC_REGISTRY_PATH_SIZE,
|
|
- NV_PROC_REGISTRY_PATH);
|
|
- }
|
|
-
|
|
- if (ret <= 0)
|
|
- {
|
|
- goto fail;
|
|
- }
|
|
-
|
|
- proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE - 1] = '\0';
|
|
-
|
|
- return;
|
|
-
|
|
-fail:
|
|
-
|
|
- proc_path[0] = '\0';
|
|
-}
|
|
-
|
|
-
|
|
-/*
|
|
* Just like strcmp(3), except that differences between '-' and '_' are
|
|
* ignored. This is useful for comparing module names, where '-' and '_'
|
|
* are supposed to be treated interchangeably.
|
|
@@ -370,18 +319,20 @@
|
|
return 0;
|
|
|
|
default:
|
|
- if (waitpid(pid, &status, 0) < 0)
|
|
- {
|
|
- return 0;
|
|
- }
|
|
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
|
|
- {
|
|
- return 1;
|
|
- }
|
|
- else
|
|
- {
|
|
- return 0;
|
|
- }
|
|
+ /*
|
|
+ * waitpid(2) is not always guaranteed to return success even if
|
|
+ * the child terminated normally. For example, if the process
|
|
+ * explicitly configured the handling of the SIGCHLD signal
|
|
+ * to SIG_IGN, then waitpid(2) will instead block until all
|
|
+ * children terminate and return the error ECHILD, regardless
|
|
+ * of the child's exit codes.
|
|
+ *
|
|
+ * Hence, ignore waitpid(2) error codes and instead check
|
|
+ * whether the desired kernel module is loaded.
|
|
+ */
|
|
+ waitpid(pid, NULL, 0);
|
|
+
|
|
+ return is_kernel_module_loaded(module_name);
|
|
}
|
|
|
|
return 1;
|
|
@@ -391,13 +342,9 @@
|
|
/*
|
|
* Attempt to load an NVIDIA kernel module
|
|
*/
|
|
-int nvidia_modprobe(const int print_errors, int module_instance)
|
|
+int nvidia_modprobe(const int print_errors)
|
|
{
|
|
- char nv_module_name[NV_MAX_MODULE_NAME_SIZE];
|
|
-
|
|
- assign_nvidia_kernel_module_name(nv_module_name, module_instance);
|
|
-
|
|
- return modprobe_helper(print_errors, nv_module_name);
|
|
+ return modprobe_helper(print_errors, NV_NVIDIA_MODULE_NAME);
|
|
}
|
|
|
|
|
|
@@ -447,7 +394,8 @@
|
|
{
|
|
*mode = value;
|
|
}
|
|
- if (strcmp(name, "ModifyDeviceFiles") == 0)
|
|
+ if ((strcmp(name, "ModifyDeviceFiles") == 0) ||
|
|
+ (strcmp(name, "DeviceFileModify") == 0))
|
|
{
|
|
*modify = value;
|
|
}
|
|
@@ -456,7 +404,7 @@
|
|
fclose(fp);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
* A helper to query device file states.
|
|
*/
|
|
static int get_file_state_helper(
|
|
@@ -494,24 +442,22 @@
|
|
return state;
|
|
}
|
|
|
|
-int nvidia_get_file_state(int minor, int module_instance)
|
|
+int nvidia_get_file_state(int minor)
|
|
{
|
|
char path[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
|
|
- char proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE];
|
|
mode_t mode;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
int modification_allowed;
|
|
int state = 0;
|
|
|
|
- assign_device_file_name(path, minor, module_instance);
|
|
- assign_proc_registry_path(proc_path, module_instance);
|
|
+ assign_device_file_name(path, minor);
|
|
|
|
init_device_file_parameters(&uid, &gid, &mode, &modification_allowed,
|
|
- proc_path);
|
|
+ NV_PROC_REGISTRY_PATH);
|
|
|
|
state = get_file_state_helper(path, NV_MAJOR_DEVICE_NUMBER, minor,
|
|
- proc_path, uid, gid, mode);
|
|
+ NV_PROC_REGISTRY_PATH, uid, gid, mode);
|
|
|
|
return state;
|
|
}
|
|
@@ -522,8 +468,8 @@
|
|
* permissions. Returns 1 if the file is successfully created; returns 0
|
|
* if the file could not be created.
|
|
*/
|
|
-int mknod_helper(int major, int minor, const char *path,
|
|
- const char *proc_path)
|
|
+static int mknod_helper(int major, int minor, const char *path,
|
|
+ const char *proc_path)
|
|
{
|
|
dev_t dev = NV_MAKE_DEVICE(major, minor);
|
|
mode_t mode;
|
|
@@ -616,15 +562,13 @@
|
|
* Attempt to create a device file with the specified minor number for
|
|
* the specified NVIDIA module instance.
|
|
*/
|
|
-int nvidia_mknod(int minor, int module_instance)
|
|
+int nvidia_mknod(int minor)
|
|
{
|
|
char path[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
|
|
- char proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE];
|
|
|
|
- assign_device_file_name(path, minor, module_instance);
|
|
- assign_proc_registry_path(proc_path, module_instance);
|
|
+ assign_device_file_name(path, minor);
|
|
|
|
- return mknod_helper(NV_MAJOR_DEVICE_NUMBER, minor, path, proc_path);
|
|
+ return mknod_helper(NV_MAJOR_DEVICE_NUMBER, minor, path, NV_PROC_REGISTRY_PATH);
|
|
}
|
|
|
|
|
|
@@ -633,7 +577,7 @@
|
|
* device with the specified name. Returns the major number on success,
|
|
* or -1 on failure.
|
|
*/
|
|
-int get_chardev_major(const char *name)
|
|
+int nvidia_get_chardev_major(const char *name)
|
|
{
|
|
int ret = -1;
|
|
char line[NV_MAX_LINE_LENGTH];
|
|
@@ -702,13 +646,86 @@
|
|
return ret;
|
|
}
|
|
|
|
+int nvidia_nvlink_get_file_state(void)
|
|
+{
|
|
+ char path[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
|
|
+ mode_t mode;
|
|
+ uid_t uid;
|
|
+ gid_t gid;
|
|
+ int modification_allowed;
|
|
+ int ret;
|
|
+ int major = nvidia_get_chardev_major(NV_NVLINK_MODULE_NAME);
|
|
+
|
|
+ if (major < 0)
|
|
+ {
|
|
+ path[0] = '\0';
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ ret = snprintf(path, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
|
|
+ NV_NVLINK_DEVICE_NAME);
|
|
+
|
|
+ if (ret < 0 || ret >= NV_MAX_CHARACTER_DEVICE_FILE_STRLEN)
|
|
+ {
|
|
+ path[0] = '\0';
|
|
+ }
|
|
+
|
|
+done:
|
|
+
|
|
+ init_device_file_parameters(&uid, &gid, &mode, &modification_allowed,
|
|
+ NV_NVLINK_PROC_PERM_PATH);
|
|
+
|
|
+ return get_file_state_helper(path, major, 0,
|
|
+ NV_NVLINK_PROC_PERM_PATH, uid, gid, mode);
|
|
+}
|
|
+
|
|
+int nvidia_nvswitch_get_file_state(int minor)
|
|
+{
|
|
+ char path[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
|
|
+ mode_t mode;
|
|
+ uid_t uid;
|
|
+ gid_t gid;
|
|
+ int modification_allowed;
|
|
+ int ret;
|
|
+ int major = nvidia_get_chardev_major(NV_NVSWITCH_MODULE_NAME);
|
|
+
|
|
+ if ((major < 0) || (minor < 0) || (minor > NV_NVSWITCH_CTL_MINOR))
|
|
+ {
|
|
+ path[0] = '\0';
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ if (minor == NV_NVSWITCH_CTL_MINOR)
|
|
+ {
|
|
+ ret = snprintf(path, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
|
|
+ NV_NVSWITCH_CTL_NAME);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ret = snprintf(path, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
|
|
+ NV_NVSWITCH_DEVICE_NAME, minor);
|
|
+ }
|
|
+
|
|
+ if (ret < 0 || ret >= NV_MAX_CHARACTER_DEVICE_FILE_STRLEN)
|
|
+ {
|
|
+ path[0] = '\0';
|
|
+ }
|
|
+
|
|
+done:
|
|
+
|
|
+ init_device_file_parameters(&uid, &gid, &mode, &modification_allowed,
|
|
+ NV_NVSWITCH_PROC_PERM_PATH);
|
|
+
|
|
+ return get_file_state_helper(path, major, minor,
|
|
+ NV_NVSWITCH_PROC_PERM_PATH, uid, gid, mode);
|
|
+}
|
|
|
|
/*
|
|
* Attempt to create the NVIDIA Unified Memory device file
|
|
*/
|
|
int nvidia_uvm_mknod(int base_minor)
|
|
{
|
|
- int major = get_chardev_major(NV_UVM_MODULE_NAME);
|
|
+ int major = nvidia_get_chardev_major(NV_UVM_MODULE_NAME);
|
|
|
|
if (major < 0)
|
|
{
|
|
@@ -743,13 +760,9 @@
|
|
*/
|
|
int nvidia_modeset_mknod(void)
|
|
{
|
|
- char proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE];
|
|
-
|
|
- assign_proc_registry_path(proc_path, NV_MODULE_INSTANCE_NONE);
|
|
-
|
|
return mknod_helper(NV_MAJOR_DEVICE_NUMBER,
|
|
NV_MODESET_MINOR_DEVICE_NUM,
|
|
- NV_MODESET_DEVICE_NAME, proc_path);
|
|
+ NV_MODESET_DEVICE_NAME, NV_PROC_REGISTRY_PATH);
|
|
}
|
|
|
|
/*
|
|
@@ -757,7 +770,7 @@
|
|
*/
|
|
int nvidia_nvlink_mknod(void)
|
|
{
|
|
- int major = get_chardev_major(NV_NVLINK_MODULE_NAME);
|
|
+ int major = nvidia_get_chardev_major(NV_NVLINK_MODULE_NAME);
|
|
|
|
if (major < 0)
|
|
{
|
|
@@ -770,25 +783,164 @@
|
|
NV_NVLINK_PROC_PERM_PATH);
|
|
}
|
|
|
|
+/*
|
|
+ * Attempt to create the NVIDIA NVSwitch driver device files.
|
|
+ */
|
|
+int nvidia_nvswitch_mknod(int minor)
|
|
+{
|
|
+ int major = 0;
|
|
+ char name[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
|
|
+ int ret;
|
|
+
|
|
+ major = nvidia_get_chardev_major(NV_NVSWITCH_MODULE_NAME);
|
|
+
|
|
+ if (major < 0)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (minor == NV_NVSWITCH_CTL_MINOR)
|
|
+ {
|
|
+ ret = snprintf(name, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
|
|
+ NV_NVSWITCH_CTL_NAME);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ret = snprintf(name, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
|
|
+ NV_NVSWITCH_DEVICE_NAME, minor);
|
|
+ }
|
|
+
|
|
+ if (ret < 0 || ret >= NV_MAX_CHARACTER_DEVICE_FILE_STRLEN)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return mknod_helper(major, minor, name, NV_NVSWITCH_PROC_PERM_PATH);
|
|
+}
|
|
+
|
|
int nvidia_vgpu_vfio_mknod(int minor_num)
|
|
{
|
|
- int major = get_chardev_major(NV_VGPU_VFIO_MODULE_NAME);
|
|
+ int major = nvidia_get_chardev_major(NV_VGPU_VFIO_MODULE_NAME);
|
|
char vgpu_dev_name[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
|
|
- char proc_path[NV_MAX_PROC_REGISTRY_PATH_SIZE];
|
|
+ int ret;
|
|
|
|
if (major < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
- assign_proc_registry_path(proc_path, NV_MODULE_INSTANCE_NONE);
|
|
-
|
|
- snprintf(vgpu_dev_name, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
|
|
- NV_VGPU_VFIO_DEVICE_NAME, minor_num);
|
|
+ ret = snprintf(vgpu_dev_name, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
|
|
+ NV_VGPU_VFIO_DEVICE_NAME, minor_num);
|
|
+ if (ret <= 0)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
|
|
vgpu_dev_name[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN - 1] = '\0';
|
|
|
|
- return mknod_helper(major, minor_num, vgpu_dev_name, proc_path);
|
|
+ return mknod_helper(major, minor_num, vgpu_dev_name, NV_PROC_REGISTRY_PATH);
|
|
+}
|
|
+
|
|
+int nvidia_cap_get_device_file_attrs(const char* cap_file_path,
|
|
+ int *major,
|
|
+ int *minor,
|
|
+ char *name)
|
|
+{
|
|
+ char field[32];
|
|
+ FILE *fp;
|
|
+ int value;
|
|
+ int ret;
|
|
+
|
|
+ *major = nvidia_get_chardev_major(NV_CAPS_MODULE_NAME);
|
|
+
|
|
+ if (*major < 0)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ fp = fopen(cap_file_path, "r");
|
|
+
|
|
+ if (fp == NULL)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ *minor = -1;
|
|
+
|
|
+ while (fscanf(fp, "%31[^:]: %d\n", field, &value) == 2)
|
|
+ {
|
|
+ field[31] = '\0';
|
|
+ if (strcmp(field, "DeviceFileMinor") == 0)
|
|
+ {
|
|
+ *minor = value;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fclose(fp);
|
|
+
|
|
+ if (*minor < 0)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ret = snprintf(name, NV_MAX_CHARACTER_DEVICE_FILE_STRLEN,
|
|
+ NV_CAP_DEVICE_NAME, *minor);
|
|
+
|
|
+ if (ret < 0 || ret >= NV_MAX_CHARACTER_DEVICE_FILE_STRLEN)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Attempt to create the NVIDIA capability device files.
|
|
+ */
|
|
+int nvidia_cap_mknod(const char* cap_file_path, int *minor)
|
|
+{
|
|
+ int major;
|
|
+ char name[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
|
|
+ int ret;
|
|
+
|
|
+ ret = nvidia_cap_get_device_file_attrs(cap_file_path, &major, minor, name);
|
|
+ if (ret == 0)
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ret = mkdir("/dev/"NV_CAPS_MODULE_NAME, 0755);
|
|
+ if ((ret != 0) && (errno != EEXIST))
|
|
+ {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return mknod_helper(major, *minor, name, cap_file_path);
|
|
+}
|
|
+
|
|
+int nvidia_cap_get_file_state(const char* cap_file_path)
|
|
+{
|
|
+ char path[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN];
|
|
+ mode_t mode;
|
|
+ uid_t uid;
|
|
+ gid_t gid;
|
|
+ int modification_allowed;
|
|
+ int ret;
|
|
+ int major;
|
|
+ int minor;
|
|
+
|
|
+ ret = nvidia_cap_get_device_file_attrs(cap_file_path, &major, &minor, path);
|
|
+ if (ret == 0)
|
|
+ {
|
|
+ path[0] = '\0';
|
|
+ }
|
|
+
|
|
+ init_device_file_parameters(&uid, &gid, &mode, &modification_allowed,
|
|
+ cap_file_path);
|
|
+
|
|
+ return get_file_state_helper(path, major, minor,
|
|
+ cap_file_path, uid, gid, mode);
|
|
}
|
|
|
|
-#endif /* NV_LINUX */
|
|
\ No newline at end of file
|
|
+#endif /* NV_LINUX */
|