2fd0237de3693c01d3d7a539c6966d1b245382d0
[openafs.git] / src / WINNT / afsd / cm_cell.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <roken.h>
13
14 #include <afs/stds.h>
15
16 #include <windows.h>
17 #include <nb30.h>
18 #include <winsock2.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <malloc.h>
22 #include <osi.h>
23 #include <string.h>
24 #define STRSAFE_NO_DEPRECATE
25 #include <strsafe.h>
26
27 #include "afsd.h"
28
29 osi_rwlock_t cm_cellLock;
30
31 /* function called as callback proc from cm_SearchCellFile.  Return 0 to
32  * continue processing.
33  *
34  * At the present time the return value is ignored by the caller.
35  */
36 long cm_AddCellProc(void *rockp, struct sockaddr_in *addrp, char *hostnamep, unsigned short adminRank)
37 {
38     cm_server_t *tsp;
39     cm_serverRef_t *tsrp;
40     cm_cell_t *cellp;
41     cm_cell_rock_t *cellrockp = (cm_cell_rock_t *)rockp;
42     afs_uint32 probe;
43
44     cellp = cellrockp->cellp;
45     probe = !(cellrockp->flags & CM_FLAG_NOPROBE);
46
47     /* if this server was previously created by fs setserverprefs */
48     if ( tsp = cm_FindServer(addrp, CM_SERVER_VLDB, FALSE))
49     {
50         if ( !tsp->cellp )
51             tsp->cellp = cellp;
52         else if (tsp->cellp != cellp) {
53             osi_Log3(afsd_logp, "found a vlserver %s associated with two cells named %s and %s",
54                      osi_LogSaveString(afsd_logp,hostnamep),
55                      osi_LogSaveString(afsd_logp,tsp->cellp->name),
56                      osi_LogSaveString(afsd_logp,cellp->name));
57         }
58     }
59     else
60         tsp = cm_NewServer(addrp, CM_SERVER_VLDB, cellp, NULL, probe ? 0 : CM_FLAG_NOPROBE);
61
62     if (adminRank)
63         tsp->adminRank = adminRank;
64
65     /* Insert the vlserver into a sorted list, sorted by server rank */
66     tsrp = cm_NewServerRef(tsp, 0);
67     cm_InsertServerList(&cellp->vlServersp, tsrp);
68
69     return 0;
70 }
71
72 /* if it's from DNS, see if it has expired
73  * and check to make sure we have a valid set of volume servers
74  * this function must not be called with a lock on cm_cellLock
75  */
76 cm_cell_t *cm_UpdateCell(cm_cell_t * cp, afs_uint32 flags)
77 {
78     long code = 0;
79     cm_cell_rock_t rock;
80     afs_uint32 mxheld = 0;
81
82     if (cp == NULL)
83         return NULL;
84
85     lock_ObtainMutex(&cp->mx);
86     mxheld = 1;
87
88 #ifdef AFS_FREELANCE_CLIENT
89     if (cp->flags & CM_CELLFLAG_FREELANCE) {
90         lock_ReleaseMutex(&cp->mx);
91         return cp;
92     }
93 #endif
94
95     if (cm_IsServerListEmpty(cp->vlServersp) ||
96         (time(0) > cp->timeout) ||
97         (cm_dnsEnabled &&
98          (cp->flags & CM_CELLFLAG_DNS) &&
99          ((cp->flags & CM_CELLFLAG_VLSERVER_INVALID))))
100     {
101         lock_ReleaseMutex(&cp->mx);
102         mxheld = 0;
103
104         /* must empty cp->vlServersp */
105         if (cp->vlServersp)
106             cm_FreeServerList(&cp->vlServersp, CM_FREESERVERLIST_DELETE);
107
108         rock.cellp = cp;
109         rock.flags = flags;
110         code = cm_SearchCellRegistry(1, cp->name, NULL, cp->linkedName, cm_AddCellProc, &rock);
111         if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
112             code = cm_SearchCellFileEx(cp->name, NULL, cp->linkedName, cm_AddCellProc, &rock);
113         if (code == 0) {
114             lock_ObtainMutex(&cp->mx);
115             mxheld = 1;
116             cp->timeout = time(0) + 7200;
117         }
118         else {
119             if (cm_dnsEnabled) {
120                 int ttl;
121
122                 code = cm_SearchCellByDNS(cp->name, NULL, &ttl, cm_AddCellProc, &rock);
123                 if (code == 0) {   /* got cell from DNS */
124                     lock_ObtainMutex(&cp->mx);
125                     mxheld = 1;
126                     _InterlockedOr(&cp->flags, CM_CELLFLAG_DNS);
127                     _InterlockedAnd(&cp->flags, ~CM_CELLFLAG_VLSERVER_INVALID);
128                     cp->timeout = time(0) + ttl;
129 #ifdef DEBUG
130                     fprintf(stderr, "cell %s: ttl=%d\n", cp->name, ttl);
131 #endif
132                 } else {
133                     /* if we fail to find it this time, we'll just do nothing and leave the
134                      * current entry alone
135                      */
136                     lock_ObtainMutex(&cp->mx);
137                     mxheld = 1;
138                     _InterlockedOr(&cp->flags, CM_CELLFLAG_VLSERVER_INVALID);
139                 }
140             }
141         }
142     }
143
144     if (code == 0)
145         cm_RandomizeServer(&cp->vlServersp);
146
147     if (mxheld)
148         lock_ReleaseMutex(&cp->mx);
149
150     return code ? NULL : cp;
151 }
152
153 /* load up a cell structure from the cell database, AFS_CELLSERVDB */
154 cm_cell_t *cm_GetCell(char *namep, afs_uint32 flags)
155 {
156     return cm_GetCell_Gen(namep, NULL, flags);
157 }
158
159 void cm_FreeCell(cm_cell_t *cellp)
160 {
161     lock_AssertWrite(&cm_cellLock);
162
163     if (cellp->vlServersp)
164         cm_FreeServerList(&cellp->vlServersp, CM_FREESERVERLIST_DELETE);
165     cellp->name[0] = '\0';
166
167     cellp->freeNextp = cm_data.freeCellsp;
168     cm_data.freeCellsp = cellp;
169 }
170
171 cm_cell_t *cm_GetCell_Gen(char *namep, char *newnamep, afs_uint32 flags)
172 {
173     cm_cell_t *cp, *cp2;
174     long code;
175     char fullname[CELL_MAXNAMELEN]="";
176     char linkedName[CELL_MAXNAMELEN]="";
177     char name[CELL_MAXNAMELEN]="";
178     int  hasWriteLock = 0;
179     int  hasMutex = 0;
180     afs_uint32 hash;
181     cm_cell_rock_t rock;
182     size_t len;
183     afs_int32 cellID;
184
185     if (namep == NULL || !namep[0] || !strcmp(namep,CM_IOCTL_FILENAME_NOSLASH))
186         return NULL;
187
188     /*
189      * Strip off any trailing dots at the end of the cell name.
190      * Failure to do so results in an undesireable alias as the
191      * result of DNS AFSDB record lookups where a trailing dot
192      * has special meaning.
193      */
194     strncpy(name, namep, CELL_MAXNAMELEN);
195     for (len = strlen(namep); len > 0 && namep[len-1] == '.'; len--) {
196         name[len-1] = '\0';
197     }
198     if (len == 0)
199         return NULL;
200     namep = name;
201
202     hash = CM_CELL_NAME_HASH(namep);
203
204     lock_ObtainRead(&cm_cellLock);
205     for (cp = cm_data.cellNameHashTablep[hash]; cp; cp=cp->nameNextp) {
206         if (cm_stricmp_utf8(namep, cp->name) == 0) {
207             strncpy(fullname, cp->name, CELL_MAXNAMELEN);
208             fullname[CELL_MAXNAMELEN-1] = '\0';
209             break;
210         }
211     }
212
213     if (!cp) {
214         for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) {
215             if (strnicmp(namep, cp->name, strlen(namep)) == 0) {
216                 strncpy(fullname, cp->name, CELL_MAXNAMELEN);
217                 fullname[CELL_MAXNAMELEN-1] = '\0';
218                 break;
219             }
220         }
221     }
222
223     if (cp) {
224         lock_ReleaseRead(&cm_cellLock);
225         cm_UpdateCell(cp, flags);
226     } else if (flags & CM_FLAG_CREATE) {
227         lock_ConvertRToW(&cm_cellLock);
228         hasWriteLock = 1;
229
230         /* when we dropped the lock the cell could have been added
231          * to the list so check again while holding the write lock
232          */
233         for (cp = cm_data.cellNameHashTablep[hash]; cp; cp=cp->nameNextp) {
234             if (cm_stricmp_utf8(namep, cp->name) == 0) {
235                 strncpy(fullname, cp->name, CELL_MAXNAMELEN);
236                 fullname[CELL_MAXNAMELEN-1] = '\0';
237                 break;
238             }
239         }
240
241         if (cp)
242             goto done;
243
244         for (cp = cm_data.allCellsp; cp; cp=cp->allNextp) {
245             if (strnicmp(namep, cp->name, strlen(namep)) == 0) {
246                 strncpy(fullname, cp->name, CELL_MAXNAMELEN);
247                 fullname[CELL_MAXNAMELEN-1] = '\0';
248                 break;
249             }
250         }
251
252         if (cp) {
253             lock_ReleaseWrite(&cm_cellLock);
254             lock_ObtainMutex(&cp->mx);
255             lock_ObtainWrite(&cm_cellLock);
256             cm_AddCellToNameHashTable(cp);
257             cm_AddCellToIDHashTable(cp);
258             lock_ReleaseMutex(&cp->mx);
259             goto done;
260         }
261
262         if ( cm_data.freeCellsp != NULL ) {
263             cp = cm_data.freeCellsp;
264             cm_data.freeCellsp = cp->freeNextp;
265
266             /*
267              * The magic, cellID, and mx fields are already set.
268              */
269         } else {
270             if ( cm_data.currentCells >= cm_data.maxCells )
271                 osi_panic("Exceeded Max Cells", __FILE__, __LINE__);
272
273             /*
274              * the cellID cannot be 0.
275              * If there is a name collision, one of the entries
276              * will end up on cm_data.freeCellsp for reuse.
277              */
278             cellID = InterlockedIncrement(&cm_data.currentCells);
279             cp = &cm_data.cellBaseAddress[cellID - 1];
280             memset(cp, 0, sizeof(cm_cell_t));
281             cp->magic = CM_CELL_MAGIC;
282             cp->cellID = cellID;
283
284             /* otherwise we found the cell, and so we're nearly done */
285             lock_InitializeMutex(&cp->mx, "cm_cell_t mutex", LOCK_HIERARCHY_CELL);
286         }
287
288         lock_ReleaseWrite(&cm_cellLock);
289         hasWriteLock = 0;
290
291         rock.cellp = cp;
292         rock.flags = flags;
293         code = cm_SearchCellRegistry(1, namep, fullname, linkedName, cm_AddCellProc, &rock);
294         if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
295             code = cm_SearchCellFileEx(namep, fullname, linkedName, cm_AddCellProc, &rock);
296         if (code) {
297             osi_Log4(afsd_logp,"in cm_GetCell_gen cm_SearchCellFileEx(%s) returns code= %d fullname= %s linkedName= %s",
298                       osi_LogSaveString(afsd_logp,namep), code, osi_LogSaveString(afsd_logp,fullname),
299                       osi_LogSaveString(afsd_logp,linkedName));
300
301             if (cm_dnsEnabled) {
302                 int ttl;
303
304                 code = cm_SearchCellByDNS(namep, fullname, &ttl, cm_AddCellProc, &rock);
305                 if ( code ) {
306                     osi_Log3(afsd_logp,"in cm_GetCell_gen cm_SearchCellByDNS(%s) returns code= %d fullname= %s",
307                              osi_LogSaveString(afsd_logp,namep), code, osi_LogSaveString(afsd_logp,fullname));
308                     lock_ObtainMutex(&cp->mx);
309                     lock_ObtainWrite(&cm_cellLock);
310                     hasWriteLock = 1;
311                     cm_RemoveCellFromIDHashTable(cp);
312                     cm_RemoveCellFromNameHashTable(cp);
313                     lock_ReleaseMutex(&cp->mx);
314                     cm_FreeCell(cp);
315                     cp = NULL;
316                     goto done;
317                 } else {   /* got cell from DNS */
318                     lock_ObtainMutex(&cp->mx);
319                     hasMutex = 1;
320                     _InterlockedOr(&cp->flags, CM_CELLFLAG_DNS);
321                     _InterlockedAnd(&cp->flags, ~CM_CELLFLAG_VLSERVER_INVALID);
322                     cp->timeout = time(0) + ttl;
323                 }
324             }
325             else
326             {
327                 lock_ObtainMutex(&cp->mx);
328                 lock_ObtainWrite(&cm_cellLock);
329                 hasWriteLock = 1;
330                 cm_RemoveCellFromIDHashTable(cp);
331                 cm_RemoveCellFromNameHashTable(cp);
332                 lock_ReleaseMutex(&cp->mx);
333                 cm_FreeCell(cp);
334                 cp = NULL;
335                 goto done;
336             }
337         } else {
338             lock_ObtainMutex(&cp->mx);
339             hasMutex = 1;
340             cp->timeout = time(0) + 7200;       /* two hour timeout */
341         }
342
343         /* we have now been given the fullname of the cell.  It may
344          * be that we already have a cell with that name.  If so,
345          * we should use it instead of completing the allocation
346          * of a new cm_cell_t
347          */
348         lock_ObtainRead(&cm_cellLock);
349         hash = CM_CELL_NAME_HASH(fullname);
350         for (cp2 = cm_data.cellNameHashTablep[hash]; cp2; cp2=cp2->nameNextp) {
351             if (cm_stricmp_utf8(fullname, cp2->name) == 0) {
352                 break;
353             }
354         }
355
356         if (cp2) {
357             if (!hasMutex) {
358                 lock_ObtainMutex(&cp->mx);
359                 hasMutex = 1;
360             }
361             lock_ConvertRToW(&cm_cellLock);
362             hasWriteLock = 1;
363             cm_RemoveCellFromIDHashTable(cp);
364             cm_RemoveCellFromNameHashTable(cp);
365             lock_ReleaseMutex(&cp->mx);
366             hasMutex = 0;
367             cm_FreeCell(cp);
368             cp = cp2;
369             goto done;
370         }
371         lock_ReleaseRead(&cm_cellLock);
372
373         /* randomise among those vlservers having the same rank*/
374         cm_RandomizeServer(&cp->vlServersp);
375
376         if (!hasMutex)
377             lock_ObtainMutex(&cp->mx);
378
379         /* copy in name */
380         strncpy(cp->name, fullname, CELL_MAXNAMELEN);
381         cp->name[CELL_MAXNAMELEN-1] = '\0';
382
383         strncpy(cp->linkedName, linkedName, CELL_MAXNAMELEN);
384         cp->linkedName[CELL_MAXNAMELEN-1] = '\0';
385
386         lock_ObtainWrite(&cm_cellLock);
387         hasWriteLock = 1;
388         cm_AddCellToNameHashTable(cp);
389         cm_AddCellToIDHashTable(cp);
390         lock_ReleaseMutex(&cp->mx);
391         hasMutex = 0;
392
393         /* append cell to global list */
394         if (cm_data.allCellsp == NULL) {
395             cm_data.allCellsp = cp;
396         } else {
397             for (cp2 = cm_data.allCellsp; cp2->allNextp; cp2=cp2->allNextp)
398                 ;
399             cp2->allNextp = cp;
400         }
401         cp->allNextp = NULL;
402
403     } else {
404         lock_ReleaseRead(&cm_cellLock);
405     }
406   done:
407     if (hasMutex && cp)
408         lock_ReleaseMutex(&cp->mx);
409     if (hasWriteLock)
410         lock_ReleaseWrite(&cm_cellLock);
411
412     /* fullname is not valid if cp == NULL */
413     if (newnamep) {
414         if (cp) {
415             strncpy(newnamep, fullname, CELL_MAXNAMELEN);
416             newnamep[CELL_MAXNAMELEN-1]='\0';
417         } else {
418             newnamep[0] = '\0';
419         }
420     }
421
422     if (cp && cp->linkedName[0]) {
423         cm_cell_t * linkedCellp = NULL;
424
425         if (!strcmp(cp->name, cp->linkedName)) {
426             cp->linkedName[0] = '\0';
427         } else if (!(flags & CM_FLAG_NOMOUNTCHASE)) {
428             linkedCellp = cm_GetCell(cp->linkedName, CM_FLAG_CREATE|CM_FLAG_NOPROBE|CM_FLAG_NOMOUNTCHASE);
429
430             lock_ObtainWrite(&cm_cellLock);
431             if (!linkedCellp ||
432                 (linkedCellp->linkedName[0] && strcmp(cp->name, linkedCellp->linkedName))) {
433                 cp->linkedName[0] = '\0';
434             } else {
435                 strncpy(linkedCellp->linkedName, cp->name, CELL_MAXNAMELEN);
436                 linkedCellp->linkedName[CELL_MAXNAMELEN-1]='\0';
437             }
438             lock_ReleaseWrite(&cm_cellLock);
439         }
440     }
441     return cp;
442 }
443
444 cm_cell_t *cm_FindCellByID(afs_int32 cellID, afs_uint32 flags)
445 {
446     cm_cell_t *cp;
447     afs_uint32 hash;
448
449     lock_ObtainRead(&cm_cellLock);
450
451     hash = CM_CELL_ID_HASH(cellID);
452
453     for (cp = cm_data.cellIDHashTablep[hash]; cp; cp=cp->idNextp) {
454         if (cellID == cp->cellID)
455             break;
456     }
457     lock_ReleaseRead(&cm_cellLock);
458
459     if (cp)
460         cm_UpdateCell(cp, flags);
461
462     return cp;
463 }
464
465 long
466 cm_ValidateCell(void)
467 {
468     cm_cell_t * cellp;
469     afs_uint32 count1, count2;
470
471     for (cellp = cm_data.allCellsp, count1 = 0; cellp; cellp=cellp->allNextp, count1++) {
472         if ( cellp->magic != CM_CELL_MAGIC ) {
473             afsi_log("cm_ValidateCell failure: cellp->magic != CM_CELL_MAGIC");
474             fprintf(stderr, "cm_ValidateCell failure: cellp->magic != CM_CELL_MAGIC\n");
475             return -1;
476         }
477         if ( count1 != 0 && cellp == cm_data.allCellsp ||
478              count1 > cm_data.maxCells ) {
479             afsi_log("cm_ValidateCell failure: cm_data.allCellsp infinite loop");
480             fprintf(stderr, "cm_ValidateCell failure: cm_data.allCellsp infinite loop\n");
481             return -2;
482         }
483     }
484
485     for (cellp = cm_data.freeCellsp, count2 = 0; cellp; cellp=cellp->freeNextp, count2++) {
486         if ( count2 != 0 && cellp == cm_data.freeCellsp ||
487              count2 > cm_data.maxCells ) {
488             afsi_log("cm_ValidateCell failure: cm_data.freeCellsp infinite loop");
489             fprintf(stderr, "cm_ValidateCell failure: cm_data.freeCellsp infinite loop\n");
490             return -3;
491         }
492     }
493
494     if ( (count1 + count2) != cm_data.currentCells ) {
495         afsi_log("cm_ValidateCell failure: count != cm_data.currentCells");
496         fprintf(stderr, "cm_ValidateCell failure: count != cm_data.currentCells\n");
497         return -4;
498     }
499
500     return 0;
501 }
502
503
504 long
505 cm_ShutdownCell(void)
506 {
507     cm_cell_t * cellp;
508
509     for (cellp = cm_data.allCellsp; cellp; cellp=cellp->allNextp)
510         lock_FinalizeMutex(&cellp->mx);
511
512     return 0;
513 }
514
515
516 void cm_InitCell(int newFile, long maxCells)
517 {
518     static osi_once_t once;
519
520     if (osi_Once(&once)) {
521         cm_cell_t * cellp;
522
523         lock_InitializeRWLock(&cm_cellLock, "cell global lock", LOCK_HIERARCHY_CELL_GLOBAL);
524
525         if ( newFile ) {
526             cm_data.allCellsp = NULL;
527             cm_data.currentCells = 0;
528             cm_data.maxCells = maxCells;
529             memset(cm_data.cellNameHashTablep, 0, sizeof(cm_cell_t *) * cm_data.cellHashTableSize);
530             memset(cm_data.cellIDHashTablep, 0, sizeof(cm_cell_t *) * cm_data.cellHashTableSize);
531
532 #ifdef AFS_FREELANCE_CLIENT
533             /* Generate a dummy entry for the Freelance cell whether or not
534              * freelance mode is being used in this session
535              */
536
537             cellp = &cm_data.cellBaseAddress[cm_data.currentCells++];
538             memset(cellp, 0, sizeof(cm_cell_t));
539             cellp->magic = CM_CELL_MAGIC;
540
541             lock_InitializeMutex(&cellp->mx, "cm_cell_t mutex", LOCK_HIERARCHY_CELL);
542
543             lock_ObtainMutex(&cellp->mx);
544             lock_ObtainWrite(&cm_cellLock);
545
546             /* copy in name */
547             strncpy(cellp->name, "Freelance.Local.Cell", CELL_MAXNAMELEN); /*safe*/
548             cellp->name[CELL_MAXNAMELEN-1] = '\0';
549
550             /* thread on global list */
551             cellp->allNextp = cm_data.allCellsp;
552             cm_data.allCellsp = cellp;
553
554             cellp->cellID = AFS_FAKE_ROOT_CELL_ID;
555             cellp->vlServersp = NULL;
556             _InterlockedOr(&cellp->flags, CM_CELLFLAG_FREELANCE);
557
558             cm_AddCellToNameHashTable(cellp);
559             cm_AddCellToIDHashTable(cellp);
560             lock_ReleaseWrite(&cm_cellLock);
561             lock_ReleaseMutex(&cellp->mx);
562 #endif
563         } else {
564             lock_ObtainRead(&cm_cellLock);
565             for (cellp = cm_data.allCellsp; cellp; cellp=cellp->allNextp) {
566                 lock_InitializeMutex(&cellp->mx, "cm_cell_t mutex", LOCK_HIERARCHY_CELL);
567                 cellp->vlServersp = NULL;
568                 _InterlockedOr(&cellp->flags, CM_CELLFLAG_VLSERVER_INVALID);
569             }
570             lock_ReleaseRead(&cm_cellLock);
571         }
572
573         osi_EndOnce(&once);
574     }
575 }
576
577 void cm_ChangeRankCellVLServer(cm_server_t *tsp)
578 {
579     cm_cell_t *cp;
580     int code;
581
582     cp = tsp->cellp;    /* cell that this vlserver belongs to */
583     if (cp) {
584         lock_ObtainMutex(&cp->mx);
585         code = cm_ChangeRankServer(&cp->vlServersp, tsp);
586
587         if ( !code )            /* if the server list was rearranged */
588             cm_RandomizeServer(&cp->vlServersp);
589
590         lock_ReleaseMutex(&cp->mx);
591     }
592 }
593
594 int cm_DumpCells(FILE *outputFile, char *cookie, int lock)
595 {
596     cm_cell_t *cellp;
597     int zilch;
598     char output[1024];
599
600     if (lock)
601         lock_ObtainRead(&cm_cellLock);
602
603     sprintf(output, "%s - dumping cells - cm_data.currentCells=%d, cm_data.maxCells=%d\r\n",
604             cookie, cm_data.currentCells, cm_data.maxCells);
605     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
606
607     for (cellp = cm_data.allCellsp; cellp; cellp=cellp->allNextp) {
608         sprintf(output, "%s cellp=0x%p,name=%s ID=%d flags=0x%x timeout=%I64u\r\n",
609                 cookie, cellp, cellp->name, cellp->cellID, cellp->flags, cellp->timeout);
610         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
611     }
612
613     sprintf(output, "%s - Done dumping cells.\r\n", cookie);
614     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
615
616     if (lock)
617         lock_ReleaseRead(&cm_cellLock);
618
619     return(0);
620 }
621
622 /* call with volume write-locked and mutex held */
623 void cm_AddCellToNameHashTable(cm_cell_t *cellp)
624 {
625     int i;
626
627     lock_AssertWrite(&cm_cellLock);
628     lock_AssertMutex(&cellp->mx);
629
630     if (cellp->flags & CM_CELLFLAG_IN_NAMEHASH)
631         return;
632
633     i = CM_CELL_NAME_HASH(cellp->name);
634
635     cellp->nameNextp = cm_data.cellNameHashTablep[i];
636     cm_data.cellNameHashTablep[i] = cellp;
637     _InterlockedOr(&cellp->flags, CM_CELLFLAG_IN_NAMEHASH);
638 }
639
640 /* call with cell write-locked and mutex held */
641 void cm_RemoveCellFromNameHashTable(cm_cell_t *cellp)
642 {
643     cm_cell_t **lcellpp;
644     cm_cell_t *tcellp;
645     int i;
646
647     lock_AssertWrite(&cm_cellLock);
648     lock_AssertMutex(&cellp->mx);
649
650     if (cellp->flags & CM_CELLFLAG_IN_NAMEHASH) {
651         /* hash it out first */
652         i = CM_CELL_NAME_HASH(cellp->name);
653         for (lcellpp = &cm_data.cellNameHashTablep[i], tcellp = cm_data.cellNameHashTablep[i];
654              tcellp;
655              lcellpp = &tcellp->nameNextp, tcellp = tcellp->nameNextp) {
656             if (tcellp == cellp) {
657                 *lcellpp = cellp->nameNextp;
658                 _InterlockedAnd(&cellp->flags, ~CM_CELLFLAG_IN_NAMEHASH);
659                 cellp->nameNextp = NULL;
660                 break;
661             }
662         }
663     }
664 }
665
666 /* call with cell write-locked and mutex held */
667 void cm_AddCellToIDHashTable(cm_cell_t *cellp)
668 {
669     int i;
670
671     lock_AssertWrite(&cm_cellLock);
672     lock_AssertMutex(&cellp->mx);
673
674     if (cellp->flags & CM_CELLFLAG_IN_IDHASH)
675         return;
676
677     i = CM_CELL_ID_HASH(cellp->cellID);
678
679     cellp->idNextp = cm_data.cellIDHashTablep[i];
680     cm_data.cellIDHashTablep[i] = cellp;
681     _InterlockedOr(&cellp->flags, CM_CELLFLAG_IN_IDHASH);
682 }
683
684 /* call with cell write-locked and mutex held */
685 void cm_RemoveCellFromIDHashTable(cm_cell_t *cellp)
686 {
687     cm_cell_t **lcellpp;
688     cm_cell_t *tcellp;
689     int i;
690
691     lock_AssertWrite(&cm_cellLock);
692     lock_AssertMutex(&cellp->mx);
693
694     if (cellp->flags & CM_CELLFLAG_IN_IDHASH) {
695         /* hash it out first */
696         i = CM_CELL_ID_HASH(cellp->cellID);
697         for (lcellpp = &cm_data.cellIDHashTablep[i], tcellp = cm_data.cellIDHashTablep[i];
698              tcellp;
699              lcellpp = &tcellp->idNextp, tcellp = tcellp->idNextp) {
700             if (tcellp == cellp) {
701                 *lcellpp = cellp->idNextp;
702                 _InterlockedAnd(&cellp->flags, ~CM_CELLFLAG_IN_IDHASH);
703                 cellp->idNextp = NULL;
704                 break;
705             }
706         }
707     }
708 }
709
710 long
711 cm_CreateCellWithInfo( char * cellname,
712                        char * linked_cellname,
713                        unsigned short vlport,
714                        afs_uint32 host_count,
715                        char *hostname[],
716                        afs_uint32 flags)
717 {
718     afs_uint32 code = 0;
719     cm_cell_rock_t rock;
720     struct hostent *thp;
721     struct sockaddr_in vlSockAddr;
722     afs_uint32 i, j;
723
724     rock.cellp = cm_GetCell(cellname, CM_FLAG_CREATE | CM_FLAG_NOPROBE);
725     rock.flags = 0;
726
727     cm_FreeServerList(&rock.cellp->vlServersp, CM_FREESERVERLIST_DELETE);
728
729     if (!(flags & CM_CELLFLAG_DNS)) {
730         for (i = 0; i < host_count; i++) {
731             thp = gethostbyname(hostname[i]);
732             if (thp) {
733                 int foundAddr = 0;
734                 for (j=0 ; thp->h_addr_list[j]; j++) {
735                     if (thp->h_addrtype != AF_INET)
736                         continue;
737                     memcpy(&vlSockAddr.sin_addr.s_addr,
738                            thp->h_addr_list[j],
739                            sizeof(long));
740                     vlSockAddr.sin_port = htons(vlport ? vlport : 7003);
741                     vlSockAddr.sin_family = AF_INET;
742                     cm_AddCellProc(&rock, &vlSockAddr, hostname[i], CM_FLAG_NOPROBE);
743                 }
744             }
745         }
746         lock_ObtainMutex(&rock.cellp->mx);
747         _InterlockedAnd(&rock.cellp->flags, ~CM_CELLFLAG_DNS);
748     } else if (cm_dnsEnabled) {
749         int ttl;
750
751         code = cm_SearchCellByDNS(rock.cellp->name, NULL, &ttl, cm_AddCellProc, &rock);
752         lock_ObtainMutex(&rock.cellp->mx);
753         if (code == 0) {   /* got cell from DNS */
754             _InterlockedOr(&rock.cellp->flags, CM_CELLFLAG_DNS);
755             rock.cellp->timeout = time(0) + ttl;
756 #ifdef DEBUG
757             fprintf(stderr, "cell %s: ttl=%d\n", rock.cellp->name, ttl);
758 #endif
759         }
760     } else {
761         lock_ObtainMutex(&rock.cellp->mx);
762         rock.cellp->flags &= ~CM_CELLFLAG_DNS;
763     }
764     _InterlockedOr(&rock.cellp->flags, CM_CELLFLAG_VLSERVER_INVALID);
765     StringCbCopy(rock.cellp->linkedName, CELL_MAXNAMELEN, linked_cellname);
766     lock_ReleaseMutex(&rock.cellp->mx);
767
768     if (rock.cellp->vlServersp)
769         cm_RandomizeServer(&rock.cellp->vlServersp);
770
771     return code;
772 }