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