#include <asm/uaccess.h>
 
-unsigned int nfsd_versbits = ~0;
-
 /*
  *     We have a single directory with 9 nodes in it.
  */
 
        if (size>0) {
                if (nfsd_serv)
+                       /* Cannot change versions without updating
+                        * nfsd_serv->sv_xdrsize, and reallocing
+                        * rq_argp and rq_resp
+                        */
                        return -EBUSY;
                if (buf[size-1] != '\n')
                        return -EINVAL;
                        case 2:
                        case 3:
                        case 4:
-                               if (sign != '-')
-                                       NFSCTL_VERSET(nfsd_versbits, num);
-                               else
-                                       NFSCTL_VERUNSET(nfsd_versbits, num);
+                               nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
                                break;
                        default:
                                return -EINVAL;
                /* If all get turned off, turn them back on, as
                 * having no versions is BAD
                 */
-               if ((nfsd_versbits & NFSCTL_VERALL)==0)
-                       nfsd_versbits = NFSCTL_VERALL;
+               nfsd_reset_versions();
        }
        /* Now write current state into reply buffer */
        len = 0;
        sep = "";
        for (num=2 ; num <= 4 ; num++)
-               if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) {
+               if (nfsd_vers(num, NFSD_AVAIL)) {
                        len += sprintf(buf+len, "%s%c%d", sep,
-                                      NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-',
+                                      nfsd_vers(num, NFSD_TEST)?'+':'-',
                                       num);
                        sep = " ";
                }
 
 
 };
 
+int nfsd_vers(int vers, enum vers_op change)
+{
+       if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
+               return -1;
+       switch(change) {
+       case NFSD_SET:
+               nfsd_versions[vers] = nfsd_version[vers];
+               break;
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+               if (vers < NFSD_ACL_NRVERS)
+                       nfsd_acl_version[vers] = nfsd_acl_version[vers];
+#endif
+       case NFSD_CLEAR:
+               nfsd_versions[vers] = NULL;
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+               if (vers < NFSD_ACL_NRVERS)
+                       nfsd_acl_version[vers] = NULL;
+#endif
+               break;
+       case NFSD_TEST:
+               return nfsd_versions[vers] != NULL;
+       case NFSD_AVAIL:
+               return nfsd_version[vers] != NULL;
+       }
+       return 0;
+}
 /*
  * Maximum number of nfsd processes
  */
                nfsd_export_flush();
        }
 }
+
+void nfsd_reset_versions(void)
+{
+       int found_one = 0;
+       int i;
+
+       for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
+               if (nfsd_program.pg_vers[i])
+                       found_one = 1;
+       }
+
+       if (!found_one) {
+               for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
+                       nfsd_program.pg_vers[i] = nfsd_version[i];
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+               for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
+                       nfsd_acl_program.pg_vers[i] =
+                               nfsd_acl_version[i];
+#endif
+       }
+}
+
 int
 nfsd_svc(unsigned short port, int nrservs)
 {
        int     error;
-       int     found_one, i;
        struct list_head *victim;
        
        lock_kernel();
-       dprintk("nfsd: creating service: vers 0x%x\n",
-               nfsd_versbits);
+       dprintk("nfsd: creating service\n");
        error = -EINVAL;
        if (nrservs <= 0)
                nrservs = 0;
        if (error<0)
                goto out;
        if (!nfsd_serv) {
-               /*
-                * Use the nfsd_ctlbits to define which
-                * versions that will be advertised.
-                * If nfsd_ctlbits doesn't list any version,
-                * export them all.
-                */
-               found_one = 0;
-
-               for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
-                       if (NFSCTL_VERISSET(nfsd_versbits, i)) {
-                               nfsd_program.pg_vers[i] = nfsd_version[i];
-                               found_one = 1;
-                       } else
-                               nfsd_program.pg_vers[i] = NULL;
-               }
-
-               if (!found_one) {
-                       for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
-                               nfsd_program.pg_vers[i] = nfsd_version[i];
-               }
-
-
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-               found_one = 0;
-
-               for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) {
-                       if (NFSCTL_VERISSET(nfsd_versbits, i)) {
-                               nfsd_acl_program.pg_vers[i] =
-                                       nfsd_acl_version[i];
-                               found_one = 1;
-                       } else
-                               nfsd_acl_program.pg_vers[i] = NULL;
-               }
-
-               if (!found_one) {
-                       for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
-                               nfsd_acl_program.pg_vers[i] =
-                                       nfsd_acl_version[i];
-               }
-#endif
+               nfsd_reset_versions();
 
                atomic_set(&nfsd_busy, 0);
                error = -ENOMEM;
 
 int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
 #endif
 
+enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
+int nfsd_vers(int vers, enum vers_op change);
+void nfsd_reset_versions(void);
+
 
 /* 
  * NFSv4 State
 
 #define NFSCTL_GETFD           7       /* get an fh by path (used by mountd) */
 #define        NFSCTL_GETFS            8       /* get an fh by path with max FH len */
 
-/*
- * Macros used to set version
- */
-#define NFSCTL_VERSET(_cltbits, _v)   ((_cltbits) |=  (1 << (_v)))
-#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v)))
-#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << (_v)))
-
-#if defined(CONFIG_NFSD_V4)
-#define        NFSCTL_VERALL   (0x1c /* 0b011100 */)
-#elif defined(CONFIG_NFSD_V3)
-#define        NFSCTL_VERALL   (0x0c /* 0b001100 */)
-#else
-#define        NFSCTL_VERALL   (0x04 /* 0b000100 */)
-#endif
-
 /* SVC */
 struct nfsctl_svc {
        unsigned short          svc_port;
 extern int             exp_export(struct nfsctl_export *nxp);
 extern int             exp_unexport(struct nfsctl_export *nxp);
 
-extern unsigned int nfsd_versbits;
-
 #endif /* __KERNEL__ */
 
 #endif /* NFSD_SYSCALL_H */