Skip to content

Commit abcb4da

Browse files
NeilBrownJ. Bruce Fields
authored andcommitted
NFSD: further refinement of content of /proc/fs/nfsd/versions
Prior to e35659f ("NFSD: correctly range-check v4.x minor version when setting versions.") v4.0 could not be disabled without disabling all NFSv4 protocols. So the 'versions' file contained ±4 ±4.1 ±4.2. Writing "-4" would disable all v4 completely. Writing +4 would enabled those minor versions that are currently enabled, either by default or otherwise. After that commit, it was possible to disable v4.0 independently. To maximize backward compatibility with use cases which never disabled v4.0, the "versions" file would never contain "+4.0" - that was implied by "+4", unless explicitly negated by "-4.0". This introduced an inconsistency in that it was possible to disable all minor versions, but still have the major version advertised. e.g. "-4.0 -4.1 -4.2 +4" would result in NFSv4 support being advertised, but all attempts to use it rejected. Commit d3635ff ("nfsd: fix configuration of supported minor versions") and following removed this inconsistency. If all minor version were disabled, the major would be disabled too. If any minor was enabled, the major would be disabled. This patch also treated "+4" as equivalent to "+4.0" and "-4" as "-4.0". A consequence of this is that writing "-4" would only disable 4.0. This is a regression against the earlier behaviour, in a use case that rpc.nfsd actually uses. The command "rpc.nfsd -N 4" will write "+2 +3 -4" to the versions files. Previously, that would disable v4 completely. Now it will only disable v4.0. Also "4.0" never appears in the "versions" file when read. So if only v4.1 is available, the previous kernel would have reported "+4 -4.0 +4.1 -4.2" the current kernel reports "-4 +4.1 -4.2" which could easily confuse. This patch restores the implication that "+4" and "-4" apply more globals and do not imply "4.0". Specifically: writing "-4" will disable all 4.x minor versions. writing "+4" will enable all 4.1 minor version if none are currently enabled. rpc.nfsd will list minor versions before major versions, so rpc.nfsd -V 4.2 -N 4.1 will write "-4.1 +4.2 +2 +3 +4" so it would be a regression for "+4" to enable always all versions. reading "-4" implies that no v4.x are enabled reading "+4" implies that some v4.x are enabled, and that v4.0 is enabled unless "-4.0" is also present. All other minor versions will explicitly be listed. Signed-off-by: NeilBrown <neilb@suse.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
1 parent c952cd4 commit abcb4da

File tree

1 file changed

+33
-10
lines changed

1 file changed

+33
-10
lines changed

fs/nfsd/nfsctl.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -538,13 +538,21 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
538538

539539
static ssize_t
540540
nfsd_print_version_support(char *buf, int remaining, const char *sep,
541-
unsigned vers, unsigned minor)
541+
unsigned vers, int minor)
542542
{
543-
const char *format = (minor == 0) ? "%s%c%u" : "%s%c%u.%u";
543+
const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u";
544544
bool supported = !!nfsd_vers(vers, NFSD_TEST);
545545

546-
if (vers == 4 && !nfsd_minorversion(minor, NFSD_TEST))
546+
if (vers == 4 && minor >= 0 &&
547+
!nfsd_minorversion(minor, NFSD_TEST))
547548
supported = false;
549+
if (minor == 0 && supported)
550+
/*
551+
* special case for backward compatability.
552+
* +4.0 is never reported, it is implied by
553+
* +4, unless -4.0 is present.
554+
*/
555+
return 0;
548556
return snprintf(buf, remaining, format, sep,
549557
supported ? '+' : '-', vers, minor);
550558
}
@@ -554,7 +562,6 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
554562
char *mesg = buf;
555563
char *vers, *minorp, sign;
556564
int len, num, remaining;
557-
unsigned minor;
558565
ssize_t tlen = 0;
559566
char *sep;
560567
struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
@@ -575,6 +582,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
575582
if (len <= 0) return -EINVAL;
576583
do {
577584
enum vers_op cmd;
585+
unsigned minor;
578586
sign = *vers;
579587
if (sign == '+' || sign == '-')
580588
num = simple_strtol((vers+1), &minorp, 0);
@@ -585,17 +593,29 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
585593
return -EINVAL;
586594
if (kstrtouint(minorp+1, 0, &minor) < 0)
587595
return -EINVAL;
588-
} else
589-
minor = 0;
596+
}
597+
590598
cmd = sign == '-' ? NFSD_CLEAR : NFSD_SET;
591599
switch(num) {
592600
case 2:
593601
case 3:
594602
nfsd_vers(num, cmd);
595603
break;
596604
case 4:
597-
if (nfsd_minorversion(minor, cmd) >= 0)
598-
break;
605+
if (*minorp == '.') {
606+
if (nfsd_minorversion(minor, cmd) < 0)
607+
return -EINVAL;
608+
} else if ((cmd == NFSD_SET) != nfsd_vers(num, NFSD_TEST)) {
609+
/*
610+
* Either we have +4 and no minors are enabled,
611+
* or we have -4 and at least one minor is enabled.
612+
* In either case, propagate 'cmd' to all minors.
613+
*/
614+
minor = 0;
615+
while (nfsd_minorversion(minor, cmd) >= 0)
616+
minor++;
617+
}
618+
break;
599619
default:
600620
return -EINVAL;
601621
}
@@ -612,9 +632,11 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
612632
sep = "";
613633
remaining = SIMPLE_TRANSACTION_LIMIT;
614634
for (num=2 ; num <= 4 ; num++) {
635+
int minor;
615636
if (!nfsd_vers(num, NFSD_AVAIL))
616637
continue;
617-
minor = 0;
638+
639+
minor = -1;
618640
do {
619641
len = nfsd_print_version_support(buf, remaining,
620642
sep, num, minor);
@@ -624,7 +646,8 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
624646
buf += len;
625647
tlen += len;
626648
minor++;
627-
sep = " ";
649+
if (len)
650+
sep = " ";
628651
} while (num == 4 && minor <= NFSD_SUPPORTED_MINOR_VERSION);
629652
}
630653
out:

0 commit comments

Comments
 (0)