d08791006742ce317a0be975f5f85405e8b2d7d3
[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     { -1,                       /* 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 == -1) {
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         case debugUtility:
926             break;
927
928         case volumeUtility:
929         case volumeServer:
930             if (V_attachState(vp) == VOL_STATE_SALVAGING ||
931                 vp->salvage.requested) {
932
933                 Log("denying offline request for volume %lu; volume is in salvaging state\n",
934                     afs_printable_uint32_lu(vp->hashid));
935                 res->hdr.reason = FSYNC_SALVAGE;
936
937                 /* the volume hasn't been checked out yet by the salvager,
938                  * but we think the volume is salvaging; schedule a
939                  * a salvage to update the salvage priority */
940                 FSYNC_backgroundSalvage(vp);
941
942                 goto deny;
943             }
944             if (VIsErrorState(V_attachState(vp))) {
945                 goto deny;
946             }
947             break;
948
949         default:
950             Log("bad program type passed to FSSYNC\n");
951             goto deny;
952         }
953
954         /* short circuit for offline volume states
955          * so we can avoid I/O penalty of attachment */
956         switch (V_attachState(vp)) {
957         case VOL_STATE_UNATTACHED:
958         case VOL_STATE_PREATTACHED:
959         case VOL_STATE_SALVAGING:
960         case VOL_STATE_ERROR:
961             /* register the volume operation metadata with the volume
962              *
963              * if the volume is currently pre-attached, attach2()
964              * will evaluate the vol op metadata to determine whether
965              * attaching the volume would be safe */
966             VRegisterVolOp_r(vp, &info);
967             vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
968             goto done;
969         default:
970             break;
971         }
972
973         /* convert to heavyweight ref */
974         nvp = VGetVolumeByVp_r(&error, vp);
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         /* kill off lightweight ref to ensure we can't deadlock against ourselves later... */
1011         VCancelReservation_r(rvp);
1012         rvp = NULL;
1013
1014         /* register the volume operation metadata with the volume */
1015         VRegisterVolOp_r(vp, &info);
1016
1017     }
1018 #endif /* AFS_DEMAND_ATTACH_FS */
1019
1020     if (vp) {
1021         if (VVolOpLeaveOnline_r(vp, &info)) {
1022             VUpdateVolume_r(&error, vp, VOL_UPDATE_WAIT);       /* At least get volume stats right */
1023             if (LogLevel) {
1024                 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n",
1025                     V_id(vp), V_name(vp),
1026                     vcom->hdr->reason == V_CLONE ? "clone" :
1027                     vcom->hdr->reason == V_READONLY ? "readonly" :
1028                     vcom->hdr->reason == V_DUMP ? "dump" :
1029                     vcom->hdr->reason == FSYNC_SALVAGE ? "salvage" :
1030                     "UNKNOWN");
1031             }
1032 #ifdef AFS_DEMAND_ATTACH_FS
1033             vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
1034 #endif
1035             VPutVolume_r(vp);
1036         } else {
1037             if (VVolOpSetVBusy_r(vp, &info)) {
1038                 vp->specialStatus = VBUSY;
1039             }
1040
1041             /* remember what volume we got, so we can keep track of how
1042              * many volumes the volserver or whatever is using.  Note that
1043              * vp is valid since leaveonline is only set when vp is valid.
1044              */
1045             if (vcom->v) {
1046                 vcom->v->volumeID = vcom->vop->volume;
1047                 strlcpy(vcom->v->partName, vp->partition->name, sizeof(vcom->v->partName));
1048             }
1049
1050 #ifdef AFS_DEMAND_ATTACH_FS
1051             VOfflineForVolOp_r(&error, vp, "A volume utility is running.");
1052             if (error==0) {
1053                 osi_Assert(vp->nUsers==0);
1054                 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline;
1055             }
1056             else {
1057                 VDeregisterVolOp_r(vp);
1058                 code = SYNC_DENIED;
1059             }
1060 #else
1061             VOffline_r(vp, "A volume utility is running.");
1062 #endif
1063             vp = NULL;
1064         }
1065     }
1066     goto done;
1067
1068  deny:
1069     code = SYNC_DENIED;
1070
1071  done:
1072 #ifdef AFS_DEMAND_ATTACH_FS
1073     if (rvp) {
1074         VCancelReservation_r(rvp);
1075     }
1076 #endif
1077     return code;
1078 }
1079
1080 /**
1081  * service an FSYNC request to mark a volume as moved.
1082  *
1083  * @param[in]   vcom  pointer command object
1084  * @param[out]  res   object in which to store response packet
1085  *
1086  * @return operation status
1087  *   @retval SYNC_OK volume marked as moved to a remote server
1088  *   @retval SYNC_FAILED invalid command protocol message
1089  *   @retval SYNC_DENIED current volume state does not permit this operation
1090  *
1091  * @note this is an FSYNC RPC server stub
1092  *
1093  * @note this operation also breaks all callbacks for the given volume
1094  *
1095  * @note this procedure handles the following FSSYNC command codes:
1096  *       - FSYNC_VOL_MOVE
1097  *
1098  * @note the supplementary reason code contains additional details.  For
1099  *       instance, SYNC_OK is still returned when the partition specified
1100  *       does not match the one registered in the volume object -- reason
1101  *       will be FSYNC_WRONG_PART in this case.
1102  *
1103  * @internal
1104  */
1105 static afs_int32
1106 FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1107 {
1108     afs_int32 code = SYNC_DENIED;
1109     Error error;
1110     Volume * vp;
1111
1112     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1113         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1114         code = SYNC_FAILED;
1115         goto done;
1116     }
1117
1118     /* Yuch:  the "reason" for the move is the site it got moved to... */
1119     /* still set specialStatus so we stop sending back VBUSY.
1120      * also should still break callbacks.  Note that I don't know
1121      * how to tell if we should break all or not, so we just do it
1122      * since it doesn't matter much if we do an extra break
1123      * volume callbacks on a volume move within the same server */
1124 #ifdef AFS_DEMAND_ATTACH_FS
1125     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1126 #else
1127     vp = VGetVolume_r(&error, vcom->vop->volume);
1128 #endif
1129     if (vp) {
1130         if (FSYNC_partMatch(vcom, vp, 1)) {
1131 #ifdef AFS_DEMAND_ATTACH_FS
1132             if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1133                 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
1134 #endif
1135                 code = SYNC_OK;
1136                 vp->specialStatus = VMOVED;
1137 #ifdef AFS_DEMAND_ATTACH_FS
1138             } else {
1139                 res->hdr.reason = FSYNC_BAD_STATE;
1140             }
1141 #endif
1142         } else {
1143             res->hdr.reason = FSYNC_WRONG_PART;
1144         }
1145 #ifndef AFS_DEMAND_ATTACH_FS
1146         VPutVolume_r(vp);
1147 #endif /* !AFS_DEMAND_ATTACH_FS */
1148     } else {
1149         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1150     }
1151
1152     if ((code == SYNC_OK) && (V_BreakVolumeCallbacks != NULL)) {
1153         Log("fssync: volume %u moved to %x; breaking all call backs\n",
1154             vcom->vop->volume, vcom->hdr->reason);
1155         VOL_UNLOCK;
1156         (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1157         VOL_LOCK;
1158     }
1159
1160
1161  done:
1162     return code;
1163 }
1164
1165 /**
1166  * service an FSYNC request to mark a volume as destroyed.
1167  *
1168  * @param[in]   vcom  pointer command object
1169  * @param[out]  res   object in which to store response packet
1170  *
1171  * @return operation status
1172  *   @retval SYNC_OK volume marked as destroyed
1173  *   @retval SYNC_FAILED invalid command protocol message
1174  *   @retval SYNC_DENIED current volume state does not permit this operation
1175  *
1176  * @note this is an FSYNC RPC server stub
1177  *
1178  * @note this procedure handles the following FSSYNC command codes:
1179  *       - FSYNC_VOL_DONE
1180  *
1181  * @note the supplementary reason code contains additional details.  For
1182  *       instance, SYNC_OK is still returned when the partition specified
1183  *       does not match the one registered in the volume object -- reason
1184  *       will be FSYNC_WRONG_PART in this case.
1185  *
1186  * @internal
1187  */
1188 static afs_int32
1189 FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1190 {
1191     afs_int32 code = SYNC_FAILED;
1192     Error error;
1193     Volume * vp;
1194
1195     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1196         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1197         goto done;
1198     }
1199
1200     /* don't try to put online, this call is made only after deleting
1201      * a volume, in which case we want to remove the vol # from the
1202      * OfflineVolumes array only */
1203     if (vcom->v)
1204         vcom->v->volumeID = 0;
1205
1206     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1207     if (vp) {
1208         if (FSYNC_partMatch(vcom, vp, 1)) {
1209 #ifdef AFS_DEMAND_ATTACH_FS
1210             if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1211                 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
1212
1213                 /* Change state to DELETED, not UNATTACHED, so clients get
1214                  * a VNOVOL error when they try to access from now on. */
1215
1216                 VChangeState_r(vp, VOL_STATE_DELETED);
1217                 VDeregisterVolOp_r(vp);
1218
1219                 /* Someday we should free the vp, too, after about 2 hours,
1220                  * possibly by putting the vp back on the VLRU. */
1221
1222                 code = SYNC_OK;
1223             } else {
1224                 code = SYNC_DENIED;
1225                 res->hdr.reason = FSYNC_BAD_STATE;
1226             }
1227 #else /* AFS_DEMAND_ATTACH_FS */
1228             if (!vp->specialStatus) {
1229                 vp->specialStatus = VNOVOL;
1230             }
1231             code = SYNC_OK;
1232 #endif /* !AFS_DEMAND_ATTACH_FS */
1233         } else {
1234             code = SYNC_OK; /* XXX is this really a good idea? */
1235             res->hdr.reason = FSYNC_WRONG_PART;
1236         }
1237     } else {
1238         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1239     }
1240
1241  done:
1242     return code;
1243 }
1244
1245 #ifdef AFS_DEMAND_ATTACH_FS
1246 /**
1247  * service an FSYNC request to transition a volume to the hard error state.
1248  *
1249  * @param[in]   vcom  pointer command object
1250  * @param[out]  res   object in which to store response packet
1251  *
1252  * @return operation status
1253  *   @retval SYNC_OK volume transitioned to hard error state
1254  *   @retval SYNC_FAILED invalid command protocol message
1255  *   @retval SYNC_DENIED (see note)
1256  *
1257  * @note this is an FSYNC RPC server stub
1258  *
1259  * @note this procedure handles the following FSSYNC command codes:
1260  *       - FSYNC_VOL_FORCE_ERROR
1261  *
1262  * @note SYNC_DENIED is returned in the following cases:
1263  *        - no partition name is specified (reason field set to
1264  *          FSYNC_WRONG_PART).
1265  *        - volume id not known to fileserver (reason field set
1266  *          to FSYNC_UNKNOWN_VOLID).
1267  *
1268  * @note demand attach fileserver only
1269  *
1270  * @internal
1271  */
1272 static afs_int32
1273 FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1274 {
1275     Error error;
1276     Volume * vp;
1277     afs_int32 code = SYNC_FAILED;
1278
1279     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1280         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1281         goto done;
1282     }
1283
1284     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1285
1286     if (!vp && vcom->hdr->reason == FSYNC_SALVAGE) {
1287         /* The requested volume doesn't seem to exist. However, it is possible
1288          * that this is triggered by trying to create or clone a volume that
1289          * was prevented from succeeding by a half-created volume in the way.
1290          * (e.g. we tried to create volume X, but volume X exists except that
1291          * its .vol header was deleted for some reason) So, still try to
1292          * a salvage for that volume ID. */
1293
1294         Log("FSYNC_com_VolError: attempting to schedule salvage for unknown "
1295             "volume %lu part %s\n", afs_printable_uint32_lu(vcom->vop->volume),
1296             vcom->vop->partName);
1297         vp = VPreAttachVolumeById_r(&error, vcom->vop->partName,
1298                                     vcom->vop->volume);
1299     }
1300
1301     if (vp) {
1302         if (FSYNC_partMatch(vcom, vp, 0)) {
1303             /* null out salvsync control state, as it's no longer relevant */
1304             memset(&vp->salvage, 0, sizeof(vp->salvage));
1305             VDeregisterVolOp_r(vp);
1306
1307             if (vcom->hdr->reason == FSYNC_SALVAGE) {
1308                 FSYNC_backgroundSalvage(vp);
1309             } else {
1310                 VChangeState_r(vp, VOL_STATE_ERROR);
1311             }
1312
1313             code = SYNC_OK;
1314         } else {
1315             res->hdr.reason = FSYNC_WRONG_PART;
1316         }
1317     } else {
1318         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1319     }
1320
1321  done:
1322     return code;
1323 }
1324 #endif /* AFS_DEMAND_ATTACH_FS */
1325
1326 /**
1327  * service an FSYNC request to break all callbacks for this volume.
1328  *
1329  * @param[in]   vcom  pointer command object
1330  * @param[out]  res   object in which to store response packet
1331  *
1332  * @return operation status
1333  *   @retval SYNC_OK callback breaks scheduled for volume
1334  *
1335  * @note this is an FSYNC RPC server stub
1336  *
1337  * @note this procedure handles the following FSSYNC command codes:
1338  *       - FSYNC_VOL_BREAKCBKS
1339  *
1340  * @note demand attach fileserver only
1341  *
1342  * @todo should do partition matching
1343  *
1344  * @internal
1345  */
1346 static afs_int32
1347 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1348 {
1349     /* if the volume is being restored, break all callbacks on it */
1350     if (V_BreakVolumeCallbacks) {
1351         Log("fssync: breaking all call backs for volume %u\n",
1352             vcom->vop->volume);
1353         VOL_UNLOCK;
1354         (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1355         VOL_LOCK;
1356     }
1357     return SYNC_OK;
1358 }
1359
1360 /**
1361  * service an FSYNC request to return the Volume object.
1362  *
1363  * @param[in]   vcom  pointer command object
1364  * @param[out]  res   object in which to store response packet
1365  *
1366  * @return operation status
1367  *   @retval SYNC_OK      volume object returned to caller
1368  *   @retval SYNC_FAILED  bad command packet, or failed to locate volume object
1369  *
1370  * @note this is an FSYNC RPC server stub
1371  *
1372  * @note this procedure handles the following FSSYNC command codes:
1373  *       - FSYNC_VOL_QUERY
1374  *
1375  * @internal
1376  */
1377 static afs_int32
1378 FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1379 {
1380     afs_int32 code = SYNC_FAILED;
1381     Error error;
1382     Volume * vp;
1383
1384     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1385         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1386         goto done;
1387     }
1388
1389 #ifdef AFS_DEMAND_ATTACH_FS
1390     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1391 #else /* !AFS_DEMAND_ATTACH_FS */
1392     vp = VGetVolume_r(&error, vcom->vop->volume);
1393 #endif /* !AFS_DEMAND_ATTACH_FS */
1394
1395     if (vp) {
1396         if (FSYNC_partMatch(vcom, vp, 1)) {
1397             if (res->payload.len >= sizeof(Volume)) {
1398                 memcpy(res->payload.buf, vp, sizeof(Volume));
1399                 res->hdr.response_len += sizeof(Volume);
1400                 code = SYNC_OK;
1401             } else {
1402                 res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1403             }
1404         } else {
1405             res->hdr.reason = FSYNC_WRONG_PART;
1406         }
1407 #ifndef AFS_DEMAND_ATTACH_FS
1408         VPutVolume_r(vp);
1409 #endif
1410     } else {
1411         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1412     }
1413
1414  done:
1415     return code;
1416 }
1417
1418 /**
1419  * service an FSYNC request to return the Volume header.
1420  *
1421  * @param[in]   vcom  pointer command object
1422  * @param[out]  res   object in which to store response packet
1423  *
1424  * @return operation status
1425  *   @retval SYNC_OK volume header returned to caller
1426  *   @retval SYNC_FAILED  bad command packet, or failed to locate volume header
1427  *
1428  * @note this is an FSYNC RPC server stub
1429  *
1430  * @note this procedure handles the following FSSYNC command codes:
1431  *       - FSYNC_VOL_QUERY_HDR
1432  *
1433  * @internal
1434  */
1435 static afs_int32
1436 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1437 {
1438     afs_int32 code = SYNC_FAILED;
1439     Error error;
1440     Volume * vp;
1441
1442     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1443         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1444         goto done;
1445     }
1446     if (res->payload.len < sizeof(VolumeDiskData)) {
1447         res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1448         goto done;
1449     }
1450
1451 #ifdef AFS_DEMAND_ATTACH_FS
1452     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1453 #else /* !AFS_DEMAND_ATTACH_FS */
1454     vp = VGetVolume_r(&error, vcom->vop->volume);
1455 #endif
1456
1457     if (vp) {
1458         if (FSYNC_partMatch(vcom, vp, 1)) {
1459 #ifdef AFS_DEMAND_ATTACH_FS
1460             if ((vp->header == NULL) ||
1461                 !(V_attachFlags(vp) & VOL_HDR_ATTACHED) ||
1462                 !(V_attachFlags(vp) & VOL_HDR_LOADED)) {
1463                 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1464                 goto cleanup;
1465             }
1466 #else /* !AFS_DEMAND_ATTACH_FS */
1467             if (!vp || !vp->header) {
1468                 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1469                 goto cleanup;
1470             }
1471 #endif /* !AFS_DEMAND_ATTACH_FS */
1472         } else {
1473             res->hdr.reason = FSYNC_WRONG_PART;
1474             goto cleanup;
1475         }
1476     } else {
1477         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1478         goto done;
1479     }
1480
1481     memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
1482     res->hdr.response_len += sizeof(VolumeDiskData);
1483     code = SYNC_OK;
1484
1485  cleanup:
1486 #ifndef AFS_DEMAND_ATTACH_FS
1487     VPutVolume_r(vp);
1488 #endif
1489
1490  done:
1491     return code;
1492 }
1493
1494 #ifdef AFS_DEMAND_ATTACH_FS
1495 static afs_int32
1496 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1497 {
1498     afs_int32 code = SYNC_OK;
1499     Error error;
1500     Volume * vp;
1501
1502     vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1503
1504     if (vp && vp->pending_vol_op) {
1505         osi_Assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
1506         memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
1507         res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
1508     } else {
1509         if (vp) {
1510             res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
1511         } else {
1512             res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1513         }
1514         code = SYNC_FAILED;
1515     }
1516     return code;
1517 }
1518
1519 static afs_int32
1520 FSYNC_com_VGQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1521 {
1522     afs_int32 code = SYNC_FAILED;
1523     int rc;
1524     struct DiskPartition64 * dp;
1525
1526     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1527         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1528         goto done;
1529     }
1530
1531     dp = VGetPartition_r(vcom->vop->partName, 0);
1532     if (dp == NULL) {
1533         res->hdr.reason = FSYNC_BAD_PART;
1534         goto done;
1535     }
1536
1537     osi_Assert(sizeof(FSSYNC_VGQry_response_t) <= res->payload.len);
1538
1539     rc = VVGCache_query_r(dp, vcom->vop->volume, res->payload.buf);
1540     switch (rc) {
1541     case 0:
1542         res->hdr.response_len += sizeof(FSSYNC_VGQry_response_t);
1543         code = SYNC_OK;
1544         break;
1545     case EAGAIN:
1546         res->hdr.reason = FSYNC_PART_SCANNING;
1547         break;
1548     case ENOENT:
1549         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1550         break;
1551     default:
1552         break;
1553     }
1554
1555  done:
1556     return code;
1557 }
1558
1559 static afs_int32
1560 FSYNC_com_VGUpdate(osi_socket fd, SYNC_command * com, SYNC_response * res)
1561 {
1562     afs_int32 code = SYNC_FAILED;
1563     struct DiskPartition64 * dp;
1564     FSSYNC_VGUpdate_command_t * vgucom;
1565     int rc;
1566
1567     if (com->recv_len != (sizeof(com->hdr) + sizeof(*vgucom))) {
1568         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1569         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1570         code = SYNC_COM_ERROR;
1571         goto done;
1572     }
1573
1574     vgucom = com->payload.buf;
1575
1576     ViceLog(125, ("FSYNC_com_VGUpdate: fd %d got command for parent %lu child "
1577                   "%lu partName %.16s\n", (int)fd,
1578                   afs_printable_uint32_lu(vgucom->parent),
1579                   afs_printable_uint32_lu(vgucom->child),
1580                   vgucom->partName));
1581
1582     if (SYNC_verifyProtocolString(vgucom->partName, sizeof(vgucom->partName))) {
1583         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1584         goto done;
1585     }
1586
1587     dp = VGetPartition_r(vgucom->partName, 0);
1588     if (dp == NULL) {
1589         res->hdr.reason = FSYNC_BAD_PART;
1590         goto done;
1591     }
1592
1593     switch(com->hdr.command) {
1594     case FSYNC_VG_ADD:
1595         rc = VVGCache_entry_add_r(dp, vgucom->parent, vgucom->child, NULL);
1596         break;
1597
1598     case FSYNC_VG_DEL:
1599         rc = VVGCache_entry_del_r(dp, vgucom->parent, vgucom->child);
1600         break;
1601
1602     default:
1603         Log("FSYNC_com_VGUpdate called improperly\n");
1604         rc = -1;
1605         break;
1606     }
1607
1608     /* EINVAL means the partition VGC doesn't exist at all; not really
1609      * an error */
1610     if (rc == 0 || rc == EINVAL) {
1611         code = SYNC_OK;
1612     }
1613
1614     if (rc == ENOENT) {
1615         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1616     } else {
1617         res->hdr.reason = FSYNC_WHATEVER;
1618     }
1619
1620  done:
1621     return code;
1622 }
1623
1624 static afs_int32
1625 FSYNC_com_VGScan(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1626 {
1627     afs_int32 code = SYNC_FAILED;
1628     struct DiskPartition64 * dp;
1629
1630     if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1631         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1632         goto done;
1633     }
1634
1635     dp = VGetPartition_r(vcom->vop->partName, 0);
1636     if (dp == NULL) {
1637         res->hdr.reason = FSYNC_BAD_PART;
1638         goto done;
1639     }
1640
1641     if (VVGCache_scanStart_r(dp) == 0) {
1642         code = SYNC_OK;
1643     }
1644
1645  done:
1646     return code;
1647 }
1648
1649 static afs_int32
1650 FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res)
1651 {
1652     afs_int32 code = SYNC_FAILED;
1653
1654     if (VVGCache_scanStart_r(NULL) == 0) {
1655         code = SYNC_OK;
1656     }
1657
1658     return code;
1659 }
1660 #endif /* AFS_DEMAND_ATTACH_FS */
1661
1662 static afs_int32
1663 FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res)
1664 {
1665     afs_int32 code = SYNC_OK;
1666     FSSYNC_VnQry_hdr * qry = com->payload.buf;
1667     Volume * vp;
1668     Vnode * vnp;
1669     Error error;
1670
1671     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
1672         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1673         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1674         return SYNC_COM_ERROR;
1675     }
1676
1677     ViceLog(125, ("FSYNC_com_VnQry: fd %d got command for vol %lu vnode %lu "
1678                   "uniq %lu spare %lu partName %.16s\n", (int)fd,
1679                   afs_printable_uint32_lu(qry->volume),
1680                   afs_printable_uint32_lu(qry->vnode),
1681                   afs_printable_uint32_lu(qry->unique),
1682                   afs_printable_uint32_lu(qry->spare),
1683                   qry->partName));
1684
1685 #ifdef AFS_DEMAND_ATTACH_FS
1686     vp = VLookupVolume_r(&error, qry->volume, NULL);
1687 #else /* !AFS_DEMAND_ATTACH_FS */
1688     vp = VGetVolume_r(&error, qry->volume);
1689 #endif /* !AFS_DEMAND_ATTACH_FS */
1690
1691     if (!vp) {
1692         res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1693         code = SYNC_FAILED;
1694         goto done;
1695     }
1696
1697     vnp = VLookupVnode(vp, qry->vnode);
1698     if (!vnp) {
1699         res->hdr.reason = FSYNC_UNKNOWN_VNID;
1700         code = SYNC_FAILED;
1701         goto cleanup;
1702     }
1703
1704     if (Vn_class(vnp)->residentSize > res->payload.len) {
1705         res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
1706         code = SYNC_FAILED;
1707         goto cleanup;
1708     }
1709
1710     memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
1711     res->hdr.response_len += Vn_class(vnp)->residentSize;
1712
1713  cleanup:
1714 #ifndef AFS_DEMAND_ATTACH_FS
1715     VPutVolume_r(vp);
1716 #endif
1717
1718  done:
1719     return code;
1720 }
1721
1722 static afs_int32
1723 FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
1724 {
1725     afs_int32 code = SYNC_OK;
1726     FSSYNC_StatsOp_command scom;
1727
1728     if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_StatsOp_hdr))) {
1729         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1730         res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1731         return SYNC_COM_ERROR;
1732     }
1733
1734     scom.hdr = &com->hdr;
1735     scom.sop = (FSSYNC_StatsOp_hdr *) com->payload.buf;
1736     scom.com = com;
1737
1738     ViceLog(125, ("FSYNC_com_StatsOp: fd %d got command for stats: "
1739                   "{vlru_generation = %lu, hash_bucket = %lu, partName = "
1740                   "%.16s}\n", (int)fd,
1741                   afs_printable_uint32_lu(scom.sop->args.vlru_generation),
1742                   afs_printable_uint32_lu(scom.sop->args.hash_bucket),
1743                   scom.sop->args.partName));
1744
1745     switch (com->hdr.command) {
1746     case FSYNC_VOL_STATS_GENERAL:
1747         code = FSYNC_com_StatsOpGeneral(&scom, res);
1748         break;
1749 #ifdef AFS_DEMAND_ATTACH_FS
1750         /* statistics for the following subsystems are only tracked
1751          * for demand attach fileservers */
1752     case FSYNC_VOL_STATS_VICEP:
1753         code = FSYNC_com_StatsOpViceP(&scom, res);
1754         break;
1755     case FSYNC_VOL_STATS_HASH:
1756         code = FSYNC_com_StatsOpHash(&scom, res);
1757         break;
1758     case FSYNC_VOL_STATS_HDR:
1759         code = FSYNC_com_StatsOpHdr(&scom, res);
1760         break;
1761     case FSYNC_VOL_STATS_VLRU:
1762         code = FSYNC_com_StatsOpVLRU(&scom, res);
1763         break;
1764 #endif /* AFS_DEMAND_ATTACH_FS */
1765     default:
1766         code = SYNC_BAD_COMMAND;
1767     }
1768
1769     return code;
1770 }
1771
1772 static afs_int32
1773 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1774 {
1775     afs_int32 code = SYNC_OK;
1776
1777     memcpy(res->payload.buf, &VStats, sizeof(VStats));
1778     res->hdr.response_len += sizeof(VStats);
1779
1780     return code;
1781 }
1782
1783 #ifdef AFS_DEMAND_ATTACH_FS
1784 static afs_int32
1785 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1786 {
1787     afs_int32 code = SYNC_OK;
1788     struct DiskPartition64 * dp;
1789     struct DiskPartitionStats64 * stats;
1790
1791     if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
1792         res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1793         code = SYNC_FAILED;
1794         goto done;
1795     }
1796
1797     dp = VGetPartition_r(scom->sop->args.partName, 0);
1798     if (!dp) {
1799         code = SYNC_FAILED;
1800     } else {
1801         stats = (struct DiskPartitionStats64 *) res->payload.buf;
1802         stats->free = dp->free;
1803         stats->totalUsable = dp->totalUsable;
1804         stats->minFree = dp->minFree;
1805         stats->f_files = dp->f_files;
1806         stats->vol_list_len = dp->vol_list.len;
1807
1808         res->hdr.response_len += sizeof(struct DiskPartitionStats64);
1809     }
1810
1811  done:
1812     return code;
1813 }
1814
1815 static afs_int32
1816 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1817 {
1818     afs_int32 code = SYNC_OK;
1819     struct VolumeHashChainStats * stats;
1820     struct VolumeHashChainHead * head;
1821
1822     if (scom->sop->args.hash_bucket >= VolumeHashTable.Size) {
1823         return SYNC_FAILED;
1824     }
1825
1826     head = &VolumeHashTable.Table[scom->sop->args.hash_bucket];
1827     stats = (struct VolumeHashChainStats *) res->payload.buf;
1828     stats->table_size = VolumeHashTable.Size;
1829     stats->chain_len = head->len;
1830     stats->chain_cacheCheck = head->cacheCheck;
1831     stats->chain_busy = head->busy;
1832     AssignInt64(head->looks, &stats->chain_looks);
1833     AssignInt64(head->gets, &stats->chain_gets);
1834     AssignInt64(head->reorders, &stats->chain_reorders);
1835
1836     res->hdr.response_len += sizeof(struct VolumeHashChainStats);
1837
1838     return code;
1839 }
1840
1841 static afs_int32
1842 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1843 {
1844     afs_int32 code = SYNC_OK;
1845
1846     memcpy(res->payload.buf, &volume_hdr_LRU.stats, sizeof(volume_hdr_LRU.stats));
1847     res->hdr.response_len += sizeof(volume_hdr_LRU.stats);
1848
1849     return code;
1850 }
1851
1852 static afs_int32
1853 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1854 {
1855     afs_int32 code = SYNC_OK;
1856
1857     code = SYNC_BAD_COMMAND;
1858
1859     return code;
1860 }
1861 #endif /* AFS_DEMAND_ATTACH_FS */
1862
1863 /**
1864  * populate an FSSYNC_VolOp_info object from a command packet object.
1865  *
1866  * @param[in]   vcom  pointer to command packet
1867  * @param[out]  info  pointer to info object which will be populated
1868  *
1869  * @note FSSYNC_VolOp_info objects are attached to Volume objects when
1870  *       a volume operation is commenced.
1871  *
1872  * @internal
1873  */
1874 static void
1875 FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
1876 {
1877     memcpy(&info->com, vcom->hdr, sizeof(SYNC_command_hdr));
1878     memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
1879     info->vol_op_state = FSSYNC_VolOpPending;
1880 }
1881
1882 /**
1883  * check whether command packet partition name matches volume
1884  * object's partition name.
1885  *
1886  * @param[in] vcom        pointer to command packet
1887  * @param[in] vp          pointer to volume object
1888  * @param[in] match_anon  anon matching control flag (see note below)
1889  *
1890  * @return whether partitions match
1891  *   @retval 0  partitions do NOT match
1892  *   @retval 1  partitions match
1893  *
1894  * @note if match_anon is non-zero, then this function will return a
1895  *       positive match for a zero-length partition string in the
1896  *       command packet.
1897  *
1898  * @internal
1899  */
1900 static int
1901 FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon)
1902 {
1903     return ((match_anon && vcom->vop->partName[0] == 0) ||
1904             (strncmp(vcom->vop->partName, V_partition(vp)->name,
1905                      sizeof(vcom->vop->partName)) == 0));
1906 }
1907
1908
1909 static void
1910 FSYNC_Drop(osi_socket fd)
1911 {
1912     struct offlineInfo *p;
1913     int i;
1914     Error error;
1915     char tvolName[VMAXPATHLEN];
1916
1917     VOL_LOCK;
1918     p = OfflineVolumes[FindHandler(fd)];
1919     for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
1920         if (p[i].volumeID) {
1921
1922             Volume *vp;
1923
1924             tvolName[0] = '/';
1925             sprintf(&tvolName[1], VFORMAT, afs_printable_uint32_lu(p[i].volumeID));
1926             vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
1927                                        V_VOLUPD);
1928             if (vp)
1929                 VPutVolume_r(vp);
1930             p[i].volumeID = 0;
1931         }
1932     }
1933     VOL_UNLOCK;
1934     RemoveHandler(fd);
1935 #ifdef AFS_NT40_ENV
1936     closesocket(fd);
1937 #else
1938     close(fd);
1939 #endif
1940     AcceptOn();
1941 }
1942
1943 static int AcceptHandler = -1;  /* handler id for accept, if turned on */
1944
1945 static void
1946 AcceptOn(void)
1947 {
1948     if (AcceptHandler == -1) {
1949         osi_Assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
1950         AcceptHandler = FindHandler(fssync_server_state.fd);
1951     }
1952 }
1953
1954 static void
1955 AcceptOff(void)
1956 {
1957     if (AcceptHandler != -1) {
1958         osi_Assert(RemoveHandler(fssync_server_state.fd));
1959         AcceptHandler = -1;
1960     }
1961 }
1962
1963 /* The multiple FD handling code. */
1964
1965 static osi_socket HandlerFD[MAXHANDLERS];
1966 static void (*HandlerProc[MAXHANDLERS]) (osi_socket);
1967
1968 static void
1969 InitHandler(void)
1970 {
1971     int i;
1972     ObtainWriteLock(&FSYNC_handler_lock);
1973     for (i = 0; i < MAXHANDLERS; i++) {
1974         HandlerFD[i] = -1;
1975         HandlerProc[i] = 0;
1976     }
1977     ReleaseWriteLock(&FSYNC_handler_lock);
1978 }
1979
1980 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1981 static void
1982 CallHandler(struct pollfd *fds, int nfds, int mask)
1983 {
1984     int i;
1985     int handler;
1986     ObtainReadLock(&FSYNC_handler_lock);
1987     for (i = 0; i < nfds; i++) {
1988         if (fds[i].revents & mask) {
1989             handler = FindHandler_r(fds[i].fd);
1990             ReleaseReadLock(&FSYNC_handler_lock);
1991             (*HandlerProc[handler]) (fds[i].fd);
1992             ObtainReadLock(&FSYNC_handler_lock);
1993         }
1994     }
1995     ReleaseReadLock(&FSYNC_handler_lock);
1996 }
1997 #else
1998 static void
1999 CallHandler(fd_set * fdsetp)
2000 {
2001     int i;
2002     ObtainReadLock(&FSYNC_handler_lock);
2003     for (i = 0; i < MAXHANDLERS; i++) {
2004         if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
2005             ReleaseReadLock(&FSYNC_handler_lock);
2006             (*HandlerProc[i]) (HandlerFD[i]);
2007             ObtainReadLock(&FSYNC_handler_lock);
2008         }
2009     }
2010     ReleaseReadLock(&FSYNC_handler_lock);
2011 }
2012 #endif
2013
2014 static int
2015 AddHandler(osi_socket afd, void (*aproc) (osi_socket))
2016 {
2017     int i;
2018     ObtainWriteLock(&FSYNC_handler_lock);
2019     for (i = 0; i < MAXHANDLERS; i++)
2020         if (HandlerFD[i] == -1)
2021             break;
2022     if (i >= MAXHANDLERS) {
2023         ReleaseWriteLock(&FSYNC_handler_lock);
2024         return 0;
2025     }
2026     HandlerFD[i] = afd;
2027     HandlerProc[i] = aproc;
2028     ReleaseWriteLock(&FSYNC_handler_lock);
2029     return 1;
2030 }
2031
2032 static int
2033 FindHandler(osi_socket afd)
2034 {
2035     int i;
2036     ObtainReadLock(&FSYNC_handler_lock);
2037     for (i = 0; i < MAXHANDLERS; i++)
2038         if (HandlerFD[i] == afd) {
2039             ReleaseReadLock(&FSYNC_handler_lock);
2040             return i;
2041         }
2042     ReleaseReadLock(&FSYNC_handler_lock);       /* just in case */
2043     osi_Assert(1 == 2);
2044     return -1;                  /* satisfy compiler */
2045 }
2046
2047 static int
2048 FindHandler_r(osi_socket afd)
2049 {
2050     int i;
2051     for (i = 0; i < MAXHANDLERS; i++)
2052         if (HandlerFD[i] == afd) {
2053             return i;
2054         }
2055     osi_Assert(1 == 2);
2056     return -1;                  /* satisfy compiler */
2057 }
2058
2059 static int
2060 RemoveHandler(osi_socket afd)
2061 {
2062     ObtainWriteLock(&FSYNC_handler_lock);
2063     HandlerFD[FindHandler_r(afd)] = -1;
2064     ReleaseWriteLock(&FSYNC_handler_lock);
2065     return 1;
2066 }
2067
2068 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
2069 static void
2070 GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
2071 {
2072     int i;
2073     int fdi = 0;
2074     ObtainReadLock(&FSYNC_handler_lock);
2075     for (i = 0; i < MAXHANDLERS; i++)
2076         if (HandlerFD[i] != -1) {
2077             osi_Assert(fdi<maxfds);
2078             fds[fdi].fd = HandlerFD[i];
2079             fds[fdi].events = events;
2080             fds[fdi].revents = 0;
2081             fdi++;
2082         }
2083     *nfds = fdi;
2084     ReleaseReadLock(&FSYNC_handler_lock);
2085 }
2086 #else
2087 static void
2088 GetHandler(fd_set * fdsetp, int *maxfdp)
2089 {
2090     int i;
2091     int maxfd = -1;
2092     FD_ZERO(fdsetp);
2093     ObtainReadLock(&FSYNC_handler_lock);        /* just in case */
2094     for (i = 0; i < MAXHANDLERS; i++)
2095         if (HandlerFD[i] != -1) {
2096             FD_SET(HandlerFD[i], fdsetp);
2097 #ifndef AFS_NT40_ENV
2098             /* On Windows the nfds parameter to select() is ignored */
2099             if (maxfd < HandlerFD[i] || maxfd == (int)-1)
2100                 maxfd = HandlerFD[i];
2101 #endif /* AFS_NT40_ENV */
2102         }
2103     *maxfdp = maxfd;
2104     ReleaseReadLock(&FSYNC_handler_lock);       /* just in case */
2105 }
2106 #endif /* HAVE_POLL && AFS_PTHREAD_ENV */
2107
2108 #endif /* FSSYNC_BUILD_SERVER */