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