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