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