2 * Copyright 2000, International Business Machines Corporation and others.
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
9 * Portions Copyright (c) 2006-2010 Sine Nomine Associates
15 Institution: The Information Technology Center, Carnegie-Mellon University
18 #ifndef AFS_PTHREAD_ENV
19 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
22 * stack size increased from 8K because the HP machine seemed to have trouble
23 * with the smaller stack
25 #define USUAL_STACK_SIZE (24 * 1024)
26 #endif /* !AFS_PTHREAD_ENV */
30 File server synchronization with external volume utilities.
31 server-side implementation
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 */
40 #define FD_SETSIZE 65536
43 #include <afsconfig.h>
44 #include <afs/param.h>
49 #include <afs/afsint.h>
50 #include <rx/rx_queue.h>
52 #include <afs/errors.h>
53 #include "daemon_com.h"
54 #include "daemon_com_inline.h"
56 #include "fssync_inline.h"
60 #include <afs/afssyscalls.h>
64 #include "volume_inline.h"
65 #include "partition.h"
71 #endif /* HAVE_POLL */
73 #ifdef USE_UNIX_SOCKETS
75 #include <afs/afsutil.h>
76 #endif /* USE_UNIX_SOCKETS */
78 #ifdef FSSYNC_BUILD_SERVER
80 int (*V_BreakVolumeCallbacks) (VolumeId volume);
82 #define MAXHANDLERS 4 /* Up to 4 clients; must be at least 2, so that
83 * move = dump+restore can run on single server */
84 #define MAXOFFLINEVOLUMES 128 /* This needs to be as big as the maximum
85 * number that would be offline for 1 operation.
86 * Current winner is salvage, which needs all
87 * cloned read-only copies offline when salvaging
88 * a single read-write volume */
92 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
95 * fssync server socket handle.
97 static SYNC_server_state_t fssync_server_state =
98 { OSI_NULLSOCKET, /* file descriptor */
99 FSSYNC_ENDPOINT_DECL, /* server endpoint */
100 FSYNC_PROTO_VERSION, /* protocol version */
101 5, /* bind() retry limit */
102 100, /* listen() queue depth */
103 "FSSYNC", /* protocol name string */
106 #ifdef AFS_DEMAND_ATTACH_FS
108 * a queue of volume pointers to salvage in the background.
110 struct fsync_salv_node {
112 Volume *vp; /**< volume to salvage */
113 unsigned char update_salv_prio; /**< whether we should update the salvage priority or not */
116 struct rx_queue head;
120 static void * FSYNC_salvageThread(void *);
121 static void FSYNC_backgroundSalvage(Volume *vp);
122 #endif /* AFS_DEMAND_ATTACH_FS */
124 /* Forward declarations */
125 static void * FSYNC_sync(void *);
126 static void FSYNC_newconnection(osi_socket afd);
127 static void FSYNC_com(osi_socket fd);
128 static void FSYNC_Drop(osi_socket fd);
129 static void AcceptOn(void);
130 static void AcceptOff(void);
131 static void InitHandler(void);
132 static int AddHandler(osi_socket fd, void (*aproc)(osi_socket));
133 static int FindHandler(osi_socket afd);
134 static int FindHandler_r(osi_socket afd);
135 static int RemoveHandler(osi_socket afd);
136 #if defined(HAVE_POLL) && defined (AFS_PTHREAD_ENV)
137 static void CallHandler(struct pollfd *fds, int nfds, int mask);
138 static void GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds);
140 static void CallHandler(fd_set * fdsetp);
141 static void GetHandler(fd_set * fdsetp, int *maxfdp);
145 static afs_int32 FSYNC_com_VolOp(osi_socket fd, SYNC_command * com, SYNC_response * res);
147 #ifdef AFS_DEMAND_ATTACH_FS
148 static afs_int32 FSYNC_com_VolError(FSSYNC_VolOp_command * com, SYNC_response * res);
150 static afs_int32 FSYNC_com_VolOn(FSSYNC_VolOp_command * com, SYNC_response * res);
151 static afs_int32 FSYNC_com_VolOff(FSSYNC_VolOp_command * com, SYNC_response * res);
152 static afs_int32 FSYNC_com_VolMove(FSSYNC_VolOp_command * com, SYNC_response * res);
153 static afs_int32 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * com, SYNC_response * res);
154 static afs_int32 FSYNC_com_VolDone(FSSYNC_VolOp_command * com, SYNC_response * res);
155 static afs_int32 FSYNC_com_VolQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
156 static afs_int32 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
157 #ifdef AFS_DEMAND_ATTACH_FS
158 static afs_int32 FSYNC_com_VGUpdate(osi_socket fd, SYNC_command * com, SYNC_response * res);
159 static afs_int32 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
160 static afs_int32 FSYNC_com_VGQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
161 static afs_int32 FSYNC_com_VGScan(FSSYNC_VolOp_command * com, SYNC_response * res);
162 static afs_int32 FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res);
163 #endif /* AFS_DEMAND_ATTACH_FS */
165 static afs_int32 FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res);
167 static afs_int32 FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res);
169 static afs_int32 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res);
171 #ifdef AFS_DEMAND_ATTACH_FS
172 static afs_int32 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res);
173 static afs_int32 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res);
174 static afs_int32 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res);
175 static afs_int32 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res);
178 static void FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info);
180 static int FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon);
184 * This lock controls access to the handler array. The overhead
185 * is minimal in non-preemptive environments.
187 struct Lock FSYNC_handler_lock;
192 #ifdef AFS_PTHREAD_ENV
194 pthread_attr_t tattr;
195 #else /* AFS_PTHREAD_ENV */
197 #endif /* AFS_PTHREAD_ENV */
199 Lock_Init(&FSYNC_handler_lock);
201 #ifdef AFS_PTHREAD_ENV
202 opr_Verify(pthread_attr_init(&tattr) == 0);
203 opr_Verify(pthread_attr_setdetachstate(&tattr,
204 PTHREAD_CREATE_DETACHED) == 0);
205 opr_Verify(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
206 #else /* AFS_PTHREAD_ENV */
207 opr_Verify(LWP_CreateProcess(FSYNC_sync, USUAL_STACK_SIZE,
208 USUAL_PRIORITY, NULL,
209 "FSYNC_sync", &pid) == LWP_SUCCESS);
210 #endif /* AFS_PTHREAD_ENV */
212 #ifdef AFS_DEMAND_ATTACH_FS
213 queue_Init(&fsync_salv.head);
214 CV_INIT(&fsync_salv.cv, "fsync salv", CV_DEFAULT, 0);
215 opr_Verify(pthread_create(&tid, &tattr, FSYNC_salvageThread, NULL) == 0);
216 #endif /* AFS_DEMAND_ATTACH_FS */
219 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
220 static struct pollfd FSYNC_readfds[MAXHANDLERS];
222 static fd_set FSYNC_readfds;
227 FSYNC_sync(void * args)
231 #ifdef AFS_PTHREAD_ENV
234 SYNC_server_state_t * state = &fssync_server_state;
235 #ifdef AFS_DEMAND_ATTACH_FS
236 VThreadOptions_t * thread_opts;
240 * For non-DAFS, only wait until we begin attaching volumes (instead
241 * of waiting until all volumes are attached), since it can take
242 * awhile until VInit == 2.
245 #endif /* AFS_DEMAND_ATTACH_FS */
247 /* we must not be called before vol package initialization, since we use
248 * vol package mutexes and conds etc */
251 SYNC_getAddr(&state->endpoint, &state->addr);
252 SYNC_cleanupSock(state);
255 (void)signal(SIGPIPE, SIG_IGN);
258 #ifdef AFS_PTHREAD_ENV
259 /* set our 'thread-id' so that the host hold table works */
260 tid = rx_SetThreadNum();
261 Log("Set thread id %d for FSYNC_sync\n", tid);
262 afs_pthread_setname_self("FSYNC_sync");
263 #endif /* AFS_PTHREAD_ENV */
267 while (VInit < min_vinit) {
268 /* Let somebody else run until all volumes have been preattached
269 * (DAFS), or we have started attaching volumes (non-DAFS). This
270 * doesn't mean that all volumes have been attached.
272 #ifdef AFS_PTHREAD_ENV
273 VOL_CV_WAIT(&vol_vinit_cond);
274 #else /* AFS_PTHREAD_ENV */
275 LWP_DispatchProcess();
276 #endif /* AFS_PTHREAD_ENV */
281 state->fd = SYNC_getSock(&state->endpoint);
282 code = SYNC_bindSock(state);
285 #ifdef AFS_DEMAND_ATTACH_FS
287 * make sure the volume package is incapable of recursively executing
288 * salvsync calls on this thread, since there is a possibility of
291 thread_opts = malloc(sizeof(VThreadOptions_t));
292 if (thread_opts == NULL) {
293 Log("failed to allocate memory for thread-specific volume package options structure\n");
296 memcpy(thread_opts, &VThread_defaults, sizeof(VThread_defaults));
297 thread_opts->disallow_salvsync = 1;
298 opr_Verify(pthread_setspecific(VThread_key, thread_opts) == 0);
300 code = VVGCache_PkgInit();
301 opr_Assert(code == 0);
308 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
310 GetHandler(FSYNC_readfds, MAXHANDLERS, POLLIN|POLLPRI, &nfds);
311 if (poll(FSYNC_readfds, nfds, -1) >=1)
312 CallHandler(FSYNC_readfds, nfds, POLLIN|POLLPRI);
315 #ifdef AFS_PTHREAD_ENV
316 struct timeval s_timeout;
318 GetHandler(&FSYNC_readfds, &maxfd);
319 /* Note: check for >= 1 below is essential since IOMGR_select
320 * doesn't have exactly same semantics as select.
322 #ifdef AFS_PTHREAD_ENV
323 s_timeout.tv_sec = SYNC_SELECT_TIMEOUT;
324 s_timeout.tv_usec = 0;
325 if (select(maxfd + 1, &FSYNC_readfds, NULL, NULL, &s_timeout) >= 1)
326 #else /* AFS_PTHREAD_ENV */
327 if (IOMGR_Select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
328 #endif /* AFS_PTHREAD_ENV */
329 CallHandler(&FSYNC_readfds);
332 return NULL; /* hush now, little gcc */
335 #ifdef AFS_DEMAND_ATTACH_FS
337 * thread for salvaging volumes in the background.
339 * Since FSSYNC handlers cannot issue SALVSYNC requests in order to avoid
340 * deadlock issues, this thread exists so code in the FSSYNC handler thread
341 * can hand off volumes to be salvaged in the background.
343 * @param[in] args unused
345 * @note DEMAND_ATTACH_FS only
348 FSYNC_salvageThread(void * args)
351 struct fsync_salv_node *node;
356 while (queue_IsEmpty(&fsync_salv.head)) {
357 VOL_CV_WAIT(&fsync_salv.cv);
360 node = queue_First(&fsync_salv.head, fsync_salv_node);
364 if (node->update_salv_prio) {
365 if (VUpdateSalvagePriority_r(vp)) {
366 ViceLog(0, ("FSYNC_salvageThread: unable to raise salvage priority "
367 "for volume %lu\n", afs_printable_uint32_lu(vp->hashid)));
374 VCancelReservation_r(vp);
383 * salvage a volume in the background.
385 * Salvages cannot be scheduled directly from the main FSYNC thread, so
386 * instead call this function to schedule a salvage asynchronously in the
387 * FSYNC_salvageThread thread.
389 * @param[in] vp volume to pointer to salvage
393 * @note DEMAND_ATTACH_FS only
396 FSYNC_backgroundSalvage(Volume *vp)
398 struct fsync_salv_node *node;
401 VCreateReservation_r(vp);
403 node = malloc(sizeof(struct fsync_salv_node));
406 /* Save this value, to know if we should VUpdateSalvagePriority_r.
407 * We need to save it here, snce VRequestSalvage_r will change it. */
408 node->update_salv_prio = vp->salvage.requested;
410 if (VRequestSalvage_r(&ec, vp, SALVSYNC_ERROR, 0)) {
411 ViceLog(0, ("FSYNC_backgroundSalvage: unable to request salvage for volume %lu\n",
412 afs_printable_uint32_lu(vp->hashid)));
415 queue_Append(&fsync_salv.head, node);
416 CV_BROADCAST(&fsync_salv.cv);
418 #endif /* AFS_DEMAND_ATTACH_FS */
421 FSYNC_newconnection(osi_socket afd)
423 #ifdef USE_UNIX_SOCKETS
424 struct sockaddr_un other;
425 #else /* USE_UNIX_SOCKETS */
426 struct sockaddr_in other;
430 junk = sizeof(other);
431 fd = accept(afd, (struct sockaddr *)&other, &junk);
432 if (fd == OSI_NULLSOCKET) {
433 Log("FSYNC_newconnection: accept failed, errno==%d\n", errno);
435 } else if (!AddHandler(fd, FSYNC_com)) {
437 opr_Verify(AddHandler(fd, FSYNC_com));
441 /* this function processes commands from an fssync file descriptor (fd) */
442 afs_int32 FS_cnt = 0;
444 FSYNC_com(osi_socket fd)
448 SYNC_PROTO_BUF_DECL(com_buf);
449 SYNC_PROTO_BUF_DECL(res_buf);
451 memset(&res.hdr, 0, sizeof(res.hdr));
453 com.payload.buf = (void *)com_buf;
454 com.payload.len = SYNC_PROTO_MAX_LEN;
455 res.hdr.response_len = sizeof(res.hdr);
456 res.payload.len = SYNC_PROTO_MAX_LEN;
457 res.payload.buf = (void *)res_buf;
460 if (SYNC_getCom(&fssync_server_state, fd, &com)) {
461 Log("FSYNC_com: read failed; dropping connection (cnt=%d)\n", FS_cnt);
466 if (com.recv_len < sizeof(com.hdr)) {
467 Log("FSSYNC_com: invalid protocol message length (%u)\n", com.recv_len);
468 res.hdr.response = SYNC_COM_ERROR;
469 res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
470 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
474 if (com.hdr.proto_version != FSYNC_PROTO_VERSION) {
475 Log("FSYNC_com: invalid protocol version (%u)\n", com.hdr.proto_version);
476 res.hdr.response = SYNC_COM_ERROR;
477 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
481 if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
482 res.hdr.response = SYNC_OK;
483 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
485 /* don't respond, just drop; senders of SYNC_COM_CHANNEL_CLOSE
486 * never wait for a response. */
490 ViceLog(125, ("FSYNC_com: from fd %d got command %ld (%s) reason %ld (%s) "
491 "pt %ld (%s) pid %ld\n", (int)fd,
492 afs_printable_int32_ld(com.hdr.command),
493 FSYNC_com2string(com.hdr.command),
494 afs_printable_int32_ld(com.hdr.reason),
495 FSYNC_reason2string(com.hdr.reason),
496 afs_printable_int32_ld(com.hdr.programType),
497 VPTypeToString(com.hdr.programType),
498 afs_printable_int32_ld(com.hdr.pid)));
500 res.hdr.com_seq = com.hdr.com_seq;
503 switch (com.hdr.command) {
505 case FSYNC_VOL_ATTACH:
506 case FSYNC_VOL_LEAVE_OFF:
508 case FSYNC_VOL_FORCE_ERROR:
509 case FSYNC_VOL_LISTVOLUMES:
510 case FSYNC_VOL_NEEDVOLUME:
512 case FSYNC_VOL_BREAKCBKS:
514 case FSYNC_VOL_QUERY:
515 case FSYNC_VOL_QUERY_HDR:
516 #ifdef AFS_DEMAND_ATTACH_FS
517 case FSYNC_VOL_QUERY_VOP:
520 case FSYNC_VG_SCAN_ALL:
522 res.hdr.response = FSYNC_com_VolOp(fd, &com, &res);
524 case FSYNC_VOL_STATS_GENERAL:
525 case FSYNC_VOL_STATS_VICEP:
526 case FSYNC_VOL_STATS_HASH:
527 case FSYNC_VOL_STATS_HDR:
528 case FSYNC_VOL_STATS_VLRU:
529 res.hdr.response = FSYNC_com_StatsOp(fd, &com, &res);
531 case FSYNC_VOL_QUERY_VNODE:
532 res.hdr.response = FSYNC_com_VnQry(fd, &com, &res);
534 #ifdef AFS_DEMAND_ATTACH_FS
537 res.hdr.response = FSYNC_com_VGUpdate(fd, &com, &res);
541 res.hdr.response = SYNC_BAD_COMMAND;
546 ViceLog(125, ("FSYNC_com: fd %d responding with code %ld (%s) reason %ld "
548 afs_printable_int32_ld(res.hdr.response),
549 SYNC_res2string(res.hdr.response),
550 afs_printable_int32_ld(res.hdr.reason),
551 FSYNC_reason2string(res.hdr.reason)));
554 SYNC_putRes(&fssync_server_state, fd, &res);
557 if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
563 FSYNC_com_VolOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
566 afs_int32 code = SYNC_OK;
567 FSSYNC_VolOp_command vcom;
569 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VolOp_hdr))) {
570 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
571 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
572 return SYNC_COM_ERROR;
575 vcom.hdr = &com->hdr;
576 vcom.vop = (FSSYNC_VolOp_hdr *) com->payload.buf;
579 vcom.volumes = OfflineVolumes[FindHandler(fd)];
580 for (vcom.v = NULL, i = 0; i < MAXOFFLINEVOLUMES; i++) {
581 if ((vcom.volumes[i].volumeID == vcom.vop->volume) &&
582 (strncmp(vcom.volumes[i].partName, vcom.vop->partName,
583 sizeof(vcom.volumes[i].partName)) == 0)) {
584 vcom.v = &vcom.volumes[i];
589 ViceLog(125, ("FSYNC_com_VolOp: fd %d got command for vol %lu part %.16s\n",
590 (int)fd, afs_printable_uint32_lu(vcom.vop->volume),
591 vcom.vop->partName));
593 switch (com->hdr.command) {
595 case FSYNC_VOL_ATTACH:
596 case FSYNC_VOL_LEAVE_OFF:
597 code = FSYNC_com_VolOn(&vcom, res);
600 case FSYNC_VOL_NEEDVOLUME:
601 code = FSYNC_com_VolOff(&vcom, res);
603 case FSYNC_VOL_LISTVOLUMES:
607 code = FSYNC_com_VolMove(&vcom, res);
609 case FSYNC_VOL_BREAKCBKS:
610 code = FSYNC_com_VolBreakCBKs(&vcom, res);
613 code = FSYNC_com_VolDone(&vcom, res);
615 case FSYNC_VOL_QUERY:
616 code = FSYNC_com_VolQuery(&vcom, res);
618 case FSYNC_VOL_QUERY_HDR:
619 code = FSYNC_com_VolHdrQuery(&vcom, res);
621 #ifdef AFS_DEMAND_ATTACH_FS
622 case FSYNC_VOL_FORCE_ERROR:
623 code = FSYNC_com_VolError(&vcom, res);
625 case FSYNC_VOL_QUERY_VOP:
626 code = FSYNC_com_VolOpQuery(&vcom, res);
629 code = FSYNC_com_VGQuery(&vcom, res);
632 code = FSYNC_com_VGScan(&vcom, res);
634 case FSYNC_VG_SCAN_ALL:
635 code = FSYNC_com_VGScanAll(&vcom, res);
637 #endif /* AFS_DEMAND_ATTACH_FS */
639 code = SYNC_BAD_COMMAND;
646 * service an FSYNC request to bring a volume online.
648 * @param[in] vcom pointer command object
649 * @param[out] res object in which to store response packet
651 * @return operation status
652 * @retval SYNC_OK volume transitioned online
653 * @retval SYNC_FAILED invalid command protocol message
654 * @retval SYNC_DENIED operation could not be completed
656 * @note this is an FSYNC RPC server stub
658 * @note this procedure handles the following FSSYNC command codes:
661 * - FSYNC_VOL_LEAVE_OFF
663 * @note the supplementary reason code contains additional details.
664 * When SYNC_DENIED is returned, the specific reason is
665 * placed in the response packet reason field.
670 FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
672 afs_int32 code = SYNC_OK;
673 #ifndef AFS_DEMAND_ATTACH_FS
674 char tvolName[VMAXPATHLEN];
679 /* Verify the partition name is null terminated. */
680 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
681 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
686 /* so, we need to attach the volume */
688 #ifdef AFS_DEMAND_ATTACH_FS
689 /* Verify the partition name is not empty. */
690 if (*vcom->vop->partName == 0) {
691 res->hdr.reason = FSYNC_BAD_PART;
696 /* check DAFS permissions */
697 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
699 FSYNC_partMatch(vcom, vp, 1) &&
700 vp->pending_vol_op &&
701 (vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
702 /* a different program has this volume checked out. deny. */
703 Log("FSYNC_VolOn: WARNING: program type %u has attempted to manipulate "
704 "state for volume %u using command code %u while the volume is "
705 "checked out by program type %u for command code %u.\n",
706 vcom->hdr->programType,
709 vp->pending_vol_op->com.programType,
710 vp->pending_vol_op->com.command);
712 res->hdr.reason = FSYNC_EXCLUSIVE;
718 vcom->v->volumeID = 0;
721 if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
722 /* nothing much to do if we're leaving the volume offline */
723 #ifdef AFS_DEMAND_ATTACH_FS
725 VCreateReservation_r(vp);
726 VWaitExclusiveState_r(vp);
728 if (vp && V_attachState(vp) != VOL_STATE_DELETED) {
729 if (FSYNC_partMatch(vcom, vp, 1)) {
730 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
731 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
732 VChangeState_r(vp, VOL_STATE_UNATTACHED);
733 VDeregisterVolOp_r(vp);
736 res->hdr.reason = FSYNC_BAD_STATE;
740 res->hdr.reason = FSYNC_WRONG_PART;
744 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
748 VCancelReservation_r(vp);
755 #ifdef AFS_DEMAND_ATTACH_FS
758 FSYNC_partMatch(vcom, vp, 0) &&
759 vp->pending_vol_op &&
760 vp->pending_vol_op->vol_op_state == FSSYNC_VolOpRunningOnline &&
761 V_attachState(vp) == VOL_STATE_ATTACHED) {
763 /* noop; the volume stayed online for the volume operation and we were
764 * simply told that the vol op is done. The vp we already have is fine,
765 * so avoid confusing volume routines with trying to preattach an
766 * attached volume. */
769 /* first, check to see whether we have such a volume defined */
770 vp = VPreAttachVolumeById_r(&error,
776 VCreateReservation_r(vp);
777 VWaitExclusiveState_r(vp);
778 VDeregisterVolOp_r(vp);
779 VCancelReservation_r(vp);
782 #else /* !AFS_DEMAND_ATTACH_FS */
783 tvolName[0] = OS_DIRSEPC;
784 snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, afs_printable_uint32_lu(vcom->vop->volume));
785 tvolName[sizeof(tvolName)-1] = '\0';
787 vp = VAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
791 #endif /* !AFS_DEMAND_ATTACH_FS */
794 res->hdr.reason = error;
802 * service an FSYNC request to take a volume offline.
804 * @param[in] vcom pointer command object
805 * @param[out] res object in which to store response packet
807 * @return operation status
808 * @retval SYNC_OK volume transitioned offline
809 * @retval SYNC_FAILED invalid command protocol message
810 * @retval SYNC_DENIED operation could not be completed
812 * @note this is an FSYNC RPC server stub
814 * @note this procedure handles the following FSSYNC command codes:
816 * - FSYNC_VOL_NEEDVOLUME
818 * @note the supplementary reason code contains additional details.
819 * When SYNC_DENIED is returned, the specific reason is
820 * placed in the response packet reason field.
825 FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
827 FSSYNC_VolOp_info info;
828 afs_int32 code = SYNC_OK;
832 #ifdef AFS_DEMAND_ATTACH_FS
833 Volume *nvp, *rvp = NULL;
836 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
837 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
842 /* not already offline, we need to find a slot for newly offline volume */
843 if (vcom->hdr->programType == debugUtility) {
844 /* debug utilities do not have their operations tracked */
848 for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
849 if (vcom->volumes[i].volumeID == 0) {
850 vcom->v = &vcom->volumes[i];
860 FSYNC_com_to_info(vcom, &info);
862 #ifdef AFS_DEMAND_ATTACH_FS
863 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
865 vp = VGetVolume_r(&error, vcom->vop->volume);
869 if (!FSYNC_partMatch(vcom, vp, 1)) {
870 /* volume on desired partition is not online, so we
871 * should treat this as an offline volume.
873 #ifndef AFS_DEMAND_ATTACH_FS
881 #ifdef AFS_DEMAND_ATTACH_FS
883 ProgramType type = (ProgramType) vcom->hdr->programType;
885 /* do initial filtering of requests */
887 /* enforce mutual exclusion for volume ops */
888 if (vp->pending_vol_op) {
889 if (vp->pending_vol_op->com.programType != type) {
890 if (vp->pending_vol_op->com.command == FSYNC_VOL_OFF &&
891 vp->pending_vol_op->com.reason == FSYNC_SALVAGE) {
893 Log("denying offline request for volume %lu; volume is salvaging\n",
894 afs_printable_uint32_lu(vp->hashid));
896 res->hdr.reason = FSYNC_SALVAGE;
899 Log("volume %u already checked out\n", vp->hashid);
901 Log("vp->vop = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x }, vop = { vol=%u, part='%s' } }\n",
902 vp->pending_vol_op->com.proto_version,
903 vp->pending_vol_op->com.programType,
904 vp->pending_vol_op->com.command,
905 vp->pending_vol_op->com.reason,
906 vp->pending_vol_op->com.command_len,
907 vp->pending_vol_op->com.flags,
908 vp->pending_vol_op->vop.volume,
909 vp->pending_vol_op->vop.partName );
910 Log("vcom = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x } , vop = { vol=%u, part='%s' } }\n",
911 vcom->hdr->proto_version,
912 vcom->hdr->programType,
915 vcom->hdr->command_len,
918 vcom->vop->partName);
919 res->hdr.reason = FSYNC_EXCLUSIVE;
922 Log("warning: volume %u recursively checked out by programType id %d\n",
923 vp->hashid, vcom->hdr->programType);
927 /* wait for exclusive ops, so we have an accurate picture of the
928 * vol attach state */
929 VCreateReservation_r(vp);
930 VWaitExclusiveState_r(vp);
933 /* filter based upon requestor
935 * volume utilities / volserver are not allowed to check out
936 * volumes which are in an error state
938 * unknown utility programs will be denied on principal
943 /* it is possible for the salvageserver to checkout a
944 * volume for salvage before its scheduling request
945 * has been sent to the salvageserver */
946 if (vp->salvage.requested && !vp->salvage.scheduled) {
947 vp->salvage.scheduled = 1;
950 /* If the volume is in VOL_STATE_SALVAGE_REQ, we need to wait
951 * for the vol to go offline before we can give it away. Also
952 * make sure we don't come out with vp in an excl state. */
953 while (V_attachState(vp) == VOL_STATE_SALVAGE_REQ ||
954 VIsExclusiveState(V_attachState(vp))) {
956 VOL_CV_WAIT(&V_attachCV(vp));
964 if (VIsSalvaging(vp)) {
965 Log("denying offline request for volume %lu; volume is in salvaging state\n",
966 afs_printable_uint32_lu(vp->hashid));
967 res->hdr.reason = FSYNC_SALVAGE;
969 /* the volume hasn't been checked out yet by the salvager,
970 * but we think the volume is salvaging; schedule a
971 * a salvage to update the salvage priority */
972 FSYNC_backgroundSalvage(vp);
976 if (VIsErrorState(V_attachState(vp))) {
982 Log("bad program type passed to FSSYNC\n");
986 /* short circuit for offline volume states
987 * so we can avoid I/O penalty of attachment */
988 switch (V_attachState(vp)) {
989 case VOL_STATE_UNATTACHED:
990 case VOL_STATE_PREATTACHED:
991 case VOL_STATE_SALVAGING:
992 case VOL_STATE_ERROR:
993 /* register the volume operation metadata with the volume
995 * if the volume is currently pre-attached, attach2()
996 * will evaluate the vol op metadata to determine whether
997 * attaching the volume would be safe */
998 VRegisterVolOp_r(vp, &info);
999 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
1002 case VOL_STATE_DELETED:
1008 /* convert to heavyweight ref */
1009 nvp = VGetVolumeByVp_r(&error, vp);
1012 * It's possible for VGetVolumeByVp_r to have dropped and
1013 * re-acquired VOL_LOCK, so volume state may have changed
1014 * back to one of the states we tested for above. Since
1015 * GetVolume can return NULL in some of those states, just
1016 * test for the states again here.
1018 switch (V_attachState(vp)) {
1019 case VOL_STATE_UNATTACHED:
1020 case VOL_STATE_PREATTACHED:
1021 case VOL_STATE_SALVAGING:
1022 case VOL_STATE_ERROR:
1023 /* register the volume operation metadata with the volume
1025 * if the volume is currently pre-attached, attach2()
1026 * will evaluate the vol op metadata to determine whether
1027 * attaching the volume would be safe */
1028 VRegisterVolOp_r(vp, &info);
1029 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningUnknown;
1032 case VOL_STATE_DELETED:
1038 Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u (state=%u, flags=0x%x)\n",
1039 vcom->vop->volume, V_attachState(vp), V_attachFlags(vp));
1040 res->hdr.reason = FSYNC_VOL_PKG_ERROR;
1042 } else if (nvp != vp) {
1043 /* i don't think this should ever happen, but just in case... */
1044 Log("FSYNC_com_VolOff: warning: potentially dangerous race detected\n");
1048 /* kill off lightweight ref to ensure we can't deadlock against ourselves later... */
1049 VCancelReservation_r(rvp);
1052 /* register the volume operation metadata with the volume */
1053 VRegisterVolOp_r(vp, &info);
1056 #endif /* AFS_DEMAND_ATTACH_FS */
1059 if (VVolOpLeaveOnline_r(vp, &info)) {
1060 VUpdateVolume_r(&error, vp, VOL_UPDATE_WAIT); /* At least get volume stats right */
1062 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n",
1063 V_id(vp), V_name(vp),
1064 vcom->hdr->reason == V_CLONE ? "clone" :
1065 vcom->hdr->reason == V_READONLY ? "readonly" :
1066 vcom->hdr->reason == V_DUMP ? "dump" :
1067 vcom->hdr->reason == FSYNC_SALVAGE ? "salvage" :
1070 #ifdef AFS_DEMAND_ATTACH_FS
1071 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
1075 if (VVolOpSetVBusy_r(vp, &info)) {
1076 vp->specialStatus = VBUSY;
1079 /* remember what volume we got, so we can keep track of how
1080 * many volumes the volserver or whatever is using. Note that
1081 * vp is valid since leaveonline is only set when vp is valid.
1084 vcom->v->volumeID = vcom->vop->volume;
1085 strlcpy(vcom->v->partName, vp->partition->name, sizeof(vcom->v->partName));
1088 #ifdef AFS_DEMAND_ATTACH_FS
1089 VCreateReservation_r(vp);
1090 VOfflineForVolOp_r(&error, vp, "A volume utility is running.");
1092 opr_Assert(vp->nUsers==0);
1093 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline;
1096 VWaitExclusiveState_r(vp);
1097 VDeregisterVolOp_r(vp);
1100 VCancelReservation_r(vp);
1102 VOffline_r(vp, "A volume utility is running.");
1113 #ifdef AFS_DEMAND_ATTACH_FS
1115 VCancelReservation_r(rvp);
1122 * service an FSYNC request to mark a volume as moved.
1124 * @param[in] vcom pointer command object
1125 * @param[out] res object in which to store response packet
1127 * @return operation status
1128 * @retval SYNC_OK volume marked as moved to a remote server
1129 * @retval SYNC_FAILED invalid command protocol message
1130 * @retval SYNC_DENIED current volume state does not permit this operation
1132 * @note this is an FSYNC RPC server stub
1134 * @note this operation also breaks all callbacks for the given volume
1136 * @note this procedure handles the following FSSYNC command codes:
1139 * @note the supplementary reason code contains additional details. For
1140 * instance, SYNC_OK is still returned when the partition specified
1141 * does not match the one registered in the volume object -- reason
1142 * will be FSYNC_WRONG_PART in this case.
1147 FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1149 afs_int32 code = SYNC_DENIED;
1153 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1154 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1159 /* Yuch: the "reason" for the move is the site it got moved to... */
1160 /* still set specialStatus so we stop sending back VBUSY.
1161 * also should still break callbacks. Note that I don't know
1162 * how to tell if we should break all or not, so we just do it
1163 * since it doesn't matter much if we do an extra break
1164 * volume callbacks on a volume move within the same server */
1165 #ifdef AFS_DEMAND_ATTACH_FS
1166 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1168 vp = VGetVolume_r(&error, vcom->vop->volume);
1171 if (FSYNC_partMatch(vcom, vp, 1)) {
1172 #ifdef AFS_DEMAND_ATTACH_FS
1173 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1174 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
1177 vp->specialStatus = VMOVED;
1178 #ifdef AFS_DEMAND_ATTACH_FS
1180 res->hdr.reason = FSYNC_BAD_STATE;
1184 res->hdr.reason = FSYNC_WRONG_PART;
1186 #ifndef AFS_DEMAND_ATTACH_FS
1188 #endif /* !AFS_DEMAND_ATTACH_FS */
1190 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1193 if ((code == SYNC_OK) && (V_BreakVolumeCallbacks != NULL)) {
1194 Log("fssync: volume %u moved to %x; breaking all call backs\n",
1195 vcom->vop->volume, vcom->hdr->reason);
1197 (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1207 * service an FSYNC request to mark a volume as destroyed.
1209 * @param[in] vcom pointer command object
1210 * @param[out] res object in which to store response packet
1212 * @return operation status
1213 * @retval SYNC_OK volume marked as destroyed
1214 * @retval SYNC_FAILED invalid command protocol message
1215 * @retval SYNC_DENIED current volume state does not permit this operation
1217 * @note this is an FSYNC RPC server stub
1219 * @note this procedure handles the following FSSYNC command codes:
1222 * @note the supplementary reason code contains additional details. For
1223 * instance, SYNC_OK is still returned when the partition specified
1224 * does not match the one registered in the volume object -- reason
1225 * will be FSYNC_WRONG_PART in this case.
1230 FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1232 afs_int32 code = SYNC_FAILED;
1236 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1237 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1241 /* don't try to put online, this call is made only after deleting
1242 * a volume, in which case we want to remove the vol # from the
1243 * OfflineVolumes array only */
1245 vcom->v->volumeID = 0;
1247 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1249 if (FSYNC_partMatch(vcom, vp, 1)) {
1250 #ifdef AFS_DEMAND_ATTACH_FS
1251 VCreateReservation_r(vp);
1252 VWaitExclusiveState_r(vp);
1254 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1255 (V_attachState(vp) == VOL_STATE_PREATTACHED) ||
1256 VIsErrorState(V_attachState(vp))) {
1258 /* Change state to DELETED, not UNATTACHED, so clients get
1259 * a VNOVOL error when they try to access from now on. */
1261 VChangeState_r(vp, VOL_STATE_DELETED);
1262 VDeregisterVolOp_r(vp);
1264 /* Volume is gone; clear out old salvage stats */
1265 memset(&vp->salvage, 0, sizeof(vp->salvage));
1267 /* Someday we should free the vp, too, after about 2 hours,
1268 * possibly by putting the vp back on the VLRU. */
1271 } else if (V_attachState(vp) == VOL_STATE_DELETED) {
1272 VDeregisterVolOp_r(vp);
1273 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1277 res->hdr.reason = FSYNC_BAD_STATE;
1280 VCancelReservation_r(vp);
1282 #else /* AFS_DEMAND_ATTACH_FS */
1283 if (!vp->specialStatus) {
1284 vp->specialStatus = VNOVOL;
1287 #endif /* !AFS_DEMAND_ATTACH_FS */
1289 code = SYNC_OK; /* XXX is this really a good idea? */
1290 res->hdr.reason = FSYNC_WRONG_PART;
1293 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1300 #ifdef AFS_DEMAND_ATTACH_FS
1302 * service an FSYNC request to transition a volume to the hard error state.
1304 * @param[in] vcom pointer command object
1305 * @param[out] res object in which to store response packet
1307 * @return operation status
1308 * @retval SYNC_OK volume transitioned to hard error state
1309 * @retval SYNC_FAILED invalid command protocol message
1310 * @retval SYNC_DENIED (see note)
1312 * @note this is an FSYNC RPC server stub
1314 * @note this procedure handles the following FSSYNC command codes:
1315 * - FSYNC_VOL_FORCE_ERROR
1317 * @note SYNC_DENIED is returned in the following cases:
1318 * - no partition name is specified (reason field set to
1319 * FSYNC_WRONG_PART).
1320 * - volume id not known to fileserver (reason field set
1321 * to FSYNC_UNKNOWN_VOLID).
1323 * @note demand attach fileserver only
1328 FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1332 afs_int32 code = SYNC_FAILED;
1334 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1335 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1339 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1341 if (!vp && vcom->hdr->reason == FSYNC_SALVAGE) {
1342 /* The requested volume doesn't seem to exist. However, it is possible
1343 * that this is triggered by trying to create or clone a volume that
1344 * was prevented from succeeding by a half-created volume in the way.
1345 * (e.g. we tried to create volume X, but volume X exists except that
1346 * its .vol header was deleted for some reason) So, still try to
1347 * a salvage for that volume ID. */
1349 Log("FSYNC_com_VolError: attempting to schedule salvage for unknown "
1350 "volume %lu part %s\n", afs_printable_uint32_lu(vcom->vop->volume),
1351 vcom->vop->partName);
1352 vp = VPreAttachVolumeById_r(&error, vcom->vop->partName,
1357 if (FSYNC_partMatch(vcom, vp, 0)) {
1358 VCreateReservation_r(vp);
1359 VWaitExclusiveState_r(vp);
1360 VDeregisterVolOp_r(vp);
1362 if (vcom->hdr->reason == FSYNC_SALVAGE) {
1363 FSYNC_backgroundSalvage(vp);
1365 /* null out salvsync control state, as it's no longer relevant */
1366 memset(&vp->salvage, 0, sizeof(vp->salvage));
1367 VChangeState_r(vp, VOL_STATE_ERROR);
1370 VCancelReservation_r(vp);
1375 res->hdr.reason = FSYNC_WRONG_PART;
1378 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1384 #endif /* AFS_DEMAND_ATTACH_FS */
1387 * service an FSYNC request to break all callbacks for this volume.
1389 * @param[in] vcom pointer command object
1390 * @param[out] res object in which to store response packet
1392 * @return operation status
1393 * @retval SYNC_OK callback breaks scheduled for volume
1395 * @note this is an FSYNC RPC server stub
1397 * @note this procedure handles the following FSSYNC command codes:
1398 * - FSYNC_VOL_BREAKCBKS
1400 * @note demand attach fileserver only
1402 * @todo should do partition matching
1407 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1409 /* if the volume is being restored, break all callbacks on it */
1410 if (V_BreakVolumeCallbacks) {
1411 Log("fssync: breaking all call backs for volume %u\n",
1414 (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1421 * service an FSYNC request to return the Volume object.
1423 * @param[in] vcom pointer command object
1424 * @param[out] res object in which to store response packet
1426 * @return operation status
1427 * @retval SYNC_OK volume object returned to caller
1428 * @retval SYNC_FAILED bad command packet, or failed to locate volume object
1430 * @note this is an FSYNC RPC server stub
1432 * @note this procedure handles the following FSSYNC command codes:
1438 FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1440 afs_int32 code = SYNC_FAILED;
1444 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1445 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1449 #ifdef AFS_DEMAND_ATTACH_FS
1450 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1451 #else /* !AFS_DEMAND_ATTACH_FS */
1452 vp = VGetVolume_r(&error, vcom->vop->volume);
1453 #endif /* !AFS_DEMAND_ATTACH_FS */
1456 if (FSYNC_partMatch(vcom, vp, 1)) {
1457 if (res->payload.len >= sizeof(Volume)) {
1458 memcpy(res->payload.buf, vp, sizeof(Volume));
1459 res->hdr.response_len += sizeof(Volume);
1462 res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1465 res->hdr.reason = FSYNC_WRONG_PART;
1467 #ifndef AFS_DEMAND_ATTACH_FS
1471 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1479 * service an FSYNC request to return the Volume header.
1481 * @param[in] vcom pointer command object
1482 * @param[out] res object in which to store response packet
1484 * @return operation status
1485 * @retval SYNC_OK volume header returned to caller
1486 * @retval SYNC_FAILED bad command packet, or failed to locate volume header
1488 * @note this is an FSYNC RPC server stub
1490 * @note this procedure handles the following FSSYNC command codes:
1491 * - FSYNC_VOL_QUERY_HDR
1496 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1498 afs_int32 code = SYNC_FAILED;
1502 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1503 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1506 if (res->payload.len < sizeof(VolumeDiskData)) {
1507 res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1511 #ifdef AFS_DEMAND_ATTACH_FS
1512 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1513 #else /* !AFS_DEMAND_ATTACH_FS */
1514 vp = VGetVolume_r(&error, vcom->vop->volume);
1518 if (FSYNC_partMatch(vcom, vp, 1)) {
1519 #ifdef AFS_DEMAND_ATTACH_FS
1520 if ((vp->header == NULL) ||
1521 !(V_attachFlags(vp) & VOL_HDR_ATTACHED) ||
1522 !(V_attachFlags(vp) & VOL_HDR_LOADED)) {
1523 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1526 #else /* !AFS_DEMAND_ATTACH_FS */
1527 if (!vp || !vp->header) {
1528 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1531 #endif /* !AFS_DEMAND_ATTACH_FS */
1533 res->hdr.reason = FSYNC_WRONG_PART;
1537 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1541 memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
1542 res->hdr.response_len += sizeof(VolumeDiskData);
1546 #ifndef AFS_DEMAND_ATTACH_FS
1554 #ifdef AFS_DEMAND_ATTACH_FS
1556 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1558 afs_int32 code = SYNC_OK;
1562 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1565 VCreateReservation_r(vp);
1566 VWaitExclusiveState_r(vp);
1569 if (vp && vp->pending_vol_op) {
1570 if (!FSYNC_partMatch(vcom, vp, 1)) {
1571 res->hdr.reason = FSYNC_WRONG_PART;
1574 opr_Assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
1575 memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
1576 res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
1579 if (!vp || V_attachState(vp) == VOL_STATE_DELETED) {
1580 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1581 } else if (!FSYNC_partMatch(vcom, vp, 1)) {
1582 res->hdr.reason = FSYNC_WRONG_PART;
1584 res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
1590 VCancelReservation_r(vp);
1596 FSYNC_com_VGQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1598 afs_int32 code = SYNC_FAILED;
1600 struct DiskPartition64 * dp;
1602 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1603 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1607 dp = VGetPartition_r(vcom->vop->partName, 0);
1609 res->hdr.reason = FSYNC_BAD_PART;
1613 opr_Assert(sizeof(FSSYNC_VGQry_response_t) <= res->payload.len);
1615 rc = VVGCache_query_r(dp, vcom->vop->volume, res->payload.buf);
1618 res->hdr.response_len += sizeof(FSSYNC_VGQry_response_t);
1622 res->hdr.reason = FSYNC_PART_SCANNING;
1625 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1636 FSYNC_com_VGUpdate(osi_socket fd, SYNC_command * com, SYNC_response * res)
1638 afs_int32 code = SYNC_FAILED;
1639 struct DiskPartition64 * dp;
1640 FSSYNC_VGUpdate_command_t * vgucom;
1643 if (com->recv_len != (sizeof(com->hdr) + sizeof(*vgucom))) {
1644 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1645 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1646 code = SYNC_COM_ERROR;
1650 vgucom = com->payload.buf;
1652 ViceLog(125, ("FSYNC_com_VGUpdate: fd %d got command for parent %lu child "
1653 "%lu partName %.16s\n", (int)fd,
1654 afs_printable_uint32_lu(vgucom->parent),
1655 afs_printable_uint32_lu(vgucom->child),
1658 if (SYNC_verifyProtocolString(vgucom->partName, sizeof(vgucom->partName))) {
1659 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1663 dp = VGetPartition_r(vgucom->partName, 0);
1665 res->hdr.reason = FSYNC_BAD_PART;
1669 switch(com->hdr.command) {
1671 rc = VVGCache_entry_add_r(dp, vgucom->parent, vgucom->child, NULL);
1675 rc = VVGCache_entry_del_r(dp, vgucom->parent, vgucom->child);
1679 Log("FSYNC_com_VGUpdate called improperly\n");
1684 /* EINVAL means the partition VGC doesn't exist at all; not really
1686 if (rc == 0 || rc == EINVAL) {
1691 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1693 res->hdr.reason = FSYNC_WHATEVER;
1701 FSYNC_com_VGScan(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1703 afs_int32 code = SYNC_FAILED;
1704 struct DiskPartition64 * dp;
1706 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1707 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1711 dp = VGetPartition_r(vcom->vop->partName, 0);
1713 res->hdr.reason = FSYNC_BAD_PART;
1717 if (VVGCache_scanStart_r(dp) == 0) {
1726 FSYNC_com_VGScanAll(FSSYNC_VolOp_command * com, SYNC_response * res)
1728 afs_int32 code = SYNC_FAILED;
1730 if (VVGCache_scanStart_r(NULL) == 0) {
1736 #endif /* AFS_DEMAND_ATTACH_FS */
1739 FSYNC_com_VnQry(osi_socket fd, SYNC_command * com, SYNC_response * res)
1741 afs_int32 code = SYNC_OK;
1742 FSSYNC_VnQry_hdr * qry = com->payload.buf;
1747 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
1748 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1749 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1750 return SYNC_COM_ERROR;
1753 ViceLog(125, ("FSYNC_com_VnQry: fd %d got command for vol %lu vnode %lu "
1754 "uniq %lu spare %lu partName %.16s\n", (int)fd,
1755 afs_printable_uint32_lu(qry->volume),
1756 afs_printable_uint32_lu(qry->vnode),
1757 afs_printable_uint32_lu(qry->unique),
1758 afs_printable_uint32_lu(qry->spare),
1761 #ifdef AFS_DEMAND_ATTACH_FS
1762 vp = VLookupVolume_r(&error, qry->volume, NULL);
1763 #else /* !AFS_DEMAND_ATTACH_FS */
1764 vp = VGetVolume_r(&error, qry->volume);
1765 #endif /* !AFS_DEMAND_ATTACH_FS */
1768 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1773 vnp = VLookupVnode(vp, qry->vnode);
1775 res->hdr.reason = FSYNC_UNKNOWN_VNID;
1780 if (Vn_class(vnp)->residentSize > res->payload.len) {
1781 res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
1786 memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
1787 res->hdr.response_len += Vn_class(vnp)->residentSize;
1790 #ifndef AFS_DEMAND_ATTACH_FS
1799 FSYNC_com_StatsOp(osi_socket fd, SYNC_command * com, SYNC_response * res)
1801 afs_int32 code = SYNC_OK;
1802 FSSYNC_StatsOp_command scom;
1804 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_StatsOp_hdr))) {
1805 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1806 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1807 return SYNC_COM_ERROR;
1810 scom.hdr = &com->hdr;
1811 scom.sop = (FSSYNC_StatsOp_hdr *) com->payload.buf;
1814 ViceLog(125, ("FSYNC_com_StatsOp: fd %d got command for stats: "
1815 "{vlru_generation = %lu, hash_bucket = %lu, partName = "
1816 "%.16s}\n", (int)fd,
1817 afs_printable_uint32_lu(scom.sop->args.vlru_generation),
1818 afs_printable_uint32_lu(scom.sop->args.hash_bucket),
1819 scom.sop->args.partName));
1821 switch (com->hdr.command) {
1822 case FSYNC_VOL_STATS_GENERAL:
1823 code = FSYNC_com_StatsOpGeneral(&scom, res);
1825 #ifdef AFS_DEMAND_ATTACH_FS
1826 /* statistics for the following subsystems are only tracked
1827 * for demand attach fileservers */
1828 case FSYNC_VOL_STATS_VICEP:
1829 code = FSYNC_com_StatsOpViceP(&scom, res);
1831 case FSYNC_VOL_STATS_HASH:
1832 code = FSYNC_com_StatsOpHash(&scom, res);
1834 case FSYNC_VOL_STATS_HDR:
1835 code = FSYNC_com_StatsOpHdr(&scom, res);
1837 case FSYNC_VOL_STATS_VLRU:
1838 code = FSYNC_com_StatsOpVLRU(&scom, res);
1840 #endif /* AFS_DEMAND_ATTACH_FS */
1842 code = SYNC_BAD_COMMAND;
1849 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1851 afs_int32 code = SYNC_OK;
1853 memcpy(res->payload.buf, &VStats, sizeof(VStats));
1854 res->hdr.response_len += sizeof(VStats);
1859 #ifdef AFS_DEMAND_ATTACH_FS
1861 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1863 afs_int32 code = SYNC_OK;
1864 struct DiskPartition64 * dp;
1865 struct DiskPartitionStats64 * stats;
1867 if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
1868 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1873 dp = VGetPartition_r(scom->sop->args.partName, 0);
1877 stats = (struct DiskPartitionStats64 *) res->payload.buf;
1878 stats->free = dp->free;
1879 stats->totalUsable = dp->totalUsable;
1880 stats->minFree = dp->minFree;
1881 stats->f_files = dp->f_files;
1882 stats->vol_list_len = dp->vol_list.len;
1884 res->hdr.response_len += sizeof(struct DiskPartitionStats64);
1892 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1894 afs_int32 code = SYNC_OK;
1895 struct VolumeHashChainStats * stats;
1896 struct VolumeHashChainHead * head;
1898 if (scom->sop->args.hash_bucket >= VolumeHashTable.Size) {
1902 head = &VolumeHashTable.Table[scom->sop->args.hash_bucket];
1903 stats = (struct VolumeHashChainStats *) res->payload.buf;
1904 stats->table_size = VolumeHashTable.Size;
1905 stats->chain_len = head->len;
1906 stats->chain_cacheCheck = head->cacheCheck;
1907 stats->chain_busy = head->busy;
1908 AssignInt64(head->looks, &stats->chain_looks);
1909 AssignInt64(head->gets, &stats->chain_gets);
1910 AssignInt64(head->reorders, &stats->chain_reorders);
1912 res->hdr.response_len += sizeof(struct VolumeHashChainStats);
1918 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1920 afs_int32 code = SYNC_OK;
1922 memcpy(res->payload.buf, &volume_hdr_LRU.stats, sizeof(volume_hdr_LRU.stats));
1923 res->hdr.response_len += sizeof(volume_hdr_LRU.stats);
1929 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1931 afs_int32 code = SYNC_OK;
1933 code = SYNC_BAD_COMMAND;
1937 #endif /* AFS_DEMAND_ATTACH_FS */
1940 * populate an FSSYNC_VolOp_info object from a command packet object.
1942 * @param[in] vcom pointer to command packet
1943 * @param[out] info pointer to info object which will be populated
1945 * @note FSSYNC_VolOp_info objects are attached to Volume objects when
1946 * a volume operation is commenced.
1951 FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
1953 memcpy(&info->com, vcom->hdr, sizeof(SYNC_command_hdr));
1954 memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
1955 info->vol_op_state = FSSYNC_VolOpPending;
1959 * check whether command packet partition name matches volume
1960 * object's partition name.
1962 * @param[in] vcom pointer to command packet
1963 * @param[in] vp pointer to volume object
1964 * @param[in] match_anon anon matching control flag (see note below)
1966 * @return whether partitions match
1967 * @retval 0 partitions do NOT match
1968 * @retval 1 partitions match
1970 * @note if match_anon is non-zero, then this function will return a
1971 * positive match for a zero-length partition string in the
1977 FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon)
1979 return ((match_anon && vcom->vop->partName[0] == 0) ||
1980 (strncmp(vcom->vop->partName, V_partition(vp)->name,
1981 sizeof(vcom->vop->partName)) == 0));
1986 FSYNC_Drop(osi_socket fd)
1988 struct offlineInfo *p;
1991 #ifndef AFS_DEMAND_ATTACH_FS
1992 char tvolName[VMAXPATHLEN];
1996 p = OfflineVolumes[FindHandler(fd)];
1997 for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
1998 if (p[i].volumeID) {
2001 #ifdef AFS_DEMAND_ATTACH_FS
2002 vp = VPreAttachVolumeById_r(&error, p[i].partName, p[i].volumeID);
2004 VCreateReservation_r(vp);
2005 VWaitExclusiveState_r(vp);
2006 VDeregisterVolOp_r(vp);
2007 VCancelReservation_r(vp);
2010 tvolName[0] = OS_DIRSEPC;
2011 sprintf(&tvolName[1], VFORMAT, afs_printable_uint32_lu(p[i].volumeID));
2012 vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
2016 #endif /* !AFS_DEMAND_ATTACH_FS */
2026 static int AcceptHandler = -1; /* handler id for accept, if turned on */
2031 if (AcceptHandler == -1) {
2032 opr_Verify(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
2033 AcceptHandler = FindHandler(fssync_server_state.fd);
2040 if (AcceptHandler != -1) {
2041 opr_Verify(RemoveHandler(fssync_server_state.fd));
2046 /* The multiple FD handling code. */
2048 static osi_socket HandlerFD[MAXHANDLERS];
2049 static void (*HandlerProc[MAXHANDLERS]) (osi_socket);
2055 ObtainWriteLock(&FSYNC_handler_lock);
2056 for (i = 0; i < MAXHANDLERS; i++) {
2057 HandlerFD[i] = OSI_NULLSOCKET;
2060 ReleaseWriteLock(&FSYNC_handler_lock);
2063 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
2065 CallHandler(struct pollfd *fds, int nfds, int mask)
2069 ObtainReadLock(&FSYNC_handler_lock);
2070 for (i = 0; i < nfds; i++) {
2071 if (fds[i].revents & mask) {
2072 handler = FindHandler_r(fds[i].fd);
2073 ReleaseReadLock(&FSYNC_handler_lock);
2074 (*HandlerProc[handler]) (fds[i].fd);
2075 ObtainReadLock(&FSYNC_handler_lock);
2078 ReleaseReadLock(&FSYNC_handler_lock);
2082 CallHandler(fd_set * fdsetp)
2085 ObtainReadLock(&FSYNC_handler_lock);
2086 for (i = 0; i < MAXHANDLERS; i++) {
2087 if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
2088 ReleaseReadLock(&FSYNC_handler_lock);
2089 (*HandlerProc[i]) (HandlerFD[i]);
2090 ObtainReadLock(&FSYNC_handler_lock);
2093 ReleaseReadLock(&FSYNC_handler_lock);
2098 AddHandler(osi_socket afd, void (*aproc) (osi_socket))
2101 ObtainWriteLock(&FSYNC_handler_lock);
2102 for (i = 0; i < MAXHANDLERS; i++)
2103 if (HandlerFD[i] == OSI_NULLSOCKET)
2105 if (i >= MAXHANDLERS) {
2106 ReleaseWriteLock(&FSYNC_handler_lock);
2110 HandlerProc[i] = aproc;
2111 ReleaseWriteLock(&FSYNC_handler_lock);
2116 FindHandler(osi_socket afd)
2119 ObtainReadLock(&FSYNC_handler_lock);
2120 for (i = 0; i < MAXHANDLERS; i++)
2121 if (HandlerFD[i] == afd) {
2122 ReleaseReadLock(&FSYNC_handler_lock);
2125 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
2127 return -1; /* satisfy compiler */
2131 FindHandler_r(osi_socket afd)
2134 for (i = 0; i < MAXHANDLERS; i++)
2135 if (HandlerFD[i] == afd) {
2139 return -1; /* satisfy compiler */
2143 RemoveHandler(osi_socket afd)
2145 ObtainWriteLock(&FSYNC_handler_lock);
2146 HandlerFD[FindHandler_r(afd)] = OSI_NULLSOCKET;
2147 ReleaseWriteLock(&FSYNC_handler_lock);
2151 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
2153 GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
2157 ObtainReadLock(&FSYNC_handler_lock);
2158 for (i = 0; i < MAXHANDLERS; i++)
2159 if (HandlerFD[i] != OSI_NULLSOCKET) {
2160 opr_Assert(fdi<maxfds);
2161 fds[fdi].fd = HandlerFD[i];
2162 fds[fdi].events = events;
2163 fds[fdi].revents = 0;
2167 ReleaseReadLock(&FSYNC_handler_lock);
2171 GetHandler(fd_set * fdsetp, int *maxfdp)
2176 ObtainReadLock(&FSYNC_handler_lock); /* just in case */
2177 for (i = 0; i < MAXHANDLERS; i++)
2178 if (HandlerFD[i] != OSI_NULLSOCKET) {
2179 FD_SET(HandlerFD[i], fdsetp);
2180 #ifndef AFS_NT40_ENV
2181 /* On Windows the nfds parameter to select() is ignored */
2182 if (maxfd < HandlerFD[i] || maxfd == (int)-1)
2183 maxfd = HandlerFD[i];
2184 #endif /* AFS_NT40_ENV */
2187 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
2189 #endif /* HAVE_POLL && AFS_PTHREAD_ENV */
2191 #endif /* FSSYNC_BUILD_SERVER */