[CRIU] [PATCH 2/4] sfd: Rework install, clone helpers to use fcntl
Andrey Vagin
avagin at virtuozzo.com
Tue May 30 14:47:55 PDT 2017
On Tue, May 30, 2017 at 09:13:31PM +0300, Cyrill Gorcunov wrote:
> dup3 closes opened target descriptor silently which already can
> be borrowed by some other code (for example with containers with
> huge memory usage, say 256G, the page transfer pipe may already
> open the fd we reserved for service engine), so we should use
> fcntl here instead and exit with error is such situation
> happened.
>
> Moreover, for calling convenience if there is previous
> sfd already assigned and marked in sfd map -- just close
> it before setting up new instance.
>
> Another problem is clone_service_fd, we may have a situation
> (say fdt_shared testcase) where service_fd_id downgrates so
> we're trying to reinstall already opened desciptors. For
> a while we simply close the desctination because it is
> early-restore-forking stage where we hardly ever get
> collistion with already opened files, but still it's
> not 100% protected and we need to improve sfd engine
> more making tracking per-id based together with proper
> locking scheme.
>
> Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
> ---
> criu/servicefd.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++--------
> 1 file changed, 79 insertions(+), 12 deletions(-)
>
> diff --git a/criu/servicefd.c b/criu/servicefd.c
> index 185021d2ef25..245891b79cbc 100644
> --- a/criu/servicefd.c
> +++ b/criu/servicefd.c
> @@ -8,18 +8,46 @@
>
> #include "servicefd.h"
> #include "bitops.h"
> -#include "log.h"
> +#include "criu-log.h"
>
> #include "common/bug.h"
>
> #undef LOG_PREFIX
> #define LOG_PREFIX "sfd: "
>
> +// #define SFD_DEBUG
> +
> +#ifdef SFD_DEBUG
> +# define pr_sfd_debug(fmt, ...) pr_debug(fmt, ##__VA_ARGS__)
> +#else
> +# define pr_sfd_debug(fmt, ...)
> +#endif
> +
> static DECLARE_BITMAP(sfd_map, SERVICE_FD_MAX);
>
> static int service_fd_rlim_cur;
> static int service_fd_id;
>
> +#define __gen_type_str(x) [x] = __stringify_1(x)
> +static char * const type_str[SERVICE_FD_MAX] = {
> + __gen_type_str(LOG_FD_OFF),
> + __gen_type_str(IMG_FD_OFF),
> + __gen_type_str(PROC_FD_OFF),
> + __gen_type_str(PROC_PID_FD_OFF),
> + __gen_type_str(CTL_TTY_OFF),
> + __gen_type_str(SELF_STDIN_OFF),
> + __gen_type_str(CR_PROC_FD_OFF),
> + __gen_type_str(ROOT_FD_OFF),
> + __gen_type_str(CGROUP_YARD),
> + __gen_type_str(USERNSD_SK),
> + __gen_type_str(NS_FD_OFF),
> + __gen_type_str(TRANSPORT_FD_OFF),
> + __gen_type_str(RPC_SK_OFF),
> + __gen_type_str(FDSTORE_SK_OFF),
> + __gen_type_str(LAZY_PAGES_SK_OFF),
> +};
> +#undef __gen_type_str
> +
> int init_service_fd(void)
> {
> struct rlimit64 rlimit;
> @@ -62,11 +90,30 @@ int reserve_service_fd(enum sfd_type type)
> int install_service_fd(enum sfd_type type, int fd)
> {
> int sfd = __get_service_fd(type, service_fd_id);
> + int ret;
>
> BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX);
> + BUG_ON(type >= ARRAY_SIZE(type_str));
> +
> + pr_sfd_debug("install %d/%d (%s)\n", service_fd_id, sfd, type_str[type]);
> + if (test_bit(type, sfd_map)) {
> + pr_sfd_debug("\tclose previous %d/%d (%s)\n",
> + service_fd_id, sfd, type_str[type]);
> + close_service_fd(type);
> + }
>
> - if (dup3(fd, sfd, O_CLOEXEC) != sfd) {
> - pr_perror("Dup %d -> %d failed", fd, sfd);
> + ret = fcntl(fd, F_DUPFD_CLOEXEC, sfd);
> + if (ret != sfd) {
> + if (ret < 0) {
> + pr_perror("%d/%d -> %d/%d (%s) transition failed",
> + service_fd_id, fd, sfd,
> + service_fd_id, type_str[type]);
> + } else {
> + pr_err("%d/%d (%s) is busy\n",
> + service_fd_id, sfd,
> + type_str[type]);
> + close(ret);
> + }
> return -1;
> }
>
> @@ -92,34 +139,54 @@ int close_service_fd(enum sfd_type type)
>
> close(fd);
> clear_bit(type, sfd_map);
> + pr_sfd_debug("close %d/%d (%s)\n", service_fd_id, fd, type_str[type]);
> return 0;
> }
>
> int clone_service_fd(int id)
> {
> - int ret = -1, i;
> + int ret, i;
>
> if (service_fd_id == id)
> return 0;
>
> + pr_sfd_debug("clone %d/%d\n", service_fd_id, id);
> for (i = SERVICE_FD_MIN + 1; i < SERVICE_FD_MAX; i++) {
> int old = get_service_fd(i);
> int new = __get_service_fd(i, id);
>
> if (old < 0)
> continue;
> - ret = dup2(old, new);
> - if (ret == -1) {
> - if (errno == EBADF)
> - continue;
> - pr_perror("Unable to clone %d->%d", old, new);
> +
> + /*
> + * Cloning of service fds happen at early stage
> + * where no other files needed are opened, so
> + * for simplicity just close the destination.
Why should we close the destination? Who could open it?
> + *
> + * FIXME: Still better to invent more deep tracking
> + * of service files opened, say every rsti(item)
> + * structure should have own sfd_map and everything
> + * should be under appropriate shared locking.
> + */
> + close(new);
I don't understand why we need this close ^^^^
If it is need, why close + fcntl is better than dup2?
> + ret = fcntl(old, F_DUPFD, new);
> + if (ret < 0 || ret != new) {
> + if (ret < 0) {
> + pr_perror("clone %d/%d -> %d/%d (%s) transition failed",
> + service_fd_id, old, id, new, type_str[i]);
> + } else {
> + pr_err("clone %d/%d -> %d/%d (%s) busy\n",
> + service_fd_id, old, id, new, type_str[i]);
> + close(ret);
> + }
> + return -1;
> }
> + pr_sfd_debug("clone %d/%d -> %d/%d (%s)\n",
> + service_fd_id, old, id, new, type_str[i]);
> }
>
> service_fd_id = id;
> - ret = 0;
> -
> - return ret;
> + return 0;
> }
>
> bool is_any_service_fd(int fd)
> --
> 2.7.4
>
More information about the CRIU
mailing list