Make sure the database contains no orphaned subvolumes. We have to be careful. Signed-off-by: Richard Weinberger <richard@xxxxxx> --- support/export/cache.c | 97 +++++++++++++++++++++++++++++++++++++++++ support/export/export.h | 3 ++ utils/exportd/exportd.c | 17 +++++++- utils/mountd/mountd.c | 1 + utils/mountd/svc_run.c | 18 ++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) diff --git a/support/export/cache.c b/support/export/cache.c index b5763b1d..94a0d79a 100644 --- a/support/export/cache.c +++ b/support/export/cache.c @@ -1181,6 +1181,103 @@ lookup_export(char *dom, char *path, struct addrinfo *ai) return found; } +static char *get_export_path(char *path) +{ + int i; + nfs_export *exp; + nfs_export *found = NULL; + + for (i = 0; i < MCL_MAXTYPES; i++) { + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { + if (!path_matches(exp, path)) + continue; + + if (!found) { + found = exp; + continue; + } + + /* Always prefer non-V4ROOT exports */ + if (exp->m_export.e_flags & NFSEXP_V4ROOT) + continue; + if (found->m_export.e_flags & NFSEXP_V4ROOT) { + found = exp; + continue; + } + + /* If one is a CROSSMOUNT, then prefer the longest path */ + if (((found->m_export.e_flags & NFSEXP_CROSSMOUNT) || + (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) && + strlen(found->m_export.e_path) != + strlen(exp->m_export.e_path)) { + + if (strlen(exp->m_export.e_path) > + strlen(found->m_export.e_path)) { + found = exp; + } + continue; + } + } + } + + if (found) + return found->m_export.e_path; + else + return NULL; +} + +int export_subvol_orphaned(char *path) +{ + struct statfs st, stp; + char *path_parent; + int ret; + + path_parent = get_export_path(path); + if (!path_parent) + /* + * Path has no parent in export list. + * Must be orphaned. + */ + return 1; + + ret = statfs(path_parent, &stp); + if (ret == -1) + /* + * Parent path is not statfs'able. Maybe not yet mounted? + * Can't be sure, don't treat path as orphaned. + */ + return 0; + + if (strcmp(path_parent, path) == 0) + /* + * This is not a subvolume, it is listed in exports. + * No need to keep tack of it. + */ + return 1; + + if (stp.f_type != 0x6969) + /* + * Parent is not a NFS mount. Maybe not yet mounted? + * Can't be sure either. + */ + return 0; + + ret = statfs(path, &st); + if (ret == -1) { + if (errno == ENOENT) + /* + * Parent is a NFS mount but path is gone. + * Must be orphaned. + */ + return 1; + } + + /* + * For all remaining cases we can't be sure either. + */ + return 0; +} + #ifdef HAVE_JUNCTION_SUPPORT #include <libxml/parser.h> diff --git a/support/export/export.h b/support/export/export.h index 8d5a0d30..45dd3da4 100644 --- a/support/export/export.h +++ b/support/export/export.h @@ -38,4 +38,7 @@ static inline bool is_ipaddr_client(char *dom) { return dom[0] == '$'; } + +int export_subvol_orphaned(char *path); + #endif /* EXPORT__H */ diff --git a/utils/exportd/exportd.c b/utils/exportd/exportd.c index 4ddfed35..6dc51a32 100644 --- a/utils/exportd/exportd.c +++ b/utils/exportd/exportd.c @@ -208,6 +208,12 @@ read_exportd_conf(char *progname, char **argv) default_ttl = ttl; } +static void subvol_cb(char *path) +{ + if (export_subvol_orphaned(path)) + reexpdb_drop_subvolume_unlocked(path); +} + int main(int argc, char **argv) { @@ -297,7 +303,16 @@ main(int argc, char **argv) /* Open files now to avoid sharing descriptors among forked processes */ cache_open(); v4clients_init(); - reexpdb_init(); + if (reexpdb_init() != 0) { + xlog(L_ERROR, "%s: Failed to init reexport database", __func__); + exit(1); + } + + /* + * Load exports into memory and garbage collect orphaned subvolumes. + */ + auth_reload(); + reexpdb_uncover_subvolumes(subvol_cb); /* Process incoming upcalls */ cache_process_loop(); diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c index bcf749fa..8555d746 100644 --- a/utils/mountd/mountd.c +++ b/utils/mountd/mountd.c @@ -32,6 +32,7 @@ #include "nfsd_path.h" #include "nfslib.h" #include "export.h" +#include "reexport.h" extern void my_svc_run(void); diff --git a/utils/mountd/svc_run.c b/utils/mountd/svc_run.c index 167b9757..9a891ff0 100644 --- a/utils/mountd/svc_run.c +++ b/utils/mountd/svc_run.c @@ -57,6 +57,7 @@ #include <rpc/rpc_com.h> #endif #include "export.h" +#include "reexport.h" void my_svc_run(void); @@ -87,6 +88,12 @@ my_svc_getreqset (fd_set *readfds) #endif +static void subvol_cb(char *path) +{ + if (export_subvol_orphaned(path)) + reexpdb_drop_subvolume_unlocked(path); +} + /* * The heart of the server. A crib from libc for the most part... */ @@ -96,6 +103,17 @@ my_svc_run(void) fd_set readfds; int selret; + if (reexpdb_init() != 0) { + xlog(L_ERROR, "%s: Failed to init reexport database", __func__); + return; + } + + /* + * Load exports into memory and garbage collect orphaned subvolumes. + */ + auth_reload(); + reexpdb_uncover_subvolumes(subvol_cb); + for (;;) { readfds = svc_fdset; -- 2.31.1