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