NFSv4.0: Fix a lock leak in nfs40_walk_client_list
[sfrench/cifs-2.6.git] / fs / nfs / nfs4client.c
index 8346ccbf2d52e518b6fa61d0c8cbb3d033ec1f02..66776f02211131bd003e31748dec6774a02a077f 100644 (file)
@@ -359,11 +359,9 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
        struct nfs_client *old;
        int error;
 
-       if (clp->cl_cons_state == NFS_CS_READY) {
+       if (clp->cl_cons_state == NFS_CS_READY)
                /* the client is initialised already */
-               dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
                return clp;
-       }
 
        /* Check NFS protocol revision and initialize RPC op vector */
        clp->rpc_ops = &nfs_v4_clientops;
@@ -421,7 +419,6 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
 error:
        nfs_mark_client_ready(clp, error);
        nfs_put_client(clp);
-       dprintk("<-- nfs4_init_client() = xerror %d\n", error);
        return ERR_PTR(error);
 }
 
@@ -469,6 +466,50 @@ static bool nfs4_same_verifier(nfs4_verifier *v1, nfs4_verifier *v2)
        return memcmp(v1->data, v2->data, sizeof(v1->data)) == 0;
 }
 
+static int nfs4_match_client(struct nfs_client  *pos,  struct nfs_client *new,
+                            struct nfs_client **prev, struct nfs_net *nn)
+{
+       int status;
+
+       if (pos->rpc_ops != new->rpc_ops)
+               return 1;
+
+       if (pos->cl_minorversion != new->cl_minorversion)
+               return 1;
+
+       /* If "pos" isn't marked ready, we can't trust the
+        * remaining fields in "pos", especially the client
+        * ID and serverowner fields.  Wait for CREATE_SESSION
+        * to finish. */
+       if (pos->cl_cons_state > NFS_CS_READY) {
+               atomic_inc(&pos->cl_count);
+               spin_unlock(&nn->nfs_client_lock);
+
+               nfs_put_client(*prev);
+               *prev = pos;
+
+               status = nfs_wait_client_init_complete(pos);
+               spin_lock(&nn->nfs_client_lock);
+
+               if (status < 0)
+                       return status;
+       }
+
+       if (pos->cl_cons_state != NFS_CS_READY)
+               return 1;
+
+       if (pos->cl_clientid != new->cl_clientid)
+               return 1;
+
+       /* NFSv4.1 always uses the uniform string, however someone
+        * might switch the uniquifier string on us.
+        */
+       if (!nfs4_match_client_owner_id(pos, new))
+               return 1;
+
+       return 0;
+}
+
 /**
  * nfs40_walk_client_list - Find server that recognizes a client ID
  *
@@ -497,34 +538,10 @@ int nfs40_walk_client_list(struct nfs_client *new,
        spin_lock(&nn->nfs_client_lock);
        list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
 
-               if (pos->rpc_ops != new->rpc_ops)
-                       continue;
-
-               if (pos->cl_minorversion != new->cl_minorversion)
-                       continue;
-
-               /* If "pos" isn't marked ready, we can't trust the
-                * remaining fields in "pos" */
-               if (pos->cl_cons_state > NFS_CS_READY) {
-                       atomic_inc(&pos->cl_count);
-                       spin_unlock(&nn->nfs_client_lock);
-
-                       nfs_put_client(prev);
-                       prev = pos;
-
-                       status = nfs_wait_client_init_complete(pos);
-                       if (status < 0)
-                               goto out;
-                       status = -NFS4ERR_STALE_CLIENTID;
-                       spin_lock(&nn->nfs_client_lock);
-               }
-               if (pos->cl_cons_state != NFS_CS_READY)
-                       continue;
-
-               if (pos->cl_clientid != new->cl_clientid)
-                       continue;
-
-               if (!nfs4_match_client_owner_id(pos, new))
+               status = nfs4_match_client(pos, new, &prev, nn);
+               if (status < 0)
+                       goto out_unlock;
+               if (status != 0)
                        continue;
                /*
                 * We just sent a new SETCLIENTID, which should have
@@ -557,8 +574,6 @@ int nfs40_walk_client_list(struct nfs_client *new,
 
                        prev = NULL;
                        *result = pos;
-                       dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
-                               __func__, pos, atomic_read(&pos->cl_count));
                        goto out;
                case -ERESTARTSYS:
                case -ETIMEDOUT:
@@ -572,31 +587,16 @@ int nfs40_walk_client_list(struct nfs_client *new,
 
                spin_lock(&nn->nfs_client_lock);
        }
+out_unlock:
        spin_unlock(&nn->nfs_client_lock);
 
        /* No match found. The server lost our clientid */
 out:
        nfs_put_client(prev);
