Merge branch 'devel-for-2.6.31' into for-2.6.31
[pandora-kernel.git] / fs / nfs / super.c
index 6063054..3d46052 100644 (file)
@@ -140,22 +140,22 @@ static const match_table_t nfs_mount_option_tokens = {
        { Opt_fscache_uniq, "fsc=%s" },
        { Opt_nofscache, "nofsc" },
 
-       { Opt_port, "port=%u" },
-       { Opt_rsize, "rsize=%u" },
-       { Opt_wsize, "wsize=%u" },
-       { Opt_bsize, "bsize=%u" },
-       { Opt_timeo, "timeo=%u" },
-       { Opt_retrans, "retrans=%u" },
-       { Opt_acregmin, "acregmin=%u" },
-       { Opt_acregmax, "acregmax=%u" },
-       { Opt_acdirmin, "acdirmin=%u" },
-       { Opt_acdirmax, "acdirmax=%u" },
-       { Opt_actimeo, "actimeo=%u" },
-       { Opt_namelen, "namlen=%u" },
-       { Opt_mountport, "mountport=%u" },
-       { Opt_mountvers, "mountvers=%u" },
-       { Opt_nfsvers, "nfsvers=%u" },
-       { Opt_nfsvers, "vers=%u" },
+       { Opt_port, "port=%s" },
+       { Opt_rsize, "rsize=%s" },
+       { Opt_wsize, "wsize=%s" },
+       { Opt_bsize, "bsize=%s" },
+       { Opt_timeo, "timeo=%s" },
+       { Opt_retrans, "retrans=%s" },
+       { Opt_acregmin, "acregmin=%s" },
+       { Opt_acregmax, "acregmax=%s" },
+       { Opt_acdirmin, "acdirmin=%s" },
+       { Opt_acdirmax, "acdirmax=%s" },
+       { Opt_actimeo, "actimeo=%s" },
+       { Opt_namelen, "namlen=%s" },
+       { Opt_mountport, "mountport=%s" },
+       { Opt_mountvers, "mountvers=%s" },
+       { Opt_nfsvers, "nfsvers=%s" },
+       { Opt_nfsvers, "vers=%s" },
        { Opt_minorversion, "minorversion=%u" },
 
        { Opt_sec, "sec=%s" },
@@ -516,7 +516,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
                const char *nostr;
        } nfs_info[] = {
                { NFS_MOUNT_SOFT, ",soft", ",hard" },
-               { NFS_MOUNT_INTR, ",intr", ",nointr" },
                { NFS_MOUNT_POSIX, ",posix", "" },
                { NFS_MOUNT_NOCTO, ",nocto", "" },
                { NFS_MOUNT_NOAC, ",noac", "" },
@@ -945,11 +944,6 @@ static int nfs_parse_security_flavors(char *value,
        return 1;
 }
 
-static void nfs_parse_invalid_value(const char *option)
-{
-       dfprintk(MOUNT, "NFS:   bad value specified for %s option\n", option);
-}
-
 /*
  * Error-check and convert a string of mount options from user space into
  * a data structure.  The whole mount string is processed; bad options are
@@ -960,7 +954,7 @@ static int nfs_parse_mount_options(char *raw,
                                   struct nfs_parsed_mount_data *mnt)
 {
        char *p, *string, *secdata;
-       int rc, sloppy = 0, errors = 0;
+       int rc, sloppy = 0, invalid_option = 0;
 
        if (!raw) {
                dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
@@ -984,7 +978,9 @@ static int nfs_parse_mount_options(char *raw,
 
        while ((p = strsep(&raw, ",")) != NULL) {
                substring_t args[MAX_OPT_ARGS];
-               int option, token;
+               unsigned long option;
+               int int_option;
+               int token;
 
                if (!*p)
                        continue;
@@ -1093,114 +1089,156 @@ static int nfs_parse_mount_options(char *raw,
                 * options that take numeric values
                 */
                case Opt_port:
-                       if (match_int(args, &option) ||
-                           option < 0 || option > USHORT_MAX) {
-                               errors++;
-                               nfs_parse_invalid_value("port");
-                       } else
-                               mnt->nfs_server.port = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0 || option > USHORT_MAX)
+                               goto out_invalid_value;
+                       mnt->nfs_server.port = option;
                        break;
                case Opt_rsize:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("rsize");
