提交 35a9f27c 编写于 作者: J Jonathan Calmels

Add support for CUDA forward compatibility

上级 ebed710b
......@@ -29,9 +29,6 @@
#include "utils.h"
#include "xfuncs.h"
#define SONAME_LIBCUDA "libcuda.so.1"
#define SONAME_LIBNVML "libnvidia-ml.so.1"
#define MAX_DEVICES 64
#define REAP_TIMEOUT_MS 10
......
......@@ -18,6 +18,9 @@ SVCXPRT *svcunixfd_create(int, u_int, u_int);
#include "error.h"
#define SONAME_LIBCUDA "libcuda.so.1"
#define SONAME_LIBNVML "libnvidia-ml.so.1"
#define SOCK_CLT 0
#define SOCK_SVC 1
......
......@@ -77,6 +77,7 @@ struct nvc_container_config {
char *bins_dir;
char *libs_dir;
char *libs32_dir;
char *cudart_dir;
char *ldconfig;
};
......
......@@ -26,6 +26,7 @@ static char *cgroup_root(char *, char *, const char *);
static char *parse_proc_file(struct error *, const char *, parse_fn, char *, const char *);
static char *find_cgroup_path(struct error *, const struct nvc_container *, const char *);
static char *find_namespace_path(struct error *, const struct nvc_container *, const char *);
static int find_library_paths(struct error *, struct nvc_container *);
static int lookup_owner(struct error *, struct nvc_container *);
static int copy_config(struct error *, struct nvc_container *, const struct nvc_container_config *);
......@@ -180,6 +181,48 @@ find_namespace_path(struct error *err, const struct nvc_container *cnt, const ch
return (ns);
}
static int
find_library_paths(struct error *err, struct nvc_container *cnt)
{
char path[PATH_MAX];
glob_t gl;
int rv = -1;
char **ptr;
if (!(cnt->flags & OPT_COMPUTE_LIBS))
return (0);
if (path_join(err, path, cnt->cfg.rootfs, cnt->cfg.cudart_dir) < 0)
return (-1);
if (path_append(err, path, "compat/lib*.so.*") < 0)
return (-1);
if (xglob(err, path, GLOB_ERR, NULL, &gl) < 0)
goto fail;
if (gl.gl_pathc > 0) {
cnt->nlibs = gl.gl_pathc;
cnt->libs = ptr = array_new(err, gl.gl_pathc);
if (cnt->libs == NULL)
goto fail;
for (size_t i = 0; i < gl.gl_pathc; ++i) {
if (path_resolve(err, path, cnt->cfg.rootfs, gl.gl_pathv[i] + strlen(cnt->cfg.rootfs)) < 0)
goto fail;
if (!str_array_match(path, (const char * const *)cnt->libs, (size_t)(ptr - cnt->libs))) {
log_infof("selecting %s%s", cnt->cfg.rootfs, path);
if ((*ptr++ = xstrdup(err, path)) == NULL)
goto fail;
}
}
array_pack(cnt->libs, &cnt->nlibs);
}
rv = 0;
fail:
globfree(&gl);
return (rv);
}
static int
lookup_owner(struct error *err, struct nvc_container *cnt)
{
......@@ -205,6 +248,7 @@ copy_config(struct error *err, struct nvc_container *cnt, const struct nvc_conta
const char *bins_dir = cfg->bins_dir;
const char *libs_dir = cfg->libs_dir;
const char *libs32_dir = cfg->libs32_dir;
const char *cudart_dir = cfg->cudart_dir;
const char *ldconfig = cfg->ldconfig;
char *rootfs;
int multiarch, ret;
......@@ -266,6 +310,8 @@ copy_config(struct error *err, struct nvc_container *cnt, const struct nvc_conta
}
}
}
if (cudart_dir == NULL)
cudart_dir = CUDA_RUNTIME_DIR;
if (ldconfig == NULL) {
/*
* Some distributions have a wrapper script around ldconfig to reduce package install time.
......@@ -284,6 +330,8 @@ copy_config(struct error *err, struct nvc_container *cnt, const struct nvc_conta
goto fail;
if ((cnt->cfg.libs32_dir = xstrdup(err, libs32_dir)) == NULL)
goto fail;
if ((cnt->cfg.cudart_dir = xstrdup(err, cudart_dir)) == NULL)
goto fail;
if ((cnt->cfg.ldconfig = xstrdup(err, ldconfig)) == NULL)
goto fail;
rv = 0;
......@@ -302,7 +350,7 @@ nvc_container_new(struct nvc_context *ctx, const struct nvc_container_config *cf
if (validate_context(ctx) < 0)
return (NULL);
if (validate_args(ctx, cfg != NULL && cfg->pid > 0 && cfg->rootfs != NULL && !str_empty(cfg->rootfs) && cfg->rootfs[0] == '/' &&
!str_empty(cfg->bins_dir) && !str_empty(cfg->libs_dir) && !str_empty(cfg->libs32_dir) && !str_empty(cfg->ldconfig)) < 0)
!str_empty(cfg->bins_dir) && !str_empty(cfg->libs_dir) && !str_empty(cfg->libs32_dir) && !str_empty(cfg->cudart_dir) && !str_empty(cfg->ldconfig)) < 0)
return (NULL);
if (opts == NULL)
opts = default_container_opts;
......@@ -322,6 +370,10 @@ nvc_container_new(struct nvc_context *ctx, const struct nvc_container_config *cf
goto fail;
if (lookup_owner(&ctx->err, cnt) < 0)
goto fail;
if (!(flags & OPT_NO_CNTLIBS)) {
if (find_library_paths(&ctx->err, cnt) < 0)
goto fail;
}
if ((cnt->mnt_ns = find_namespace_path(&ctx->err, cnt, "mnt")) == NULL)
goto fail;
if (!(flags & OPT_NO_CGROUPS)) {
......@@ -335,6 +387,7 @@ nvc_container_new(struct nvc_context *ctx, const struct nvc_container_config *cf
log_infof("setting bins directory to %s", cnt->cfg.bins_dir);
log_infof("setting libs directory to %s", cnt->cfg.libs_dir);
log_infof("setting libs32 directory to %s", cnt->cfg.libs32_dir);
log_infof("setting cudart directory to %s", cnt->cfg.cudart_dir);
log_infof("setting ldconfig to %s%s", cnt->cfg.ldconfig, (cnt->cfg.ldconfig[0] == '@') ? " (host relative)" : "");
log_infof("setting mount namespace to %s", cnt->mnt_ns);
if (!(flags & OPT_NO_CGROUPS))
......@@ -355,8 +408,10 @@ nvc_container_free(struct nvc_container *cnt)
free(cnt->cfg.bins_dir);
free(cnt->cfg.libs_dir);
free(cnt->cfg.libs32_dir);
free(cnt->cfg.cudart_dir);
free(cnt->cfg.ldconfig);
free(cnt->mnt_ns);
free(cnt->dev_cg);
array_free(cnt->libs, cnt->nlibs);
free(cnt);
}
......@@ -134,7 +134,7 @@ select_libraries(struct error *err, void *ptr, const char *root, const char *ori
/* Check the driver version. */
if ((rv = str_has_suffix(lib, info->nvrm_version)) == false)
goto done;
if (str_array_match(lib, graphics_libs_compat, nitems(graphics_libs_compat))) {
if (str_array_match_prefix(lib, graphics_libs_compat, nitems(graphics_libs_compat))) {
/* Only choose OpenGL/EGL libraries issued by NVIDIA. */
if ((rv = elftool_has_dependency(&et, "libnvidia-glcore.so")) != false)
goto done;
......@@ -394,9 +394,9 @@ lookup_ipcs(struct error *err, struct nvc_driver_info *info, const char *root, i
bool
match_binary_flags(const char *bin, int32_t flags)
{
if ((flags & OPT_UTILITY_BINS) && str_array_match(bin, utility_bins, nitems(utility_bins)))
if ((flags & OPT_UTILITY_BINS) && str_array_match_prefix(bin, utility_bins, nitems(utility_bins)))
return (true);
if ((flags & OPT_COMPUTE_BINS) && str_array_match(bin, compute_bins, nitems(compute_bins)))
if ((flags & OPT_COMPUTE_BINS) && str_array_match_prefix(bin, compute_bins, nitems(compute_bins)))
return (true);
return (false);
}
......@@ -404,15 +404,15 @@ match_binary_flags(const char *bin, int32_t flags)
bool
match_library_flags(const char *lib, int32_t flags)
{
if ((flags & OPT_UTILITY_LIBS) && str_array_match(lib, utility_libs, nitems(utility_libs)))
if ((flags & OPT_UTILITY_LIBS) && str_array_match_prefix(lib, utility_libs, nitems(utility_libs)))
return (true);
if ((flags & OPT_COMPUTE_LIBS) && str_array_match(lib, compute_libs, nitems(compute_libs)))
if ((flags & OPT_COMPUTE_LIBS) && str_array_match_prefix(lib, compute_libs, nitems(compute_libs)))
return (true);
if ((flags & OPT_VIDEO_LIBS) && str_array_match(lib, video_libs, nitems(video_libs)))
if ((flags & OPT_VIDEO_LIBS) && str_array_match_prefix(lib, video_libs, nitems(video_libs)))
return (true);
if ((flags & OPT_GRAPHICS_LIBS) && (str_array_match(lib, graphics_libs, nitems(graphics_libs)) ||
str_array_match(lib, graphics_libs_glvnd, nitems(graphics_libs_glvnd)) ||
str_array_match(lib, graphics_libs_compat, nitems(graphics_libs_compat))))
if ((flags & OPT_GRAPHICS_LIBS) && (str_array_match_prefix(lib, graphics_libs, nitems(graphics_libs)) ||
str_array_match_prefix(lib, graphics_libs_glvnd, nitems(graphics_libs_glvnd)) ||
str_array_match_prefix(lib, graphics_libs_compat, nitems(graphics_libs_compat))))
return (true);
return (false);
}
......
......@@ -36,6 +36,8 @@
#define NV_UVM_PROC_DRIVER "/proc/driver/nvidia-uvm"
#define NV_APP_PROFILE_DIR "/etc/nvidia/nvidia-application-profiles-rc.d"
#define CUDA_RUNTIME_DIR "/usr/local/cuda"
struct nvc_context {
bool initialized;
struct error err;
......@@ -51,6 +53,8 @@ struct nvc_container {
gid_t gid;
char *mnt_ns;
char *dev_cg;
char **libs;
size_t nlibs;
};
enum {
......
......@@ -33,6 +33,7 @@ static void unmount(const char *);
static int setup_cgroup(struct error *, const char *, dev_t);
static int symlink_library(struct error *, const char *, const char *, const char *, uid_t, gid_t);
static int symlink_libraries(struct error *, const struct nvc_container *, const char * const [], size_t);
static void filter_libraries(const struct nvc_driver_info *, char * [], size_t *);
static char **
mount_files(struct error *err, const char *root, const struct nvc_container *cnt, const char *dir, char *paths[], size_t size)
......@@ -397,7 +398,7 @@ symlink_libraries(struct error *err, const struct nvc_container *cnt, const char
lib = basename(paths[i]);
if (str_has_prefix(lib, "libcuda.so")) {
/* XXX Many applications wrongly assume that libcuda.so exists (e.g. with dlopen). */
if (symlink_library(err, paths[i], lib, "libcuda.so", cnt->uid, cnt->gid) < 0)
if (symlink_library(err, paths[i], SONAME_LIBCUDA, "libcuda.so", cnt->uid, cnt->gid) < 0)
return (-1);
} else if (str_has_prefix(lib, "libGLX_nvidia.so")) {
/* XXX GLVND requires this symlink for indirect GLX support. */
......@@ -408,6 +409,27 @@ symlink_libraries(struct error *err, const struct nvc_container *cnt, const char
return (0);
}
static void
filter_libraries(const struct nvc_driver_info *info, char * paths[], size_t *size)
{
char *lib, *maj;
/*
* XXX Filter out any library that matches the major version of RM to prevent us from
* running into an unsupported configurations (e.g. CUDA compat on Geforce or non-LTS drivers).
*/
for (size_t i = 0; i < *size; ++i) {
lib = basename(paths[i]);
if ((maj = strstr(lib, ".so.")) != NULL) {
maj += strlen(".so.");
if (strncmp(info->nvrm_version, maj, strspn(maj, "0123456789")))
continue;
}
paths[i] = NULL;
}
array_pack(paths, size);
}
int
nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const struct nvc_driver_info *info)
{
......@@ -423,7 +445,7 @@ nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const
if (ns_enter(&ctx->err, cnt->mnt_ns, CLONE_NEWNS) < 0)
return (-1);
nmnt = 2 + info->nbins + info->nlibs + info->nlibs32 + info->nipcs + info->ndevs;
nmnt = 2 + info->nbins + info->nlibs + cnt->nlibs + info->nlibs32 + info->nipcs + info->ndevs;
mnt = ptr = (const char **)array_new(&ctx->err, nmnt);
if (mnt == NULL)
goto fail;
......@@ -431,12 +453,14 @@ nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const
/* Procfs mount */
if ((*ptr++ = mount_procfs(&ctx->err, ctx->cfg.root, cnt)) == NULL)
goto fail;
/* Application profile mount */
if (cnt->flags & OPT_GRAPHICS_LIBS) {
if ((*ptr++ = mount_app_profile(&ctx->err, cnt)) == NULL)
goto fail;
}
/* Binary and library mounts */
/* Host binary and library mounts */
if (info->bins != NULL && info->nbins > 0) {
if ((tmp = (const char **)mount_files(&ctx->err, ctx->cfg.root, cnt, cnt->cfg.bins_dir, info->bins, info->nbins)) == NULL)
goto fail;
......@@ -457,6 +481,24 @@ nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const
}
if (symlink_libraries(&ctx->err, cnt, mnt, (size_t)(ptr - mnt)) < 0)
goto fail;
/* Container library mounts */
if (cnt->libs != NULL && cnt->nlibs > 0) {
size_t nlibs = cnt->nlibs;
char **libs = array_copy(&ctx->err, (const char * const *)cnt->libs, cnt->nlibs);
if (libs == NULL)
goto fail;
filter_libraries(info, libs, &nlibs);
if ((tmp = (const char **)mount_files(&ctx->err, cnt->cfg.rootfs, cnt, cnt->cfg.libs_dir, libs, nlibs)) == NULL) {
free(libs);
goto fail;
}
ptr = array_append(ptr, tmp, array_size(tmp));
free(tmp);
free(libs);
}
/* IPC mounts */
for (size_t i = 0; i < info->nipcs; ++i) {
/* XXX Only utility libraries require persistenced IPC, everything else is compute only. */
......@@ -468,6 +510,7 @@ nvc_driver_mount(struct nvc_context *ctx, const struct nvc_container *cnt, const
if ((*ptr++ = mount_ipc(&ctx->err, ctx->cfg.root, cnt, info->ipcs[i])) == NULL)
goto fail;
}
/* Device mounts */
for (size_t i = 0; i < info->ndevs; ++i) {
/* XXX Only compute libraries require specific devices (e.g. UVM). */
......
......@@ -55,17 +55,18 @@ enum {
OPT_STANDALONE = 1 << 1,
OPT_NO_CGROUPS = 1 << 2,
OPT_NO_DEVBIND = 1 << 3,
OPT_UTILITY_LIBS = 1 << 4,
OPT_COMPUTE_LIBS = 1 << 5,
OPT_VIDEO_LIBS = 1 << 6,
OPT_GRAPHICS_LIBS = 1 << 7,
OPT_DISPLAY = 1 << 8,
OPT_UTILITY_BINS = 1 << 9,
OPT_COMPUTE_BINS = 1 << 10,
OPT_NO_CNTLIBS = 1 << 4,
OPT_UTILITY_LIBS = 1 << 5,
OPT_COMPUTE_LIBS = 1 << 6,
OPT_VIDEO_LIBS = 1 << 7,
OPT_GRAPHICS_LIBS = 1 << 8,
OPT_DISPLAY = 1 << 9,
OPT_UTILITY_BINS = 1 << 10,
OPT_COMPUTE_BINS = 1 << 11,
#if defined(__powerpc64__) /* ppc64le doesn't support compat32. */
OPT_COMPAT32 = 1 << 0,
#else
OPT_COMPAT32 = 1 << 11,
OPT_COMPAT32 = 1 << 12,
#endif /* defined(__powerpc64__) */
};
......@@ -74,6 +75,7 @@ static const struct option container_opts[] = {
{"standalone", OPT_STANDALONE},
{"no-cgroups", OPT_NO_CGROUPS},
{"no-devbind", OPT_NO_DEVBIND},
{"no-cntlibs", OPT_NO_CNTLIBS},
{"utility", OPT_UTILITY_BINS|OPT_UTILITY_LIBS},
{"compute", OPT_COMPUTE_BINS|OPT_COMPUTE_LIBS},
{"video", OPT_VIDEO_LIBS|OPT_COMPUTE_LIBS},
......
......@@ -172,7 +172,7 @@ str_empty(const char *str)
}
bool
str_array_match(const char *str, const char * const arr[], size_t size)
str_array_match_prefix(const char *str, const char * const arr[], size_t size)
{
for (size_t i = 0; i < size; ++i) {
if (str_has_prefix(str, arr[i]))
......@@ -181,6 +181,16 @@ str_array_match(const char *str, const char * const arr[], size_t size)
return (false);
}
bool
str_array_match(const char *str, const char * const arr[], size_t size)
{
for (size_t i = 0; i < size; ++i) {
if (str_equal(str, arr[i]))
return (true);
}
return (false);
}
int
str_join(struct error *err, char **s1, const char *s2, const char *sep)
{
......@@ -327,7 +337,7 @@ ns_enter(struct error *err, const char *path, int nstype)
char **
array_new(struct error *err, size_t size)
{
char **arr = NULL;
char **arr;
arr = xcalloc(err, size, sizeof(*arr));
return (arr);
......@@ -350,6 +360,17 @@ array_append(const char **ptr, const char * const arr[], size_t size)
return (ptr + size);
}
char **
array_copy(struct error *err, const char * const arr[], size_t size)
{
char **ptr;
if ((ptr = array_new(err, size)) == NULL)
return (NULL);
array_append((const char **)ptr, arr, size);
return (ptr);
}
void
array_pack(char *arr[], size_t *size)
{
......
......@@ -49,6 +49,7 @@ bool str_case_equal(const char *, const char *);
bool str_has_prefix(const char *, const char *);
bool str_has_suffix(const char *, const char *);
bool str_empty(const char *);
bool str_array_match_prefix(const char *, const char * const [], size_t);
bool str_array_match(const char *, const char * const [], size_t);
int str_to_pid(struct error *, const char *, pid_t *);
int str_to_ugid(struct error *, char *, uid_t *, gid_t *);
......@@ -60,6 +61,7 @@ int ns_enter(struct error *, const char *, int);
char **array_new(struct error *, size_t);
void array_free(char *[], size_t);
void array_pack(char *[], size_t *);
char **array_copy(struct error *, const char * const [], size_t);
size_t array_size(const char * const []);
const char **array_append(const char **, const char * const [], size_t);
......
......@@ -10,7 +10,9 @@
#include <sys/types.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -30,6 +32,7 @@ static inline void *xdlopen(struct error *, const char *, int);
static inline int xdlclose(struct error *, void *);
static inline int xmount(struct error *, const char *, const char *,
const char *, unsigned long, const void *);
static inline int xglob(struct error *, const char *, int, int (*)(const char *, int), glob_t *);
#include "error.h"
......@@ -154,4 +157,21 @@ xmount(struct error *err, const char *source, const char *target,
return (rv);
}
static inline int
xglob(struct error *err, const char *pattern, int flags, int (*errfn)(const char *, int), glob_t *pglob)
{
int rv;
rv = glob(pattern, flags, errfn, pglob);
if (rv != 0 && rv != GLOB_NOMATCH && errno != ENOENT) {
error_set(err, "glob search failed: %s", pattern);
return (-1);
}
if (rv != 0) {
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
}
return (0);
}
#endif /* HEADER_XFUNCS_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册