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