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