diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfsctl.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 73e75ac90525..8bf8f667a8cf 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -538,13 +538,21 @@ out_free: | |||
538 | 538 | ||
539 | static ssize_t | 539 | static ssize_t |
540 | nfsd_print_version_support(char *buf, int remaining, const char *sep, | 540 | nfsd_print_version_support(char *buf, int remaining, const char *sep, |
541 | unsigned vers, unsigned minor) | 541 | unsigned vers, int minor) |
542 | { | 542 | { |
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"; |
544 | bool supported = !!nfsd_vers(vers, NFSD_TEST); | 544 | bool supported = !!nfsd_vers(vers, NFSD_TEST); |
545 | 545 | ||
546 | if (vers == 4 && !nfsd_minorversion(minor, NFSD_TEST)) | 546 | if (vers == 4 && minor >= 0 && |
547 | !nfsd_minorversion(minor, NFSD_TEST)) | ||
547 | supported = false; | 548 | 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; | ||
548 | return snprintf(buf, remaining, format, sep, | 556 | return snprintf(buf, remaining, format, sep, |
549 | supported ? '+' : '-', vers, minor); | 557 | supported ? '+' : '-', vers, minor); |
550 | } | 558 | } |
@@ -554,7 +562,6 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
554 | char *mesg = buf; | 562 | char *mesg = buf; |
555 | char *vers, *minorp, sign; | 563 | char *vers, *minorp, sign; |
556 | int len, num, remaining; | 564 | int len, num, remaining; |
557 | unsigned minor; | ||
558 | ssize_t tlen = 0; | 565 | ssize_t tlen = 0; |
559 | char *sep; | 566 | char *sep; |
560 | struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id); | 567 | 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) | |||
575 | if (len <= 0) return -EINVAL; | 582 | if (len <= 0) return -EINVAL; |
576 | do { | 583 | do { |
577 | enum vers_op cmd; | 584 | enum vers_op cmd; |
585 | unsigned minor; | ||
578 | sign = *vers; | 586 | sign = *vers; |
579 | if (sign == '+' || sign == '-') | 587 | if (sign == '+' || sign == '-') |
580 | num = simple_strtol((vers+1), &minorp, 0); | 588 | num = simple_strtol((vers+1), &minorp, 0); |
@@ -585,8 +593,8 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
585 | return -EINVAL; | 593 | return -EINVAL; |
586 | if (kstrtouint(minorp+1, 0, &minor) < 0) | 594 | if (kstrtouint(minorp+1, 0, &minor) < 0) |
587 | return -EINVAL; | 595 | return -EINVAL; |
588 | } else | 596 | } |
589 | minor = 0; | 597 | |
590 | cmd = sign == '-' ? NFSD_CLEAR : NFSD_SET; | 598 | cmd = sign == '-' ? NFSD_CLEAR : NFSD_SET; |
591 | switch(num) { | 599 | switch(num) { |
592 | case 2: | 600 | case 2: |
@@ -594,8 +602,20 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
594 | nfsd_vers(num, cmd); | 602 | nfsd_vers(num, cmd); |
595 | break; | 603 | break; |
596 | case 4: | 604 | case 4: |
597 | if (nfsd_minorversion(minor, cmd) >= 0) | 605 | if (*minorp == '.') { |
598 | break; | 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; | ||
599 | default: | 619 | default: |
600 | return -EINVAL; | 620 | return -EINVAL; |
601 | } | 621 | } |
@@ -612,9 +632,11 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
612 | sep = ""; | 632 | sep = ""; |
613 | remaining = SIMPLE_TRANSACTION_LIMIT; | 633 | remaining = SIMPLE_TRANSACTION_LIMIT; |
614 | for (num=2 ; num <= 4 ; num++) { | 634 | for (num=2 ; num <= 4 ; num++) { |
635 | int minor; | ||
615 | if (!nfsd_vers(num, NFSD_AVAIL)) | 636 | if (!nfsd_vers(num, NFSD_AVAIL)) |
616 | continue; | 637 | continue; |
617 | minor = 0; | 638 | |
639 | minor = -1; | ||
618 | do { | 640 | do { |
619 | len = nfsd_print_version_support(buf, remaining, | 641 | len = nfsd_print_version_support(buf, remaining, |
620 | sep, num, minor); | 642 | sep, num, minor); |
@@ -624,7 +646,8 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
624 | buf += len; | 646 | buf += len; |
625 | tlen += len; | 647 | tlen += len; |
626 | minor++; | 648 | minor++; |
627 | sep = " "; | 649 | if (len) |
650 | sep = " "; | ||
628 | } while (num == 4 && minor <= NFSD_SUPPORTED_MINOR_VERSION); | 651 | } while (num == 4 && minor <= NFSD_SUPPORTED_MINOR_VERSION); |
629 | } | 652 | } |
630 | out: | 653 | out: |