Skip to content

Commit

Permalink
fuse-overlayfs: add plugin system
Browse files Browse the repository at this point in the history
Add a simple plugin mechanism that will help to expand fuse-overlayfs
functionalities, in particular it allows to load data from a layer on
demand.

A plugin is loaded into fuse-overlayfs using the option:

-o plugins=path/to/plugin.so:path/to/another/plugin.so

A layer can use a plugin with the syntax:

-o lowerdir=//plugin-name/DATA-FOR-THE-PLUGIN/path

Each time a file/directory is looked up, if a plugin is registered for
a layer, the plugin is first notified about the request.

After the callback is invoked, fuse-overlayfs still expects the data
to be accessible at the specified directory.

Signed-off-by: Giuseppe Scrivano <[email protected]>
  • Loading branch information
giuseppe committed Sep 13, 2019
1 parent 5604e3a commit b512206
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 10 deletions.
4 changes: 2 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ bin_PROGRAMS = fuse-overlayfs

ACLOCAL_AMFLAGS = -Im4

EXTRA_DIST = m4/gnulib-cache.m4 rpm/fuse-overlayfs.spec.template autogen.sh fuse-overlayfs.1.md utils.h NEWS
EXTRA_DIST = m4/gnulib-cache.m4 rpm/fuse-overlayfs.spec.template autogen.sh fuse-overlayfs.1.md utils.h NEWS plugin.h plugin-manager.h

CLEANFILES = fuse-overlayfs.1

fuse_overlayfs_CFLAGS = -I . -I $(abs_srcdir)/lib $(FUSE_CFLAGS)
fuse_overlayfs_LDFLAGS =
fuse_overlayfs_LDADD = lib/libgnu.a $(FUSE_LIBS)
fuse_overlayfs_SOURCES = main.c direct.c utils.c
fuse_overlayfs_SOURCES = main.c direct.c utils.c plugin-manager.c

WD := $(shell pwd)

Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ LDFLAGS=$old_LDFLAGS

AC_DEFINE_UNQUOTED([HAVE_FUSE_CACHE_READDIR], $cache_readdir, [Define if libfuse is available])

AC_SEARCH_LIBS([dlopen], [dl], [], [AC_MSG_ERROR([unable to find dlopen()])])

AC_FUNC_ERROR_AT_LINE
AC_FUNC_MALLOC
Expand Down
11 changes: 7 additions & 4 deletions direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,16 @@ direct_readlinkat (struct ovl_layer *l, const char *path, char *buf, size_t bufs
}

