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