-       dprintk("NFS: <-- %s status = %d\n", __func__, status);
        return status;
 }
 
 #ifdef CONFIG_NFS_V4_1
-/*
- * Returns true if the client IDs match
- */
-static bool nfs4_match_clientids(u64 a, u64 b)
-{
-       if (a != b) {
-               dprintk("NFS: --> %s client ID %llx does not match %llx\n",
-                       __func__, a, b);
-               return false;
-       }
-       dprintk("NFS: --> %s client ID %llx matches %llx\n",
-               __func__, a, b);
-       return true;
-}
-
 /*
  * Returns true if the server major ids match
  */
@@ -605,36 +605,8 @@ nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
                                struct nfs41_server_owner *o2)
 {
        if (o1->major_id_sz != o2->major_id_sz)
-               goto out_major_mismatch;
-       if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
-               goto out_major_mismatch;
-
-       dprintk("NFS: --> %s server owner major IDs match\n", __func__);
-       return true;
-
-out_major_mismatch:
-       dprintk("NFS: --> %s server owner major IDs do not match\n",
-               __func__);
-       return false;
-}
-
-/*
- * Returns true if server minor ids match
- */
-static bool
-nfs4_check_serverowner_minor_id(struct nfs41_server_owner *o1,
-                               struct nfs41_server_owner *o2)
-{
-       /* Check eir_server_owner so_minor_id */
-       if (o1->minor_id != o2->minor_id)
-               goto out_minor_mismatch;
-
-       dprintk("NFS: --> %s server owner minor IDs match\n", __func__);
-       return true;
-
-out_minor_mismatch:
-       dprintk("NFS: --> %s server owner minor IDs do not match\n", __func__);
-       return false;
+               return false;
+       return memcmp(o1->major_id, o2->major_id, o1->major_id_sz) == 0;
 }
 
 /*
@@ -645,18 +617,9 @@ nfs4_check_server_scope(struct nfs41_server_scope *s1,
                        struct nfs41_server_scope *s2)
 {
        if (s1->server_scope_sz != s2->server_scope_sz)
-               goto out_scope_mismatch;
-       if (memcmp(s1->server_scope, s2->server_scope,
-                  s1->server_scope_sz) != 0)
-               goto out_scope_mismatch;
-
-       dprintk("NFS: --> %s server scopes match\n", __func__);
-       return true;
-
-out_scope_mismatch:
-       dprintk("NFS: --> %s server scopes do not match\n",
-               __func__);
-       return false;
+               return false;
+       return memcmp(s1->server_scope, s2->server_scope,
+                                       s1->server_scope_sz) == 0;
 }
 
 /**
@@ -680,7 +643,7 @@ int nfs4_detect_session_trunking(struct nfs_client *clp,
                                 struct rpc_xprt *xprt)
 {
        /* Check eir_clientid */
-       if (!nfs4_match_clientids(clp->cl_clientid, res->clientid))
+       if (clp->cl_clientid != res->clientid)
                goto out_err;
 
        /* Check eir_server_owner so_major_id */
