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