-                       } else
-                               mnt->rsize = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->rsize = option;
                        break;
                case Opt_wsize:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("wsize");
-                       } else
-                               mnt->wsize = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->wsize = option;
                        break;
                case Opt_bsize:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("bsize");
-                       } else
-                               mnt->bsize = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->bsize = option;
                        break;
                case Opt_timeo:
-                       if (match_int(args, &option) || option <= 0) {
-                               errors++;
-                               nfs_parse_invalid_value("timeo");
-                       } else
-                               mnt->timeo = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0 || option == 0)
+                               goto out_invalid_value;
+                       mnt->timeo = option;
                        break;
                case Opt_retrans:
-                       if (match_int(args, &option) || option <= 0) {
-                               errors++;
-                               nfs_parse_invalid_value("retrans");
-                       } else
-                               mnt->retrans = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0 || option == 0)
+                               goto out_invalid_value;
+                       mnt->retrans = option;
                        break;
                case Opt_acregmin:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("acregmin");
-                       } else
-                               mnt->acregmin = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->acregmin = option;
                        break;
                case Opt_acregmax:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("acregmax");
-                       } else
-                               mnt->acregmax = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->acregmax = option;
                        break;
                case Opt_acdirmin:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("acdirmin");
-                       } else
-                               mnt->acdirmin = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->acdirmin = option;
                        break;
                case Opt_acdirmax:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("acdirmax");
-                       } else
-                               mnt->acdirmax = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->acdirmax = option;
                        break;
                case Opt_actimeo:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("actimeo");
-                       } else
-                               mnt->acregmin = mnt->acregmax =
-                               mnt->acdirmin = mnt->acdirmax = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->acregmin = mnt->acregmax =
+                       mnt->acdirmin = mnt->acdirmax = option;
                        break;
                case Opt_namelen:
-                       if (match_int(args, &option) || option < 0) {
-                               errors++;
-                               nfs_parse_invalid_value("namlen");
-                       } else
-                               mnt->namlen = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
+                       mnt->namlen = option;
                        break;
                case Opt_mountport:
-                       if (match_int(args, &option) ||
-                           option < 0 || option > USHORT_MAX) {
-                               errors++;
-                               nfs_parse_invalid_value("mountport");
-                       } else
-                               mnt->mount_server.port = option;
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0 || option > USHORT_MAX)
+                               goto out_invalid_value;
+                       mnt->mount_server.port = option;
                        break;
                case Opt_mountvers:
-                       if (match_int(args, &option) ||
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0 ||
                            option < NFS_MNT_VERSION ||
-                           option > NFS_MNT3_VERSION) {
-                               errors++;
-                               nfs_parse_invalid_value("mountvers");
-                       } else
-                               mnt->mount_server.version = option;
+                           option > NFS_MNT3_VERSION)
+                               goto out_invalid_value;
+                       mnt->mount_server.version = option;
                        break;
                case Opt_nfsvers:
-                       if (match_int(args, &option)) {
-                               errors++;
-                               nfs_parse_invalid_value("nfsvers");
-                               break;
-                       }
+                       string = match_strdup(args);
+                       if (string == NULL)
+                               goto out_nomem;
+                       rc = strict_strtoul(string, 10, &option);
+                       kfree(string);
+                       if (rc != 0)
+                               goto out_invalid_value;
                        switch (option) {
                        case NFS2_VERSION:
                                mnt->flags &= ~NFS_MOUNT_VER3;
@@ -1209,16 +1247,15 @@ static int nfs_parse_mount_options(char *raw,
                                mnt->flags |= NFS_MOUNT_VER3;
                                break;
                        default:
-                               errors++;
-                               nfs_parse_invalid_value("nfsvers");
+                               goto out_invalid_value;
                        }
                        break;
                case Opt_minorversion:
-                       if (match_int(args, &option))
+                       if (match_int(args, &int_option))
                                return 0;
-                       if (option < 0 || option > NFS4_MAX_MINOR_VERSION)
+                       if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION)
                                return 0;