@@ -689,8 +652,7 @@ int nfs4_detect_session_trunking(struct nfs_client *clp,
                goto out_err;
 
        /* Check eir_server_owner so_minor_id */
-       if (!nfs4_check_serverowner_minor_id(clp->cl_serverowner,
-                                            res->server_owner))
+       if (clp->cl_serverowner->minor_id != res->server_owner->minor_id)
                goto out_err;
 
        /* Check eir_server_scope */
@@ -739,33 +701,10 @@ int nfs41_walk_client_list(struct nfs_client *new,
                if (pos == new)
                        goto found;
 
-               if (pos->rpc_ops != new->rpc_ops)
-                       continue;
-
-               if (pos->cl_minorversion != new->cl_minorversion)
-                       continue;
-
-               /* If "pos" isn't marked ready, we can't trust the
-                * remaining fields in "pos", especially the client
-                * ID and serverowner fields.  Wait for CREATE_SESSION
-                * to finish. */
-               if (pos->cl_cons_state > NFS_CS_READY) {
-                       atomic_inc(&pos->cl_count);
-                       spin_unlock(&nn->nfs_client_lock);
-
-                       nfs_put_client(prev);
-                       prev = pos;
-
-                       status = nfs_wait_client_init_complete(pos);
-                       spin_lock(&nn->nfs_client_lock);
-                       if (status < 0)
-                               break;
-                       status = -NFS4ERR_STALE_CLIENTID;
-               }
-               if (pos->cl_cons_state != NFS_CS_READY)
-                       continue;
-
-               if (!nfs4_match_clientids(pos->cl_clientid, new->cl_clientid))
+               status = nfs4_match_client(pos, new, &prev, nn);
+               if (status < 0)
+                       goto out;
+               if (status != 0)
                        continue;
 
                /*
@@ -777,23 +716,15 @@ int nfs41_walk_client_list(struct nfs_client *new,
                                                     new->cl_serverowner))
                        continue;
 
-               /* Unlike NFSv4.0, we know that NFSv4.1 always uses the
-                * uniform string, however someone might switch the
-                * uniquifier string on us.
-                */
-               if (!nfs4_match_client_owner_id(pos, new))
-                       continue;
 found:
                atomic_inc(&pos->cl_count);
                *result = pos;
                status = 0;
-               dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
-                       __func__, pos, atomic_read(&pos->cl_count));
                break;
        }
 
+out:
        spin_unlock(&nn->nfs_client_lock);
-       dprintk("NFS: <-- %s status = %d\n", __func__, status);
        nfs_put_client(prev);
        return status;
 }
@@ -916,9 +847,6 @@ static int nfs4_set_client(struct nfs_server *server,
                .timeparms = timeparms,
        };
        struct nfs_client *clp;
-       int error;
-
-       dprintk("--> nfs4_set_client()\n");
 
        if (server->flags & NFS_MOUNT_NORESVPORT)
                set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
@@ -927,15 +855,11 @@ static int nfs4_set_client(struct nfs_server *server,
 
        /* Allocate or find a client reference we can use */
        clp = nfs_get_client(&cl_init);
-       if (IS_ERR(clp)) {
-               error = PTR_ERR(clp);
-               goto error;
-       }
+       if (IS_ERR(clp))
+               return PTR_ERR(clp);
 
-       if (server->nfs_client == clp) {
-               error = -ELOOP;
-               goto error;
-       }
+       if (server->nfs_client == clp)
+               return -ELOOP;
 
        /*
         * Query for the lease time on clientid setup or renewal
@@ -947,11 +871,7 @@ static int nfs4_set_client(struct nfs_server *server,
        set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
 
        server->nfs_client = clp;
-       dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
        return 0;
-error:
-       dprintk("<-- nfs4_set_client() = xerror %d\n", error);
-       return error;
 }
 
 /*
@@ -982,7 +902,6 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
                .net = mds_clp->cl_net,
                .timeparms = &ds_timeout,
        };
-       struct nfs_client *clp;
        char buf[INET6_ADDRSTRLEN + 1];
 
        if (rpc_ntop(ds_addr, buf, sizeof(buf)) <= 0)
@@ -998,10 +917,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
         * (section 13.1 RFC 5661).
         */
        nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
-       clp = nfs_get_client(&cl_init);
-
-       dprintk("<-- %s %p\n", __func__, clp);
-       return clp;
+       return nfs_get_client(&cl_init);
 }
 EXPORT_SYMBOL_GPL(nfs4_set_ds_client);
 
