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