s3:winbind: Fork multiple children per domain
authorVolker Lendecke <vl@samba.org>
Wed, 7 Apr 2010 15:45:12 +0000 (17:45 +0200)
committerMichael Adam <obnox@samba.org>
Fri, 21 Jan 2011 12:51:27 +0000 (13:51 +0100)
This makes us scale better with many simultaneous winbind requests,
some of which might be slow.

This implementation breaks offline logons, as the cached credentials are
maintained in a child (this needs fixing). So, if the offline logons are
active, only allow one DC connection.

Probably the offline logon and the scalable file server cases are
separate enough so that this patch is useful even with the restriction.

24 files changed:
source3/include/proto.h
source3/param/loadparm.c
source3/winbindd/wb_dsgetdcname.c
source3/winbindd/wb_group_members.c
source3/winbindd/wb_lookupname.c
source3/winbindd/wb_lookupsid.c
source3/winbindd/wb_lookupuseraliases.c
source3/winbindd/wb_lookupusergroups.c
source3/winbindd/wb_next_grent.c
source3/winbindd/wb_query_user_list.c
source3/winbindd/wb_queryuser.c
source3/winbindd/wb_seqnum.c
source3/winbindd/winbindd.h
source3/winbindd/winbindd_change_machine_acct.c
source3/winbindd/winbindd_check_machine_acct.c
source3/winbindd/winbindd_domain.c
source3/winbindd/winbindd_dual.c
source3/winbindd/winbindd_list_groups.c
source3/winbindd/winbindd_list_users.c
source3/winbindd/winbindd_lookuprids.c
source3/winbindd/winbindd_ndr.c
source3/winbindd/winbindd_ping_dc.c
source3/winbindd/winbindd_proto.h
source3/winbindd/winbindd_util.c

index f3ec4d16c60024960024804b0042bffab73f6862..de6e7acc9e9438cce1d5176881b1950db5474f57 100644 (file)
@@ -3230,6 +3230,7 @@ bool lp_winbind_offline_logon(void);
 bool lp_winbind_normalize_names(void);
 bool lp_winbind_rpc_only(void);
 bool lp_create_krb5_conf(void);
+int lp_winbind_max_domain_connections(void);
 const char *lp_idmap_backend(void);
 bool lp_idmap_read_only(void);
 int lp_idmap_cache_time(void);
index 875cab1629ea7685152fda8857ce2728eb21a1c5..b45e045d6466b88eb2e80662c491589075cb63c6 100644 (file)
@@ -216,6 +216,7 @@ struct global {
        bool bWinbindNormalizeNames;
        bool bWinbindRpcOnly;
        bool bCreateKrb5Conf;
+       int winbindMaxDomainConnections;
        char *szIdmapBackend;
        bool bIdmapReadOnly;
        char *szAddShareCommand;
@@ -4773,6 +4774,15 @@ static struct parm_struct parm_table[] = {
                .enum_list      = NULL,
                .flags          = FLAG_ADVANCED,
        },
+       {
+               .label          = "winbind max domain connections",
+               .type           = P_INTEGER,
+               .p_class        = P_GLOBAL,
+               .ptr            = &Globals.winbindMaxDomainConnections,
+               .special        = NULL,
+               .enum_list      = NULL,
+               .flags          = FLAG_ADVANCED,
+       },
 
        {NULL,  P_BOOL,  P_NONE,  NULL,  NULL,  NULL,  0}
 };
@@ -5279,6 +5289,7 @@ static void init_globals(bool reinit_globals)
        Globals.bResetOnZeroVC = False;
        Globals.bLogWriteableFilesOnExit = False;
        Globals.bCreateKrb5Conf = true;
+       Globals.winbindMaxDomainConnections = 1;
 
        /* hostname lookups can be very expensive and are broken on
           a large number of sites (tridge) */
@@ -5651,6 +5662,19 @@ FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon)
 FN_GLOBAL_BOOL(lp_winbind_normalize_names, &Globals.bWinbindNormalizeNames)
 FN_GLOBAL_BOOL(lp_winbind_rpc_only, &Globals.bWinbindRpcOnly)
 FN_GLOBAL_BOOL(lp_create_krb5_conf, &Globals.bCreateKrb5Conf)
