All of lore.kernel.org
 help / color / mirror / Atom feed
From: "NeilBrown" <neilb@suse.de>
To: Chuck Lever III <chuck.lever@oracle.com>,
	Benjamin Coddington <bcodding@redhat.com>,
	Steve Dickson <SteveD@RedHat.com>,
	Trond Myklebust <trondmy@hammerspace.com>
Cc: Linux NFS Mailing List <linux-nfs@vger.kernel.org>
Subject: [PATCH/RFC] mount.nfs: handle EADDRINUSE from mount(2)
Date: Fri, 25 Mar 2022 11:28:09 +1100	[thread overview]
Message-ID: <164816808982.6096.11435363819568479436@noble.neil.brown.name> (raw)


[[This is the followup to the kernel patch I recently posted.
  It changes the behaviour of incorrectly configured containers to
  get unique client identities - so lease stealing doesn't happen
  so data corruption is avoided - but does not provide stable
  identities, so reboot recovery is not ideal.
  What is best to do when configuration is wrong?  Provide best service
  possible despite it not being perfect, or provide no service so the
  config will not get fixed.  I could be swayed either way.
]]

When NFS filesystems are mounted in different network namespaces, each
network namespace must provide a different hostname (via accompanying
UTS namespace) or different identifier (via sysfs).

If the kernel finds that the identity that it constructs is already in
use in a different namespace it will fail the mount with EADDRINUSE.

This patch catches that error and, if the sysfs identifier is unset,
writes a random string and retries.  This allows the mount to complete
safely even when misconfigured.  The random string has 128 bits of
entropy and so is extremely likely to be globally unique.

A lock is taken on the identifier file, and it is only updated if no
identifier is set.  Thus two concurrent mount attempts will not generate
different identities.  The mount is retried in any case as a race may
have updated the identifier while waiting for the lock.

This is not an ideal solution as an unclean restart of the host cannot
be detected by the server except by a lease timeout.  If the identifier
is configured correctly and is stable across restarts, the server can
detect the restart immediately.  Consequently a warning message is
generated to encourage correct configuration.

Signed-off-by: NeilBrown <neilb@suse.de>
---
 utils/mount/stropts.c | 54 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index dbdd11e76b41..84266830b84a 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -32,6 +32,7 @@
 
 #include <sys/socket.h>
 #include <sys/mount.h>
+#include <sys/file.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
@@ -749,6 +750,50 @@ out:
 	return ret;
 }
 
+#define ENTROPY_BITS 128
+static void set_random_identifier(void)
+{
+	int fd = open("/sys/fs/nfs/net/nfs_client/identifier", O_RDWR);
+	int rfd = -1;
+	unsigned char rbuf[ENTROPY_BITS / 8];
+	char buf[sizeof(rbuf)*2 + 2];
+	int n, rn;
+	int cnt = 1000;
+
+	if (fd < 0)
+		goto out;
+	/* wait at most one second */
+	while (flock(fd, LOCK_EX | LOCK_NB) != 0) {
+		cnt -= 20;
+		if (cnt < 0)
+			goto out;
+		usleep(20 * 1000);
+	}
+	n = read(fd, buf, sizeof(buf)-1);
+	if (n <= 0)
+		goto out;
+	buf[n] = 0;
+	if (n != 7 || strcmp(buf, "(null)\n") != 0)
+		/* already set */
+		goto out;
+	rfd = open("/dev/urandom", O_RDONLY);
+	if (rfd < 0)
+		goto out;
+	rn = read(rfd, rbuf, sizeof(rbuf));
+	if (rn < (int)sizeof(rbuf))
+		goto out;
+	for (n = 0; n < rn; n++)
+		snprintf(&buf[n*2], 3, "%02x", rbuf[n]);
+	strcpy(&buf[n*2], "\n");
+	lseek(fd, SEEK_SET, 0);
+	write(fd, buf, strlen(buf));
+out:
+	if (rfd >= 0)
+		close(rfd);
+	if (fd >= 0)
+		close(fd);
+}
+
 static int nfs_do_mount_v4(struct nfsmount_info *mi,
 		struct sockaddr *sap, socklen_t salen)
 {
@@ -844,7 +889,14 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi,
 			progname, extra_opts);
 
 	result = nfs_sys_mount(mi, options);
-
+	if (!result && errno == EADDRINUSE) {
+		/* client id is not unique, try to create unique id
+		 * and try again
+		 */
+		set_random_identifier();
+		xlog_warn("Retry mount with randomized identifier. Please configure a stable identifier.");
+		result = nfs_sys_mount(mi, options);
+	}
 	/*
 	 * If success, update option string to be recorded in /etc/mtab.
 	 */
-- 
2.35.1


             reply	other threads:[~2022-03-25  0:28 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-25  0:28 NeilBrown [this message]
2022-04-06 15:57 ` [PATCH/RFC] mount.nfs: handle EADDRINUSE from mount(2) Steve Dickson
2022-04-06 22:51   ` NeilBrown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=164816808982.6096.11435363819568479436@noble.neil.brown.name \
    --to=neilb@suse.de \
    --cc=SteveD@RedHat.com \
    --cc=bcodding@redhat.com \
    --cc=chuck.lever@oracle.com \
    --cc=linux-nfs@vger.kernel.org \
    --cc=trondmy@hammerspace.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.