static int
direct_load_data_source (struct ovl_layer *l, const char *opaque)
direct_load_data_source (struct ovl_layer *l, const char *opaque, const char *path)
{
l->path = realpath (opaque, NULL);
l->path = realpath (path, NULL);
if (l->path == NULL)
return -1;
{
fprintf (stderr, "cannot resolve path %s\n", path);
return -1;
}

l->fd = open (l->path, O_DIRECTORY);
l->fd = open (path, O_DIRECTORY);
if (l->fd < 0)
{
free (l->path);
Expand Down
11 changes: 9 additions & 2 deletions fuse-overlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@
#ifndef FUSE_OVERLAYFS_H
# define FUSE_OVERLAYFS_H

# include <hash.h>
# include <sys/stat.h>
# include <plugin-manager.h>
# include <stdbool.h>
# include <sys/types.h>

typedef struct hash_table Hash_table;

struct ovl_ino
{
Expand Down Expand Up @@ -76,6 +80,7 @@ struct ovl_data
char *upperdir;
char *workdir;
char *redirect_dir;
char *plugins;
int workdir_fd;
int debug;
struct ovl_layer *layers;
Expand All @@ -94,6 +99,8 @@ struct ovl_data
/* current uid/gid*/
uid_t uid;
uid_t gid;

struct ovl_plugin_context *plugins_ctx;
};

struct ovl_layer
Expand All @@ -109,7 +116,7 @@ struct ovl_layer
/* a data_source defines the methods for accessing a lower layer. */
struct data_source
{
int (*load_data_source)(struct ovl_layer *l, const char *opaque);
int (*load_data_source)(struct ovl_layer *l, const char *opaque, const char *path);
int (*cleanup)(struct ovl_layer *l);
int (*file_exists)(struct ovl_layer *l, const char *pathname);
int (*statat)(struct ovl_layer *l, const char *path, struct stat *st, int flags);
Expand Down
74 changes: 72 additions & 2 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@

#include <pthread.h>

#include <plugin.h>

#ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(expression) \
(__extension__ \
Expand Down Expand Up @@ -211,6 +213,8 @@ static const struct fuse_opt ovl_opts[] = {
offsetof (struct ovl_data, writeback), 1},
{"noxattrs=%d",
offsetof (struct ovl_data, disable_xattrs), 1},
{"plugins=%s",
offsetof (struct ovl_data, plugins), 0},
FUSE_OPT_END
};

Expand Down Expand Up @@ -1526,21 +1530,80 @@ read_dirs (struct ovl_data *lo, char *path, bool low, struct ovl_layer *layers)

for (it = strtok_r (buf, ":", &saveptr); it; it = strtok_r (NULL, ":", &saveptr))
{
char *name, *data;
char *it_path = it;
cleanup_layer struct ovl_layer *l = NULL;

l = calloc (1, sizeof (*l));
if (l == NULL)
return NULL;


/* By default use the direct access data store. */
l->ds = &direct_access_ds;

if (it[0] != '/' || it[1] != '/')
{
data = NULL;
path = it_path;
}
else
{
struct ovl_plugin *p;
char *plugin_data_sep, *plugin_sep;

if (! low)
{
fprintf (stderr, "plugins are supported only with lower layers\n");
return NULL;
}

plugin_sep = strchr (it + 2, '/');
if (! plugin_sep)
{
fprintf (stderr, "invalid separator for plugin\n");
return NULL;
}

*plugin_sep = '\0';

name = it + 2;
data = plugin_sep + 1;

plugin_data_sep = strchr (data, '/');
if (! plugin_data_sep)
{
fprintf (stderr, "invalid separator for plugin\n");
return NULL;
}

*plugin_data_sep = '\0';
path = plugin_data_sep + 1;

p = plugin_find (lo->plugins_ctx, name);
if (! p)
{
fprintf (stderr, "cannot find plugin %s\n", name);
return NULL;
}
l->ds = p->load (l, data, path);
if (l->ds == NULL)
{
fprintf (stderr, "cannot load plugin %s\n", name);
return NULL;
}
}

l->ovl_data = lo;

l->path = NULL;
l->fd = -1;

if (l->ds->load_data_source (l, it) < 0)
return NULL;
if (l->ds->load_data_source (l, data, path) < 0)
{
fprintf (stderr, "cannot load store %s at %s\n", data, path);
return NULL;
}

l->low = low;
if (low)
Expand Down Expand Up @@ -4883,6 +4946,7 @@ main (int argc, char *argv[])
fprintf (stderr, "workdir=%s\n", lo.workdir);
fprintf (stderr, "lowerdir=%s\n", lo.lowerdir);
fprintf (stderr, "mountpoint=%s\n", lo.mountpoint);
fprintf (stderr, "plugins=%s\n", lo.plugins);
}

lo.uid_mappings = lo.uid_str ? read_mappings (lo.uid_str) : NULL;
Expand All @@ -4896,6 +4960,9 @@ main (int argc, char *argv[])
error (EXIT_FAILURE, errno, "cannot convert %s", lo.timeout_str);
}

if (lo.plugins)
lo.plugins_ctx = load_plugins (lo.plugins);

layers = read_dirs (&lo, lo.lowerdir, true, NULL);
if (layers == NULL)
{
Expand Down Expand Up @@ -4979,6 +5046,9 @@ main (int argc, char *argv[])

hash_free (lo.inodes);

if (lo.plugins)
plugin_free_all (lo.plugins_ctx);

free_mapping (lo.uid_mappings);
free_mapping (lo.gid_mappings);

Expand Down
122 changes: 122 additions & 0 deletions plugin-manager.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/* fuse-overlayfs: Overlay Filesystem in Userspace
Copyright (C) 2019 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 3 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, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>
#include <plugin.h>
#include <stdlib.h>
#include <error.h>
#include <errno.h>
#include <string.h>

struct ovl_plugin_context *
load_plugins (const char *plugins)
{
char *saveptr = NULL, *it;
cleanup_free char *buf = NULL;
struct ovl_plugin_context *ctx;

ctx = calloc (1, sizeof (*ctx));
if (ctx == NULL)
error (EXIT_FAILURE, errno, "cannot allocate context");

buf = strdup (plugins);
if (buf == NULL)
error (EXIT_FAILURE, errno, "cannot allocate memory");

for (it = strtok_r (buf, ":", &saveptr); it; it = strtok_r (NULL, ":", &saveptr))
plugin_load_one (ctx, it);

return ctx;
}

void
plugin_load_one (struct ovl_plugin_context *context, const char *path)
{
plugin_name name;
struct ovl_plugin *p;
plugin_version version;
void *handle = dlopen (path, RTLD_NOW|RTLD_LOCAL);
if (! handle)
error (EXIT_FAILURE, 0, "cannot load plugin %s: %s", path, dlerror());

p = calloc (1, sizeof (*p));
if (p == NULL)
error (EXIT_FAILURE, errno, "cannot load plugin %s", path);
p->next = context->plugins;

version = dlsym (handle, "plugin_version");
if (version == NULL)
error (EXIT_FAILURE, 0, "cannot find symbol `plugin_version` in plugin %s", path);

if (version () != 1)
error (EXIT_FAILURE, 0, "invalid plugin version for %s", path);

p->handle = handle;
name = dlsym (handle, "plugin_name");
if (name == NULL)
error (EXIT_FAILURE, 0, "cannot find symbol `plugin_name` in plugin %s", path);

p->name = name ();

if (plugin_find (context, p->name))
error (EXIT_FAILURE, 0, "plugin %s added twice", p->name);

p->load = dlsym (handle, "plugin_load");
if (p->load == NULL)
error (EXIT_FAILURE, 0, "cannot find symbol `plugin_load` in plugin %s", path);

p->release = dlsym (handle, "plugin_release");
if (p->release == NULL)
error (EXIT_FAILURE, 0, "cannot find symbol `plugin_release` in plugin %s", path);

context->plugins = p;
}

struct ovl_plugin *
plugin_find (struct ovl_plugin_context *context, const char *name)
{
struct ovl_plugin *it;

for (it = context->plugins; it; it = it->next)
{
if (strcmp (name, it->name) == 0)
return it;
}
return NULL;
}

int
plugin_free_all (struct ovl_plugin_context *context)
{
struct ovl_plugin *it, *next;

it = context->plugins;
while (it)
{
next = it->next;

dlclose (it->handle);
free (it);

it = next;
}

free (context);

return 0;
}
35 changes: 35 additions & 0 deletions plugin-manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* fuse-overlayfs: Overlay Filesystem in Userspace
Copyright (C) 2019 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 3 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, see <http://www.gnu.org/licenses/>.
*/

#ifndef PLUGIN_MANAGER_H
# define PLUGIN_MANAGER_H
# include <config.h>

# include <dlfcn.h>

struct ovl_plugin_context
{
struct ovl_plugin *plugins;
};

void plugin_load_one (struct ovl_plugin_context *context, const char *path);
int plugin_free_all (struct ovl_plugin_context *context);
struct ovl_plugin *plugin_find (struct ovl_plugin_context *context, const char *name);
struct ovl_plugin_context *load_plugins (const char *plugins);

#endif
Loading

0 comments on commit b512206

Please sign in to comment.