@@ -1098,8 +1014,6 @@ static int nfs4_init_server(struct nfs_server *server,
        struct rpc_timeout timeparms;
        int error;
 
-       dprintk("--> nfs4_init_server()\n");
-
        nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
                        data->timeo, data->retrans);
 
@@ -1127,7 +1041,7 @@ static int nfs4_init_server(struct nfs_server *server,
                        data->minorversion,
                        data->net);
        if (error < 0)
-               goto error;
+               return error;
 
        if (data->rsize)
                server->rsize = nfs_block_size(data->rsize, NULL);
@@ -1138,16 +1052,10 @@ static int nfs4_init_server(struct nfs_server *server,
        server->acregmax = data->acregmax * HZ;
        server->acdirmin = data->acdirmin * HZ;
        server->acdirmax = data->acdirmax * HZ;
+       server->port     = data->nfs_server.port;
 
-       server->port = data->nfs_server.port;
-
-       error = nfs_init_server_rpcclient(server, &timeparms,
-                                         data->selected_flavor);
-
-error:
-       /* Done */
-       dprintk("<-- nfs4_init_server() = %d\n", error);
-       return error;
+       return nfs_init_server_rpcclient(server, &timeparms,
+                                        data->selected_flavor);
 }
 
 /*
@@ -1163,8 +1071,6 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
        bool auth_probe;
        int error;
 
-       dprintk("--> nfs4_create_server()\n");
-
        server = nfs_alloc_server();
        if (!server)
                return ERR_PTR(-ENOMEM);
@@ -1180,12 +1086,10 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
        if (error < 0)
                goto error;
 
-       dprintk("<-- nfs4_create_server() = %p\n", server);
        return server;
 
 error:
        nfs_free_server(server);
-       dprintk("<-- nfs4_create_server() = error %d\n", error);
        return ERR_PTR(error);
 }
 
@@ -1200,8 +1104,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
        bool auth_probe;
        int error;
 
-       dprintk("--> nfs4_create_referral_server()\n");
-
        server = nfs_alloc_server();
        if (!server)
                return ERR_PTR(-ENOMEM);
@@ -1235,12 +1137,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
        if (error < 0)
                goto error;
 
-       dprintk("<-- nfs_create_referral_server() = %p\n", server);
        return server;
 
 error:
        nfs_free_server(server);
-       dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
        return ERR_PTR(error);
 }
 
@@ -1300,31 +1200,16 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
        struct sockaddr *localaddr = (struct sockaddr *)&address;
        int error;
 
-       dprintk("--> %s: move FSID %llx:%llx to \"%s\")\n", __func__,
-                       (unsigned long long)server->fsid.major,
-                       (unsigned long long)server->fsid.minor,
-                       hostname);
-
        error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
-       if (error != 0) {
-               dprintk("<-- %s(): rpc_switch_client_transport returned %d\n",
-                       __func__, error);
-               goto out;
-       }
+       if (error != 0)
+               return error;
 
        error = rpc_localaddr(clnt, localaddr, sizeof(address));
-       if (error != 0) {
-               dprintk("<-- %s(): rpc_localaddr returned %d\n",
-                       __func__, error);
-               goto out;
-       }
+       if (error != 0)
+               return error;
 
-       error = -EAFNOSUPPORT;
-       if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0) {
-               dprintk("<-- %s(): rpc_ntop returned %d\n",
-                       __func__, error);
-               goto out;
-       }
+       if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0)
+               return -EAFNOSUPPORT;
 
        nfs_server_remove_lists(server);
        error = nfs4_set_client(server, hostname, sap, salen, buf,
@@ -1333,21 +1218,12 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
        nfs_put_client(clp);
        if (error != 0) {
                nfs_server_insert_lists(server);
-               dprintk("<-- %s(): nfs4_set_client returned %d\n",
-                       __func__, error);
-               goto out;
+               return error;
        }
 
        if (server->nfs_client->cl_hostname == NULL)
                server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
        nfs_server_insert_lists(server);
 
-       error = nfs_probe_destination(server);
-       if (error < 0)
-               goto out;
-
-       dprintk("<-- %s() succeeded\n", __func__);
-
-out:
-       return error;
+       return nfs_probe_destination(server);
 }