You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
749 lines
15 KiB
749 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
gs.c
|
|
|
|
Abstract:
|
|
|
|
Creation and deletion of groups
|
|
|
|
Author:
|
|
|
|
Ahmed Mohamed (ahmedm) 12, 01, 2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "gs.h"
|
|
#include "gsp.h"
|
|
#include <stdio.h>
|
|
|
|
extern void ConfigInit();
|
|
|
|
extern gs_nid_t GsLocalNodeId;
|
|
extern int GsMaxNodeId;
|
|
extern int GsMinNodeId;
|
|
|
|
void cm_init();
|
|
void cm_start();
|
|
|
|
gs_group_t GsGroupTable[GsGroupTableSize];
|
|
|
|
HANDLE ns_gd;
|
|
|
|
HANDLE
|
|
WINAPI
|
|
GsGetGroupHandle(HANDLE msgd)
|
|
{
|
|
gs_msg_t *msg = (gs_msg_t *)msgd;
|
|
|
|
return (HANDLE) &GsGroupTable[msg->m_hdr.h_gid];
|
|
}
|
|
|
|
int
|
|
WINAPI
|
|
GsGetSourceMemberid(HANDLE msgd)
|
|
{
|
|
gs_msg_t *msg = (gs_msg_t *)msgd;
|
|
|
|
return (int) msg->m_hdr.h_sid;
|
|
}
|
|
|
|
void
|
|
GspInitGroup(gs_group_t *gd, int wsz);
|
|
|
|
|
|
// Internal routines
|
|
|
|
gs_group_t *
|
|
GspLookupGroup(gs_gid_t gid)
|
|
{
|
|
gs_group_t *gd;
|
|
|
|
if (gid >= GsGroupTableSize) {
|
|
return NULL;
|
|
}
|
|
gd = &GsGroupTable[gid];
|
|
assert(gd->g_id == gid);
|
|
if (gd->g_state == GS_GROUP_STATE_FREE ||
|
|
gd->g_state == GS_GROUP_STATE_NEW) {
|
|
return NULL;
|
|
}
|
|
|
|
assert(gd->g_state != GS_GROUP_STATE_FREE);
|
|
return gd;
|
|
}
|
|
|
|
gs_group_t *
|
|
GspLookupGroupByName(char *name, int len)
|
|
{
|
|
gs_group_t *gd;
|
|
int i;
|
|
|
|
for (i = 0; i < GsGroupTableSize; i++) {
|
|
gd = &GsGroupTable[i];
|
|
if (gd->g_state != GS_GROUP_STATE_FREE &&
|
|
len == gd->g_namelen && !strcmp(gd->g_name, name)) {
|
|
return gd;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
gs_group_t *
|
|
GspAllocateGroup(char *name, int len)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < GsGroupTableSize; i++) {
|
|
gs_group_t *gd;
|
|
|
|
gd = &GsGroupTable[i];
|
|
if (gd->g_state == GS_GROUP_STATE_FREE) {
|
|
// set everything to zero
|
|
memset(gd, 0, sizeof(*gd));
|
|
|
|
gd->g_id = i;
|
|
gd->g_nid = GsLocalNodeId;
|
|
|
|
GsLockInit(gd->g_lock);
|
|
|
|
gd->g_name = name;
|
|
gd->g_namelen = len;
|
|
gd->g_state = GS_GROUP_STATE_NEW;
|
|
|
|
return gd;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
GspDeleteGroup(gs_group_t *gd)
|
|
{
|
|
|
|
// xxx: grab lock in write mode
|
|
assert(gd->g_state != GS_GROUP_STATE_FREE);
|
|
|
|
if (gd->g_name) {
|
|
free(gd->g_name);
|
|
}
|
|
gd->g_name = NULL;
|
|
gd->g_namelen = 0;
|
|
|
|
gd->g_mset = 0;
|
|
gd->g_state = GS_GROUP_STATE_FREE;
|
|
|
|
if (gd->g_mlist) {
|
|
free((char *) gd->g_mlist);
|
|
}
|
|
if (gd->g_send.s_ctxpool) {
|
|
free((char *) gd->g_send.s_ctxpool);
|
|
}
|
|
// xxx: drop lock
|
|
}
|
|
|
|
void
|
|
GspAddMember(gs_group_t *gd, gs_memberid_t mid, int wsz)
|
|
{
|
|
gs_member_t *p;
|
|
|
|
ns_log(("Add member gid %d sz %d mid %d\n",
|
|
gd->g_id, gd->g_sz, mid));
|
|
|
|
p = (gs_member_t *) malloc(sizeof(gs_member_t) * (gd->g_sz+1));
|
|
if (p == NULL) {
|
|
err_log(("Unable to extend member table\n"));
|
|
exit(1);
|
|
}
|
|
|
|
if (gd->g_mlist) {
|
|
memcpy(p, gd->g_mlist, sizeof(gs_member_t) * (gd->g_sz));
|
|
free((char *)gd->g_mlist);
|
|
}
|
|
gd->g_mlist = p;
|
|
gd->g_mset |= (1 << mid);
|
|
p += gd->g_sz;
|
|
gd->g_sz++;
|
|
gd->g_curview++;
|
|
|
|
// init member state
|
|
p->m_id = gd->g_sz;
|
|
p->m_expected_seq = 0;
|
|
p->m_wsz = (UINT16) wsz;
|
|
p->m_msz = (UINT16) GS_DEFAULT_MAX_MSG_SZ;
|
|
|
|
}
|
|
|
|
void
|
|
GspSetMaster(gs_group_t *gd, gs_memberid_t mid)
|
|
{
|
|
gd->g_mid = mid;
|
|
}
|
|
|
|
void
|
|
GspInitGroup(gs_group_t *gd, int wsz)
|
|
{
|
|
int i;
|
|
|
|
// init send state
|
|
|
|
GsSemaInit(gd->g_send.s_sema, wsz);
|
|
gd->g_send.s_wsz = (UINT16) wsz;
|
|
|
|
// allocate window size contexts
|
|
gd->g_send.s_ctxpool = (gs_context_t *) malloc(sizeof(gs_context_t) * wsz);
|
|
if (gd->g_send.s_ctxpool == NULL) {
|
|
assert(0);
|
|
}
|
|
|
|
for (i = 0; i < wsz; i++) {
|
|
gs_context_t *p = &gd->g_send.s_ctxpool[i];
|
|
|
|
p->ctx_id = GS_CONTEXT_INVALID_ID;
|
|
p->ctx_gid = gd->g_id;
|
|
p->ctx_buf = 0;
|
|
p->ctx_rbuf = 0;
|
|
p->ctx_msg = 0;
|
|
p->ctx_event = 0;
|
|
GsEventInit(p->ctx_syncevent);
|
|
}
|
|
|
|
// init receive state
|
|
gd->g_recv.r_next = &gd->g_recv.r_head;
|
|
}
|
|
|
|
|
|
void
|
|
WINAPI
|
|
GsInit()
|
|
{
|
|
int i;
|
|
void NsForm();
|
|
void NsJoin();
|
|
|
|
timeBeginPeriod(50);
|
|
|
|
ConfigInit();
|
|
|
|
// Initialize global data structure
|
|
for (i = 0; i < GsGroupTableSize; i++) {
|
|
gs_group_t *gd;
|
|
|
|
gd = &GsGroupTable[i];
|
|
gd->g_state = GS_GROUP_STATE_FREE;
|
|
gd->g_mset = 0;
|
|
}
|
|
|
|
// init and start connection manager
|
|
cm_init();
|
|
|
|
NsForm();
|
|
|
|
cm_start();
|
|
|
|
NsJoin();
|
|
}
|
|
|
|
void
|
|
WINAPI
|
|
GsExit()
|
|
{
|
|
int i;
|
|
|
|
// stop messaging
|
|
msg_exit();
|
|
|
|
// free context pool and membership list for each group in group table
|
|
for (i = 0; i < GsGroupTableSize; i++) {
|
|
gs_group_t *gd;
|
|
|
|
gd = &GsGroupTable[i];
|
|
GspDeleteGroup(gd);
|
|
}
|
|
|
|
timeEndPeriod(50);
|
|
}
|
|
|
|
#define NS_TABLE_READ 0
|
|
#define NS_TABLE_ADD 1
|
|
|
|
HANDLE
|
|
WINAPI
|
|
GsCreateGroup(gs_callback_t func, char *name, int len, int wsz,
|
|
int disposition, HANDLE *join_ctx)
|
|
|
|
{
|
|
gs_group_t *gd;
|
|
PVOID io[GS_MAX_GROUP_SZ];
|
|
int result[GS_MAX_GROUP_SZ];
|
|
int i;
|
|
NTSTATUS err;
|
|
IO_STATUS_BLOCK status[GS_MAX_GROUP_SZ];
|
|
gs_ns_info_t info;
|
|
int GspJoin(HANDLE group, gs_event_t event, PVOID io[], IO_STATUS_BLOCK status[],
|
|
int wsz, HANDLE *context);
|
|
gs_event_t event;
|
|
union {
|
|
int cmd;
|
|
gs_tag_t tag;
|
|
}tag;
|
|
|
|
if (name == NULL || len > GS_MAX_NAME_SZ) {
|
|
return NULL;
|
|
}
|
|
|
|
ns_log(("Create group %s\n", name));
|
|
|
|
for (i = 0; i < GS_MAX_GROUP_SZ; i++) {
|
|
status[i].Information = 0;
|
|
io[i] = (PVOID)&result[i];
|
|
result[i] = TRUE;
|
|
}
|
|
|
|
// Based on disposition we either form or join
|
|
info.owner = (USHORT) ((gs_group_t *)ns_gd)->g_nid;
|
|
info.wsz = (UINT16) wsz;
|
|
strcpy(info.name, name);
|
|
GsEventInit(event);
|
|
|
|
retry:
|
|
tag.cmd = NS_TABLE_ADD;
|
|
err = GsSendDeliveredRequest(ns_gd, event,
|
|
tag.tag, (PVOID) &info, sizeof(info),
|
|
io, sizeof(result[0]),
|
|
status,
|
|
NULL);
|
|
|
|
if (err != ERROR_SUCCESS) {
|
|
GsEventFree(event);
|
|
err_log(("Create group failed %d\n", err));
|
|
return NULL;
|
|
}
|
|
// xxx: make sure result is true
|
|
gd = GspLookupGroupByName(name, len);
|
|
if (gd != NULL) {
|
|
int err;
|
|
|
|
ns_log(("Init group %x\n", gd));
|
|
GspInitGroup(gd, wsz);
|
|
GsRegisterHandler((HANDLE)gd, func);
|
|
err = GspJoin((HANDLE) gd, event, io, status, wsz, join_ctx);
|
|
if (err) {
|
|
ns_log(("Init group gspjoin failed, need to retry\n"));
|
|
goto retry;
|
|
}
|
|
}
|
|
ns_log(("Created group %x\n", gd));
|
|
GsEventFree(event);
|
|
return (HANDLE) gd;
|
|
}
|
|
|
|
NTSTATUS
|
|
GsCloseGroup(HANDLE group)
|
|
{
|
|
gs_group_t *gd = (gs_group_t *)group;
|
|
|
|
GspDeleteGroup(gd);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
void
|
|
GsRegisterHandler(HANDLE group, gs_callback_t func)
|
|
{
|
|
gs_group_t *gd = (gs_group_t *) group;
|
|
|
|
gd->g_callback = func;
|
|
}
|
|
|
|
NTSTATUS
|
|
GsQueryGroup(HANDLE group, gs_info_t *info)
|
|
{
|
|
gs_group_t *gd;
|
|
|
|
if (group == NULL) {
|
|
group = ns_gd;
|
|
}
|
|
|
|
gd = (gs_group_t *) group;
|
|
if (!gd || !info) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
info->lid = gd->g_nid;
|
|
info->mid = gd->g_mid;
|
|
info->group_size = gd->g_sz;
|
|
info->cluster_size = msg_getsize();
|
|
info->mset = gd->g_mset;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
// Name server
|
|
|
|
NTSTATUS
|
|
ns_callback(HANDLE group, gs_tag_t mtag, PVOID buf, IO_STATUS_BLOCK *ios)
|
|
{
|
|
|
|
gs_ns_info_t table[GS_MAX_GROUPS];
|
|
int i, j, result;
|
|
gs_group_t *gd = (gs_group_t *) group;
|
|
NTSTATUS err;
|
|
gs_ns_info_t *info;
|
|
int tag = *((int *)mtag);
|
|
|
|
switch(ios->Status) {
|
|
case GsEventData:
|
|
ns_log(("NsCallback Disposition %d\n", tag));
|
|
switch(tag) {
|
|
case NS_TABLE_READ:
|
|
|
|
// only group table master reponse to reads
|
|
if (GsGroupTable[0].g_mid == GsGroupTable[0].g_nid) {
|
|
j = 0;
|
|
for (i = 1; i < GsGroupTableSize; i++) {
|
|
gd = &GsGroupTable[i];
|
|
if (gd->g_state != GS_GROUP_STATE_FREE) {
|
|
table[j].owner = gd->g_mid;
|
|
table[j].id = (USHORT) i;
|
|
strcpy(table[j].name, gd->g_name);
|
|
j++;
|
|
}
|
|
}
|
|
|
|
ns_log(("Sending table size %d\n", j));
|
|
err = GsSendReply(group, (PVOID) table, sizeof(table[0]) * j, STATUS_SUCCESS);
|
|
if (err != ERROR_SUCCESS) {
|
|
printf("Failed to respond to table read ns\n");
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case NS_TABLE_ADD:
|
|
|
|
info = (gs_ns_info_t *)buf;
|
|
assert(ios->Information == sizeof(*info));
|
|
// xxx: lock table
|
|
gd = GspLookupGroupByName(info->name, strlen(info->name));
|
|
if (gd == NULL) {
|
|
char * strsave(char *s);
|
|
|
|
gd = GspAllocateGroup(strsave(info->name), strlen(info->name));
|
|
|
|
if (gd != NULL) {
|
|
GspSetMaster(gd, info->owner);
|
|
}
|
|
ns_log(("Ns Created group %s id %d owner %d\n",
|
|
info->name, gd->g_id, gd->g_mid));
|
|
}
|
|
// xxx: unlock table
|
|
if (gd != NULL) {
|
|
result = TRUE;
|
|
} else {
|
|
result = FALSE;
|
|
}
|
|
err = GsSendReply(group, (PVOID) &result, sizeof(result), STATUS_SUCCESS);
|
|
if (err != ERROR_SUCCESS) {
|
|
err_log(("Failed to respond to add ns\n"));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err_log(("Invalid ns opcode, %d\n", tag));
|
|
exit(1);
|
|
}
|
|
break;
|
|
|
|
case GsEventMemberJoin:
|
|
ns_log(("NsCallback member join %d\n", tag));
|
|
break;
|
|
case GsEventMemberUp:
|
|
ns_log(("NsCallback member up %d\n", tag));
|
|
break;
|
|
case GsEventMemberDown:
|
|
ns_log(("NsCallback member down %d\n", tag));
|
|
break;
|
|
default:
|
|
ns_log(("Ns invalid event %d\n", ios->Status));
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
NsForm()
|
|
{
|
|
char *name = "Name server";
|
|
|
|
ns_gd = (HANDLE) GspAllocateGroup(name, strlen(name));
|
|
if (ns_gd == NULL) {
|
|
err_log(("Unable to create name server group!\n"));
|
|
exit(1);
|
|
}
|
|
GspInitGroup((gs_group_t *)ns_gd, 1);
|
|
GsRegisterHandler(ns_gd, ns_callback);
|
|
}
|
|
|
|
void
|
|
NsSetOwner(gs_nid_t nid)
|
|
{
|
|
gs_group_t *gd = (gs_group_t *) ns_gd;
|
|
|
|
ns_log(("Name server: master %d\n", nid));
|
|
|
|
GsLockEnter(gd->g_lock);
|
|
|
|
GspSetMaster(gd, (gs_memberid_t)nid);
|
|
if (gd->g_rs != NULL && gd->g_mid != gd->g_nid) {
|
|
gd->g_rs->rs_mset = (1 << gd->g_nid) | (1 << gd->g_mid);
|
|
}
|
|
|
|
GsLockExit(gd->g_lock);
|
|
}
|
|
|
|
int
|
|
GspJoin(HANDLE group, gs_event_t event, PVOID io[], IO_STATUS_BLOCK status[],
|
|
int wsz, HANDLE *context)
|
|
{
|
|
|
|
// if we don't master the name server, we simply send a
|
|
// join request to this group and receive a table of
|
|
// group names and owners
|
|
gs_join_info_t info;
|
|
int table[GS_MAX_GROUP_SZ];
|
|
gs_group_t *gd = (gs_group_t *) group;
|
|
gs_context_t *ctx;
|
|
gs_memberid_t mid;
|
|
union {
|
|
int mid;
|
|
gs_tag_t tag;
|
|
}tag;
|
|
|
|
if (context) *context = NULL;
|
|
|
|
while (TRUE) {
|
|
int err, i;
|
|
UINT32 sz, flags;
|
|
gs_msg_hdr_t hdr;
|
|
|
|
GsLockEnter(gd->g_lock);
|
|
ns_log(("join group %s mid %d\n", gd->g_name, gd->g_mid));
|
|
if ((mid = gd->g_mid) == gd->g_nid) {
|
|
gs_msg_t msg;
|
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.m_hdr.h_type = GS_MSG_TYPE_UP;
|
|
msg.m_buf = (char *) &wsz;
|
|
*((gs_memberid_t *)msg.m_hdr.h_tag) = mid;
|
|
msg.m_hdr.h_len = sizeof(wsz);
|
|
msg.m_hdr.h_flags = GS_FLAGS_REPLY;
|
|
msg.m_hdr.h_gid = gd->g_id;
|
|
GspDeliverMsg(gd, &msg);
|
|
gd->g_state = GS_GROUP_STATE_FORM;
|
|
GsLockExit(gd->g_lock);
|
|
break;
|
|
}
|
|
|
|
gd->g_state = GS_GROUP_STATE_JOIN;
|
|
|
|
GsLockExit(gd->g_lock);
|
|
|
|
GspOpenContext(gd, &ctx);
|
|
|
|
io[0] = (PVOID) &info;
|
|
status[0].Information = 0;
|
|
tag.mid = gd->g_nid,
|
|
err = GspSendDirectedRequest(gd, ctx, event, mid,
|
|
tag.tag, NULL, 0,
|
|
&io[0], sizeof(info),
|
|
&status[0],
|
|
GS_FLAGS_DELIVERED,
|
|
GS_MSG_TYPE_JOIN_REQUEST);
|
|
|
|
|
|
GsLockEnter(gd->g_lock);
|
|
if (gd->g_mid != mid) {
|
|
GsLockExit(gd->g_lock);
|
|
GspCloseContext(gd, ctx);
|
|
continue;
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS) {
|
|
err_log(("Join failed %d\n", err));
|
|
return 1;
|
|
}
|
|
|
|
if (status[0].Information != sizeof(info)) {
|
|
err_log(("GspJoin: invalid returned size %d\n",
|
|
status[0].Information));
|
|
halt(1);
|
|
}
|
|
|
|
ns_log(("GspJoin: group %s mastered by %d curset %x\n",
|
|
gd->g_name, mid, info.mset));
|
|
|
|
ns_log(("GspJoin: Mseq %d Curview %d Gsz %d mset %x\n",
|
|
info.mseq, info.viewnum, info.sz, info.mset));
|
|
|
|
// init some state
|
|
gd->g_curview = info.viewnum;
|
|
gd->g_startview = info.viewnum;
|
|
gd->g_mset = info.mset;
|
|
gd->g_recv.r_mseq = info.mseq;
|
|
gd->g_recv.r_bnum = 1; // set starting point
|
|
gd->g_send.s_lseq = info.mseq;
|
|
gd->g_sz = info.sz;
|
|
|
|
GsLockExit(gd->g_lock);
|
|
sz = sizeof(table);
|
|
for (i = 0; i < GS_MAX_GROUP_SZ; i++) {
|
|
status[i].Information = 0;
|
|
io[i] = (PVOID) &table[i];
|
|
table[i] = TRUE;
|
|
}
|
|
tag.mid = gd->g_nid;
|
|
err = GspSendRequest(gd, ctx, event, GS_MSG_TYPE_JOIN, mid,
|
|
tag.tag,
|
|
(PVOID)&wsz, sizeof(wsz),
|
|
io, sizeof(table[0]),
|
|
status,
|
|
GS_FLAGS_DELIVERED | GS_FLAGS_CONTINUED | GS_FLAGS_LAST,
|
|
&info);
|
|
|
|
if (err != ERROR_SUCCESS) {
|
|
err_log(("Join failed %d\n", err));
|
|
halt(1);
|
|
}
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < GS_MAX_GROUP_SZ; i++) {
|
|
if (table[i] != TRUE) {
|
|
err_log(("GsJoin: Failed was rejected by member %d\n", i));
|
|
halt(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (context == NULL) {
|
|
flags = GS_FLAGS_DELIVERED | GS_FLAGS_CLOSE | GS_FLAGS_LAST;
|
|
} else {
|
|
flags = GS_FLAGS_DELIVERED | GS_FLAGS_CONTINUED | GS_FLAGS_LAST;
|
|
}
|
|
|
|
// add ourself to membership set
|
|
info.sz++;
|
|
info.mset |= (1 << gd->g_nid);
|
|
sz = 0;
|
|
tag.mid = gd->g_nid;
|
|
err = GspSendRequest(gd, ctx, event, GS_MSG_TYPE_UP, mid,
|
|
tag.tag,
|
|
(PVOID) &wsz, sizeof(wsz), NULL, 0, status, flags, &info);
|
|
|
|
|
|
// advance our startview
|
|
gd->g_startview++;
|
|
gd->g_state = GS_GROUP_STATE_FORM;
|
|
|
|
if (context != NULL) {
|
|
*context = (HANDLE) ctx;
|
|
} else {
|
|
GspCloseContext(gd, ctx);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
NsJoin()
|
|
|
|
{
|
|
HANDLE ctx;
|
|
gs_ns_info_t table[GS_MAX_GROUPS];
|
|
UINT32 i, sz;
|
|
PVOID io[GS_MAX_GROUP_SZ];
|
|
IO_STATUS_BLOCK status[GS_MAX_GROUP_SZ];
|
|
NTSTATUS err;
|
|
gs_event_t event;
|
|
union {
|
|
int cmd;
|
|
gs_tag_t tag;
|
|
}tag;
|
|
|
|
GsEventInit(event);
|
|
|
|
GspJoin(ns_gd, event, io, status, 1, &ctx);
|
|
if (ctx == NULL) {
|
|
GsEventFree(event);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < GS_MAX_GROUP_SZ; i++) {
|
|
status[i].Information = 0;
|
|
io[i] = (PVOID)table;
|
|
}
|
|
tag.cmd = NS_TABLE_READ;
|
|
err = GsSendContinuedRequest(ctx, event,
|
|
tag.tag, NULL, 0,
|
|
io, sizeof(table),
|
|
status,
|
|
TRUE);
|
|
|
|
if (err != ERROR_SUCCESS) {
|
|
err_log(("Table read failed %x\n", err));
|
|
halt(1);
|
|
}
|
|
|
|
sz = 0;
|
|
for (i = 0; i < GS_MAX_GROUP_SZ; i++) {
|
|
if (status[i].Information != 0) {
|
|
sz = ((UINT32)status[i].Information) / sizeof(table[0]);
|
|
break;
|
|
}
|
|
}
|
|
assert(i != GS_MAX_GROUP_SZ);
|
|
ns_log(("NsJoin: Got table %x from master %d sz %d\n", table, i,
|
|
status[i].Information));
|
|
|
|
for (i = 0; i < sz; i++) {
|
|
gs_group_t *gd;
|
|
|
|
ns_log(("NsJoin: Table%d: %s owner %d\n",
|
|
table[i].id,
|
|
table[i].name, table[i].owner));
|
|
|
|
gd = GspLookupGroupByName(table[i].name, strlen(table[i].name));
|
|
if (gd == NULL) {
|
|
gd = GspAllocateGroup(strsave(table[i].name), strlen(table[i].name));
|
|
if (gd == NULL) {
|
|
err_log(("unable to alloc group %s, exiting..\n",
|
|
table[i].name));
|
|
halt(1);
|
|
}
|
|
GspSetMaster(gd, table[i].owner);
|
|
} else {
|
|
err_log(("found group %s already, exiting..\n", table[i].name));
|
|
halt(1);
|
|
}
|
|
}
|
|
|
|
GsEventFree(event);
|
|
}
|
|
|
|
|
|
|
|
|
|
|