+static FN_GLOBAL_INTEGER(lp_winbind_max_domain_connections_int,
+                 &Globals.winbindMaxDomainConnections)
+
+int lp_winbind_max_domain_connections(void)
+{
+       if (lp_winbind_offline_logon() &&
+           lp_winbind_max_domain_connections_int() > 1) {
+               DEBUG(1, ("offline logons active, restricting max domain "
+                         "connections to 1\n"));
+               return 1;
+       }
+       return MAX(1, lp_winbind_max_domain_connections_int());
+}
 
 FN_GLOBAL_CONST_STRING(lp_idmap_backend, &Globals.szIdmapBackend)
 FN_GLOBAL_BOOL(lp_idmap_read_only, &Globals.bIdmapReadOnly)
index fdd9a6d7df0265a67b70e175d001ead82d7dc736..207d1b61ea4c8ce525dfdc894383a9df35c13475 100644 (file)
@@ -64,7 +64,7 @@ struct tevent_req *wb_dsgetdcname_send(TALLOC_CTX *mem_ctx,
                child = locator_child();
        } else {
                struct winbindd_domain *domain = find_our_domain();
-               child = &domain->child;
+               child = choose_domain_child(domain);
        }
 
        if (domain_guid != NULL) {
index 024b3173b987fb2296959259332c42b092b3fde2..c9603e73f8bffe72b6a9703888d314bdbbb8ffc3 100644 (file)
@@ -73,7 +73,7 @@ static struct tevent_req *wb_lookupgroupmem_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = dcerpc_wbint_LookupGroupMembers_send(
-               state, ev, domain->child.binding_handle, &state->sid, type,
+               state, ev, dom_child_handle(domain), &state->sid, type,
                &state->members);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
index 4429149f7a9705c593e1fcc3f72119314f5cad3f..a9b4dfa586d9df6dda2f6029460d78f06c7ab96b 100644 (file)
@@ -70,7 +70,8 @@ struct tevent_req *wb_lookupname_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = dcerpc_wbint_LookupName_send(
-               state, ev, domain->child.binding_handle, state->dom_name, state->name,
+               state, ev, dom_child_handle(domain),
+               state->dom_name, state->name,
                flags, &state->type, &state->sid);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -111,7 +112,8 @@ static void wb_lookupname_done(struct tevent_req *subreq)
        }
 
        subreq = dcerpc_wbint_LookupName_send(
-               state, state->ev, root_domain->child.binding_handle, state->dom_name,
+               state, state->ev, dom_child_handle(root_domain),
+               state->dom_name,
                state->name, state->flags, &state->type, &state->sid);
        if (tevent_req_nomem(subreq, req)) {
                return;
index 52e8bcbdeada22d8218ba6bf8dc6ad3244f6b192..2e1b21a8d889a90b6a7e88d2ede9b366a0f1d2a5 100644 (file)
@@ -56,7 +56,7 @@ struct tevent_req *wb_lookupsid_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = dcerpc_wbint_LookupSid_send(
-               state, ev, state->lookup_domain->child.binding_handle,
+               state, ev, dom_child_handle(state->lookup_domain),
                &state->sid, &state->type, &state->domname, &state->name);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
@@ -96,7 +96,7 @@ static void wb_lookupsid_done(struct tevent_req *subreq)
        state->lookup_domain = forest_root;
 
        subreq = dcerpc_wbint_LookupSid_send(
-               state, state->ev, state->lookup_domain->child.binding_handle,
+               state, state->ev, dom_child_handle(state->lookup_domain),
                &state->sid, &state->type, &state->domname, &state->name);
        if (tevent_req_nomem(subreq, req)) {
                return;
index 1e9b4c318ef9570d5a31d9a8745832da3151048d..f6fe855a856965c84a582a73ce936feab0b9d17e 100644 (file)
@@ -47,7 +47,7 @@ struct tevent_req *wb_lookupuseraliases_send(TALLOC_CTX *mem_ctx,
        state->sids.sids = CONST_DISCARD(struct dom_sid *, sids);
 
        subreq = dcerpc_wbint_LookupUserAliases_send(
-               state, ev, domain->child.binding_handle, &state->sids, &state->rids);
+               state, ev, dom_child_handle(domain), &state->sids, &state->rids);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
index 27a6a5b00ed60f2c04c67917d3495acb20144155..aeffc178d9bc689fa42a6123fac43428ebd23f14 100644 (file)
@@ -46,7 +46,7 @@ struct tevent_req *wb_lookupusergroups_send(TALLOC_CTX *mem_ctx,
        sid_copy(&state->sid, sid);
 
        subreq = dcerpc_wbint_LookupUserGroups_send(
-               state, ev, domain->child.binding_handle, &state->sid, &state->sids);
+               state, ev, dom_child_handle(domain), &state->sid, &state->sids);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
index 7eec3e0b946d6c10ae7316300d855161151be5c0..54c4c1c440e06f1c497be52d685e48653abcdab1 100644 (file)
@@ -70,7 +70,7 @@ struct tevent_req *wb_next_grent_send(TALLOC_CTX *mem_ctx,
                        return tevent_req_post(req, ev);
                }
                subreq = dcerpc_wbint_QueryGroupList_send(
-                       state, state->ev, state->gstate->domain->child.binding_handle,
+                       state, state->ev, dom_child_handle(state->gstate->domain),
                        &state->next_groups);
                if (tevent_req_nomem(subreq, req)) {
                        return tevent_req_post(req, ev);
@@ -134,7 +134,7 @@ static void wb_next_grent_fetch_done(struct tevent_req *subreq)
                        return;
                }
                subreq = dcerpc_wbint_QueryGroupList_send(
-                       state, state->ev, state->gstate->domain->child.binding_handle,
+                       state, state->ev, dom_child_handle(state->gstate->domain),
                        &state->next_groups);
                if (tevent_req_nomem(subreq, req)) {
                        return;
index c4eb200d888a8b388cb8a4855deaf6651f561153..abbf7668e97821a73916b730654e1bfaf8541b59 100644 (file)
@@ -41,7 +41,7 @@ struct tevent_req *wb_query_user_list_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = dcerpc_wbint_QueryUserList_send(state, ev,
-                                                domain->child.binding_handle,
+                                                dom_child_handle(domain),
                                                 &state->users);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
index 870bfd3366396a2a35392a2d9dc84c134221bce7..33416b9017b2462fb9ee7d6174055330d79fc014 100644 (file)
@@ -54,7 +54,7 @@ struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       subreq = dcerpc_wbint_QueryUser_send(state, ev, domain->child.binding_handle,
+       subreq = dcerpc_wbint_QueryUser_send(state, ev, dom_child_handle(domain),
                                             &state->sid, state->info);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
index 0a314e7abe8eff5142cbcad68d812b64244f79bb..4a92e036dc4f1f56fe66e228dea5bc94053a0fea 100644 (file)
@@ -39,7 +39,7 @@ struct tevent_req *wb_seqnum_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
        subreq = dcerpc_wbint_QuerySequenceNumber_send(
-               state, ev, domain->child.binding_handle, &state->seqnum);
+               state, ev, dom_child_handle(domain), &state->seqnum);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
index d276b869479178827bc2166e8b9f4564389db895..3217acc8ea260be1f42377a461eef25667c395c8 100644 (file)
@@ -205,7 +205,7 @@ struct winbindd_domain {
 
        /* The child pid we're talking to */
 
-       struct winbindd_child child;
+       struct winbindd_child *children;
 
        /* Callback we use to try put us back online. */
 
index ad050ad7424f3c4275725e27fb01e322a488b55c..a5514e22ebca5336129208eb327a83ddd66c6b6f 100644 (file)
@@ -58,7 +58,7 @@ struct tevent_req *winbindd_change_machine_acct_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = dcerpc_wbint_ChangeMachineAccount_send(state, ev,
-                                                       domain->child.binding_handle);
+                                                       dom_child_handle(domain));
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
index 6d969c93538dbfd0dc48f295e699afb990614ac4..279370146a611e27554122b535415ad6bf873ca4 100644 (file)
@@ -62,7 +62,7 @@ struct tevent_req *winbindd_check_machine_acct_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = dcerpc_wbint_CheckMachineAccount_send(state, ev,
-                                                      domain->child.binding_handle);
+                                                      dom_child_handle(domain));
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
index cd3370852b39d4bd8d7e041dd5d817e142c3d650..e998275c8e2a7f78489127f60f83fe778fcb3819 100644 (file)
@@ -69,6 +69,12 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
 
 void setup_domain_child(struct winbindd_domain *domain)
 {
-       setup_child(domain, &domain->child, domain_dispatch_table,
-                   "log.wb", domain->name);
+       int i;
+
+        for (i=0; i<lp_winbind_max_domain_connections(); i++) {
+                setup_child(domain, &domain->children[i],
+                           domain_dispatch_table,
+                            "log.wb", domain->name);
+               domain->children[i].domain = domain;
+       }
 }
index 344b7e4bd1ac128b3af0fa90281ad030045cb0ea..a32459d595044c4babc44963e1c4ae77126dc3df 100644 (file)
@@ -193,9 +193,47 @@ int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
        return 0;
 }
 
+static bool winbindd_child_busy(struct winbindd_child *child)
+{
+       return tevent_queue_length(child->queue) > 0;
+}
+
+static struct winbindd_child *find_idle_child(struct winbindd_domain *domain)
+{
+       int i;
+
+       for (i=0; i<lp_winbind_max_domain_connections(); i++) {
+               if (!winbindd_child_busy(&domain->children[i])) {
+                       return &domain->children[i];
+               }
+       }
+
+       return NULL;
+}
+
+struct winbindd_child *choose_domain_child(struct winbindd_domain *domain)
+{
+       struct winbindd_child *result;
+
+       result = find_idle_child(domain);
+       if (result != NULL) {
+               return result;
+       }
+       return &domain->children[rand() % lp_winbind_max_domain_connections()];
+}
+
+struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain)
+{
+       struct winbindd_child *child;
+
+       child = choose_domain_child(domain);
+       return child->binding_handle;
+}
+
 struct wb_domain_request_state {
        struct tevent_context *ev;
        struct winbindd_domain *domain;
+       struct winbindd_child *child;
        struct winbindd_request *request;
        struct winbindd_request *init_req;
        struct winbindd_response *response;
@@ -219,8 +257,10 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
+       state->child = choose_domain_child(domain);
+
        if (domain->initialized) {
-               subreq = wb_child_request_send(state, ev, &domain->child,
+               subreq = wb_child_request_send(state, ev, state->child,
                                               request);
                if (tevent_req_nomem(subreq, req)) {
                        return tevent_req_post(req, ev);
@@ -245,7 +285,7 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
                state->init_req->data.init_conn.is_primary = domain->primary;
                fstrcpy(state->init_req->data.init_conn.dcname, "");
 
-               subreq = wb_child_request_send(state, ev, &domain->child,
+               subreq = wb_child_request_send(state, ev, state->child,
                                               state->init_req);
                if (tevent_req_nomem(subreq, req)) {
                        return tevent_req_post(req, ev);
@@ -266,7 +306,7 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx,
        state->init_req->cmd = WINBINDD_GETDCNAME;
        fstrcpy(state->init_req->domain_name, domain->name);
 
-       subreq = wb_child_request_send(state, ev, &domain->child, request);
+       subreq = wb_child_request_send(state, ev, state->child, request);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -297,7 +337,7 @@ static void wb_domain_request_gotdc(struct tevent_req *subreq)
 
        TALLOC_FREE(response);
 
-       subreq = wb_child_request_send(state, state->ev, &state->domain->child,
+       subreq = wb_child_request_send(state, state->ev, state->child,
                                       state->init_req);
        if (tevent_req_nomem(subreq, req)) {
                return;
@@ -337,7 +377,7 @@ static void wb_domain_request_initialized(struct tevent_req *subreq)
 
        TALLOC_FREE(response);
 
-       subreq = wb_child_request_send(state, state->ev, &state->domain->child,
+       subreq = wb_child_request_send(state, state->ev, state->child,
                                       state->request);
        if (tevent_req_nomem(subreq, req)) {
                return;
index 4236794485991bd0cd39cdd0def45293e2d3658c..2e2c70a33de84f3ffa34a575fb5b422ba6a28c0a 100644 (file)
@@ -91,7 +91,7 @@ struct tevent_req *winbindd_list_groups_send(TALLOC_CTX *mem_ctx,
                struct winbindd_list_groups_domstate *d = &state->domains[i];
 
                d->subreq = dcerpc_wbint_QueryGroupList_send(
-                       state->domains, ev, d->domain->child.binding_handle,
+                       state->domains, ev, dom_child_handle(d->domain),
                        &d->groups);
                if (tevent_req_nomem(d->subreq, req)) {
                        TALLOC_FREE(state->domains);
index 18b8fdd58972735195c72ffe2aa4267808188400..54e0106e3d68ce3b53062f585e1773c17787fa95 100644 (file)
@@ -91,7 +91,7 @@ struct tevent_req *winbindd_list_users_send(TALLOC_CTX *mem_ctx,
                struct winbindd_list_users_domstate *d = &state->domains[i];
 
                d->subreq = dcerpc_wbint_QueryUserList_send(
-                       state->domains, ev, d->domain->child.binding_handle,
+                       state->domains, ev, dom_child_handle(d->domain),
                        &d->users);
                if (tevent_req_nomem(d->subreq, req)) {
                        TALLOC_FREE(state->domains);
index b921818bc6aff4e49442faef716ec343d2f12eba..738adbaefc3bb42cb2207849102474b0eaf98dbf 100644 (file)
@@ -84,7 +84,7 @@ struct tevent_req *winbindd_lookuprids_send(TALLOC_CTX *mem_ctx,
        }
 
        subreq = dcerpc_wbint_LookupRids_send(
-               state, ev, domain->child.binding_handle, &state->rids,
+               state, ev, dom_child_handle(domain), &state->rids,
                &state->domain_name, &state->names);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
index 396aa06985d60b37d08acb067b291c1c9382fb4f..94aa7eb965bf8d67ebfe8ccd44279540c5259f7f 100644 (file)
@@ -120,6 +120,7 @@ void ndr_print_winbindd_domain(struct ndr_print *ndr,
                               const char *name,
                               const struct winbindd_domain *r)
 {
+       int i;
        if (!r) {
                return;
        }
@@ -150,7 +151,9 @@ void ndr_print_winbindd_domain(struct ndr_print *ndr,
        ndr_print_uint32(ndr, "sequence_number", r->sequence_number);
        ndr_print_NTSTATUS(ndr, "last_status", r->last_status);
        ndr_print_winbindd_cm_conn(ndr, "conn", &r->conn);
-       ndr_print_winbindd_child(ndr, "child", &r->child);
+       for (i=0; i<lp_winbind_max_domain_connections(); i++) {
+               ndr_print_winbindd_child(ndr, "children", &r->children[i]);
+       }
        ndr_print_uint32(ndr, "check_online_timeout", r->check_online_timeout);
        ndr_print_ptr(ndr, "check_online_event", r->check_online_event);
        ndr->depth--;
index 36c4def0aba5f7804ffe5c27b9071aab675937f9..2304828030b3e6c3463dc0c084010144d08bc35a 100644 (file)
@@ -61,7 +61,7 @@ struct tevent_req *winbindd_ping_dc_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       subreq = dcerpc_wbint_PingDc_send(state, ev, domain->child.binding_handle);
+       subreq = dcerpc_wbint_PingDc_send(state, ev, dom_child_handle(domain));
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
index 5cb6c4c15555abae9d5c493211b8b599a0e93e49..c822baa462641351cc17063053372976415a7d9c 100644 (file)
@@ -227,6 +227,9 @@ void setup_domain_child(struct winbindd_domain *domain);
 
 /* The following definitions come from winbindd/winbindd_dual.c  */
 
+struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain);
+struct winbindd_child *choose_domain_child(struct winbindd_domain *domain);
+
 struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx,
                                         struct tevent_context *ev,
                                         struct winbindd_child *child,
index e27c35fe60828cf285ffa18dd4aaa79f6842f753..58cec444aaf95b0bf9da33becb7f94df01a3d034 100644 (file)
@@ -162,6 +162,16 @@ static struct winbindd_domain *add_trusted_domain(const char *domain_name, const
 
        ZERO_STRUCTP(domain);
 
+       domain->children = SMB_MALLOC_ARRAY(
+               struct winbindd_child, lp_winbind_max_domain_connections());
+       if (domain->children == NULL) {
+               SAFE_FREE(domain);
+               return NULL;
+       }
+       memset(domain->children, 0,
+              sizeof(struct winbindd_child)
+              * lp_winbind_max_domain_connections());
+
        fstrcpy(domain->name, domain_name);
        if (alternative_name) {
                fstrcpy(domain->alt_name, alternative_name);