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