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