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