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