This covers the cross mount case. When mountd/exportd detect a cross mount on a re-exported NFS volume a identifier has to be found to make nfsd happy. Signed-off-by: Richard Weinberger <richard@xxxxxx> --- support/export/Makefile.am | 2 + support/export/cache.c | 140 +++++++++++++++++++++++++++++++++---- utils/exportd/Makefile.am | 8 ++- utils/exportd/exportd.c | 2 + utils/mountd/Makefile.am | 6 ++ 5 files changed, 144 insertions(+), 14 deletions(-) diff --git a/support/export/Makefile.am b/support/export/Makefile.am index eec737f6..90109b1e 100644 --- a/support/export/Makefile.am +++ b/support/export/Makefile.am @@ -14,6 +14,8 @@ libexport_a_SOURCES = client.c export.c hostname.c \ xtab.c mount_clnt.c mount_xdr.c \ cache.c auth.c v4root.c fsloc.c \ v4clients.c +libexport_a_CPPFLAGS = -I$(top_srcdir)/support/reexport + BUILT_SOURCES = $(GENFILES) noinst_HEADERS = mount.h diff --git a/support/export/cache.c b/support/export/cache.c index a5823e92..6039745e 100644 --- a/support/export/cache.c +++ b/support/export/cache.c @@ -33,6 +33,7 @@ #include "export.h" #include "pseudoflavors.h" #include "xcommon.h" +#include "reexport.h" #ifdef HAVE_JUNCTION_SUPPORT #include "fsloc.h" @@ -235,6 +236,16 @@ static void auth_unix_gid(int f) xlog(L_ERROR, "auth_unix_gid: error writing reply"); } +static int match_crossmnt_fsidnum(uint32_t parsed_fsidnum, char *path) +{ + uint32_t fsidnum; + + if (reexpdb_fsidnum_by_path(path, &fsidnum, 0) == 0) + return 0; + + return fsidnum == parsed_fsidnum; +} + #ifdef USE_BLKID static const char *get_uuid_blkdev(char *path) { @@ -331,7 +342,52 @@ static const unsigned long nonblkid_filesystems[] = { 0 /* last */ }; -static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) +static int get_uuid_from_fsid(char *path, char *uuid_str, size_t len) +{ + unsigned int min_dev, maj_dev, min_fsid, maj_fsid; + int rc, n, found = 0, header_seen = 0; + struct stat stb; + FILE *nfsfs_fd; + char line[128]; + + rc = nfsd_path_stat(path, &stb); + if (rc) { + xlog(L_WARNING, "Unable to stat %s", path); + return 0; + } + + nfsfs_fd = fopen("/proc/fs/nfsfs/volumes", "r"); + if (nfsfs_fd == NULL) { + xlog(L_WARNING, "Unable to open nfsfs volume file: %m"); + return 0; + } + + while (fgets(line, sizeof(line), nfsfs_fd) != NULL) { + if (!header_seen) { + header_seen = 1; + continue; + } + n = sscanf(line, "v%*u %*x %*u %u:%u %x:%x %*s", &maj_dev, + &min_dev, &maj_fsid, &min_fsid); + + if (n != 4) { + xlog(L_WARNING, "Unable to parse nfsfs volume line: %d, %s", n, line); + continue; + } + + if (makedev(maj_dev, min_dev) == stb.st_dev) { + found = 1; + snprintf(uuid_str, len, "%08x%08x", maj_fsid, min_fsid); + break; + } + } + + fclose(nfsfs_fd); + + return found; +} + +static int uuid_by_path(struct exportent *exp, char *path, int type, size_t uuidlen, char *uuid) { /* get a uuid for the filesystem found at 'path'. * There are several possible ways of generating the @@ -362,7 +418,7 @@ static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) */ struct statfs64 st; char fsid_val[17]; - const char *blkid_val = NULL; + const char *fsuuid_val = NULL; const char *val; int rc; @@ -375,7 +431,20 @@ static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) break; } if (*bad == 0) - blkid_val = get_uuid_blkdev(path); + fsuuid_val = get_uuid_blkdev(path); + else if (exp->e_reexport == REEXP_REMOTE_DEVFSID && + *bad == 0x6969 /* NFS_SUPER_MAGIC */) { + char tmp[17]; + int ret = get_uuid_from_fsid(path, tmp, sizeof(tmp)); + + if (ret < 0) { + xlog(L_WARNING, "Unable to read nfsfs volume file: %i", ret); + } else if (ret == 0) { + xlog(L_WARNING, "Unable to find nfsfs volume entry for %s", path); + } else { + fsuuid_val = tmp; + } + } } if (rc == 0 && @@ -385,8 +454,8 @@ static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) else fsid_val[0] = 0; - if (blkid_val && (type--) == 0) - val = blkid_val; + if (fsuuid_val && (type--) == 0) + val = fsuuid_val; else if (fsid_val[0] && (type--) == 0) val = fsid_val; else @@ -684,8 +753,13 @@ static int match_fsid(struct parsed_fsid *parsed, nfs_export *exp, char *path) goto match; case FSID_NUM: if (((exp->m_export.e_flags & NFSEXP_FSID) == 0 || - exp->m_export.e_fsid != parsed->fsidnum)) + exp->m_export.e_fsid != parsed->fsidnum)) { + if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT && + match_crossmnt_fsidnum(parsed->fsidnum, path)) + goto match; + goto nomatch; + } goto match; case FSID_UUID4_INUM: case FSID_UUID16_INUM: @@ -708,7 +782,7 @@ static int match_fsid(struct parsed_fsid *parsed, nfs_export *exp, char *path) } else for (type = 0; - uuid_by_path(path, type, parsed->uuidlen, u); + uuid_by_path(&exp->m_export, path, type, parsed->uuidlen, u); type++) if (memcmp(u, parsed->fhuuid, parsed->uuidlen) == 0) goto match; @@ -932,7 +1006,7 @@ static void write_fsloc(char **bp, int *blen, struct exportent *ep) release_replicas(servers); } #endif -static void write_secinfo(char **bp, int *blen, struct exportent *ep, int flag_mask) +static void write_secinfo(char **bp, int *blen, struct exportent *ep, int flag_mask, int extra_flag) { struct sec_entry *p; @@ -947,11 +1021,20 @@ static void write_secinfo(char **bp, int *blen, struct exportent *ep, int flag_m qword_addint(bp, blen, p - ep->e_secinfo); for (p = ep->e_secinfo; p->flav; p++) { qword_addint(bp, blen, p->flav->fnum); - qword_addint(bp, blen, p->flags & flag_mask); + qword_addint(bp, blen, (p->flags | extra_flag) & flag_mask); } } +static int can_reexport_via_fsidnum(struct exportent *exp, struct statfs64 *st) +{ + if (st->f_type != 0x6969 /* NFS_SUPER_MAGIC */) + return 0; + + return exp->e_reexport == REEXP_PREDEFINED_FSIDNUM || + exp->e_reexport == REEXP_AUTO_FSIDNUM; +} + static int dump_to_cache(int f, char *buf, int blen, char *domain, char *path, struct exportent *exp, int ttl) { @@ -968,21 +1051,52 @@ static int dump_to_cache(int f, char *buf, int blen, char *domain, if (exp) { int different_fs = strcmp(path, exp->e_path) != 0; int flag_mask = different_fs ? ~NFSEXP_FSID : ~0; + int rc, do_fsidnum = 0; + uint32_t fsidnum = exp->e_fsid; + + if (different_fs) { + struct statfs64 st; + + rc = nfsd_path_statfs64(path, &st); + if (rc) { + xlog(L_WARNING, "unable to statfs %s", path); + errno = EINVAL; + return -1; + } + + if (can_reexport_via_fsidnum(exp, &st)) { + do_fsidnum = 1; + flag_mask = ~0; + } + } qword_adduint(&bp, &blen, now + exp->e_ttl); - qword_addint(&bp, &blen, exp->e_flags & flag_mask); + + if (do_fsidnum) { + uint32_t search_fsidnum = 0; + if (reexpdb_fsidnum_by_path(path, &search_fsidnum, + exp->e_reexport == REEXP_AUTO_FSIDNUM) == 0) { + errno = EINVAL; + return -1; + } + fsidnum = search_fsidnum; + qword_addint(&bp, &blen, exp->e_flags | NFSEXP_FSID); + } else { + qword_addint(&bp, &blen, exp->e_flags & flag_mask); + } + qword_addint(&bp, &blen, exp->e_anonuid); qword_addint(&bp, &blen, exp->e_anongid); - qword_addint(&bp, &blen, exp->e_fsid); + qword_addint(&bp, &blen, fsidnum); #ifdef HAVE_JUNCTION_SUPPORT write_fsloc(&bp, &blen, exp); #endif - write_secinfo(&bp, &blen, exp, flag_mask); + write_secinfo(&bp, &blen, exp, flag_mask, do_fsidnum ? NFSEXP_FSID : 0); if (exp->e_uuid == NULL || different_fs) { char u[16]; if ((exp->e_flags & flag_mask & NFSEXP_FSID) == 0 && - uuid_by_path(path, 0, 16, u)) { + uuid_by_path(exp, path, 0, 16, u)) { qword_add(&bp, &blen, "uuid"); qword_addhex(&bp, &blen, u, 16); } diff --git a/utils/exportd/Makefile.am b/utils/exportd/Makefile.am index c95bdee7..b0ec9034 100644 --- a/utils/exportd/Makefile.am +++ b/utils/exportd/Makefile.am @@ -16,11 +16,17 @@ exportd_SOURCES = exportd.c exportd_LDADD = ../../support/export/libexport.a \ ../../support/nfs/libnfs.la \ ../../support/misc/libmisc.a \ - $(OPTLIBS) $(LIBBLKID) $(LIBPTHREAD) -luuid + $(OPTLIBS) $(LIBBLKID) $(LIBPTHREAD) \ + -luuid +if CONFIG_REEXPORT +exportd_LDADD += ../../support/reexport/libreexport.a $(LIBSQLITE) -lrt +endif exportd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ -I$(top_srcdir)/support/export +exportd_CPPFLAGS += -I$(top_srcdir)/support/reexport + MAINTAINERCLEANFILES = Makefile.in ####################################################################### diff --git a/utils/exportd/exportd.c b/utils/exportd/exportd.c index 2dd12cb6..4ddfed35 100644 --- a/utils/exportd/exportd.c +++ b/utils/exportd/exportd.c @@ -22,6 +22,7 @@ #include "conffile.h" #include "exportfs.h" #include "export.h" +#include "reexport.h" extern void my_svc_run(void); @@ -296,6 +297,7 @@ main(int argc, char **argv) /* Open files now to avoid sharing descriptors among forked processes */ cache_open(); v4clients_init(); + reexpdb_init(); /* Process incoming upcalls */ cache_process_loop(); diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am index 13b25c90..569d335a 100644 --- a/utils/mountd/Makefile.am +++ b/utils/mountd/Makefile.am @@ -20,10 +20,16 @@ mountd_LDADD = ../../support/export/libexport.a \ $(OPTLIBS) \ $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) -luuid $(LIBTIRPC) \ $(LIBPTHREAD) +if CONFIG_REEXPORT +mountd_LDADD += ../../support/reexport/libreexport.a $(LIBSQLITE) -lrt +endif + mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ -I$(top_builddir)/support/include \ -I$(top_srcdir)/support/export +mountd_CPPFLAGS += -I$(top_srcdir)/support/reexport + MAINTAINERCLEANFILES = Makefile.in ####################################################################### -- 2.31.1