From patchwork Thu Feb 17 13:15:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Weinberger X-Patchwork-Id: 12750034 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4A03BC4332F for ; Thu, 17 Feb 2022 13:22:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230153AbiBQNXL (ORCPT ); Thu, 17 Feb 2022 08:23:11 -0500 Received: from mxb-00190b01.gslb.pphosted.com ([23.128.96.19]:51070 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240747AbiBQNXJ (ORCPT ); Thu, 17 Feb 2022 08:23:09 -0500 Received: from lithops.sigma-star.at (lithops.sigma-star.at [195.201.40.130]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EA1C398F7A for ; Thu, 17 Feb 2022 05:22:52 -0800 (PST) Received: from localhost (localhost [127.0.0.1]) by lithops.sigma-star.at (Postfix) with ESMTP id D6A1760ED821; Thu, 17 Feb 2022 14:16:40 +0100 (CET) Received: from lithops.sigma-star.at ([127.0.0.1]) by localhost (lithops.sigma-star.at [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id 8HEKE043ZNLK; Thu, 17 Feb 2022 14:16:39 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by lithops.sigma-star.at (Postfix) with ESMTP id 7408E60765A3; Thu, 17 Feb 2022 14:16:39 +0100 (CET) Received: from lithops.sigma-star.at ([127.0.0.1]) by localhost (lithops.sigma-star.at [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id w30w7zKvo9uz; Thu, 17 Feb 2022 14:16:39 +0100 (CET) Received: from blindfold.corp.sigma-star.at (213-47-184-186.cable.dynamic.surfer.at [213.47.184.186]) by lithops.sigma-star.at (Postfix) with ESMTPSA id EAC65608898A; Thu, 17 Feb 2022 14:16:38 +0100 (CET) From: Richard Weinberger To: linux-nfs@vger.kernel.org Cc: david@sigma-star.at, bfields@fieldses.org, luis.turcitu@appsbroker.com, david.young@appsbroker.com, david.oberhollenzer@sigma-star.at, trond.myklebust@hammerspace.com, anna.schumaker@netapp.com, chris.chilvers@appsbroker.com, Richard Weinberger Subject: [RFC PATCH 3/6] export: Implement logic behind reexport= Date: Thu, 17 Feb 2022 14:15:28 +0100 Message-Id: <20220217131531.2890-4-richard@nod.at> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20220217131531.2890-1-richard@nod.at> References: <20220217131531.2890-1-richard@nod.at> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org 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 --- 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 #######################################################################