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 <[email protected]>
---
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