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