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