diff options
Diffstat (limited to 'sys-libs/libnvidia-container/files/libnvidia-container-1.1.1-add-utils-c.patch')
-rw-r--r-- | sys-libs/libnvidia-container/files/libnvidia-container-1.1.1-add-utils-c.patch | 801 |
1 files changed, 801 insertions, 0 deletions
diff --git a/sys-libs/libnvidia-container/files/libnvidia-container-1.1.1-add-utils-c.patch b/sys-libs/libnvidia-container/files/libnvidia-container-1.1.1-add-utils-c.patch new file mode 100644 index 000000000..47949f221 --- /dev/null +++ b/sys-libs/libnvidia-container/files/libnvidia-container-1.1.1-add-utils-c.patch @@ -0,0 +1,801 @@ +diff --git a/src/nvidia-modprobe-utils.c b/src/nvidia-modprobe-utils.c +new file mode 100644 +index 0000000..0f97cf9 +--- /dev/null ++++ b/src/nvidia-modprobe-utils.c +@@ -0,0 +1,794 @@ ++ ++#if defined(NV_LINUX) ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <unistd.h> ++#include <errno.h> ++#include <sys/types.h> ++#include <sys/wait.h> ++#include <fcntl.h> ++ ++#include "nvidia-modprobe-utils.h" ++#include "pci-enum.h" ++ ++#define NV_PROC_MODPROBE_PATH "/proc/sys/kernel/modprobe" ++#define NV_PROC_MODULES_PATH "/proc/modules" ++#define NV_PROC_DEVICES_PATH "/proc/devices" ++ ++#define NV_PROC_MODPROBE_PATH_MAX 1024 ++#define NV_MAX_MODULE_NAME_SIZE 16 ++#define NV_MAX_PROC_REGISTRY_PATH_SIZE NV_MAX_CHARACTER_DEVICE_FILE_STRLEN ++#define NV_MAX_LINE_LENGTH 256 ++ ++#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" ++ ++#define NV_MODESET_MODULE_NAME "nvidia-modeset" ++ ++#define NV_VGPU_VFIO_MODULE_NAME "nvidia-vgpu-vfio" ++ ++#define NV_NVLINK_MODULE_NAME "nvidia-nvlink" ++#define NV_NVLINK_PROC_PERM_PATH "/proc/driver/nvidia-nvlink/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_MAJOR_DEVICE_NUMBER 195 ++ ++#define NV_PCI_VENDOR_ID 0x10DE ++ ++#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. ++ */ ++static int modcmp(const char *a, const char *b) ++{ ++ int i; ++ ++ /* Walk both strings and compare each character */ ++ for (i = 0; a[i] && b[i]; i++) ++ { ++ if (a[i] != b[i]) ++ { ++ /* ignore differences between '-' and '_' */ ++ if (((a[i] == '-') || (a[i] == '_')) && ++ ((b[i] == '-') || (b[i] == '_'))) ++ { ++ continue; ++ } ++ ++ break; ++ } ++ } ++ ++ /* ++ * If the strings are of unequal length, only one of a[i] or b[i] == '\0'. ++ * If they are the same length, both will be '\0', and the strings match. ++ */ ++ return a[i] - b[i]; ++} ++ ++ ++/* ++ * Check whether the specified module is loaded by reading ++ * NV_PROC_MODULES_PATH; returns 1 if the kernel module is loaded. ++ * Otherwise, it returns 0. ++ */ ++static int is_kernel_module_loaded(const char *nv_module_name) ++{ ++ FILE *fp; ++ char module_name[NV_MAX_MODULE_NAME_SIZE]; ++ int module_loaded = 0; ++ ++ fp = fopen(NV_PROC_MODULES_PATH, "r"); ++ ++ if (fp == NULL) ++ { ++ return 0; ++ } ++ ++ while (fscanf(fp, "%15s%*[^\n]\n", module_name) == 1) ++ { ++ module_name[15] = '\0'; ++ if (modcmp(module_name, nv_module_name) == 0) ++ { ++ module_loaded = 1; ++ break; ++ } ++ } ++ ++ fclose(fp); ++ ++ return module_loaded; ++} ++ ++/* ++ * Attempt to redirect STDOUT and STDERR to /dev/null. ++ * ++ * This is only for the cosmetics of silencing warnings, so do not ++ * treat any errors here as fatal. ++ */ ++static void silence_current_process(void) ++{ ++ int dev_null_fd = open("/dev/null", O_RDWR); ++ if (dev_null_fd < 0) ++ { ++ return; ++ } ++ ++ dup2(dev_null_fd, STDOUT_FILENO); ++ dup2(dev_null_fd, STDERR_FILENO); ++ close(dev_null_fd); ++} ++ ++/* ++ * Attempt to load a kernel module; returns 1 if kernel module is ++ * successfully loaded. Returns 0 if the kernel module could not be ++ * loaded. ++ * ++ * If any error is encountered and print_errors is non-0, then print the ++ * error to stderr. ++ */ ++static int modprobe_helper(const int print_errors, const char *module_name) ++{ ++ char modprobe_path[NV_PROC_MODPROBE_PATH_MAX]; ++ int status = 1; ++ struct stat file_status; ++ pid_t pid; ++ const char *envp[] = { "PATH=/sbin", NULL }; ++ FILE *fp; ++ ++ /* ++ * Use PCI_BASE_CLASS_MASK to cover both types of DISPLAY controllers that ++ * NVIDIA ships (VGA = 0x300 and 3D = 0x302). ++ */ ++ struct pci_id_match id_match = { ++ NV_PCI_VENDOR_ID, /* Vendor ID = 0x10DE */ ++ PCI_MATCH_ANY, /* Device ID = any */ ++ PCI_MATCH_ANY, /* Subvendor ID = any */ ++ PCI_MATCH_ANY, /* Subdevice ID = any */ ++ 0x0300, /* Device Class = PCI_BASE_CLASS_DISPLAY */ ++ PCI_BASE_CLASS_MASK, /* Display Mask = base class only */ ++ 0 /* Initial number of matches */ ++ }; ++ ++ modprobe_path[0] = '\0'; ++ ++ if (module_name == NULL || module_name[0] == '\0') { ++ return 0; ++ } ++ ++ /* If the kernel module is already loaded, nothing more to do: success. */ ++ ++ if (is_kernel_module_loaded(module_name)) ++ { ++ return 1; ++ } ++ ++ /* ++ * Before attempting to load the module, look for any NVIDIA PCI devices. ++ * If none exist, exit instead of attempting the modprobe, because doing so ++ * would issue error messages that are really irrelevant if there are no ++ * NVIDIA PCI devices present. ++ * ++ * If our check fails, for whatever reason, continue with the modprobe just ++ * in case. ++ */ ++ status = pci_enum_match_id(&id_match); ++ if (status == 0 && id_match.num_matches == 0) ++ { ++ if (print_errors) ++ { ++ fprintf(stderr, ++ "NVIDIA: no NVIDIA devices found\n"); ++ } ++ ++ return 0; ++ } ++ ++ /* Only attempt to load the kernel module if root. */ ++ ++ if (geteuid() != 0) ++ { ++ return 0; ++ } ++ ++ /* Attempt to read the full path to the modprobe executable from /proc. */ ++ ++ fp = fopen(NV_PROC_MODPROBE_PATH, "r"); ++ if (fp != NULL) ++ { ++ char *str; ++ size_t n; ++ ++ n = fread(modprobe_path, 1, sizeof(modprobe_path), fp); ++ ++ /* ++ * Null terminate the string, but make sure 'n' is in the range ++ * [0, sizeof(modprobe_path)-1]. ++ */ ++ n = NV_MIN(n, sizeof(modprobe_path) - 1); ++ modprobe_path[n] = '\0'; ++ ++ /* ++ * If str was longer than a line, we might still have a ++ * newline in modprobe_path: if so, overwrite it with the nul ++ * terminator. ++ */ ++ str = strchr(modprobe_path, '\n'); ++ if (str != NULL) ++ { ++ *str = '\0'; ++ } ++ ++ fclose(fp); ++ } ++ ++ /* If we couldn't read it from /proc, pick a reasonable default. */ ++ ++ if (modprobe_path[0] == '\0') ++ { ++ sprintf(modprobe_path, "/sbin/modprobe"); ++ } ++ ++ /* Do not attempt to exec(3) modprobe if it does not exist. */ ++ ++ if (stat(modprobe_path, &file_status) != 0 || ++ !S_ISREG(file_status.st_mode) || ++ (file_status.st_mode & S_IXUSR) != S_IXUSR) ++ { ++ return 0; ++ } ++ ++ /* Fork and exec modprobe from the child process. */ ++ ++ switch (pid = fork()) ++ { ++ case 0: ++ ++ /* ++ * modprobe might complain in expected scenarios. E.g., ++ * `modprobe nvidia` on a Tegra system with dGPU where no nvidia.ko is ++ * present will complain: ++ * ++ * "modprobe: FATAL: Module nvidia not found." ++ * ++ * Silence the current process to avoid such unwanted messages. ++ */ ++ silence_current_process(); ++ ++ execle(modprobe_path, "modprobe", ++ module_name, NULL, envp); ++ ++ /* If execl(3) returned, then an error has occurred. */ ++ ++ if (print_errors) ++ { ++ fprintf(stderr, ++ "NVIDIA: failed to execute `%s`: %s.\n", ++ modprobe_path, strerror(errno)); ++ } ++ exit(1); ++ ++ case -1: ++ return 0; ++ ++ default: ++ if (waitpid(pid, &status, 0) < 0) ++ { ++ return 0; ++ } ++ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) ++ { ++ return 1; ++ } ++ else ++ { ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++ ++/* ++ * Attempt to load an NVIDIA kernel module ++ */ ++int nvidia_modprobe(const int print_errors, int module_instance) ++{ ++ 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); ++} ++ ++ ++/* ++ * Determine the requested device file parameters: allow users to ++ * override the default UID/GID and/or mode of the NVIDIA device ++ * files, or even whether device file modification should be allowed; ++ * the attributes are managed globally, and can be adjusted via the ++ * appropriate kernel module parameters. ++ */ ++static void init_device_file_parameters(uid_t *uid, gid_t *gid, mode_t *mode, ++ int *modify, const char *proc_path) ++{ ++ FILE *fp; ++ char name[32]; ++ unsigned int value; ++ ++ *mode = NV_DEVICE_FILE_MODE; ++ *uid = NV_DEVICE_FILE_UID; ++ *gid = NV_DEVICE_FILE_GID; ++ *modify = 1; ++ ++ if (proc_path == NULL || proc_path[0] == '\0') ++ { ++ return; ++ } ++ ++ fp = fopen(proc_path, "r"); ++ ++ if (fp == NULL) ++ { ++ return; ++ } ++ ++ while (fscanf(fp, "%31[^:]: %u\n", name, &value) == 2) ++ { ++ name[31] = '\0'; ++ if (strcmp(name, "DeviceFileUID") == 0) ++ { ++ *uid = value; ++ } ++ if (strcmp(name, "DeviceFileGID") == 0) ++ { ++ *gid = value; ++ } ++ if (strcmp(name, "DeviceFileMode") == 0) ++ { ++ *mode = value; ++ } ++ if (strcmp(name, "ModifyDeviceFiles") == 0) ++ { ++ *modify = value; ++ } ++ } ++ ++ fclose(fp); ++} ++ ++/* ++ * A helper to query device file states. ++ */ ++static int get_file_state_helper( ++ const char *path, ++ int major, ++ int minor, ++ const char *proc_path, ++ uid_t uid, ++ gid_t gid, ++ mode_t mode) ++{ ++ dev_t dev = NV_MAKE_DEVICE(major, minor); ++ struct stat stat_buf; ++ int ret; ++ int state = 0; ++ ++ ret = stat(path, &stat_buf); ++ if (ret == 0) ++ { ++ nvidia_update_file_state(&state, NvDeviceFileStateFileExists); ++ ++ if (S_ISCHR(stat_buf.st_mode) && (stat_buf.st_rdev == dev)) ++ { ++ nvidia_update_file_state(&state, NvDeviceFileStateChrDevOk); ++ } ++ ++ if (((stat_buf.st_mode & NV_DEVICE_FILE_MODE_MASK) == mode) && ++ (stat_buf.st_uid == uid) && ++ (stat_buf.st_gid == gid)) ++ { ++ nvidia_update_file_state(&state, NvDeviceFileStatePermissionsOk); ++ } ++ } ++ ++ return state; ++} ++ ++int nvidia_get_file_state(int minor, int module_instance) ++{ ++ 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); ++ ++ init_device_file_parameters(&uid, &gid, &mode, &modification_allowed, ++ proc_path); ++ ++ state = get_file_state_helper(path, NV_MAJOR_DEVICE_NUMBER, minor, ++ proc_path, uid, gid, mode); ++ ++ return state; ++} ++ ++/* ++ * Attempt to create the specified device file with the specified major ++ * and minor number. If proc_path is specified, scan it for custom file ++ * 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) ++{ ++ dev_t dev = NV_MAKE_DEVICE(major, minor); ++ mode_t mode; ++ uid_t uid; ++ gid_t gid; ++ int modification_allowed; ++ int ret; ++ int state; ++ int do_mknod; ++ ++ if (path == NULL || path[0] == '\0') ++ { ++ return 0; ++ } ++ ++ init_device_file_parameters(&uid, &gid, &mode, &modification_allowed, ++ proc_path); ++ ++ /* If device file modification is not allowed, nothing to do: success. */ ++ ++ if (modification_allowed != 1) ++ { ++ return 1; ++ } ++ ++ state = get_file_state_helper(path, major, minor, ++ proc_path, uid, gid, mode); ++ ++ if (nvidia_test_file_state(state, NvDeviceFileStateFileExists) && ++ nvidia_test_file_state(state, NvDeviceFileStateChrDevOk) && ++ nvidia_test_file_state(state, NvDeviceFileStatePermissionsOk)) ++ { ++ return 1; ++ } ++ ++ /* If the stat(2) above failed, we need to create the device file. */ ++ ++ do_mknod = 0; ++ ++ if (!nvidia_test_file_state(state, NvDeviceFileStateFileExists)) ++ { ++ do_mknod = 1; ++ } ++ ++ /* ++ * If the file exists but the file is either not a character device or has ++ * the wrong major/minor character device number, then we need to delete it ++ * and recreate it. ++ */ ++ if (!do_mknod && ++ !nvidia_test_file_state(state, NvDeviceFileStateChrDevOk)) ++ { ++ ret = remove(path); ++ if (ret != 0) ++ { ++ return 0; ++ } ++ do_mknod = 1; ++ } ++ ++ if (do_mknod) ++ { ++ ret = mknod(path, S_IFCHR | mode, dev); ++ if (ret != 0) ++ { ++ return 0; ++ } ++ } ++ ++ /* ++ * Make sure the permissions and ownership are set correctly; if ++ * we created the device above and either of the below fails, then ++ * also delete the device file. ++ */ ++ if ((chmod(path, mode) != 0) || ++ (chown(path, uid, gid) != 0)) ++ { ++ if (do_mknod) ++ { ++ remove(path); ++ } ++ return 0; ++ } ++ ++ return 1; ++} ++ ++ ++/* ++ * 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) ++{ ++ 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); ++ ++ return mknod_helper(NV_MAJOR_DEVICE_NUMBER, minor, path, proc_path); ++} ++ ++ ++/* ++ * Scan NV_PROC_DEVICES_PATH to find the major number of the character ++ * device with the specified name. Returns the major number on success, ++ * or -1 on failure. ++ */ ++int get_chardev_major(const char *name) ++{ ++ int ret = -1; ++ char line[NV_MAX_LINE_LENGTH]; ++ FILE *fp; ++ ++ line[NV_MAX_LINE_LENGTH - 1] = '\0'; ++ ++ fp = fopen(NV_PROC_DEVICES_PATH, "r"); ++ if (!fp) ++ { ++ goto done; ++ } ++ ++ /* Find the beginning of the 'Character devices:' section */ ++ ++ while (fgets(line, NV_MAX_LINE_LENGTH - 1, fp)) ++ { ++ if (strcmp(line, "Character devices:\n") == 0) ++ { ++ break; ++ } ++ } ++ ++ if (ferror(fp)) { ++ goto done; ++ } ++ ++ /* Search for the given module name */ ++ ++ while (fgets(line, NV_MAX_LINE_LENGTH - 1, fp)) ++ { ++ char *found; ++ ++ if (strcmp(line, "\n") == 0 ) ++ { ++ /* we've reached the end of the 'Character devices:' section */ ++ break; ++ } ++ ++ found = strstr(line, name); ++ ++ /* Check for a newline to avoid partial matches */ ++ ++ if (found && found[strlen(name)] == '\n') ++ { ++ int major; ++ ++ /* Read the device major number */ ++ ++ if (sscanf(line, " %d %*s", &major) == 1) ++ { ++ ret = major; ++ } ++ ++ break; ++ } ++ } ++ ++done: ++ ++ if (fp) ++ { ++ fclose(fp); ++ } ++ ++ return ret; ++} ++ ++ ++/* ++ * 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); ++ ++ if (major < 0) ++ { ++ return 0; ++ } ++ ++ return mknod_helper(major, base_minor, NV_UVM_DEVICE_NAME, NULL) && ++ mknod_helper(major, base_minor + 1, NV_UVM_TOOLS_DEVICE_NAME, NULL); ++} ++ ++ ++/* ++ * Attempt to load the NVIDIA Unified Memory kernel module ++ */ ++int nvidia_uvm_modprobe(void) ++{ ++ return modprobe_helper(0, NV_UVM_MODULE_NAME); ++} ++ ++ ++/* ++ * Attempt to load the NVIDIA modeset driver. ++ */ ++int nvidia_modeset_modprobe(void) ++{ ++ return modprobe_helper(0, NV_MODESET_MODULE_NAME); ++} ++ ++ ++/* ++ * Attempt to create the NVIDIA modeset driver device file. ++ */ ++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); ++} ++ ++/* ++ * Attempt to create the NVIDIA NVLink driver device file. ++ */ ++int nvidia_nvlink_mknod(void) ++{ ++ int major = get_chardev_major(NV_NVLINK_MODULE_NAME); ++ ++ if (major < 0) ++ { ++ return 0; ++ } ++ ++ return mknod_helper(major, ++ 0, ++ NV_NVLINK_DEVICE_NAME, ++ NV_NVLINK_PROC_PERM_PATH); ++} ++ ++int nvidia_vgpu_vfio_mknod(int minor_num) ++{ ++ int major = 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]; ++ ++ 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); ++ ++ vgpu_dev_name[NV_MAX_CHARACTER_DEVICE_FILE_STRLEN - 1] = '\0'; ++ ++ return mknod_helper(major, minor_num, vgpu_dev_name, proc_path); ++} ++ ++#endif /* NV_LINUX */ +\ No newline at end of file |