mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
Since SELinux userspace v3.4 [1], setfiles command supports "-T nthreads"
option, which allows parallel execution. "-T 0" allows using as many
threads as there're available CPU cores. This might speed up the process
of filesystem relabeling in case the appliance is being run with multiple
vCPUs. The latter is true for at least v2v starting from d2b64ecc67
("v2v: Set the number of vCPUs to same as host number of pCPUs.").
For instance, when running virt-v2v-in-place on my 12-core Xeon host
with SSD, with appliance being run with 8 vCPUs (the upper limit specified
in d2b64ecc67), and on the ~150GiB disk VM (physical size on the host),
I get the following results:
./in-place/virt-v2v-in-place -i libvirt fedora37-vm -v -x
Without this patch:
...
commandrvf: setfiles -F -e /sysroot/dev -e /sysroot/proc -e /sysroot/sys -m -C -r /sysroot -v /sysroot/etc/selinux/targeted/contexts/files/file_contexts /sysroot/^M
libguestfs: trace: v2v: selinux_relabel = 0
libguestfs: trace: v2v: rm_f "/.autorelabel"
guestfsd: => selinux_relabel (0x1d3) took 17.94 secs
...
With this patch:
...
commandrvf: setfiles -F -e /sysroot/dev -e /sysroot/proc -e /sysroot/sys -m -C -T 0 -r /sysroot -v /sysroot/etc/selinux/targeted/contexts/files/file_contexts /sysroot/^M
libguestfs: trace: v2v: selinux_relabel = 0
libguestfs: trace: v2v: rm_f "/.autorelabel"
guestfsd: => selinux_relabel (0x1d3) took 5.88 secs
...
So in my scenario it's getting 3 times faster.
[1] https://github.com/SELinuxProject/selinux/releases/tag/3.4
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
170 lines
5.1 KiB
C
170 lines
5.1 KiB
C
/* libguestfs - the guestfsd daemon
|
|
* Copyright (C) 2016 Red Hat Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "guestfs_protocol.h"
|
|
#include "daemon.h"
|
|
#include "actions.h"
|
|
#include "optgroups.h"
|
|
|
|
#include "ignore-value.h"
|
|
|
|
#define MAX_ARGS 64
|
|
|
|
int
|
|
optgroup_selinuxrelabel_available (void)
|
|
{
|
|
return prog_exists ("setfiles");
|
|
}
|
|
|
|
static int
|
|
dir_exists (const char *dir)
|
|
{
|
|
struct stat statbuf;
|
|
|
|
if (stat (dir, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
setfiles_has_option (int *flag, char opt_char)
|
|
{
|
|
CLEANUP_FREE char *err = NULL;
|
|
|
|
if (*flag == -1) {
|
|
char option[] = { '-', opt_char, '\0' }; /* "-X" */
|
|
char err_opt[32]; /* "invalid option -- 'X'" */
|
|
|
|
snprintf(err_opt, sizeof(err_opt), "invalid option -- '%c'", opt_char);
|
|
ignore_value (command (NULL, &err, "setfiles", option, NULL));
|
|
*flag = err && strstr (err, /* "invalid option -- " */ err_opt) == NULL;
|
|
}
|
|
|
|
return *flag;
|
|
}
|
|
|
|
/* Takes optional arguments, consult optargs_bitmask. */
|
|
int
|
|
do_selinux_relabel (const char *specfile, const char *path,
|
|
int force)
|
|
{
|
|
static int flag_m = -1;
|
|
static int flag_C = -1;
|
|
static int flag_T = -1;
|
|
const char *argv[MAX_ARGS];
|
|
CLEANUP_FREE char *s_dev = NULL, *s_proc = NULL, *s_selinux = NULL,
|
|
*s_sys = NULL, *s_specfile = NULL, *s_path = NULL;
|
|
CLEANUP_FREE char *err = NULL;
|
|
size_t i = 0;
|
|
int setfiles_status;
|
|
|
|
s_dev = sysroot_path ("/dev");
|
|
if (!s_dev) {
|
|
malloc_error:
|
|
reply_with_perror ("malloc");
|
|
return -1;
|
|
}
|
|
s_proc = sysroot_path ("/proc"); if (!s_proc) goto malloc_error;
|
|
s_selinux = sysroot_path ("/selinux"); if (!s_selinux) goto malloc_error;
|
|
s_sys = sysroot_path ("/sys"); if (!s_sys) goto malloc_error;
|
|
s_specfile = sysroot_path (specfile); if (!s_specfile) goto malloc_error;
|
|
s_path = sysroot_path (path); if (!s_path) goto malloc_error;
|
|
|
|
/* Default settings if not selected. */
|
|
if (!(optargs_bitmask & GUESTFS_SELINUX_RELABEL_FORCE_BITMASK))
|
|
force = 0;
|
|
|
|
/* If setfiles takes an excessively long time to run (but still
|
|
* completes) then removing .../contexts/files/file_contexts.bin
|
|
* appears to help. If you find any such cases, please add
|
|
* observations to the bug report:
|
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1396297
|
|
*/
|
|
ADD_ARG (argv, i, "setfiles");
|
|
if (force)
|
|
ADD_ARG (argv, i, "-F");
|
|
|
|
/* Exclude some directories that should never be relabelled in
|
|
* ordinary Linux guests. These won't be mounted anyway. We have
|
|
* to prefix all these with the sysroot path.
|
|
*/
|
|
ADD_ARG (argv, i, "-e"); ADD_ARG (argv, i, s_dev);
|
|
ADD_ARG (argv, i, "-e"); ADD_ARG (argv, i, s_proc);
|
|
ADD_ARG (argv, i, "-e"); ADD_ARG (argv, i, s_sys);
|
|
if (dir_exists (s_selinux)) {
|
|
ADD_ARG (argv, i, "-e"); ADD_ARG (argv, i, s_selinux);
|
|
}
|
|
|
|
/* You have to use the -m option (where available) otherwise
|
|
* setfiles puts all the mountpoints on the excludes list for no
|
|
* useful reason (RHBZ#1433577).
|
|
*/
|
|
if (setfiles_has_option (&flag_m, 'm'))
|
|
ADD_ARG (argv, i, "-m");
|
|
|
|
/* Not only do we want setfiles to trudge through individual relabeling
|
|
* errors, we also want the setfiles exit status to differentiate a fatal
|
|
* error from "relabeling errors only". See RHBZ#1794518.
|
|
*/
|
|
if (setfiles_has_option (&flag_C, 'C'))
|
|
ADD_ARG (argv, i, "-C");
|
|
|
|
/* If the appliance is being run with multiple vCPUs, running setfiles
|
|
* in multithreading mode might speeds up the process. Option "-T" was
|
|
* introduced in SELinux userspace v3.4, and we need to check whether it's
|
|
* supported. Passing "-T 0" creates as many threads as there're available
|
|
* vCPU cores.
|
|
* https://github.com/SELinuxProject/selinux/releases/tag/3.4
|
|
*/
|
|
if (setfiles_has_option (&flag_T, 'T')) {
|
|
ADD_ARG (argv, i, "-T"); ADD_ARG (argv, i, "0");
|
|
}
|
|
|
|
/* Relabelling in a chroot. */
|
|
if (STRNEQ (sysroot, "/")) {
|
|
ADD_ARG (argv, i, "-r");
|
|
ADD_ARG (argv, i, sysroot);
|
|
}
|
|
|
|
if (verbose)
|
|
ADD_ARG (argv, i, "-v");
|
|
else
|
|
/* Suppress non-error output. */
|
|
ADD_ARG (argv, i, "-q");
|
|
|
|
/* Add parameters. */
|
|
ADD_ARG (argv, i, s_specfile);
|
|
ADD_ARG (argv, i, s_path);
|
|
ADD_ARG (argv, i, NULL);
|
|
|
|
setfiles_status = commandrv (NULL, &err, argv);
|
|
if ((setfiles_status == 0) || (setfiles_status == 1 && flag_C))
|
|
return 0;
|
|
|
|
reply_with_error ("%s", err);
|
|
return -1;
|
|
}
|