-                       mnt->minorversion = option;
+                       mnt->minorversion = int_option;
                        break;
 
                /*
@@ -1231,9 +1268,9 @@ static int nfs_parse_mount_options(char *raw,
                        rc = nfs_parse_security_flavors(string, mnt);
                        kfree(string);
                        if (!rc) {
-                               errors++;
                                dfprintk(MOUNT, "NFS:   unrecognized "
                                                "security flavor\n");
+                               return 0;
                        }
                        break;
                case Opt_proto:
@@ -1247,23 +1284,25 @@ static int nfs_parse_mount_options(char *raw,
                        case Opt_xprt_udp:
                                mnt->flags &= ~NFS_MOUNT_TCP;
                                mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+                               kfree(string);
                                break;
                        case Opt_xprt_tcp:
                                mnt->flags |= NFS_MOUNT_TCP;
                                mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+                               kfree(string);
                                break;
                        case Opt_xprt_rdma:
                                /* vector side protocols to TCP */
                                mnt->flags |= NFS_MOUNT_TCP;
                                mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
                                xprt_load_transport(string);
+                               kfree(string);
                                break;
                        default:
-                               errors++;
                                dfprintk(MOUNT, "NFS:   unrecognized "
                                                "transport protocol\n");
+                               return 0;
                        }
-                       kfree(string);
                        break;
                case Opt_mountproto:
                        string = match_strdup(args);
@@ -1282,9 +1321,9 @@ static int nfs_parse_mount_options(char *raw,
                                break;
                        case Opt_xprt_rdma: /* not used for side protocols */
                        default:
-                               errors++;
                                dfprintk(MOUNT, "NFS:   unrecognized "
                                                "transport protocol\n");
+                               return 0;
                        }
                        break;
                case Opt_addr:
@@ -1340,9 +1379,9 @@ static int nfs_parse_mount_options(char *raw,
                                        mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
                                        break;
                                default:
-                                       errors++;
                                        dfprintk(MOUNT, "NFS:   invalid "
                                                        "lookupcache argument\n");
+                                       return 0;
                        };
                        break;
 
@@ -1360,20 +1399,20 @@ static int nfs_parse_mount_options(char *raw,
                        break;
 
                default:
-                       errors++;
+                       invalid_option = 1;
                        dfprintk(MOUNT, "NFS:   unrecognized mount option "
                                        "'%s'\n", p);
                }
        }
 
-       if (errors > 0) {
-               dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n",
-                               errors, (errors == 1 ? "" : "s"));
-               if (!sloppy)
-                       return 0;
-       }
+       if (!sloppy && invalid_option)
+               return 0;
+
        return 1;
 
+out_invalid_value:
+       printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p);
+       return 0;
 out_nomem:
        printk(KERN_INFO "NFS: not enough memory to parse option\n");
        return 0;
@@ -1390,6 +1429,7 @@ out_security_failure:
 static int nfs_try_mount(struct nfs_parsed_mount_data *args,
                         struct nfs_fh *root_fh)
 {
+       unsigned int auth_flavor_len = 0;
        struct nfs_mount_request request = {
                .sap            = (struct sockaddr *)
                                                &args->mount_server.address,
@@ -1397,6 +1437,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
                .protocol       = args->mount_server.protocol,
                .fh             = root_fh,
                .noresvport     = args->flags & NFS_MOUNT_NORESVPORT,
+               .auth_flav_len  = &auth_flavor_len,
        };
        int status;
 
@@ -2249,6 +2290,11 @@ static void nfs4_fill_super(struct super_block *sb)
        nfs_initialise_sb(sb);
 }
 
+static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
+{
+       args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3);
+}
+
 /*
  * Validate NFSv4 mount options
  */
@@ -2346,6 +2392,8 @@ static int nfs4_validate_mount_data(void *options,
 
                nfs_validate_transport_protocol(args);
 
+               nfs4_validate_mount_flags(args);
+
                if (args->auth_flavor_len > 1)
                        goto out_inval_auth;