Include stdint.h when using intptr_t
[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-2010 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 #ifndef AFS_PTHREAD_ENV
19 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
20
21 /*
22  * stack size increased from 8K because the HP machine seemed to have trouble
23  * with the smaller stack
24  */
25 #define USUAL_STACK_SIZE        (24 * 1024)
26 #endif /* !AFS_PTHREAD_ENV */
27
28 /*
29    fssync-server.c
30    File server synchronization with external volume utilities.
31    server-side implementation
32  */
33
34 /* This controls the size of an fd_set; it must be defined early before
35  * the system headers define that type and the macros that operate on it.
36  * Its value should be as large as the maximum file descriptor limit we
37  * are likely to run into on any platform.  Right now, that is 65536
38  * which is the default hard fd limit on Solaris 9 */
39 #ifndef _WIN32
40 #define FD_SETSIZE 65536
41 #endif
42
43 #include <afsconfig.h>
44 #include <afs/param.h>
45
46
47 #include <sys/types.h>
48 #include <stdio.h>
49 #ifdef HAVE_STDINT_H
50 # include <stdint.h>
51 #endif
52 #ifdef AFS_NT40_ENV
53 #include <winsock2.h>
54 #include <time.h>
55 #else
56 #include <sys/param.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
59 #include <netdb.h>
60 #include <sys/time.h>
61 #include <unistd.h>
62 #endif
63 #include <errno.h>
64 #ifdef AFS_PTHREAD_ENV
65 #include <assert.h>
66 #else /* AFS_PTHREAD_ENV */
67 #include <afs/assert.h>
68 #endif /* AFS_PTHREAD_ENV */
69 #include <signal.h>
70 #include <string.h>
71
72 #include <rx/xdr.h>
73 #include <afs/afsint.h>
74 #include "nfs.h"
75 #include <afs/errors.h>
76 #include "daemon_com.h"
77 #include "fssync.h"
78 #include "salvsync.h"
79 #include "lwp.h"
80 #include "lock.h"
81 #include <afs/afssyscalls.h>
82 #include "ihandle.h"
83 #include "vnode.h"
84 #include "volume.h"
85 #include "volume_inline.h"
86 #include "partition.h"
87 #include "vg_cache.h"
88
89 #ifdef HAVE_POLL
90 #include <sys/poll.h>
91 #endif /* HAVE_POLL */
92
93 #ifdef USE_UNIX_SOCKETS
94 #include <sys/un.h>
95 #include <afs/afsutil.h>
96 #endif /* USE_UNIX_SOCKETS */
97
98 #ifdef FSSYNC_BUILD_SERVER
99
100 /*@printflike@*/ extern void Log(const char *format, ...);
101
102 int (*V_BreakVolumeCallbacks) (VolumeId volume);
103
104 #define MAXHANDLERS     4       /* Up to 4 clients; must be at least 2, so that
105                                  * move = dump+restore can run on single server */
106 #define MAXOFFLINEVOLUMES 128   /* This needs to be as big as the maximum
107                                  * number that would be offline for 1 operation.
108                                  * Current winner is salvage, which needs all
109                                  * cloned read-only copies offline when salvaging
110                                  * a single read-write volume */
111
112
113
114 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
115
116 /**
117  * fssync server socket handle.
118  */
119 static SYNC_server_state_t fssync_server_state = 
120     { -1,                       /* file descriptor */
121       FSSYNC_ENDPOINT_DECL,     /* server endpoint */
122       FSYNC_PROTO_VERSION,      /* protocol version */
123       5,                        /* bind() retry limit */
124       100,                      /* listen() queue depth */
125       "FSSYNC",                 /* protocol name string */
126     };
127
128 #ifdef AFS_DEMAND_ATTACH_FS
129 /**
130  * a queue of volume pointers to salvage in the background.
131  */
132 struct fsync_salv_node {
133     struct rx_queue q;
134     Volume *vp;                     /**< volume to salvage */
135     unsigned char update_salv_prio; /**< whether we should update the salvage priority or not */
136 };
137 static struct {
138     struct rx_queue head;
139     pthread_cond_t cv;
140 } fsync_salv;
141
142 static void * FSYNC_salvageThread(void *);
143 static void FSYNC_backgroundSalvage(Volume *vp);
144 #endif /* AFS_DEMAND_ATTACH_FS */
145
146 /* Forward declarations */
147 static void * FSYNC_sync(void *);
148 static void FSYNC_newconnection(osi_socket afd);
149 static void FSYNC_com(osi_socket fd);
150 static void FSYNC_Drop(osi_socket fd);
151 static void AcceptOn(void);
152 static void AcceptOff(void);
153 static void InitHandler(void);
154 static int AddHandler(osi_socket fd, void (*aproc)(osi_socket));
155 static int FindHandler(osi_socket afd);
156 static int FindHandler_r(osi_socket afd);
157 static int RemoveHandler(osi_socket afd);
158 #if defined(HAVE_POLL) && defined (AFS_PTHREAD_ENV)
159 static void CallHandler(struct pollfd *fds, int nfds, int mask);
160 static void GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds);
161 #else
162 static void CallHandler(fd_set * fdsetp);
163 static void GetHandler(fd_set * fdsetp, int *maxfdp);
164 #endif
165 extern int LogLevel;
166
167 static afs_int32 FSYNC_com_VolOp(osi_socket fd, SYNC_command * com, SYNC_response * res);
168
169 #ifdef AFS_DEMAND_ATTACH_FS
170 static afs_int32 FSYNC_com_VolError(FSSYNC_VolOp_command * com, SYNC_response * res);
171 #endif
172 static afs_int32 FSYNC_com_VolOn(FSSYNC_VolOp_command * com, SYNC_response * res);
173 static afs_int32 FSYNC_com_VolOff(FSSYNC_VolOp_command * com, SYNC_response * res);
174 static afs_int32 FSYNC_com_VolMove(FSSYNC_VolOp_command * com, SYNC_response * res);
175 static afs_int32 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * com, SYNC_response * res);
176 static afs_int32 FSYNC_com_VolDone(FSSYNC_VolOp_command * com, SYNC_response * res);
177 static afs_int32 FSYNC_com_VolQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
178 static afs_int32 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
179 #ifdef AFS_DEMAND_ATTACH_FS
180 static afs_int32 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
181 static afs_int32 FSYNC_com_VGQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
182 static afs_int32 FSYNC_com_VGUpdate(SYNC_command * com, SYNC_response * res);
183 static afs_int32 FSYNC_com_VGScan(FSSYNC_VolOp_command * com, SYNC_response * res);
184 static afs_int32 FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res);
185 #endif /* AFS_DEMAND_ATTACH_FS */
186
187 static afs_int32 FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res);
188
189 static afs_int32 FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res);
190
191 static afs_int32 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res);
192
193 #ifdef AFS_DEMAND_ATTACH_FS
194 static afs_int32 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res);
195 static afs_int32 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res);
196 static afs_int32 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res);
197 static afs_int32 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res);
198 #endif
199
200 static void FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info);
201
202 static int FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon);
203
204
205 /*
206  * This lock controls access to the handler array. The overhead
207  * is minimal in non-preemptive environments.
208  */
209 struct Lock FSYNC_handler_lock;
210
211 void
212 FSYNC_fsInit(void)
213 {
214 #ifdef AFS_PTHREAD_ENV
215     pthread_t tid;
216     pthread_attr_t tattr;
217 #else /* AFS_PTHREAD_ENV */
218     PROCESS pid;
219 #endif /* AFS_PTHREAD_ENV */
220
221     Lock_Init(&FSYNC_handler_lock);
222
223 #ifdef AFS_PTHREAD_ENV
224     assert(pthread_attr_init(&tattr) == 0);
225     assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
226     assert(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
227 #else /* AFS_PTHREAD_ENV */
228     assert(LWP_CreateProcess
229            (FSYNC_sync, USUAL_STACK_SIZE, USUAL_PRIORITY, (void *)0,
230             "FSYNC_sync", &pid) == LWP_SUCCESS);
231 #endif /* AFS_PTHREAD_ENV */
232
233 #ifdef AFS_DEMAND_ATTACH_FS
234     queue_Init(&fsync_salv.head);
235     assert(pthread_cond_init(&fsync_salv.cv, NULL) == 0);
236     assert(pthread_create(&tid, &tattr, FSYNC_salvageThread, NULL) == 0);
237 #endif /* AFS_DEMAND_ATTACH_FS */
238 }
239
240 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
241 static struct pollfd FSYNC_readfds[MAXHANDLERS];
242 #else
243 static fd_set FSYNC_readfds;
244 #endif
245
246
247 static void *
248 FSYNC_sync(void * args)
249 {
250     extern int VInit;
251     int code;
252 #ifdef AFS_PTHREAD_ENV
253     int tid;
254 #endif
255     SYNC_server_state_t * state = &fssync_server_state;
256 #ifdef AFS_DEMAND_ATTACH_FS
257     VThreadOptions_t * thread_opts;
258     int min_vinit = 2;
259 #else
260     /*
261      * For non-DAFS, only wait until we begin attaching volumes (instead
262      * of waiting until all volumes are attached), since it can take
263      * awhile until VInit == 2.
264      */
265     int min_vinit = 1;
266 #endif /* AFS_DEMAND_ATTACH_FS */
267
268     SYNC_getAddr(&state->endpoint, &state->addr);
269     SYNC_cleanupSock(state);
270
271 #ifndef AFS_NT40_ENV
272     (void)signal(SIGPIPE, SIG_IGN);
273 #endif
274
275 #ifdef AFS_PTHREAD_ENV
276     /* set our 'thread-id' so that the host hold table works */
277     MUTEX_ENTER(&rx_stats_mutex);       /* protects rxi_pthread_hinum */
278     tid = ++rxi_pthread_hinum;
279     MUTEX_EXIT(&rx_stats_mutex);
280     pthread_setspecific(rx_thread_id_key, (void *)(intptr_t)tid);
281     Log("Set thread id %d for FSYNC_sync\n", tid);
282 #endif /* AFS_PTHREAD_ENV */
283
284     while (VInit < min_vinit) {
285         /* Let somebody else run until all volumes have been preattached
286          * (DAFS), or we have started attaching volumes (non-DAFS). This
287          * doesn't mean that all volumes have been attached.
288          */
289 #ifdef AFS_PTHREAD_ENV
290         pthread_yield();
291 #else /* AFS_PTHREAD_ENV */
292         LWP_DispatchProcess();
293 #endif /* AFS_PTHREAD_ENV */
294     }
295     state->fd = SYNC_getSock(&state->endpoint);
296     code = SYNC_bindSock(state);
297     assert(!code);
298
299 #ifdef AFS_DEMAND_ATTACH_FS
300     /*
301      * make sure the volume package is incapable of recursively executing
302      * salvsync calls on this thread, since there is a possibility of
303      * deadlock.
304      */
305     thread_opts = malloc(sizeof(VThreadOptions_t));
306     if (thread_opts == NULL) {
307         Log("failed to allocate memory for thread-specific volume package options structure\n");
308         return NULL;
309     }
310     memcpy(thread_opts, &VThread_defaults, sizeof(VThread_defaults));
311     thread_opts->disallow_salvsync = 1;
312     assert(pthread_setspecific(VThread_key, thread_opts) == 0);
313
314     code = VVGCache_PkgInit();
315     assert(code == 0);
316 #endif
317
318     InitHandler();
319     AcceptOn();
320
321     for (;;) {
322 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
323         int nfds;
324         GetHandler(FSYNC_readfds, MAXHANDLERS, POLLIN|POLLPRI, &nfds);
325         if (poll(FSYNC_readfds, nfds, -1) >=1)
326             CallHandler(FSYNC_readfds, nfds, POLLIN|POLLPRI);
327 #else
328         int maxfd;
329         GetHandler(&FSYNC_readfds, &maxfd);
330         /* Note: check for >= 1 below is essential since IOMGR_select
331          * doesn't have exactly same semantics as select.
332          */
333 #ifdef AFS_PTHREAD_ENV
334         if (select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
335 #else /* AFS_PTHREAD_ENV */
336         if (IOMGR_Select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
337 #endif /* AFS_PTHREAD_ENV */
338             CallHandler(&FSYNC_readfds);
339 #endif
340     }
341     return NULL; /* hush now, little gcc */
342 }
343
344 #ifdef AFS_DEMAND_ATTACH_FS
345 /**
346  * thread for salvaging volumes in the background.
347  *
348  * Since FSSYNC handlers cannot issue SALVSYNC requests in order to avoid
349  * deadlock issues, this thread exists so code in the FSSYNC handler thread
350  * can hand off volumes to be salvaged in the background.
351  *
352  * @param[in] args  unused
353  *
354  * @note DEMAND_ATTACH_FS only
355  */
356 static void *
357 FSYNC_salvageThread(void * args)
358 {
359     Volume *vp;
360     struct fsync_salv_node *node;
361
362     VOL_LOCK;
363
364     for (;;) {
365         while (queue_IsEmpty(&fsync_salv.head)) {
366             VOL_CV_WAIT(&fsync_salv.cv);
367         }
368
369         node = queue_First(&fsync_salv.head, fsync_salv_node);
370         queue_Remove(node);
371
372         vp = node->vp;
373         if (node->update_salv_prio) {
374             if (VUpdateSalvagePriority_r(vp)) {
375                 ViceLog(0, ("FSYNC_salvageThread: unable to raise salvage priority "
376                             "for volume %lu\n", afs_printable_uint32_lu(vp->hashid)));
377             }
378         }
379
380         free(node);
381         node = NULL;
382
383         VCancelReservation_r(vp);
384     }
385
386     VOL_UNLOCK;
387
388     return NULL;
389 }
390
391 /**
392  * salvage a volume in the background.
393  *
394  * Salvages cannot be scheduled directly from the main FSYNC thread, so
395  * instead call this function to schedule a salvage asynchronously in the
396  * FSYNC_salvageThread thread.
397  *
398  * @param[in] vp  volume to pointer to salvage
399  *
400  * @pre VOL_LOCK held
401  *
402  * @note DEMAND_ATTACH_FS only
403  */
404 static void
405 FSYNC_backgroundSalvage(Volume *vp)
406 {
407     struct fsync_salv_node *node;
408     Error ec;
409
410     VCreateReservation_r(vp);
411
412     node = malloc(sizeof(struct fsync_salv_node));
413     node->vp = vp;
414
415     /* Save this value, to know if we should VUpdateSalvagePriority_r.
416      * We need to save it here, snce VRequestSalvage_r will change it. */
417     node->update_salv_prio = vp->salvage.requested;
418
419     if (VRequestSalvage_r(&ec, vp, SALVSYNC_ERROR, 0)) {
420         ViceLog(0, ("FSYNC_backgroundSalvage: unable to request salvage for volume %lu\n",
421                     afs_printable_uint32_lu(vp->hashid)));
422     }
423
424     queue_Append(&fsync_salv.head, node);
425     assert(pthread_cond_broadcast(&fsync_salv.cv) == 0);
426 }
427 #endif /* AFS_DEMAND_ATTACH_FS */
428
429 static void
430 FSYNC_newconnection(osi_socket afd)
431 {
432 #ifdef USE_UNIX_SOCKETS
433     struct sockaddr_un other;
434 #else  /* USE_UNIX_SOCKETS */
435     struct sockaddr_in other;
436 #endif
437     osi_socket fd;
438     socklen_t junk;
439     junk = sizeof(other);
440     fd = accept(afd, (struct sockaddr *)&other, &junk);
441     if (fd == -1) {
442         Log("FSYNC_newconnection:  accept failed, errno==%d\n", errno);
443         assert(1 == 2);
444     } else if (!AddHandler(fd, FSYNC_com)) {
445         AcceptOff();
446         assert(AddHandler(fd, FSYNC_com));
447     }
448 }
449
450 /* this function processes commands from an fssync file descriptor (fd) */
451 afs_int32 FS_cnt = 0;
452 static void
453 FSYNC_com(osi_socket fd)
454 {
455     SYNC_command com;
456     SYNC_response res;
457     SYNC_PROTO_BUF_DECL(com_buf);
458     SYNC_PROTO_BUF_DECL(res_buf);
459
460     memset(&res.hdr, 0, sizeof(res.hdr));
461
462     com.payload.buf = (void *)com_buf;
463     com.payload.len = SYNC_PROTO_MAX_LEN;
464     res.hdr.response_len = sizeof(res.hdr);
465     res.payload.len = SYNC_PROTO_MAX_LEN;
466     res.payload.buf = (void *)res_buf;
467
468     FS_cnt++;
469     if (SYNC_getCom(&fssync_server_state, fd, &com)) {
470         Log("FSYNC_com:  read failed; dropping connection (cnt=%d)\n", FS_cnt);
471         FSYNC_Drop(fd);
472         return;
473     }
474
475     if (com.recv_len < sizeof(com.hdr)) {
476         Log("FSSYNC_com:  invalid protocol message length (%u)\n", com.recv_len);
477         res.hdr.response = SYNC_COM_ERROR;
478         res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
479         res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
480         goto respond;
481     }
482
483     if (com.hdr.proto_version != FSYNC_PROTO_VERSION) {
484         Log("FSYNC_com:  invalid protocol version (%u)\n", com.hdr.proto_version);
485         res.hdr.response = SYNC_COM_ERROR;
486         res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
487         goto respond;
488     }
489
490     if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
491         res.hdr.response = SYNC_OK;
492         res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
493
494         /* don't respond, just drop; senders of SYNC_COM_CHANNEL_CLOSE
495          * never wait for a response. */
496         goto done;
497     }
498
499     res.hdr.com_seq = com.hdr.com_seq;
500
501     VOL_LOCK;
502     switch (com.hdr.command) {
503     case FSYNC_VOL_ON:
504     case FSYNC_VOL_ATTACH:
505     case FSYNC_VOL_LEAVE_OFF:
506     case FSYNC_VOL_OFF:
507     case FSYNC_VOL_FORCE_ERROR:
508     case FSYNC_VOL_LISTVOLUMES:
509     case FSYNC_VOL_NEEDVOLUME:
510     case FSYNC_VOL_MOVE:
511     case FSYNC_VOL_BREAKCBKS:
512     case FSYNC_VOL_DONE:
513     case FSYNC_VOL_QUERY:
514     case FSYNC_VOL_QUERY_HDR:
515     case FSYNC_VOL_QUERY_VOP:
516 #ifdef AFS_DEMAND_ATTACH_FS
517     case FSYNC_VG_QUERY:
518     case FSYNC_VG_SCAN:
519     case FSYNC_VG_SCAN_ALL:
520 #endif
521         res.hdr.response = FSYNC_com_VolOp(fd, &com, &res);
522         break;
523     case FSYNC_VOL_STATS_GENERAL:
524     case FSYNC_VOL_STATS_VICEP:
525     case FSYNC_VOL_STATS_HASH:
526     case FSYNC_VOL_STATS_HDR:
527     case FSYNC_VOL_STATS_VLRU:
528         res.hdr.response = FSYNC_com_StatsOp(fd, &com, &res);
529         break;
530     case FSYNC_VOL_QUERY_VNODE:
531         res.hdr.response = FSYNC_com_VnQry(fd, &com, &res);
532         break;
533 #ifdef AFS_DEMAND_ATTACH_FS
534     case FSYNC_VG_ADD:
535     case FSYNC_VG_DEL:
536         res.hdr.response = FSYNC_com_VGUpdate(&com, &res);
537         break;
538 #endif
539     default:
540         res.hdr.response = SYNC_BAD_COMMAND;
541         break;
542     }
543     VOL_UNLOCK;
544
545  respond:
546     SYNC_putRes(&fssync_server_state, fd, &res);
547
548  done:
549     if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
550         FSYNC_Drop(fd);
551     }
552 }
553
554 static afs_int32
555 FSYNC_com_VolOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
556 {
557     int i;
558     afs_int32 code = SYNC_OK;
559     FSSYNC_VolOp_command vcom;
560
561     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VolOp_hdr))) {
562         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
563         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
564         return SYNC_COM_ERROR;
565     }
566
567     vcom.hdr = &com->hdr;
568     vcom.vop = (FSSYNC_VolOp_hdr *) com->payload.buf;
569     vcom.com = com;
570
571     vcom.volumes = OfflineVolumes[FindHandler(fd)];
572     for (vcom.v = NULL, i = 0; i < MAXOFFLINEVOLUMES; i++) {
573         if ((vcom.volumes[i].volumeID == vcom.vop->volume) &&
574             (strncmp(vcom.volumes[i].partName, vcom.vop->partName,
575                      sizeof(vcom.volumes[i].partName)) == 0)) {
576             vcom.v = &vcom.volumes[i];
577             break;
578         }
579     }
580
581     switch (com->hdr.command) {
582     case FSYNC_VOL_ON:
583     case FSYNC_VOL_ATTACH:
584     case FSYNC_VOL_LEAVE_OFF:
585         code = FSYNC_com_VolOn(&vcom, res);
586         break;
587     case FSYNC_VOL_OFF:
588     case FSYNC_VOL_NEEDVOLUME:
589         code = FSYNC_com_VolOff(&vcom, res);
590         break;
591     case FSYNC_VOL_LISTVOLUMES:
592         code = SYNC_OK;
593         break;
594     case FSYNC_VOL_MOVE:
595         code = FSYNC_com_VolMove(&vcom, res);
596         break;
597     case FSYNC_VOL_BREAKCBKS:
598         code = FSYNC_com_VolBreakCBKs(&vcom, res);
599         break;
600     case FSYNC_VOL_DONE:
601         code = FSYNC_com_VolDone(&vcom, res);
602         break;
603     case FSYNC_VOL_QUERY:
604         code = FSYNC_com_VolQuery(&vcom, res);
605         break;
606     case FSYNC_VOL_QUERY_HDR:
607         code = FSYNC_com_VolHdrQuery(&vcom, res);
608         break;
609 #ifdef AFS_DEMAND_ATTACH_FS
610     case FSYNC_VOL_FORCE_ERROR:
611         code = FSYNC_com_VolError(&vcom, res);
612         break;
613     case FSYNC_VOL_QUERY_VOP:
614         code = FSYNC_com_VolOpQuery(&vcom, res);
615         break;
616     case FSYNC_VG_QUERY:
617         code = FSYNC_com_VGQuery(&vcom, res);
618         break;
619     case FSYNC_VG_SCAN:
620         code = FSYNC_com_VGScan(&vcom, res);
621         break;
622     case FSYNC_VG_SCAN_ALL:
623         code = FSYNC_com_VGScanAll(&vcom, res);
624         break;
625 #endif /* AFS_DEMAND_ATTACH_FS */
626     default:
627         code = SYNC_BAD_COMMAND;
628     }
629
630     return code;
631 }
632
633 /**
634  * service an FSYNC request to bring a volume online.
635  *
636  * @param[in]   vcom  pointer command object
637  * @param[out]  res   object in which to store response packet
638  *
639  * @return operation status
640  *   @retval SYNC_OK volume transitioned online
641  *   @retval SYNC_FAILED invalid command protocol message
642  *   @retval SYNC_DENIED operation could not be completed
643  *
644  * @note this is an FSYNC RPC server stub
645  *
646  * @note this procedure handles the following FSSYNC command codes:
647  *       - FSYNC_VOL_ON
648  *       - FSYNC_VOL_ATTACH
649  *       - FSYNC_VOL_LEAVE_OFF
650  *
651  * @note the supplementary reason code contains additional details.
652  *       When SYNC_DENIED is returned, the specific reason is
653  *       placed in the response packet reason field.
654  *
655  * @internal
656  */
657 static afs_int32
658 FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
659 {
660     afs_int32 code = SYNC_OK;
661 #ifndef AFS_DEMAND_ATTACH_FS
662     char tvolName[VMAXPATHLEN];
663 #endif
664     Volume * vp;
665     Error error;
666
667     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
668         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
669         code = SYNC_FAILED;
670         goto done;
671     }
672
673     /* so, we need to attach the volume */
674
675 #ifdef AFS_DEMAND_ATTACH_FS
676     /* check DAFS permissions */
677     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
678     if (vp &&
679         FSYNC_partMatch(vcom, vp, 1) &&
680         vp->pending_vol_op && 
681         (vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
682         /* a different program has this volume checked out. deny. */
683         Log("FSYNC_VolOn: WARNING: program type %u has attempted to manipulate "
684             "state for volume %u using command code %u while the volume is " 
685             "checked out by program type %u for command code %u.\n",
686             vcom->hdr->programType,
687             vcom->vop->volume,
688             vcom->hdr->command,
689             vp->pending_vol_op->com.programType,
690             vp->pending_vol_op->com.command);
691         code = SYNC_DENIED;
692         res->hdr.reason = FSYNC_EXCLUSIVE;
693         goto done;
694     }
695 #endif
696
697     if (vcom->v)
698         vcom->v->volumeID = 0;
699
700
701     if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
702         /* nothing much to do if we're leaving the volume offline */
703 #ifdef AFS_DEMAND_ATTACH_FS
704         if (vp) {
705             if (FSYNC_partMatch(vcom, vp, 1)) {
706                 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
707                     (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
708                     VChangeState_r(vp, VOL_STATE_UNATTACHED);
709                     VDeregisterVolOp_r(vp);
710                 } else {
711                     code = SYNC_DENIED;
712                     res->hdr.reason = FSYNC_BAD_STATE;
713                 }
714             } else {
715                 code = SYNC_DENIED;
716                 res->hdr.reason = FSYNC_WRONG_PART;
717             }
718         } else {
719             code = SYNC_DENIED;
720             res->hdr.reason = FSYNC_UNKNOWN_VOLID;
721         }
722 #endif
723         goto done;
724     }
725
726 #ifdef AFS_DEMAND_ATTACH_FS
727     /* first, check to see whether we have such a volume defined */
728     vp = VPreAttachVolumeById_r(&error,
729                                 vcom->vop->partName,
730                                 vcom->vop->volume);
731     if (vp) {
732         VDeregisterVolOp_r(vp);
733     }
734 #else /* !AFS_DEMAND_ATTACH_FS */
735     tvolName[0] = '/';
736     snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, afs_printable_uint32_lu(vcom->vop->volume));
737     tvolName[sizeof(tvolName)-1] = '\0';
738
739     vp = VAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
740                                V_VOLUPD);
741     if (vp)
742         VPutVolume_r(vp);
743     if (error) {
744         code = SYNC_DENIED;
745         res->hdr.reason = error;
746     }
747 #endif /* !AFS_DEMAND_ATTACH_FS */
748
749  done:
750     return code;
751 }
752
753 /**
754  * service an FSYNC request to take a volume offline.
755  *
756  * @param[in]   vcom  pointer command object
757  * @param[out]  res   object in which to store response packet
758  *
759  * @return operation status
760  *   @retval SYNC_OK volume transitioned offline
761  *   @retval SYNC_FAILED invalid command protocol message
762  *   @retval SYNC_DENIED operation could not be completed
763  *
764  * @note this is an FSYNC RPC server stub
765  *
766  * @note this procedure handles the following FSSYNC command codes:
767  *       - FSYNC_VOL_OFF 
768  *       - FSYNC_VOL_NEEDVOLUME
769  *
770  * @note the supplementary reason code contains additional details.
771  *       When SYNC_DENIED is returned, the specific reason is
772  *       placed in the response packet reason field.
773  *
774  * @internal
775  */
776 static afs_int32
777 FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
778 {
779     FSSYNC_VolOp_info info;
780     afs_int32 code = SYNC_OK;
781     int i;
782     Volume * vp;
783     Error error;
784 #ifdef AFS_DEMAND_ATTACH_FS
785     Volume *nvp, *rvp = NULL;
786 #endif
787
788     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
789         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
790         code = SYNC_FAILED;
791         goto done;
792     }
793
794     /* not already offline, we need to find a slot for newly offline volume */
795     if (vcom->hdr->programType == debugUtility) {
796         /* debug utilities do not have their operations tracked */
797         vcom->v = NULL;
798     } else {
799         if (!vcom->v) {
800             for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
801                 if (vcom->volumes[i].volumeID == 0) {
802                     vcom->v = &vcom->volumes[i];
803                     break;
804                 }
805             }
806         }
807         if (!vcom->v) {
808             goto deny;
809         }
810     }
811
812     FSYNC_com_to_info(vcom, &info);
813
814 #ifdef AFS_DEMAND_ATTACH_FS
815     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
816 #else
817     vp = VGetVolume_r(&error, vcom->vop->volume);
818 #endif
819
820     if (vp) {
821             if (!FSYNC_partMatch(vcom, vp, 1)) {
822             /* volume on desired partition is not online, so we
823              * should treat this as an offline volume.
824              */
825 #ifndef AFS_DEMAND_ATTACH_FS
826             VPutVolume_r(vp);
827 #endif
828             vp = NULL;
829             goto done;
830         }
831     }
832
833 #ifdef AFS_DEMAND_ATTACH_FS
834     if (vp) {
835         ProgramType type = (ProgramType) vcom->hdr->programType;
836
837         /* do initial filtering of requests */
838
839         /* enforce mutual exclusion for volume ops */
840         if (vp->pending_vol_op) {
841             if (vp->pending_vol_op->com.programType != type) {
842                 if (vp->pending_vol_op->com.command == FSYNC_VOL_OFF &&
843                     vp->pending_vol_op->com.reason == FSYNC_SALVAGE) {
844
845                     Log("denying offline request for volume %lu; volume is salvaging\n",
846                         afs_printable_uint32_lu(vp->hashid));
847
848                     res->hdr.reason = FSYNC_SALVAGE;
849                     goto deny;
850                 }
851                 Log("volume %u already checked out\n", vp->hashid);
852                 /* XXX debug */
853                 Log("vp->vop = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x }, vop = { vol=%u, part='%s' } }\n",
854                     vp->pending_vol_op->com.proto_version, 
855                     vp->pending_vol_op->com.programType,
856                     vp->pending_vol_op->com.command,
857                     vp->pending_vol_op->com.reason,
858                     vp->pending_vol_op->com.command_len,
859                     vp->pending_vol_op->com.flags,
860                     vp->pending_vol_op->vop.volume,
861                     vp->pending_vol_op->vop.partName );
862                 Log("vcom = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x } , vop = { vol=%u, part='%s' } }\n",
863                     vcom->hdr->proto_version,
864                     vcom->hdr->programType,
865                     vcom->hdr->command,
866                     vcom->hdr->reason,
867                     vcom->hdr->command_len,
868                     vcom->hdr->flags,
869                     vcom->vop->volume,
870                     vcom->vop->partName);
871                 res->hdr.reason = FSYNC_EXCLUSIVE;
872                 goto deny;
873             } else {
874                 Log("warning: volume %u recursively checked out by programType id %d\n",
875                     vp->hashid, vcom->hdr->programType);
876             }
877         }
878
879         /* wait for exclusive ops, so we have an accurate picture of the
880          * vol attach state */
881         VCreateReservation_r(vp);
882         VWaitExclusiveState_r(vp);
883         rvp = vp;
884
885         /* filter based upon requestor
886          *
887          * volume utilities / volserver are not allowed to check out
888          * volumes which are in an error state
889          *
890          * unknown utility programs will be denied on principal
891          */
892         switch (type) {
893         case salvageServer:
894             /* it is possible for the salvageserver to checkout a 
895              * volume for salvage before its scheduling request
896              * has been sent to the salvageserver */
897             if (vp->salvage.requested && !vp->salvage.scheduled) {
898                 vp->salvage.scheduled = 1;
899             }
900         case debugUtility:
901             break;
902
903         case volumeUtility:
904         case volumeServer:
905             if (V_attachState(vp) == VOL_STATE_SALVAGING ||
906                 vp->salvage.requested) {
907
908                 Log("denying offline request for volume %lu; volume is in salvaging state\n",
909                     afs_printable_uint32_lu(vp->hashid));
910                 res->hdr.reason = FSYNC_SALVAGE;
911
912                 /* the volume hasn't been checked out yet by the salvager,
913                  * but we think the volume is salvaging; schedule a
914                  * a salvage to update the salvage priority */
915                 FSYNC_backgroundSalvage(vp);
916
917                 goto deny;
918             }
919             if (VIsErrorState(V_attachState(vp))) {
920                 goto deny;
921             }
922             break;
923
924         default:
925             Log("bad program type passed to FSSYNC\n");
926             goto deny;
927         }
928
929         /* short circuit for offline volume states
930          * so we can avoid I/O penalty of attachment */
931         switch (V_attachState(vp)) {
932         case VOL_STATE_UNATTACHED:
933         case VOL_STATE_PREATTACHED:
934         case VOL_STATE_SALVAGING:
935         case VOL_STATE_ERROR:
936             /* register the volume operation metadata with the volume
937              *
938              * if the volume is currently pre-attached, attach2()
939              * will evaluate the vol op metadata to determine whether
940              * attaching the volume would be safe */
941             VRegisterVolOp_r(vp, &info);
942             vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
943             goto done;
944         default:
945             break;
946         }
947
948         /* convert to heavyweight ref */
949         nvp = VGetVolumeByVp_r(&error, vp);
950         VCancelReservation_r(rvp);
951         rvp = NULL;
952
953         if (!nvp) {
954             /*
955              * It's possible for VGetVolumeByVp_r to have dropped and
956              * re-acquired VOL_LOCK, so volume state may have changed
957              * back to one of the states we tested for above. Since
958              * GetVolume can return NULL in some of those states, just
959              * test for the states again here.
960              */
961             switch (V_attachState(vp)) {
962             case VOL_STATE_UNATTACHED:
963             case VOL_STATE_PREATTACHED:
964             case VOL_STATE_SALVAGING:
965             case VOL_STATE_ERROR:
966                 /* register the volume operation metadata with the volume
967                  *
968                  * if the volume is currently pre-attached, attach2()
969                  * will evaluate the vol op metadata to determine whether
970                  * attaching the volume would be safe */
971                 VRegisterVolOp_r(vp, &info);
972                 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
973                 goto done;
974             default:
975                 break;
976             }
977
978             Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
979                 vcom->vop->volume);
980             res->hdr.reason = FSYNC_VOL_PKG_ERROR;
981             goto deny;
982         } else if (nvp != vp) {
983             /* i don't think this should ever happen, but just in case... */
984             Log("FSYNC_com_VolOff: warning: potentially dangerous race detected\n");
985             vp = nvp;
986         }
987
988         /* register the volume operation metadata with the volume */
989         VRegisterVolOp_r(vp, &info);
990
991     }
992 #endif /* AFS_DEMAND_ATTACH_FS */
993
994     if (vp) {
995         if (VVolOpLeaveOnline_r(vp, &info)) {
996             VUpdateVolume_r(&error, vp, VOL_UPDATE_WAIT);       /* At least get volume stats right */
997             if (LogLevel) {
998                 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n", 
999                     V_id(vp), V_name(vp), 
1000                     vcom->hdr->reason == V_CLONE ? "clone" : 
1001                     vcom->hdr->reason == V_READONLY ? "readonly" : 
1002                     vcom->hdr->reason == V_DUMP ? "dump" : 
1003                     vcom->hdr->reason == FSYNC_SALVAGE ? "salvage" :
1004                     "UNKNOWN");
1005             }
1006 #ifdef AFS_DEMAND_ATTACH_FS
1007             vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
1008 #endif
1009             VPutVolume_r(vp);
1010         } else {
1011             if (VVolOpSetVBusy_r(vp, &info)) {
1012                 vp->specialStatus = VBUSY;
1013             }
1014
1015             /* remember what volume we got, so we can keep track of how
1016              * many volumes the volserver or whatever is using.  Note that
1017              * vp is valid since leaveonline is only set when vp is valid.
1018              */
1019             if (vcom->v) {
1020                 vcom->v->volumeID = vcom->vop->volume;
1021                 strlcpy(vcom->v->partName, vp->partition->name, sizeof(vcom->v->partName));
1022             }
1023
1024 #ifdef AFS_DEMAND_ATTACH_FS
1025             VOfflineForVolOp_r(&error, vp, "A volume utility is running.");
1026             if (error==0) {
1027                 assert(vp->nUsers==0);
1028                 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline; 
1029             }
1030             else {
1031                 VDeregisterVolOp_r(vp);
1032                 code = SYNC_DENIED;
1033             }
1034 #else
1035             VOffline_r(vp, "A volume utility is running.");
1036 #endif
1037             vp = NULL;
1038         }
1039     }
1040     goto done;
1041
1042  deny:
1043     code = SYNC_DENIED;
1044
1045  done:
1046 #ifdef AFS_DEMAND_ATTACH_FS
1047     if (rvp) {
1048         VCancelReservation_r(rvp);
1049     }
1050 #endif
1051     return code;
1052 }
1053
1054 /**
1055  * service an FSYNC request to mark a volume as moved.
1056  *
1057  * @param[in]   vcom  pointer command object
1058  * @param[out]  res   object in which to store response packet
1059  *
1060  * @return operation status
1061  *   @retval SYNC_OK volume marked as moved to a remote server
1062  *   @retval SYNC_FAILED invalid command protocol message
1063  *   @retval SYNC_DENIED current volume state does not permit this operation
1064  *
1065  * @note this is an FSYNC RPC server stub
1066  *
1067  * @note this operation also breaks all callbacks for the given volume
1068  *
1069  * @note this procedure handles the following FSSYNC command codes:
1070  *       - FSYNC_VOL_MOVE
1071  *
1072  * @note the supplementary reason code contains additional details.  For
1073  *       instance, SYNC_OK is still returned when the partition specified
1074  *       does not match the one registered in the volume object -- reason
1075  *       will be FSYNC_WRONG_PART in this case.
1076  *
1077  * @internal
1078  */
1079 static afs_int32
1080 FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1081 {
1082     afs_int32 code = SYNC_DENIED;
1083     Error error;
1084     Volume * vp;
1085
1086     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1087         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1088         code = SYNC_FAILED;
1089         goto done;
1090     }
1091
1092     /* Yuch:  the "reason" for the move is the site it got moved to... */
1093     /* still set specialStatus so we stop sending back VBUSY.
1094      * also should still break callbacks.  Note that I don't know
1095      * how to tell if we should break all or not, so we just do it
1096      * since it doesn't matter much if we do an extra break
1097      * volume callbacks on a volume move within the same server */
1098 #ifdef AFS_DEMAND_ATTACH_FS
1099     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1100 #else
1101     vp = VGetVolume_r(&error, vcom->vop->volume);
1102 #endif
1103     if (vp) {
1104         if (FSYNC_partMatch(vcom, vp, 1)) {
1105 #ifdef AFS_DEMAND_ATTACH_FS
1106             if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1107                 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
1108 #endif
1109                 code = SYNC_OK;
1110                 vp->specialStatus = VMOVED;
1111 #ifdef AFS_DEMAND_ATTACH_FS
1112             } else {
1113                 res->hdr.reason = FSYNC_BAD_STATE;
1114             }
1115 #endif
1116         } else {
1117             res->hdr.reason = FSYNC_WRONG_PART;
1118         }
1119 #ifndef AFS_DEMAND_ATTACH_FS
1120         VPutVolume_r(vp);
1121 #endif /* !AFS_DEMAND_ATTACH_FS */
1122     } else {
1123         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1124     }
1125
1126     if ((code == SYNC_OK) && (V_BreakVolumeCallbacks != NULL)) {
1127         Log("fssync: volume %u moved to %x; breaking all call backs\n",
1128             vcom->vop->volume, vcom->hdr->reason);
1129         VOL_UNLOCK;
1130         (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1131         VOL_LOCK;
1132     }
1133
1134
1135  done:
1136     return code;
1137 }
1138
1139 /**
1140  * service an FSYNC request to mark a volume as destroyed.
1141  *
1142  * @param[in]   vcom  pointer command object
1143  * @param[out]  res   object in which to store response packet
1144  *
1145  * @return operation status
1146  *   @retval SYNC_OK volume marked as destroyed
1147  *   @retval SYNC_FAILED invalid command protocol message
1148  *   @retval SYNC_DENIED current volume state does not permit this operation
1149  *
1150  * @note this is an FSYNC RPC server stub
1151  *
1152  * @note this procedure handles the following FSSYNC command codes:
1153  *       - FSYNC_VOL_DONE
1154  *
1155  * @note the supplementary reason code contains additional details.  For
1156  *       instance, SYNC_OK is still returned when the partition specified
1157  *       does not match the one registered in the volume object -- reason
1158  *       will be FSYNC_WRONG_PART in this case.
1159  *
1160  * @internal
1161  */
1162 static afs_int32
1163 FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1164 {
1165     afs_int32 code = SYNC_FAILED;
1166 #ifdef AFS_DEMAND_ATTACH_FS
1167     Error error;
1168     Volume * vp;
1169 #endif
1170
1171     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1172         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1173         goto done;
1174     }
1175
1176     /* don't try to put online, this call is made only after deleting
1177      * a volume, in which case we want to remove the vol # from the
1178      * OfflineVolumes array only */
1179     if (vcom->v)
1180         vcom->v->volumeID = 0;
1181
1182 #ifdef AFS_DEMAND_ATTACH_FS
1183     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1184     if (vp) {
1185         if (FSYNC_partMatch(vcom, vp, 1)) {
1186             if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1187                 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
1188                 VChangeState_r(vp, VOL_STATE_UNATTACHED);
1189                 VDeregisterVolOp_r(vp);
1190                 code = SYNC_OK;
1191             } else {
1192                 code = SYNC_DENIED;
1193                 res->hdr.reason = FSYNC_BAD_STATE;
1194             }
1195         } else {
1196             code = SYNC_OK; /* XXX is this really a good idea? */
1197             res->hdr.reason = FSYNC_WRONG_PART;
1198         }
1199     } else {
1200         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1201     }
1202 #endif
1203
1204  done:
1205     return code;
1206 }
1207
1208 #ifdef AFS_DEMAND_ATTACH_FS
1209 /**
1210  * service an FSYNC request to transition a volume to the hard error state.
1211  *
1212  * @param[in]   vcom  pointer command object
1213  * @param[out]  res   object in which to store response packet
1214  *
1215  * @return operation status
1216  *   @retval SYNC_OK volume transitioned to hard error state
1217  *   @retval SYNC_FAILED invalid command protocol message
1218  *   @retval SYNC_DENIED (see note)
1219  *
1220  * @note this is an FSYNC RPC server stub
1221  *
1222  * @note this procedure handles the following FSSYNC command codes:
1223  *       - FSYNC_VOL_FORCE_ERROR
1224  *
1225  * @note SYNC_DENIED is returned in the following cases:
1226  *        - no partition name is specified (reason field set to
1227  *          FSYNC_WRONG_PART).
1228  *        - volume id not known to fileserver (reason field set
1229  *          to FSYNC_UNKNOWN_VOLID).
1230  *
1231  * @note demand attach fileserver only
1232  *
1233  * @internal
1234  */
1235 static afs_int32
1236 FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1237 {
1238     Error error;
1239     Volume * vp;
1240     afs_int32 code = SYNC_FAILED;
1241
1242     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1243         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1244         goto done;
1245     }
1246
1247     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1248     if (vp) {
1249         if (FSYNC_partMatch(vcom, vp, 0)) {
1250             /* null out salvsync control state, as it's no longer relevant */
1251             memset(&vp->salvage, 0, sizeof(vp->salvage));
1252             VDeregisterVolOp_r(vp);
1253
1254             if (vcom->hdr->reason == FSYNC_SALVAGE) {
1255                 FSYNC_backgroundSalvage(vp);
1256             } else {
1257                 VChangeState_r(vp, VOL_STATE_ERROR);
1258             }
1259
1260             code = SYNC_OK;
1261         } else {
1262             res->hdr.reason = FSYNC_WRONG_PART;
1263         }
1264     } else {
1265         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1266     }
1267
1268  done:
1269     return code;
1270 }
1271 #endif /* AFS_DEMAND_ATTACH_FS */
1272
1273 /**
1274  * service an FSYNC request to break all callbacks for this volume.
1275  *
1276  * @param[in]   vcom  pointer command object
1277  * @param[out]  res   object in which to store response packet
1278  *
1279  * @return operation status
1280  *   @retval SYNC_OK callback breaks scheduled for volume
1281  *
1282  * @note this is an FSYNC RPC server stub
1283  *
1284  * @note this procedure handles the following FSSYNC command codes:
1285  *       - FSYNC_VOL_BREAKCBKS
1286  *
1287  * @note demand attach fileserver only
1288  *
1289  * @todo should do partition matching
1290  *
1291  * @internal
1292  */
1293 static afs_int32
1294 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1295 {
1296     /* if the volume is being restored, break all callbacks on it */
1297     if (V_BreakVolumeCallbacks) {
1298         Log("fssync: breaking all call backs for volume %u\n",
1299             vcom->vop->volume);
1300         VOL_UNLOCK;
1301         (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1302         VOL_LOCK;
1303     }
1304     return SYNC_OK;
1305 }
1306
1307 /**
1308  * service an FSYNC request to return the Volume object.
1309  *
1310  * @param[in]   vcom  pointer command object
1311  * @param[out]  res   object in which to store response packet
1312  *
1313  * @return operation status
1314  *   @retval SYNC_OK      volume object returned to caller
1315  *   @retval SYNC_FAILED  bad command packet, or failed to locate volume object
1316  *
1317  * @note this is an FSYNC RPC server stub
1318  *
1319  * @note this procedure handles the following FSSYNC command codes:
1320  *       - FSYNC_VOL_QUERY
1321  *
1322  * @internal
1323  */
1324 static afs_int32
1325 FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1326 {
1327     afs_int32 code = SYNC_FAILED;
1328     Error error;
1329     Volume * vp;
1330
1331     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1332         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1333         goto done;
1334     }
1335
1336 #ifdef AFS_DEMAND_ATTACH_FS
1337     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1338 #else /* !AFS_DEMAND_ATTACH_FS */
1339     vp = VGetVolume_r(&error, vcom->vop->volume);
1340 #endif /* !AFS_DEMAND_ATTACH_FS */
1341
1342     if (vp) {
1343         if (FSYNC_partMatch(vcom, vp, 1)) {
1344             if (res->payload.len >= sizeof(Volume)) {
1345                 memcpy(res->payload.buf, vp, sizeof(Volume));
1346                 res->hdr.response_len += sizeof(Volume);
1347                 code = SYNC_OK;
1348             } else {
1349                 res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1350             }
1351         } else {
1352             res->hdr.reason = FSYNC_WRONG_PART;
1353         }
1354 #ifndef AFS_DEMAND_ATTACH_FS
1355         VPutVolume_r(vp);
1356 #endif
1357     } else {
1358         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1359     }
1360
1361  done:
1362     return code;
1363 }
1364
1365 /**
1366  * service an FSYNC request to return the Volume header.
1367  *
1368  * @param[in]   vcom  pointer command object
1369  * @param[out]  res   object in which to store response packet
1370  *
1371  * @return operation status
1372  *   @retval SYNC_OK volume header returned to caller
1373  *   @retval SYNC_FAILED  bad command packet, or failed to locate volume header
1374  *
1375  * @note this is an FSYNC RPC server stub
1376  *
1377  * @note this procedure handles the following FSSYNC command codes:
1378  *       - FSYNC_VOL_QUERY_HDR
1379  *
1380  * @internal
1381  */
1382 static afs_int32
1383 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1384 {
1385     afs_int32 code = SYNC_FAILED;
1386     Error error;
1387     Volume * vp;
1388
1389     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1390         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1391         goto done;
1392     }
1393     if (res->payload.len < sizeof(VolumeDiskData)) {
1394         res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1395         goto done;
1396     }
1397
1398 #ifdef AFS_DEMAND_ATTACH_FS
1399     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1400 #else /* !AFS_DEMAND_ATTACH_FS */
1401     vp = VGetVolume_r(&error, vcom->vop->volume);
1402 #endif
1403
1404     if (vp) {
1405         if (FSYNC_partMatch(vcom, vp, 1)) {
1406 #ifdef AFS_DEMAND_ATTACH_FS
1407             if ((vp->header == NULL) ||
1408                 !(V_attachFlags(vp) & VOL_HDR_ATTACHED) ||
1409                 !(V_attachFlags(vp) & VOL_HDR_LOADED)) {
1410                 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1411                 goto cleanup;
1412             }
1413 #else /* !AFS_DEMAND_ATTACH_FS */
1414             if (!vp || !vp->header) {
1415                 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1416                 goto cleanup;
1417             }
1418 #endif /* !AFS_DEMAND_ATTACH_FS */
1419         } else {
1420             res->hdr.reason = FSYNC_WRONG_PART;
1421             goto cleanup;
1422         }
1423     } else {
1424         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1425         goto done;
1426     }
1427
1428     memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
1429     res->hdr.response_len += sizeof(VolumeDiskData);
1430     code = SYNC_OK;
1431
1432  cleanup:
1433 #ifndef AFS_DEMAND_ATTACH_FS
1434     VPutVolume_r(vp);
1435 #endif
1436
1437  done:
1438     return code;
1439 }
1440
1441 #ifdef AFS_DEMAND_ATTACH_FS
1442 static afs_int32
1443 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1444 {
1445     afs_int32 code = SYNC_OK;
1446     Error error;
1447     Volume * vp;
1448
1449     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1450
1451     if (vp && vp->pending_vol_op) {
1452         assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
1453         memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
1454         res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
1455     } else {
1456         if (vp) {
1457             res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
1458         } else {
1459             res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1460         }
1461         code = SYNC_FAILED;
1462     }
1463     return code;
1464 }
1465
1466 static afs_int32
1467 FSYNC_com_VGQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1468 {
1469     afs_int32 code = SYNC_FAILED;
1470     int rc;
1471     struct DiskPartition64 * dp;
1472
1473     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1474         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1475         goto done;
1476     }
1477
1478     dp = VGetPartition_r(vcom->vop->partName, 0);
1479     if (dp == NULL) {
1480         res->hdr.reason = FSYNC_BAD_PART;
1481         goto done;
1482     }
1483
1484     assert(sizeof(FSSYNC_VGQry_response_t) <= res->payload.len);
1485
1486     rc = VVGCache_query_r(dp, vcom->vop->volume, res->payload.buf);
1487     switch (rc) {
1488     case 0:
1489         res->hdr.response_len += sizeof(FSSYNC_VGQry_response_t);
1490         code = SYNC_OK;
1491         break;
1492     case EAGAIN:
1493         res->hdr.reason = FSYNC_PART_SCANNING;
1494         break;
1495     case ENOENT:
1496         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1497         break;
1498     default:
1499         break;
1500     }
1501
1502  done:
1503     return code;
1504 }
1505
1506 static afs_int32
1507 FSYNC_com_VGUpdate(SYNC_command * com, SYNC_response * res)
1508 {
1509     afs_int32 code = SYNC_FAILED;
1510     struct DiskPartition64 * dp;
1511     FSSYNC_VGUpdate_command_t * vgucom;
1512     int rc;
1513
1514     if (com->recv_len != (sizeof(com->hdr) + sizeof(*vgucom))) {
1515         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1516         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1517         code = SYNC_COM_ERROR;
1518         goto done;
1519     }
1520
1521     vgucom = com->payload.buf;
1522
1523     if (SYNC_verifyProtocolString(vgucom->partName, sizeof(vgucom->partName))) {
1524         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1525         goto done;
1526     }
1527
1528     dp = VGetPartition_r(vgucom->partName, 0);
1529     if (dp == NULL) {
1530         res->hdr.reason = FSYNC_BAD_PART;
1531         goto done;
1532     }
1533
1534     switch(com->hdr.command) {
1535     case FSYNC_VG_ADD:
1536         rc = VVGCache_entry_add_r(dp, vgucom->parent, vgucom->child, NULL);
1537         break;
1538
1539     case FSYNC_VG_DEL:
1540         rc = VVGCache_entry_del_r(dp, vgucom->parent, vgucom->child);
1541         break;
1542
1543     default:
1544         Log("FSYNC_com_VGUpdate called improperly\n");
1545         rc = -1;
1546         break;
1547     }
1548
1549     /* EINVAL means the partition VGC doesn't exist at all; not really
1550      * an error */
1551     if (rc == 0 || rc == EINVAL) {
1552         code = SYNC_OK;
1553     }
1554
1555     if (rc == ENOENT) {
1556         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1557     } else {
1558         res->hdr.reason = FSYNC_WHATEVER;
1559     }
1560
1561  done:
1562     return code;
1563 }
1564
1565 static afs_int32
1566 FSYNC_com_VGScan(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1567 {
1568     afs_int32 code = SYNC_FAILED;
1569     struct DiskPartition64 * dp;
1570
1571     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1572         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1573         goto done;
1574     }
1575
1576     dp = VGetPartition_r(vcom->vop->partName, 0);
1577     if (dp == NULL) {
1578         res->hdr.reason = FSYNC_BAD_PART;
1579         goto done;
1580     }
1581
1582     if (VVGCache_scanStart_r(dp) == 0) {
1583         code = SYNC_OK;
1584     }
1585
1586  done:
1587     return code;
1588 }
1589
1590 static afs_int32
1591 FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res)
1592 {
1593     afs_int32 code = SYNC_FAILED;
1594
1595     if (VVGCache_scanStart_r(NULL) == 0) {
1596         code = SYNC_OK;
1597     }
1598
1599     return code;
1600 }
1601 #endif /* AFS_DEMAND_ATTACH_FS */
1602
1603 static afs_int32
1604 FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res)
1605 {
1606     afs_int32 code = SYNC_OK;
1607     FSSYNC_VnQry_hdr * qry = com->payload.buf;
1608     Volume * vp;
1609     Vnode * vnp;
1610     Error error;
1611
1612     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
1613         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1614         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1615         return SYNC_COM_ERROR;
1616     }
1617
1618 #ifdef AFS_DEMAND_ATTACH_FS
1619     vp = VLookupVolume_r(&error, qry->volume, NULL);
1620 #else /* !AFS_DEMAND_ATTACH_FS */
1621     vp = VGetVolume_r(&error, qry->volume);
1622 #endif /* !AFS_DEMAND_ATTACH_FS */
1623
1624     if (!vp) {
1625         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1626         code = SYNC_FAILED;
1627         goto done;
1628     }
1629
1630     vnp = VLookupVnode(vp, qry->vnode);
1631     if (!vnp) {
1632         res->hdr.reason = FSYNC_UNKNOWN_VNID;
1633         code = SYNC_FAILED;
1634         goto cleanup;
1635     }
1636
1637     if (Vn_class(vnp)->residentSize > res->payload.len) {
1638         res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
1639         code = SYNC_FAILED;
1640         goto cleanup;
1641     }
1642
1643     memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
1644     res->hdr.response_len += Vn_class(vnp)->residentSize;
1645
1646  cleanup:
1647 #ifndef AFS_DEMAND_ATTACH_FS
1648     VPutVolume_r(vp);
1649 #endif
1650
1651  done:
1652     return code;
1653 }
1654
1655 static afs_int32
1656 FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
1657 {
1658     afs_int32 code = SYNC_OK;
1659     FSSYNC_StatsOp_command scom;
1660
1661     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_StatsOp_hdr))) {
1662         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1663         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1664         return SYNC_COM_ERROR;
1665     }
1666
1667     scom.hdr = &com->hdr;
1668     scom.sop = (FSSYNC_StatsOp_hdr *) com->payload.buf;
1669     scom.com = com;
1670
1671     switch (com->hdr.command) {
1672     case FSYNC_VOL_STATS_GENERAL:
1673         code = FSYNC_com_StatsOpGeneral(&scom, res);
1674         break;
1675 #ifdef AFS_DEMAND_ATTACH_FS
1676         /* statistics for the following subsystems are only tracked
1677          * for demand attach fileservers */
1678     case FSYNC_VOL_STATS_VICEP:
1679         code = FSYNC_com_StatsOpViceP(&scom, res);
1680         break;
1681     case FSYNC_VOL_STATS_HASH:
1682         code = FSYNC_com_StatsOpHash(&scom, res);
1683         break;
1684     case FSYNC_VOL_STATS_HDR:
1685         code = FSYNC_com_StatsOpHdr(&scom, res);
1686         break;
1687     case FSYNC_VOL_STATS_VLRU:
1688         code = FSYNC_com_StatsOpVLRU(&scom, res);
1689         break;
1690 #endif /* AFS_DEMAND_ATTACH_FS */
1691     default:
1692         code = SYNC_BAD_COMMAND;
1693     }
1694
1695     return code;
1696 }
1697
1698 static afs_int32
1699 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1700 {
1701     afs_int32 code = SYNC_OK;
1702
1703     memcpy(res->payload.buf, &VStats, sizeof(VStats));
1704     res->hdr.response_len += sizeof(VStats);
1705
1706     return code;
1707 }
1708
1709 #ifdef AFS_DEMAND_ATTACH_FS
1710 static afs_int32
1711 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1712 {
1713     afs_int32 code = SYNC_OK;
1714     struct DiskPartition64 * dp;
1715     struct DiskPartitionStats64 * stats;
1716
1717     if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
1718         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1719         code = SYNC_FAILED;
1720         goto done;
1721     }
1722
1723     dp = VGetPartition_r(scom->sop->args.partName, 0);
1724     if (!dp) {
1725         code = SYNC_FAILED;
1726     } else {
1727         stats = (struct DiskPartitionStats64 *) res->payload.buf;
1728         stats->free = dp->free;
1729         stats->totalUsable = dp->totalUsable;
1730         stats->minFree = dp->minFree;
1731         stats->f_files = dp->f_files;
1732         stats->vol_list_len = dp->vol_list.len;
1733         
1734         res->hdr.response_len += sizeof(struct DiskPartitionStats64);
1735     }
1736
1737  done:
1738     return code;
1739 }
1740
1741 static afs_int32
1742 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1743 {
1744     afs_int32 code = SYNC_OK;
1745     struct VolumeHashChainStats * stats;
1746     struct VolumeHashChainHead * head;
1747
1748     if (scom->sop->args.hash_bucket >= VolumeHashTable.Size) {
1749         return SYNC_FAILED;
1750     }
1751
1752     head = &VolumeHashTable.Table[scom->sop->args.hash_bucket];
1753     stats = (struct VolumeHashChainStats *) res->payload.buf;
1754     stats->table_size = VolumeHashTable.Size;
1755     stats->chain_len = head->len;
1756     stats->chain_cacheCheck = head->cacheCheck;
1757     stats->chain_busy = head->busy;
1758     AssignInt64(head->looks, &stats->chain_looks);
1759     AssignInt64(head->gets, &stats->chain_gets);
1760     AssignInt64(head->reorders, &stats->chain_reorders);
1761
1762     res->hdr.response_len += sizeof(struct VolumeHashChainStats);
1763     
1764     return code;
1765 }
1766
1767 static afs_int32
1768 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1769 {
1770     afs_int32 code = SYNC_OK;
1771
1772     memcpy(res->payload.buf, &volume_hdr_LRU.stats, sizeof(volume_hdr_LRU.stats));
1773     res->hdr.response_len += sizeof(volume_hdr_LRU.stats);
1774
1775     return code;
1776 }
1777
1778 static afs_int32
1779 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1780 {
1781     afs_int32 code = SYNC_OK;
1782
1783     code = SYNC_BAD_COMMAND;
1784
1785     return code;
1786 }
1787 #endif /* AFS_DEMAND_ATTACH_FS */
1788
1789 /**
1790  * populate an FSSYNC_VolOp_info object from a command packet object.
1791  *
1792  * @param[in]   vcom  pointer to command packet
1793  * @param[out]  info  pointer to info object which will be populated
1794  *
1795  * @note FSSYNC_VolOp_info objects are attached to Volume objects when
1796  *       a volume operation is commenced.
1797  *
1798  * @internal
1799  */
1800 static void
1801 FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
1802 {
1803     memcpy(&info->com, vcom->hdr, sizeof(SYNC_command_hdr));
1804     memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
1805     info->vol_op_state = FSSYNC_VolOpPending;
1806 }
1807
1808 /**
1809  * check whether command packet partition name matches volume 
1810  * object's partition name.
1811  *
1812  * @param[in] vcom        pointer to command packet
1813  * @param[in] vp          pointer to volume object
1814  * @param[in] match_anon  anon matching control flag (see note below)
1815  *
1816  * @return whether partitions match
1817  *   @retval 0  partitions do NOT match
1818  *   @retval 1  partitions match
1819  *
1820  * @note if match_anon is non-zero, then this function will return a
1821  *       positive match for a zero-length partition string in the
1822  *       command packet.
1823  *
1824  * @internal
1825  */
1826 static int 
1827 FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon)
1828 {
1829     return ((match_anon && vcom->vop->partName[0] == 0) ||
1830             (strncmp(vcom->vop->partName, V_partition(vp)->name, 
1831                      sizeof(vcom->vop->partName)) == 0));
1832 }
1833
1834
1835 static void
1836 FSYNC_Drop(osi_socket fd)
1837 {
1838     struct offlineInfo *p;
1839     int i;
1840     Error error;
1841     char tvolName[VMAXPATHLEN];
1842
1843     VOL_LOCK;
1844     p = OfflineVolumes[FindHandler(fd)];
1845     for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
1846         if (p[i].volumeID) {
1847
1848             Volume *vp;
1849
1850             tvolName[0] = '/';
1851             sprintf(&tvolName[1], VFORMAT, afs_printable_uint32_lu(p[i].volumeID));
1852             vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
1853                                        V_VOLUPD);
1854             if (vp)
1855                 VPutVolume_r(vp);
1856             p[i].volumeID = 0;
1857         }
1858     }
1859     VOL_UNLOCK;
1860     RemoveHandler(fd);
1861 #ifdef AFS_NT40_ENV
1862     closesocket(fd);
1863 #else
1864     close(fd);
1865 #endif
1866     AcceptOn();
1867 }
1868
1869 static int AcceptHandler = -1;  /* handler id for accept, if turned on */
1870
1871 static void
1872 AcceptOn(void)
1873 {
1874     if (AcceptHandler == -1) {
1875         assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
1876         AcceptHandler = FindHandler(fssync_server_state.fd);
1877     }
1878 }
1879
1880 static void
1881 AcceptOff(void)
1882 {
1883     if (AcceptHandler != -1) {
1884         assert(RemoveHandler(fssync_server_state.fd));
1885         AcceptHandler = -1;
1886     }
1887 }
1888
1889 /* The multiple FD handling code. */
1890
1891 static osi_socket HandlerFD[MAXHANDLERS];
1892 static void (*HandlerProc[MAXHANDLERS]) (osi_socket);
1893
1894 static void
1895 InitHandler(void)
1896 {
1897     register int i;
1898     ObtainWriteLock(&FSYNC_handler_lock);
1899     for (i = 0; i < MAXHANDLERS; i++) {
1900         HandlerFD[i] = -1;
1901         HandlerProc[i] = 0;
1902     }
1903     ReleaseWriteLock(&FSYNC_handler_lock);
1904 }
1905
1906 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1907 static void
1908 CallHandler(struct pollfd *fds, int nfds, int mask)
1909 {
1910     int i;
1911     int handler;
1912     ObtainReadLock(&FSYNC_handler_lock);
1913     for (i = 0; i < nfds; i++) {
1914         if (fds[i].revents & mask) {
1915             handler = FindHandler_r(fds[i].fd);
1916             ReleaseReadLock(&FSYNC_handler_lock);
1917             (*HandlerProc[handler]) (fds[i].fd);
1918             ObtainReadLock(&FSYNC_handler_lock);
1919         }
1920     }
1921     ReleaseReadLock(&FSYNC_handler_lock);
1922 }
1923 #else
1924 static void
1925 CallHandler(fd_set * fdsetp)
1926 {
1927     register int i;
1928     ObtainReadLock(&FSYNC_handler_lock);
1929     for (i = 0; i < MAXHANDLERS; i++) {
1930         if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
1931             ReleaseReadLock(&FSYNC_handler_lock);
1932             (*HandlerProc[i]) (HandlerFD[i]);
1933             ObtainReadLock(&FSYNC_handler_lock);
1934         }
1935     }
1936     ReleaseReadLock(&FSYNC_handler_lock);
1937 }
1938 #endif
1939
1940 static int
1941 AddHandler(osi_socket afd, void (*aproc) (osi_socket))
1942 {
1943     register int i;
1944     ObtainWriteLock(&FSYNC_handler_lock);
1945     for (i = 0; i < MAXHANDLERS; i++)
1946         if (HandlerFD[i] == -1)
1947             break;
1948     if (i >= MAXHANDLERS) {
1949         ReleaseWriteLock(&FSYNC_handler_lock);
1950         return 0;
1951     }
1952     HandlerFD[i] = afd;
1953     HandlerProc[i] = aproc;
1954     ReleaseWriteLock(&FSYNC_handler_lock);
1955     return 1;
1956 }
1957
1958 static int
1959 FindHandler(register osi_socket afd)
1960 {
1961     register int i;
1962     ObtainReadLock(&FSYNC_handler_lock);
1963     for (i = 0; i < MAXHANDLERS; i++)
1964         if (HandlerFD[i] == afd) {
1965             ReleaseReadLock(&FSYNC_handler_lock);
1966             return i;
1967         }
1968     ReleaseReadLock(&FSYNC_handler_lock);       /* just in case */
1969     assert(1 == 2);
1970     return -1;                  /* satisfy compiler */
1971 }
1972
1973 static int
1974 FindHandler_r(register osi_socket afd)
1975 {
1976     register int i;
1977     for (i = 0; i < MAXHANDLERS; i++)
1978         if (HandlerFD[i] == afd) {
1979             return i;
1980         }
1981     assert(1 == 2);
1982     return -1;                  /* satisfy compiler */
1983 }
1984
1985 static int
1986 RemoveHandler(register osi_socket afd)
1987 {
1988     ObtainWriteLock(&FSYNC_handler_lock);
1989     HandlerFD[FindHandler_r(afd)] = -1;
1990     ReleaseWriteLock(&FSYNC_handler_lock);
1991     return 1;
1992 }
1993
1994 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1995 static void
1996 GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
1997 {
1998     int i;
1999     int fdi = 0;
2000     ObtainReadLock(&FSYNC_handler_lock);
2001     for (i = 0; i < MAXHANDLERS; i++)
2002         if (HandlerFD[i] != -1) {
2003             assert(fdi<maxfds);
2004             fds[fdi].fd = HandlerFD[i];
2005             fds[fdi].events = events;
2006             fds[fdi].revents = 0;
2007             fdi++;
2008         }
2009     *nfds = fdi;
2010     ReleaseReadLock(&FSYNC_handler_lock);
2011 }
2012 #else
2013 static void
2014 GetHandler(fd_set * fdsetp, int *maxfdp)
2015 {
2016     register int i;
2017     register int maxfd = -1;
2018     FD_ZERO(fdsetp);
2019     ObtainReadLock(&FSYNC_handler_lock);        /* just in case */
2020     for (i = 0; i < MAXHANDLERS; i++)
2021         if (HandlerFD[i] != -1) {
2022             FD_SET(HandlerFD[i], fdsetp);
2023 #ifndef AFS_NT40_ENV
2024             /* On Windows the nfds parameter to select() is ignored */
2025             if (maxfd < HandlerFD[i] || maxfd == (int)-1)
2026                 maxfd = HandlerFD[i];
2027 #endif /* AFS_NT40_ENV */
2028         }
2029     *maxfdp = maxfd;
2030     ReleaseReadLock(&FSYNC_handler_lock);       /* just in case */
2031 }
2032 #endif /* HAVE_POLL && AFS_PTHREAD_ENV */
2033
2034 #endif /* FSSYNC_BUILD_SERVER */