windows-windows-pipes-20080210
[openafs.git] / src / vol / fssync-server.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  * Portions Copyright (c) 2006-2008 Sine Nomine Associates
10  */
11
12 /*
13         System:         VICE-TWO
14         Module:         fssync.c
15         Institution:    The Information Technology Center, Carnegie-Mellon University
16
17  */
18 #ifdef notdef
19
20 /* All this is going away in early 1989 */
21 int newVLDB;                    /* Compatibility flag */
22
23 #endif
24 static int newVLDB = 1;
25
26
27 #ifndef AFS_PTHREAD_ENV
28 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
29
30 /*
31  * stack size increased from 8K because the HP machine seemed to have trouble
32  * with the smaller stack
33  */
34 #define USUAL_STACK_SIZE        (24 * 1024)
35 #endif /* !AFS_PTHREAD_ENV */
36
37 /*
38    fssync-server.c
39    File server synchronization with external volume utilities.
40    server-side implementation
41  */
42
43 /* This controls the size of an fd_set; it must be defined early before
44  * the system headers define that type and the macros that operate on it.
45  * Its value should be as large as the maximum file descriptor limit we
46  * are likely to run into on any platform.  Right now, that is 65536
47  * which is the default hard fd limit on Solaris 9 */
48 #ifndef _WIN32
49 #define FD_SETSIZE 65536
50 #endif
51
52 #include <afsconfig.h>
53 #include <afs/param.h>
54
55 RCSID
56     ("$Header$");
57
58 #include <sys/types.h>
59 #include <stdio.h>
60 #ifdef AFS_NT40_ENV
61 #include <winsock2.h>
62 #include <time.h>
63 #else
64 #include <sys/param.h>
65 #include <sys/socket.h>
66 #include <netinet/in.h>
67 #include <netdb.h>
68 #include <sys/time.h>
69 #endif
70 #include <errno.h>
71 #ifdef AFS_PTHREAD_ENV
72 #include <assert.h>
73 #else /* AFS_PTHREAD_ENV */
74 #include <afs/assert.h>
75 #endif /* AFS_PTHREAD_ENV */
76 #include <signal.h>
77 #include <string.h>
78
79 #include <rx/xdr.h>
80 #include <afs/afsint.h>
81 #include "nfs.h"
82 #include <afs/errors.h>
83 #include "daemon_com.h"
84 #include "fssync.h"
85 #include "lwp.h"
86 #include "lock.h"
87 #include <afs/afssyscalls.h>
88 #include "ihandle.h"
89 #include "vnode.h"
90 #include "volume.h"
91 #include "volume_inline.h"
92 #include "partition.h"
93
94 #ifdef HAVE_POLL
95 #include <sys/poll.h>
96 #endif /* HAVE_POLL */
97
98 #ifdef USE_UNIX_SOCKETS
99 #include <sys/un.h>
100 #include <afs/afsutil.h>
101 #endif /* USE_UNIX_SOCKETS */
102
103 #ifdef FSSYNC_BUILD_SERVER
104
105 /*@printflike@*/ extern void Log(const char *format, ...);
106
107 #ifdef osi_Assert
108 #undef osi_Assert
109 #endif
110 #define osi_Assert(e) (void)(e)
111
112 int (*V_BreakVolumeCallbacks) ();
113
114 #define MAXHANDLERS     4       /* Up to 4 clients; must be at least 2, so that
115                                  * move = dump+restore can run on single server */
116 #define MAXOFFLINEVOLUMES 128   /* This needs to be as big as the maximum
117                                  * number that would be offline for 1 operation.
118                                  * Current winner is salvage, which needs all
119                                  * cloned read-only copies offline when salvaging
120                                  * a single read-write volume */
121
122
123
124 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
125
126 /**
127  * fssync server socket handle.
128  */
129 static SYNC_server_state_t fssync_server_state = 
130     { -1,                       /* file descriptor */
131       FSSYNC_ENDPOINT_DECL,     /* server endpoint */
132       FSYNC_PROTO_VERSION,      /* protocol version */
133       5,                        /* bind() retry limit */
134       100,                      /* listen() queue depth */
135       "FSSYNC",                 /* protocol name string */
136     };
137
138
139 /* Forward declarations */
140 static void * FSYNC_sync(void *);
141 static void FSYNC_newconnection();
142 static void FSYNC_com();
143 static void FSYNC_Drop();
144 static void AcceptOn();
145 static void AcceptOff();
146 static void InitHandler();
147 static int AddHandler();
148 static int FindHandler();
149 static int FindHandler_r();
150 static int RemoveHandler();
151 #if defined(HAVE_POLL) && defined (AFS_PTHREAD_ENV)
152 static void CallHandler(struct pollfd *fds, int nfds, int mask);
153 static void GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds);
154 #else
155 static void CallHandler(fd_set * fdsetp);
156 static void GetHandler(fd_set * fdsetp, int *maxfdp);
157 #endif
158 extern int LogLevel;
159
160 static afs_int32 FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res);
161
162 static afs_int32 FSYNC_com_VolError(FSSYNC_VolOp_command * com, SYNC_response * res);
163 static afs_int32 FSYNC_com_VolOn(FSSYNC_VolOp_command * com, SYNC_response * res);
164 static afs_int32 FSYNC_com_VolOff(FSSYNC_VolOp_command * com, SYNC_response * res);
165 static afs_int32 FSYNC_com_VolMove(FSSYNC_VolOp_command * com, SYNC_response * res);
166 static afs_int32 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * com, SYNC_response * res);
167 static afs_int32 FSYNC_com_VolDone(FSSYNC_VolOp_command * com, SYNC_response * res);
168 static afs_int32 FSYNC_com_VolQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
169 static afs_int32 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
170 #ifdef AFS_DEMAND_ATTACH_FS
171 static afs_int32 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
172 #endif /* AFS_DEMAND_ATTACH_FS */
173
174 static afs_int32 FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res);
175
176 static afs_int32 FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res);
177
178 static afs_int32 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res);
179 static afs_int32 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res);
180 static afs_int32 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res);
181 static afs_int32 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res);
182 static afs_int32 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res);
183
184
185 static void FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info);
186
187
188 /*
189  * This lock controls access to the handler array. The overhead
190  * is minimal in non-preemptive environments.
191  */
192 struct Lock FSYNC_handler_lock;
193
194 void
195 FSYNC_fsInit(void)
196 {
197 #ifdef AFS_PTHREAD_ENV
198     pthread_t tid;
199     pthread_attr_t tattr;
200 #else /* AFS_PTHREAD_ENV */
201     PROCESS pid;
202 #endif /* AFS_PTHREAD_ENV */
203
204     Lock_Init(&FSYNC_handler_lock);
205
206 #ifdef AFS_PTHREAD_ENV
207     assert(pthread_attr_init(&tattr) == 0);
208     assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
209     assert(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
210 #else /* AFS_PTHREAD_ENV */
211     assert(LWP_CreateProcess
212            (FSYNC_sync, USUAL_STACK_SIZE, USUAL_PRIORITY, (void *)0,
213             "FSYNC_sync", &pid) == LWP_SUCCESS);
214 #endif /* AFS_PTHREAD_ENV */
215 }
216
217 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
218 static struct pollfd FSYNC_readfds[MAXHANDLERS];
219 #else
220 static fd_set FSYNC_readfds;
221 #endif
222
223
224 static void *
225 FSYNC_sync(void * args)
226 {
227 #ifdef USE_UNIX_SOCKETS
228     char tbuffer[AFSDIR_PATH_MAX];
229 #endif /* USE_UNIX_SOCKETS */
230     int on = 1;
231     extern int VInit;
232     int code;
233     int numTries;
234 #ifdef AFS_PTHREAD_ENV
235     int tid;
236 #endif
237     SYNC_server_state_t * state = &fssync_server_state;
238
239     SYNC_getAddr(&state->endpoint, &state->addr);
240     SYNC_cleanupSock(state);
241
242 #ifndef AFS_NT40_ENV
243     (void)signal(SIGPIPE, SIG_IGN);
244 #endif
245
246 #ifdef AFS_PTHREAD_ENV
247     /* set our 'thread-id' so that the host hold table works */
248     MUTEX_ENTER(&rx_stats_mutex);       /* protects rxi_pthread_hinum */
249     tid = ++rxi_pthread_hinum;
250     MUTEX_EXIT(&rx_stats_mutex);
251     pthread_setspecific(rx_thread_id_key, (void *)tid);
252     Log("Set thread id %d for FSYNC_sync\n", tid);
253 #endif /* AFS_PTHREAD_ENV */
254
255     while (!VInit) {
256         /* Let somebody else run until level > 0.  That doesn't mean that 
257          * all volumes have been attached. */
258 #ifdef AFS_PTHREAD_ENV
259         pthread_yield();
260 #else /* AFS_PTHREAD_ENV */
261         LWP_DispatchProcess();
262 #endif /* AFS_PTHREAD_ENV */
263     }
264
265     state->fd = SYNC_getSock(&state->endpoint);
266     code = SYNC_bindSock(state);
267     assert(!code);
268
269     InitHandler();
270     AcceptOn();
271
272     for (;;) {
273 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
274         int nfds;
275         GetHandler(FSYNC_readfds, MAXHANDLERS, POLLIN|POLLPRI, &nfds);
276         if (poll(FSYNC_readfds, nfds, -1) >=1)
277             CallHandler(FSYNC_readfds, nfds, POLLIN|POLLPRI);
278 #else
279         int maxfd;
280         GetHandler(&FSYNC_readfds, &maxfd);
281         /* Note: check for >= 1 below is essential since IOMGR_select
282          * doesn't have exactly same semantics as select.
283          */
284 #ifdef AFS_PTHREAD_ENV
285         if (select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
286 #else /* AFS_PTHREAD_ENV */
287         if (IOMGR_Select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
288 #endif /* AFS_PTHREAD_ENV */
289             CallHandler(&FSYNC_readfds);
290 #endif
291     }
292 }
293
294 static void
295 FSYNC_newconnection(int afd)
296 {
297 #ifdef USE_UNIX_SOCKETS
298     struct sockaddr_un other;
299 #else  /* USE_UNIX_SOCKETS */
300     struct sockaddr_in other;
301 #endif
302     int junk, fd;
303     junk = sizeof(other);
304     fd = accept(afd, (struct sockaddr *)&other, &junk);
305     if (fd == -1) {
306         Log("FSYNC_newconnection:  accept failed, errno==%d\n", errno);
307         assert(1 == 2);
308     } else if (!AddHandler(fd, FSYNC_com)) {
309         AcceptOff();
310         assert(AddHandler(fd, FSYNC_com));
311     }
312 }
313
314 /* this function processes commands from an fssync file descriptor (fd) */
315 afs_int32 FS_cnt = 0;
316 static void
317 FSYNC_com(int fd)
318 {
319     SYNC_command com;
320     SYNC_response res;
321     SYNC_PROTO_BUF_DECL(com_buf);
322     SYNC_PROTO_BUF_DECL(res_buf);
323
324     memset(&res.hdr, 0, sizeof(res.hdr));
325
326     com.payload.buf = (void *)com_buf;
327     com.payload.len = SYNC_PROTO_MAX_LEN;
328     res.hdr.response_len = sizeof(res.hdr);
329     res.hdr.proto_version = FSYNC_PROTO_VERSION;
330     res.payload.len = SYNC_PROTO_MAX_LEN;
331     res.payload.buf = (void *)res_buf;
332
333     FS_cnt++;
334     if (SYNC_getCom(fd, &com)) {
335         Log("FSYNC_com:  read failed; dropping connection (cnt=%d)\n", FS_cnt);
336         FSYNC_Drop(fd);
337         return;
338     }
339
340     if (com.recv_len < sizeof(com.hdr)) {
341         Log("FSSYNC_com:  invalid protocol message length (%u)\n", com.recv_len);
342         res.hdr.response = SYNC_COM_ERROR;
343         res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
344         res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
345         goto respond;
346     }
347
348     if (com.hdr.proto_version != FSYNC_PROTO_VERSION) {
349         Log("FSYNC_com:  invalid protocol version (%u)\n", com.hdr.proto_version);
350         res.hdr.response = SYNC_COM_ERROR;
351         res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
352         goto respond;
353     }
354
355     if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
356         res.hdr.response = SYNC_OK;
357         res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
358         goto respond;
359     }
360
361
362     VOL_LOCK;
363     switch (com.hdr.command) {
364     case FSYNC_VOL_ON:
365     case FSYNC_VOL_ATTACH:
366     case FSYNC_VOL_LEAVE_OFF:
367     case FSYNC_VOL_OFF:
368     case FSYNC_VOL_FORCE_ERROR:
369     case FSYNC_VOL_LISTVOLUMES:
370     case FSYNC_VOL_NEEDVOLUME:
371     case FSYNC_VOL_MOVE:
372     case FSYNC_VOL_BREAKCBKS:
373     case FSYNC_VOL_DONE:
374     case FSYNC_VOL_QUERY:
375     case FSYNC_VOL_QUERY_HDR:
376     case FSYNC_VOL_QUERY_VOP:
377         res.hdr.response = FSYNC_com_VolOp(fd, &com, &res);
378         break;
379     case FSYNC_VOL_STATS_GENERAL:
380     case FSYNC_VOL_STATS_VICEP:
381     case FSYNC_VOL_STATS_HASH:
382     case FSYNC_VOL_STATS_HDR:
383     case FSYNC_VOL_STATS_VLRU:
384         res.hdr.response = FSYNC_com_StatsOp(fd, &com, &res);
385         break;
386     case FSYNC_VOL_QUERY_VNODE:
387         res.hdr.response = FSYNC_com_VnQry(fd, &com, &res);
388         break;
389     default:
390         res.hdr.response = SYNC_BAD_COMMAND;
391         break;
392     }
393     VOL_UNLOCK;
394
395  respond:
396     SYNC_putRes(fd, &res);
397     if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
398         FSYNC_Drop(fd);
399     }
400 }
401
402 static afs_int32
403 FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
404 {
405     int i;
406     afs_int32 code = SYNC_OK;
407     FSSYNC_VolOp_command vcom;
408
409     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VolOp_hdr))) {
410         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
411         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
412         return SYNC_COM_ERROR;
413     }
414
415     vcom.hdr = &com->hdr;
416     vcom.vop = (FSSYNC_VolOp_hdr *) com->payload.buf;
417     vcom.com = com;
418
419     vcom.volumes = OfflineVolumes[FindHandler(fd)];
420     for (vcom.v = NULL, i = 0; i < MAXOFFLINEVOLUMES; i++) {
421         if ((vcom.volumes[i].volumeID == vcom.vop->volume) &&
422             (strncmp(vcom.volumes[i].partName, vcom.vop->partName,
423                      sizeof(vcom.volumes[i].partName)) == 0)) {
424             vcom.v = &vcom.volumes[i];
425             break;
426         }
427     }
428
429     switch (com->hdr.command) {
430     case FSYNC_VOL_ON:
431     case FSYNC_VOL_ATTACH:
432     case FSYNC_VOL_LEAVE_OFF:
433         code = FSYNC_com_VolOn(&vcom, res);
434         break;
435     case FSYNC_VOL_OFF:
436     case FSYNC_VOL_NEEDVOLUME:
437         code = FSYNC_com_VolOff(&vcom, res);
438         break;
439     case FSYNC_VOL_LISTVOLUMES:
440         code = SYNC_OK;
441         break;
442     case FSYNC_VOL_MOVE:
443         code = FSYNC_com_VolMove(&vcom, res);
444         break;
445     case FSYNC_VOL_BREAKCBKS:
446         code = FSYNC_com_VolBreakCBKs(&vcom, res);
447         break;
448     case FSYNC_VOL_DONE:
449         code = FSYNC_com_VolDone(&vcom, res);
450         break;
451     case FSYNC_VOL_QUERY:
452         code = FSYNC_com_VolQuery(&vcom, res);
453         break;
454     case FSYNC_VOL_QUERY_HDR:
455         code = FSYNC_com_VolHdrQuery(&vcom, res);
456         break;
457 #ifdef AFS_DEMAND_ATTACH_FS
458     case FSYNC_VOL_FORCE_ERROR:
459         code = FSYNC_com_VolError(&vcom, res);
460         break;
461     case FSYNC_VOL_QUERY_VOP:
462         code = FSYNC_com_VolOpQuery(&vcom, res);
463         break;
464 #endif /* AFS_DEMAND_ATTACH_FS */
465     default:
466         code = SYNC_BAD_COMMAND;
467     }
468
469     return code;
470 }
471
472 static afs_int32
473 FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
474 {
475     afs_int32 code = SYNC_OK;
476     char tvolName[VMAXPATHLEN];
477     Volume * vp;
478     Error error;
479
480     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
481         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
482         code = SYNC_FAILED;
483         goto done;
484     }
485
486     /*
487       This is where a detatched volume gets reattached. However in the
488       special case where the volume is merely busy, it is already
489       attatched and it is only necessary to clear the busy flag. See
490       defect #2080 for details.
491     */
492
493     /* is the volume already attatched? */
494 #ifdef  notdef
495     /*
496      * XXX With the following enabled we had bizarre problems where the backup id would
497      * be reset to 0; that was due to the interaction between fileserver/volserver in that they
498      * both keep volumes in memory and the changes wouldn't be made to the fileserver. Some of
499      * the problems were due to refcnt changes as result of VGetVolume/VPutVolume which would call
500      * VOffline, etc. when we don't want to; someday the whole #2080 issue should be revisited to
501      * be done right XXX
502      */
503     vp = VGetVolume_r(&error, vcom->vop->volume);
504     if (vp) {
505         /* yep, is the BUSY flag set? */
506         if (vp->specialStatus == VBUSY) {
507
508             /* yep, clear BUSY flag */
509
510             vp->specialStatus = 0;
511             /* make sure vol is online */
512             if (vcom->v) {
513                 vcom->v->volumeID = 0;
514                 V_inUse(vp) = 1;        /* online */
515             }
516             VPutVolume_r(vp);
517             break;
518         }
519         VPutVolume_r(vp);
520     }
521 #endif /* notdef */
522
523     /* so, we need to attach the volume */
524
525 #ifdef AFS_DEMAND_ATTACH_FS
526     /* check DAFS permissions */
527     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
528     if (vp && !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName) &&
529         vp->pending_vol_op && 
530         (vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
531         /* a different program has this volume checked out. deny. */
532         Log("FSYNC_VolOn: WARNING: program type %u has attempted to manipulate "
533             "state for volume %u using command code %u while the volume is " 
534             "checked out by program type %u for command code %u.\n",
535             vcom->hdr->programType,
536             vcom->vop->volume,
537             vcom->hdr->command,
538             vp->pending_vol_op->com.programType,
539             vp->pending_vol_op->com.command);
540         code = SYNC_DENIED;
541         res->hdr.reason = FSYNC_EXCLUSIVE;
542         goto done;
543     }
544 #endif
545
546     if (vcom->v)
547         vcom->v->volumeID = 0;
548
549
550     if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
551         /* nothing much to do if we're leaving the volume offline */
552 #ifdef AFS_DEMAND_ATTACH_FS
553         if (vp &&
554             !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName)) {
555             VDeregisterVolOp_r(vp);
556             VChangeState_r(vp, VOL_STATE_UNATTACHED);
557         }
558 #endif
559         goto done;
560     }
561
562 #ifdef AFS_DEMAND_ATTACH_FS
563     /* first, check to see whether we have such a volume defined */
564     vp = VPreAttachVolumeById_r(&error,
565                                 vcom->vop->partName,
566                                 vcom->vop->volume);
567     if (vp) {
568         VDeregisterVolOp_r(vp);
569     }
570 #else /* !AFS_DEMAND_ATTACH_FS */
571     tvolName[0] = '/';
572     snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, vcom->vop->volume);
573     tvolName[sizeof(tvolName)-1] = '\0';
574
575     vp = VAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
576                                V_VOLUPD);
577     if (vp)
578         VPutVolume_r(vp);
579     if (error) {
580         code = SYNC_DENIED;
581         res->hdr.reason = error;
582     }
583 #endif /* !AFS_DEMAND_ATTACH_FS */
584
585  done:
586     return code;
587 }
588
589 static afs_int32
590 FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
591 {
592     FSSYNC_VolOp_info info;
593     afs_int32 code = SYNC_OK;
594     int i;
595     Volume * vp, * nvp;
596     Error error;
597
598     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
599         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
600         code = SYNC_FAILED;
601         goto done;
602     }
603
604     /* not already offline, we need to find a slot for newly offline volume */
605     if (vcom->hdr->programType == debugUtility) {
606         /* debug utilities do not have their operations tracked */
607         vcom->v = NULL;
608     } else {
609         if (!vcom->v) {
610             for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
611                 if (vcom->volumes[i].volumeID == 0) {
612                     vcom->v = &vcom->volumes[i];
613                     break;
614                 }
615             }
616         }
617         if (!vcom->v) {
618             goto deny;
619         }
620     }
621
622     FSYNC_com_to_info(vcom, &info);
623
624 #ifdef AFS_DEMAND_ATTACH_FS
625     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
626 #else
627     vp = VGetVolume_r(&error, vcom->vop->volume);
628 #endif
629
630     if (vp) {
631         if ((vcom->vop->partName[0] != 0) &&
632             (strncmp(vcom->vop->partName, vp->partition->name, 
633                     sizeof(vcom->vop->partName)) != 0)) {
634             /* volume on desired partition is not online, so we
635              * should treat this as an offline volume.
636              */
637 #ifndef AFS_DEMAND_ATTACH_FS
638             VPutVolume_r(vp);
639 #endif
640             vp = NULL;
641             goto done;
642         }
643     }
644
645 #ifdef AFS_DEMAND_ATTACH_FS
646     if (vp) {
647         ProgramType type = (ProgramType) vcom->hdr->programType;
648
649         /* do initial filtering of requests */
650
651         /* enforce mutual exclusion for volume ops */
652         if (vp->pending_vol_op) {
653             if (vp->pending_vol_op->com.programType != type) {
654                 Log("volume %u already checked out\n", vp->hashid);
655                 /* XXX debug */
656                 Log("vp->vop = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x }, vop = { vol=%u, part='%s' } }\n",
657                     vp->pending_vol_op->com.proto_version, 
658                     vp->pending_vol_op->com.programType,
659                     vp->pending_vol_op->com.command,
660                     vp->pending_vol_op->com.reason,
661                     vp->pending_vol_op->com.command_len,
662                     vp->pending_vol_op->com.flags,
663                     vp->pending_vol_op->vop.volume,
664                     vp->pending_vol_op->vop.partName );
665                 Log("vcom = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x } , vop = { vol=%u, part='%s' } }\n",
666                     vcom->hdr->proto_version,
667                     vcom->hdr->programType,
668                     vcom->hdr->command,
669                     vcom->hdr->reason,
670                     vcom->hdr->command_len,
671                     vcom->hdr->flags,
672                     vcom->vop->volume,
673                     vcom->vop->partName);
674                 res->hdr.reason = FSYNC_EXCLUSIVE;
675                 goto deny;
676             } else {
677                 Log("warning: volume %u recursively checked out by programType id %d\n",
678                     vp->hashid, vcom->hdr->programType);
679             }
680         }
681
682         /* filter based upon requestor
683          *
684          * volume utilities are not allowed to check out volumes
685          * which are in an error state
686          *
687          * unknown utility programs will be denied on principal
688          */
689         switch (type) {
690         case salvageServer:
691         case debugUtility:
692             /* give the salvageserver lots of liberty */
693             break;
694         case volumeUtility:
695             if ((V_attachState(vp) == VOL_STATE_ERROR) ||
696                 (V_attachState(vp) == VOL_STATE_SALVAGING)) {
697                 goto deny;
698             }
699             break;
700         default:
701             Log("bad program type passed to FSSYNC\n");
702             goto deny;
703         }
704
705         /* short circuit for offline volume states
706          * so we can avoid I/O penalty of attachment */
707         switch (V_attachState(vp)) {
708         case VOL_STATE_UNATTACHED:
709         case VOL_STATE_PREATTACHED:
710         case VOL_STATE_SALVAGING:
711         case VOL_STATE_ERROR:
712             /* register the volume operation metadata with the volume
713              *
714              * if the volume is currently pre-attached, attach2()
715              * will evaluate the vol op metadata to determine whether
716              * attaching the volume would be safe */
717             VRegisterVolOp_r(vp, &info);
718             goto done;
719         default:
720             break;
721         }
722
723         /* convert to heavyweight ref */
724         nvp = VGetVolumeByVp_r(&error, vp);
725
726         /* register the volume operation metadata with the volume */
727         VRegisterVolOp_r(vp, &info);
728
729         if (!nvp) {
730             Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
731                 vcom->vop->volume);
732             res->hdr.reason = FSYNC_VOL_PKG_ERROR;
733             goto deny;
734         }
735         vp = nvp;
736     }
737 #endif /* AFS_DEMAND_ATTACH_FS */
738
739     if (vp) {
740         if (VVolOpLeaveOnline_r(vp, &info)) {
741             VUpdateVolume_r(&error, vp, VOL_UPDATE_WAIT);       /* At least get volume stats right */
742             if (LogLevel) {
743                 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n", 
744                     V_id(vp), V_name(vp), 
745                     vcom->hdr->reason == V_CLONE ? "clone" : 
746                     vcom->hdr->reason == V_READONLY ? "readonly" : 
747                     vcom->hdr->reason == V_DUMP ? "dump" : 
748                     "UNKNOWN");
749             }
750             VPutVolume_r(vp);
751         } else {
752             if (VVolOpSetVBusy_r(vp, &info)) {
753                 vp->specialStatus = VBUSY;
754             }
755
756             /* remember what volume we got, so we can keep track of how
757              * many volumes the volserver or whatever is using.  Note that
758              * vp is valid since leaveonline is only set when vp is valid.
759              */
760             if (vcom->v) {
761                 vcom->v->volumeID = vcom->vop->volume;
762                 strlcpy(vcom->v->partName, vp->partition->name, sizeof(vcom->v->partName));
763             }
764
765             VOffline_r(vp, "A volume utility is running.");
766             vp = NULL;
767         }
768     }
769
770  done:
771     return code;
772
773  deny:
774     return SYNC_DENIED;
775 }
776
777 static afs_int32
778 FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
779 {
780     Error error;
781     Volume * vp;
782
783     /* Yuch:  the "reason" for the move is the site it got moved to... */
784     /* still set specialStatus so we stop sending back VBUSY.
785      * also should still break callbacks.  Note that I don't know
786      * how to tell if we should break all or not, so we just do it
787      * since it doesn't matter much if we do an extra break
788      * volume callbacks on a volume move within the same server */
789 #ifdef AFS_DEMAND_ATTACH_FS
790     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
791 #else
792     vp = VGetVolume_r(&error, vcom->vop->volume);
793 #endif
794     if (vp) {
795         vp->specialStatus = VMOVED;
796 #ifndef AFS_DEMAND_ATTACH_FS
797         VPutVolume_r(vp);
798 #endif
799     }
800
801     if (V_BreakVolumeCallbacks) {
802         Log("fssync: volume %u moved to %x; breaking all call backs\n",
803             vcom->vop->volume, vcom->hdr->reason);
804         VOL_UNLOCK;
805         (*V_BreakVolumeCallbacks) (vcom->vop->volume);
806         VOL_LOCK;
807     }
808
809     return SYNC_OK;
810 }
811
812 static afs_int32
813 FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
814 {
815 #ifdef AFS_DEMAND_ATTACH_FS
816     Error error;
817     Volume * vp;
818 #endif
819
820     /* don't try to put online, this call is made only after deleting
821      * a volume, in which case we want to remove the vol # from the
822      * OfflineVolumes array only */
823     if (vcom->v)
824         vcom->v->volumeID = 0;
825
826 #ifdef AFS_DEMAND_ATTACH_FS
827     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
828     if (vp) {
829         VDeregisterVolOp_r(vp);
830     }
831 #endif
832
833     return SYNC_OK;
834 }
835
836 #ifdef AFS_DEMAND_ATTACH_FS
837 /**
838  * force a volume into the hard error state.
839  */
840 static afs_int32
841 FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
842 {
843     Error error;
844     Volume * vp;
845     afs_int32 code = SYNC_DENIED;
846
847     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
848     if (vp && !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName)) {
849         memset(&vp->salvage, 0, sizeof(vp->salvage));
850         VChangeState_r(vp, VOL_STATE_ERROR);
851         code = SYNC_OK;
852     } else {
853         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
854     }
855         
856     return code;
857 }
858 #endif
859
860 static afs_int32
861 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
862 {
863     /* if the volume is being restored, break all callbacks on it */
864     if (V_BreakVolumeCallbacks) {
865         Log("fssync: breaking all call backs for volume %u\n",
866             vcom->vop->volume);
867         VOL_UNLOCK;
868         (*V_BreakVolumeCallbacks) (vcom->vop->volume);
869         VOL_LOCK;
870     }
871     return SYNC_OK;
872 }
873
874 static afs_int32
875 FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
876 {
877     afs_int32 code = SYNC_OK;
878     Error error;
879     Volume * vp;
880
881 #ifdef AFS_DEMAND_ATTACH_FS
882     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
883 #else /* !AFS_DEMAND_ATTACH_FS */
884     vp = VGetVolume_r(&error, vcom->vop->volume);
885 #endif /* !AFS_DEMAND_ATTACH_FS */
886
887     if (vp) {
888         assert(sizeof(Volume) <= res->payload.len);
889         memcpy(res->payload.buf, vp, sizeof(Volume));
890         res->hdr.response_len += sizeof(Volume);
891 #ifndef AFS_DEMAND_ATTACH_FS
892         VPutVolume_r(vp);
893 #endif
894     } else {
895         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
896         code = SYNC_FAILED;
897     }
898     return code;
899 }
900
901 static afs_int32
902 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
903 {
904     afs_int32 code = SYNC_OK;
905     Error error;
906     Volume * vp;
907     int hdr_ok = 0;
908
909 #ifdef AFS_DEMAND_ATTACH_FS
910     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
911     if (vp &&
912         (vp->header != NULL) &&
913         (V_attachFlags(vp) & VOL_HDR_ATTACHED) &&
914         (V_attachFlags(vp) & VOL_HDR_LOADED)) {
915         hdr_ok = 1;
916     }
917 #else /* !AFS_DEMAND_ATTACH_FS */
918     vp = VGetVolume_r(&error, vcom->vop->volume);
919     if (vp && vp->header) {
920         hdr_ok = 1;
921     }
922 #endif /* !AFS_DEMAND_ATTACH_FS */
923
924  load_done:
925     if (hdr_ok) {
926         assert(sizeof(VolumeDiskData) <= res->payload.len);
927         memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
928         res->hdr.response_len += sizeof(VolumeDiskData);
929 #ifndef AFS_DEMAND_ATTACH_FS
930         VPutVolume_r(vp);
931 #endif
932     } else {
933         if (vp) {
934             res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
935         } else {
936             res->hdr.reason = FSYNC_UNKNOWN_VOLID;
937         }
938         code = SYNC_FAILED;
939     }
940     return code;
941 }
942
943 #ifdef AFS_DEMAND_ATTACH_FS
944 static afs_int32
945 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
946 {
947     afs_int32 code = SYNC_OK;
948     Error error;
949     Volume * vp;
950
951     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
952
953     if (vp && vp->pending_vol_op) {
954         assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
955         memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
956         res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
957     } else {
958         if (vp) {
959             res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
960         } else {
961             res->hdr.reason = FSYNC_UNKNOWN_VOLID;
962         }
963         code = SYNC_FAILED;
964     }
965     return code;
966 }
967 #endif /* AFS_DEMAND_ATTACH_FS */
968
969 static afs_int32
970 FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res)
971 {
972     afs_int32 code = SYNC_OK;
973     FSSYNC_VnQry_hdr * qry = com->payload.buf;
974     Volume * vp;
975     Vnode * vnp;
976     Error error;
977
978     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
979         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
980         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
981         return SYNC_COM_ERROR;
982     }
983
984 #ifdef AFS_DEMAND_ATTACH_FS
985     vp = VLookupVolume_r(&error, qry->volume, NULL);
986 #else /* !AFS_DEMAND_ATTACH_FS */
987     vp = VGetVolume_r(&error, qry->volume);
988 #endif /* !AFS_DEMAND_ATTACH_FS */
989
990     if (!vp) {
991         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
992         code = SYNC_FAILED;
993         goto done;
994     }
995
996     vnp = VLookupVnode(vp, qry->vnode);
997     if (!vnp) {
998         res->hdr.reason = FSYNC_UNKNOWN_VNID;
999         code = SYNC_FAILED;
1000         goto cleanup;
1001     }
1002
1003     if (Vn_class(vnp)->residentSize > res->payload.len) {
1004         res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
1005         code = SYNC_FAILED;
1006         goto cleanup;
1007     }
1008
1009     memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
1010     res->hdr.response_len += Vn_class(vnp)->residentSize;
1011
1012  cleanup:
1013 #ifndef AFS_DEMAND_ATTACH_FS
1014     VPutVolume_r(vp);
1015 #endif
1016
1017  done:
1018     return code;
1019 }
1020
1021 static afs_int32
1022 FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res)
1023 {
1024     afs_int32 code = SYNC_OK;
1025     FSSYNC_StatsOp_command scom;
1026
1027     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_StatsOp_hdr))) {
1028         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1029         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1030         return SYNC_COM_ERROR;
1031     }
1032
1033     scom.hdr = &com->hdr;
1034     scom.sop = (FSSYNC_StatsOp_hdr *) com->payload.buf;
1035     scom.com = com;
1036
1037     switch (com->hdr.command) {
1038     case FSYNC_VOL_STATS_GENERAL:
1039         code = FSYNC_com_StatsOpGeneral(&scom, res);
1040         break;
1041 #ifdef AFS_DEMAND_ATTACH_FS
1042         /* statistics for the following subsystems are only tracked
1043          * for demand attach fileservers */
1044     case FSYNC_VOL_STATS_VICEP:
1045         code = FSYNC_com_StatsOpViceP(&scom, res);
1046         break;
1047     case FSYNC_VOL_STATS_HASH:
1048         code = FSYNC_com_StatsOpHash(&scom, res);
1049         break;
1050     case FSYNC_VOL_STATS_HDR:
1051         code = FSYNC_com_StatsOpHdr(&scom, res);
1052         break;
1053     case FSYNC_VOL_STATS_VLRU:
1054         code = FSYNC_com_StatsOpVLRU(&scom, res);
1055         break;
1056 #endif /* AFS_DEMAND_ATTACH_FS */
1057     default:
1058         code = SYNC_BAD_COMMAND;
1059     }
1060
1061     return code;
1062 }
1063
1064 static afs_int32
1065 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1066 {
1067     afs_int32 code = SYNC_OK;
1068
1069     memcpy(res->payload.buf, &VStats, sizeof(VStats));
1070     res->hdr.response_len += sizeof(VStats);
1071
1072     return code;
1073 }
1074
1075 #ifdef AFS_DEMAND_ATTACH_FS
1076 static afs_int32
1077 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1078 {
1079     afs_int32 code = SYNC_OK;
1080     struct DiskPartition * dp;
1081     struct DiskPartitionStats * stats;
1082
1083     if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
1084         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1085         code = SYNC_FAILED;
1086         goto done;
1087     }
1088
1089     dp = VGetPartition_r(scom->sop->args.partName, 0);
1090     if (!dp) {
1091         code = SYNC_FAILED;
1092     } else {
1093         stats = (struct DiskPartitionStats *) res->payload.buf;
1094         stats->free = dp->free;
1095         stats->totalUsable = dp->totalUsable;
1096         stats->minFree = dp->minFree;
1097         stats->f_files = dp->f_files;
1098         stats->vol_list_len = dp->vol_list.len;
1099         
1100         res->hdr.response_len += sizeof(struct DiskPartitionStats);
1101     }
1102
1103  done:
1104     return code;
1105 }
1106
1107 static afs_int32
1108 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1109 {
1110     afs_int32 code = SYNC_OK;
1111     struct VolumeHashChainStats * stats;
1112     struct VolumeHashChainHead * head;
1113
1114     if (scom->sop->args.hash_bucket >= VolumeHashTable.Size) {
1115         return SYNC_FAILED;
1116     }
1117
1118     head = &VolumeHashTable.Table[scom->sop->args.hash_bucket];
1119     stats = (struct VolumeHashChainStats *) res->payload.buf;
1120     stats->table_size = VolumeHashTable.Size;
1121     stats->chain_len = head->len;
1122     stats->chain_cacheCheck = head->cacheCheck;
1123     stats->chain_busy = head->busy;
1124     AssignInt64(head->looks, &stats->chain_looks);
1125     AssignInt64(head->gets, &stats->chain_gets);
1126     AssignInt64(head->reorders, &stats->chain_reorders);
1127
1128     res->hdr.response_len += sizeof(struct VolumeHashChainStats);
1129     
1130     return code;
1131 }
1132
1133 static afs_int32
1134 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1135 {
1136     afs_int32 code = SYNC_OK;
1137
1138     memcpy(res->payload.buf, &volume_hdr_LRU.stats, sizeof(volume_hdr_LRU.stats));
1139     res->hdr.response_len += sizeof(volume_hdr_LRU.stats);
1140
1141     return code;
1142 }
1143
1144 static afs_int32
1145 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1146 {
1147     afs_int32 code = SYNC_OK;
1148
1149     code = SYNC_BAD_COMMAND;
1150
1151     return code;
1152 }
1153 #endif /* AFS_DEMAND_ATTACH_FS */
1154
1155 static void
1156 FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
1157 {
1158     memcpy(&info->com, vcom->hdr, sizeof(SYNC_command_hdr));
1159     memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
1160 }
1161
1162 static void
1163 FSYNC_Drop(int fd)
1164 {
1165     struct offlineInfo *p;
1166     int i;
1167     Error error;
1168     char tvolName[VMAXPATHLEN];
1169
1170     VOL_LOCK;
1171     p = OfflineVolumes[FindHandler(fd)];
1172     for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
1173         if (p[i].volumeID) {
1174
1175             Volume *vp;
1176
1177             tvolName[0] = '/';
1178             sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
1179             vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
1180                                        V_VOLUPD);
1181             if (vp)
1182                 VPutVolume_r(vp);
1183             p[i].volumeID = 0;
1184         }
1185     }
1186     VOL_UNLOCK;
1187     RemoveHandler(fd);
1188 #ifdef AFS_NT40_ENV
1189     closesocket(fd);
1190 #else
1191     close(fd);
1192 #endif
1193     AcceptOn();
1194 }
1195
1196 static int AcceptHandler = -1;  /* handler id for accept, if turned on */
1197
1198 static void
1199 AcceptOn()
1200 {
1201     if (AcceptHandler == -1) {
1202         assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
1203         AcceptHandler = FindHandler(fssync_server_state.fd);
1204     }
1205 }
1206
1207 static void
1208 AcceptOff()
1209 {
1210     if (AcceptHandler != -1) {
1211         assert(RemoveHandler(fssync_server_state.fd));
1212         AcceptHandler = -1;
1213     }
1214 }
1215
1216 /* The multiple FD handling code. */
1217
1218 static int HandlerFD[MAXHANDLERS];
1219 static int (*HandlerProc[MAXHANDLERS]) ();
1220
1221 static void
1222 InitHandler()
1223 {
1224     register int i;
1225     ObtainWriteLock(&FSYNC_handler_lock);
1226     for (i = 0; i < MAXHANDLERS; i++) {
1227         HandlerFD[i] = -1;
1228         HandlerProc[i] = 0;
1229     }
1230     ReleaseWriteLock(&FSYNC_handler_lock);
1231 }
1232
1233 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1234 static void
1235 CallHandler(struct pollfd *fds, int nfds, int mask)
1236 {
1237     int i;
1238     int handler;
1239     ObtainReadLock(&FSYNC_handler_lock);
1240     for (i = 0; i < nfds; i++) {
1241         if (fds[i].revents & mask) {
1242             handler = FindHandler_r(fds[i].fd);
1243             ReleaseReadLock(&FSYNC_handler_lock);
1244             (*HandlerProc[handler]) (fds[i].fd);
1245             ObtainReadLock(&FSYNC_handler_lock);
1246         }
1247     }
1248     ReleaseReadLock(&FSYNC_handler_lock);
1249 }
1250 #else
1251 static void
1252 CallHandler(fd_set * fdsetp)
1253 {
1254     register int i;
1255     ObtainReadLock(&FSYNC_handler_lock);
1256     for (i = 0; i < MAXHANDLERS; i++) {
1257         if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
1258             ReleaseReadLock(&FSYNC_handler_lock);
1259             (*HandlerProc[i]) (HandlerFD[i]);
1260             ObtainReadLock(&FSYNC_handler_lock);
1261         }
1262     }
1263     ReleaseReadLock(&FSYNC_handler_lock);
1264 }
1265 #endif
1266
1267 static int
1268 AddHandler(int afd, int (*aproc) ())
1269 {
1270     register int i;
1271     ObtainWriteLock(&FSYNC_handler_lock);
1272     for (i = 0; i < MAXHANDLERS; i++)
1273         if (HandlerFD[i] == -1)
1274             break;
1275     if (i >= MAXHANDLERS) {
1276         ReleaseWriteLock(&FSYNC_handler_lock);
1277         return 0;
1278     }
1279     HandlerFD[i] = afd;
1280     HandlerProc[i] = aproc;
1281     ReleaseWriteLock(&FSYNC_handler_lock);
1282     return 1;
1283 }
1284
1285 static int
1286 FindHandler(register int afd)
1287 {
1288     register int i;
1289     ObtainReadLock(&FSYNC_handler_lock);
1290     for (i = 0; i < MAXHANDLERS; i++)
1291         if (HandlerFD[i] == afd) {
1292             ReleaseReadLock(&FSYNC_handler_lock);
1293             return i;
1294         }
1295     ReleaseReadLock(&FSYNC_handler_lock);       /* just in case */
1296     assert(1 == 2);
1297     return -1;                  /* satisfy compiler */
1298 }
1299
1300 static int
1301 FindHandler_r(register int afd)
1302 {
1303     register int i;
1304     for (i = 0; i < MAXHANDLERS; i++)
1305         if (HandlerFD[i] == afd) {
1306             return i;
1307         }
1308     assert(1 == 2);
1309     return -1;                  /* satisfy compiler */
1310 }
1311
1312 static int
1313 RemoveHandler(register int afd)
1314 {
1315     ObtainWriteLock(&FSYNC_handler_lock);
1316     HandlerFD[FindHandler_r(afd)] = -1;
1317     ReleaseWriteLock(&FSYNC_handler_lock);
1318     return 1;
1319 }
1320
1321 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1322 static void
1323 GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
1324 {
1325     int i;
1326     int fdi = 0;
1327     ObtainReadLock(&FSYNC_handler_lock);
1328     for (i = 0; i < MAXHANDLERS; i++)
1329         if (HandlerFD[i] != -1) {
1330             assert(fdi<maxfds);
1331             fds[fdi].fd = HandlerFD[i];
1332             fds[fdi].events = events;
1333             fds[fdi].revents = 0;
1334             fdi++;
1335         }
1336     *nfds = fdi;
1337     ReleaseReadLock(&FSYNC_handler_lock);
1338 }
1339 #else
1340 static void
1341 GetHandler(fd_set * fdsetp, int *maxfdp)
1342 {
1343     register int i;
1344     register int maxfd = -1;
1345     FD_ZERO(fdsetp);
1346     ObtainReadLock(&FSYNC_handler_lock);        /* just in case */
1347     for (i = 0; i < MAXHANDLERS; i++)
1348         if (HandlerFD[i] != -1) {
1349             FD_SET(HandlerFD[i], fdsetp);
1350             if (maxfd < HandlerFD[i])
1351                 maxfd = HandlerFD[i];
1352         }
1353     *maxfdp = maxfd;
1354     ReleaseReadLock(&FSYNC_handler_lock);       /* just in case */
1355 }
1356 #endif /* HAVE_POLL && AFS_PTHREAD_ENV */
1357
1358 #endif /* FSSYNC_BUILD_SERVER */