dafs-accurately-track-inuse-20080317
[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         VChangeState_r(vp, VOL_STATE_UNATTACHED);
830         VDeregisterVolOp_r(vp);
831     }
832 #endif
833
834     return SYNC_OK;
835 }
836
837 #ifdef AFS_DEMAND_ATTACH_FS
838 /**
839  * force a volume into the hard error state.
840  */
841 static afs_int32
842 FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
843 {
844     Error error;
845     Volume * vp;
846     afs_int32 code = SYNC_DENIED;
847
848     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
849     if (vp && !strcmp(VPartitionPath(V_partition(vp)), vcom->vop->partName)) {
850         memset(&vp->salvage, 0, sizeof(vp->salvage));
851         VChangeState_r(vp, VOL_STATE_ERROR);
852         code = SYNC_OK;
853     } else {
854         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
855     }
856         
857     return code;
858 }
859 #endif
860
861 static afs_int32
862 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
863 {
864     /* if the volume is being restored, break all callbacks on it */
865     if (V_BreakVolumeCallbacks) {
866         Log("fssync: breaking all call backs for volume %u\n",
867             vcom->vop->volume);
868         VOL_UNLOCK;
869         (*V_BreakVolumeCallbacks) (vcom->vop->volume);
870         VOL_LOCK;
871     }
872     return SYNC_OK;
873 }
874
875 static afs_int32
876 FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
877 {
878     afs_int32 code = SYNC_OK;
879     Error error;
880     Volume * vp;
881
882 #ifdef AFS_DEMAND_ATTACH_FS
883     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
884 #else /* !AFS_DEMAND_ATTACH_FS */
885     vp = VGetVolume_r(&error, vcom->vop->volume);
886 #endif /* !AFS_DEMAND_ATTACH_FS */
887
888     if (vp) {
889         assert(sizeof(Volume) <= res->payload.len);
890         memcpy(res->payload.buf, vp, sizeof(Volume));
891         res->hdr.response_len += sizeof(Volume);
892 #ifndef AFS_DEMAND_ATTACH_FS
893         VPutVolume_r(vp);
894 #endif
895     } else {
896         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
897         code = SYNC_FAILED;
898     }
899     return code;
900 }
901
902 static afs_int32
903 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
904 {
905     afs_int32 code = SYNC_OK;
906     Error error;
907     Volume * vp;
908     int hdr_ok = 0;
909
910 #ifdef AFS_DEMAND_ATTACH_FS
911     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
912     if (vp &&
913         (vp->header != NULL) &&
914         (V_attachFlags(vp) & VOL_HDR_ATTACHED) &&
915         (V_attachFlags(vp) & VOL_HDR_LOADED)) {
916         hdr_ok = 1;
917     }
918 #else /* !AFS_DEMAND_ATTACH_FS */
919     vp = VGetVolume_r(&error, vcom->vop->volume);
920     if (vp && vp->header) {
921         hdr_ok = 1;
922     }
923 #endif /* !AFS_DEMAND_ATTACH_FS */
924
925  load_done:
926     if (hdr_ok) {
927         assert(sizeof(VolumeDiskData) <= res->payload.len);
928         memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
929         res->hdr.response_len += sizeof(VolumeDiskData);
930 #ifndef AFS_DEMAND_ATTACH_FS
931         VPutVolume_r(vp);
932 #endif
933     } else {
934         if (vp) {
935             res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
936         } else {
937             res->hdr.reason = FSYNC_UNKNOWN_VOLID;
938         }
939         code = SYNC_FAILED;
940     }
941     return code;
942 }
943
944 #ifdef AFS_DEMAND_ATTACH_FS
945 static afs_int32
946 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
947 {
948     afs_int32 code = SYNC_OK;
949     Error error;
950     Volume * vp;
951
952     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
953
954     if (vp && vp->pending_vol_op) {
955         assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
956         memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
957         res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
958     } else {
959         if (vp) {
960             res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
961         } else {
962             res->hdr.reason = FSYNC_UNKNOWN_VOLID;
963         }
964         code = SYNC_FAILED;
965     }
966     return code;
967 }
968 #endif /* AFS_DEMAND_ATTACH_FS */
969
970 static afs_int32
971 FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res)
972 {
973     afs_int32 code = SYNC_OK;
974     FSSYNC_VnQry_hdr * qry = com->payload.buf;
975     Volume * vp;
976     Vnode * vnp;
977     Error error;
978
979     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
980         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
981         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
982         return SYNC_COM_ERROR;
983     }
984
985 #ifdef AFS_DEMAND_ATTACH_FS
986     vp = VLookupVolume_r(&error, qry->volume, NULL);
987 #else /* !AFS_DEMAND_ATTACH_FS */
988     vp = VGetVolume_r(&error, qry->volume);
989 #endif /* !AFS_DEMAND_ATTACH_FS */
990
991     if (!vp) {
992         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
993         code = SYNC_FAILED;
994         goto done;
995     }
996
997     vnp = VLookupVnode(vp, qry->vnode);
998     if (!vnp) {
999         res->hdr.reason = FSYNC_UNKNOWN_VNID;
1000         code = SYNC_FAILED;
1001         goto cleanup;
1002     }
1003
1004     if (Vn_class(vnp)->residentSize > res->payload.len) {
1005         res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
1006         code = SYNC_FAILED;
1007         goto cleanup;
1008     }
1009
1010     memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
1011     res->hdr.response_len += Vn_class(vnp)->residentSize;
1012
1013  cleanup:
1014 #ifndef AFS_DEMAND_ATTACH_FS
1015     VPutVolume_r(vp);
1016 #endif
1017
1018  done:
1019     return code;
1020 }
1021
1022 static afs_int32
1023 FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res)
1024 {
1025     afs_int32 code = SYNC_OK;
1026     FSSYNC_StatsOp_command scom;
1027
1028     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_StatsOp_hdr))) {
1029         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1030         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1031         return SYNC_COM_ERROR;
1032     }
1033
1034     scom.hdr = &com->hdr;
1035     scom.sop = (FSSYNC_StatsOp_hdr *) com->payload.buf;
1036     scom.com = com;
1037
1038     switch (com->hdr.command) {
1039     case FSYNC_VOL_STATS_GENERAL:
1040         code = FSYNC_com_StatsOpGeneral(&scom, res);
1041         break;
1042 #ifdef AFS_DEMAND_ATTACH_FS
1043         /* statistics for the following subsystems are only tracked
1044          * for demand attach fileservers */
1045     case FSYNC_VOL_STATS_VICEP:
1046         code = FSYNC_com_StatsOpViceP(&scom, res);
1047         break;
1048     case FSYNC_VOL_STATS_HASH:
1049         code = FSYNC_com_StatsOpHash(&scom, res);
1050         break;
1051     case FSYNC_VOL_STATS_HDR:
1052         code = FSYNC_com_StatsOpHdr(&scom, res);
1053         break;
1054     case FSYNC_VOL_STATS_VLRU:
1055         code = FSYNC_com_StatsOpVLRU(&scom, res);
1056         break;
1057 #endif /* AFS_DEMAND_ATTACH_FS */
1058     default:
1059         code = SYNC_BAD_COMMAND;
1060     }
1061
1062     return code;
1063 }
1064
1065 static afs_int32
1066 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1067 {
1068     afs_int32 code = SYNC_OK;
1069
1070     memcpy(res->payload.buf, &VStats, sizeof(VStats));
1071     res->hdr.response_len += sizeof(VStats);
1072
1073     return code;
1074 }
1075
1076 #ifdef AFS_DEMAND_ATTACH_FS
1077 static afs_int32
1078 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1079 {
1080     afs_int32 code = SYNC_OK;
1081     struct DiskPartition64 * dp;
1082     struct DiskPartitionStats64 * stats;
1083
1084     if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
1085         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1086         code = SYNC_FAILED;
1087         goto done;
1088     }
1089
1090     dp = VGetPartition_r(scom->sop->args.partName, 0);
1091     if (!dp) {
1092         code = SYNC_FAILED;
1093     } else {
1094         stats = (struct DiskPartitionStats64 *) res->payload.buf;
1095         stats->free = dp->free;
1096         stats->totalUsable = dp->totalUsable;
1097         stats->minFree = dp->minFree;
1098         stats->f_files = dp->f_files;
1099         stats->vol_list_len = dp->vol_list.len;
1100         
1101         res->hdr.response_len += sizeof(struct DiskPartitionStats64);
1102     }
1103
1104  done:
1105     return code;
1106 }
1107
1108 static afs_int32
1109 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1110 {
1111     afs_int32 code = SYNC_OK;
1112     struct VolumeHashChainStats * stats;
1113     struct VolumeHashChainHead * head;
1114
1115     if (scom->sop->args.hash_bucket >= VolumeHashTable.Size) {
1116         return SYNC_FAILED;
1117     }
1118
1119     head = &VolumeHashTable.Table[scom->sop->args.hash_bucket];
1120     stats = (struct VolumeHashChainStats *) res->payload.buf;
1121     stats->table_size = VolumeHashTable.Size;
1122     stats->chain_len = head->len;
1123     stats->chain_cacheCheck = head->cacheCheck;
1124     stats->chain_busy = head->busy;
1125     AssignInt64(head->looks, &stats->chain_looks);
1126     AssignInt64(head->gets, &stats->chain_gets);
1127     AssignInt64(head->reorders, &stats->chain_reorders);
1128
1129     res->hdr.response_len += sizeof(struct VolumeHashChainStats);
1130     
1131     return code;
1132 }
1133
1134 static afs_int32
1135 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1136 {
1137     afs_int32 code = SYNC_OK;
1138
1139     memcpy(res->payload.buf, &volume_hdr_LRU.stats, sizeof(volume_hdr_LRU.stats));
1140     res->hdr.response_len += sizeof(volume_hdr_LRU.stats);
1141
1142     return code;
1143 }
1144
1145 static afs_int32
1146 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1147 {
1148     afs_int32 code = SYNC_OK;
1149
1150     code = SYNC_BAD_COMMAND;
1151
1152     return code;
1153 }
1154 #endif /* AFS_DEMAND_ATTACH_FS */
1155
1156 static void
1157 FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
1158 {
1159     memcpy(&info->com, vcom->hdr, sizeof(SYNC_command_hdr));
1160     memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
1161 }
1162
1163 static void
1164 FSYNC_Drop(int fd)
1165 {
1166     struct offlineInfo *p;
1167     int i;
1168     Error error;
1169     char tvolName[VMAXPATHLEN];
1170
1171     VOL_LOCK;
1172     p = OfflineVolumes[FindHandler(fd)];
1173     for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
1174         if (p[i].volumeID) {
1175
1176             Volume *vp;
1177
1178             tvolName[0] = '/';
1179             sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
1180             vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
1181                                        V_VOLUPD);
1182             if (vp)
1183                 VPutVolume_r(vp);
1184             p[i].volumeID = 0;
1185         }
1186     }
1187     VOL_UNLOCK;
1188     RemoveHandler(fd);
1189 #ifdef AFS_NT40_ENV
1190     closesocket(fd);
1191 #else
1192     close(fd);
1193 #endif
1194     AcceptOn();
1195 }
1196
1197 static int AcceptHandler = -1;  /* handler id for accept, if turned on */
1198
1199 static void
1200 AcceptOn()
1201 {
1202     if (AcceptHandler == -1) {
1203         assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
1204         AcceptHandler = FindHandler(fssync_server_state.fd);
1205     }
1206 }
1207
1208 static void
1209 AcceptOff()
1210 {
1211     if (AcceptHandler != -1) {
1212         assert(RemoveHandler(fssync_server_state.fd));
1213         AcceptHandler = -1;
1214     }
1215 }
1216
1217 /* The multiple FD handling code. */
1218
1219 static int HandlerFD[MAXHANDLERS];
1220 static int (*HandlerProc[MAXHANDLERS]) ();
1221
1222 static void
1223 InitHandler()
1224 {
1225     register int i;
1226     ObtainWriteLock(&FSYNC_handler_lock);
1227     for (i = 0; i < MAXHANDLERS; i++) {
1228         HandlerFD[i] = -1;
1229         HandlerProc[i] = 0;
1230     }
1231     ReleaseWriteLock(&FSYNC_handler_lock);
1232 }
1233
1234 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1235 static void
1236 CallHandler(struct pollfd *fds, int nfds, int mask)
1237 {
1238     int i;
1239     int handler;
1240     ObtainReadLock(&FSYNC_handler_lock);
1241     for (i = 0; i < nfds; i++) {
1242         if (fds[i].revents & mask) {
1243             handler = FindHandler_r(fds[i].fd);
1244             ReleaseReadLock(&FSYNC_handler_lock);
1245             (*HandlerProc[handler]) (fds[i].fd);
1246             ObtainReadLock(&FSYNC_handler_lock);
1247         }
1248     }
1249     ReleaseReadLock(&FSYNC_handler_lock);
1250 }
1251 #else
1252 static void
1253 CallHandler(fd_set * fdsetp)
1254 {
1255     register int i;
1256     ObtainReadLock(&FSYNC_handler_lock);
1257     for (i = 0; i < MAXHANDLERS; i++) {
1258         if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
1259             ReleaseReadLock(&FSYNC_handler_lock);
1260             (*HandlerProc[i]) (HandlerFD[i]);
1261             ObtainReadLock(&FSYNC_handler_lock);
1262         }
1263     }
1264     ReleaseReadLock(&FSYNC_handler_lock);
1265 }
1266 #endif
1267
1268 static int
1269 AddHandler(int afd, int (*aproc) ())
1270 {
1271     register int i;
1272     ObtainWriteLock(&FSYNC_handler_lock);
1273     for (i = 0; i < MAXHANDLERS; i++)
1274         if (HandlerFD[i] == -1)
1275             break;
1276     if (i >= MAXHANDLERS) {
1277         ReleaseWriteLock(&FSYNC_handler_lock);
1278         return 0;
1279     }
1280     HandlerFD[i] = afd;
1281     HandlerProc[i] = aproc;
1282     ReleaseWriteLock(&FSYNC_handler_lock);
1283     return 1;
1284 }
1285
1286 static int
1287 FindHandler(register int afd)
1288 {
1289     register int i;
1290     ObtainReadLock(&FSYNC_handler_lock);
1291     for (i = 0; i < MAXHANDLERS; i++)
1292         if (HandlerFD[i] == afd) {
1293             ReleaseReadLock(&FSYNC_handler_lock);
1294             return i;
1295         }
1296     ReleaseReadLock(&FSYNC_handler_lock);       /* just in case */
1297     assert(1 == 2);
1298     return -1;                  /* satisfy compiler */
1299 }
1300
1301 static int
1302 FindHandler_r(register int afd)
1303 {
1304     register int i;
1305     for (i = 0; i < MAXHANDLERS; i++)
1306         if (HandlerFD[i] == afd) {
1307             return i;
1308         }
1309     assert(1 == 2);
1310     return -1;                  /* satisfy compiler */
1311 }
1312
1313 static int
1314 RemoveHandler(register int afd)
1315 {
1316     ObtainWriteLock(&FSYNC_handler_lock);
1317     HandlerFD[FindHandler_r(afd)] = -1;
1318     ReleaseWriteLock(&FSYNC_handler_lock);
1319     return 1;
1320 }
1321
1322 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1323 static void
1324 GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
1325 {
1326     int i;
1327     int fdi = 0;
1328     ObtainReadLock(&FSYNC_handler_lock);
1329     for (i = 0; i < MAXHANDLERS; i++)
1330         if (HandlerFD[i] != -1) {
1331             assert(fdi<maxfds);
1332             fds[fdi].fd = HandlerFD[i];
1333             fds[fdi].events = events;
1334             fds[fdi].revents = 0;
1335             fdi++;
1336         }
1337     *nfds = fdi;
1338     ReleaseReadLock(&FSYNC_handler_lock);
1339 }
1340 #else
1341 static void
1342 GetHandler(fd_set * fdsetp, int *maxfdp)
1343 {
1344     register int i;
1345     register int maxfd = -1;
1346     FD_ZERO(fdsetp);
1347     ObtainReadLock(&FSYNC_handler_lock);        /* just in case */
1348     for (i = 0; i < MAXHANDLERS; i++)
1349         if (HandlerFD[i] != -1) {
1350             FD_SET(HandlerFD[i], fdsetp);
1351             if (maxfd < HandlerFD[i])
1352                 maxfd = HandlerFD[i];
1353         }
1354     *maxfdp = maxfd;
1355     ReleaseReadLock(&FSYNC_handler_lock);       /* just in case */
1356 }
1357 #endif /* HAVE_POLL && AFS_PTHREAD_ENV */
1358
1359 #endif /* FSSYNC_BUILD_SERVER */