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