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-2008 Sine Nomine Associates
15 Institution: The Information Technology Center, Carnegie-Mellon University
20 /* All this is going away in early 1989 */
21 int newVLDB; /* Compatibility flag */
24 static int newVLDB = 1;
27 #ifndef AFS_PTHREAD_ENV
28 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
31 * stack size increased from 8K because the HP machine seemed to have trouble
32 * with the smaller stack
34 #define USUAL_STACK_SIZE (24 * 1024)
35 #endif /* !AFS_PTHREAD_ENV */
39 File server synchronization with external volume utilities.
40 server-side implementation
43 /* This controls the size of an fd_set; it must be defined early before
44 * the system headers define that type and the macros that operate on it.
45 * Its value should be as large as the maximum file descriptor limit we
46 * are likely to run into on any platform. Right now, that is 65536
47 * which is the default hard fd limit on Solaris 9 */
49 #define FD_SETSIZE 65536
52 #include <afsconfig.h>
53 #include <afs/param.h>
58 #include <sys/types.h>
64 #include <sys/param.h>
65 #include <sys/socket.h>
66 #include <netinet/in.h>
71 #ifdef AFS_PTHREAD_ENV
73 #else /* AFS_PTHREAD_ENV */
74 #include <afs/assert.h>
75 #endif /* AFS_PTHREAD_ENV */
80 #include <afs/afsint.h>
82 #include <afs/errors.h>
83 #include "daemon_com.h"
87 #include <afs/afssyscalls.h>
91 #include "volume_inline.h"
92 #include "partition.h"
96 #endif /* HAVE_POLL */
98 #ifdef USE_UNIX_SOCKETS
100 #include <afs/afsutil.h>
101 #endif /* USE_UNIX_SOCKETS */
103 #ifdef FSSYNC_BUILD_SERVER
105 /*@printflike@*/ extern void Log(const char *format, ...);
107 int (*V_BreakVolumeCallbacks) ();
109 #define MAXHANDLERS 4 /* Up to 4 clients; must be at least 2, so that
110 * move = dump+restore can run on single server */
111 #define MAXOFFLINEVOLUMES 128 /* This needs to be as big as the maximum
112 * number that would be offline for 1 operation.
113 * Current winner is salvage, which needs all
114 * cloned read-only copies offline when salvaging
115 * a single read-write volume */
119 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
122 * fssync server socket handle.
124 static SYNC_server_state_t fssync_server_state =
125 { -1, /* file descriptor */
126 FSSYNC_ENDPOINT_DECL, /* server endpoint */
127 FSYNC_PROTO_VERSION, /* protocol version */
128 5, /* bind() retry limit */
129 100, /* listen() queue depth */
130 "FSSYNC", /* protocol name string */
134 /* Forward declarations */
135 static void * FSYNC_sync(void *);
136 static void FSYNC_newconnection();
137 static void FSYNC_com();
138 static void FSYNC_Drop();
139 static void AcceptOn();
140 static void AcceptOff();
141 static void InitHandler();
142 static int AddHandler();
143 static int FindHandler();
144 static int FindHandler_r();
145 static int RemoveHandler();
146 #if defined(HAVE_POLL) && defined (AFS_PTHREAD_ENV)
147 static void CallHandler(struct pollfd *fds, int nfds, int mask);
148 static void GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds);
150 static void CallHandler(fd_set * fdsetp);
151 static void GetHandler(fd_set * fdsetp, int *maxfdp);
155 static afs_int32 FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res);
157 static afs_int32 FSYNC_com_VolError(FSSYNC_VolOp_command * com, SYNC_response * res);
158 static afs_int32 FSYNC_com_VolOn(FSSYNC_VolOp_command * com, SYNC_response * res);
159 static afs_int32 FSYNC_com_VolOff(FSSYNC_VolOp_command * com, SYNC_response * res);
160 static afs_int32 FSYNC_com_VolMove(FSSYNC_VolOp_command * com, SYNC_response * res);
161 static afs_int32 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * com, SYNC_response * res);
162 static afs_int32 FSYNC_com_VolDone(FSSYNC_VolOp_command * com, SYNC_response * res);
163 static afs_int32 FSYNC_com_VolQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
164 static afs_int32 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
165 #ifdef AFS_DEMAND_ATTACH_FS
166 static afs_int32 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * com, SYNC_response * res);
167 #endif /* AFS_DEMAND_ATTACH_FS */
169 static afs_int32 FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res);
171 static afs_int32 FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res);
173 static afs_int32 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res);
174 static afs_int32 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res);
175 static afs_int32 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res);
176 static afs_int32 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res);
177 static afs_int32 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res);
180 static void FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info);
182 static int FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon);
186 * This lock controls access to the handler array. The overhead
187 * is minimal in non-preemptive environments.
189 struct Lock FSYNC_handler_lock;
194 #ifdef AFS_PTHREAD_ENV
196 pthread_attr_t tattr;
197 #else /* AFS_PTHREAD_ENV */
199 #endif /* AFS_PTHREAD_ENV */
201 Lock_Init(&FSYNC_handler_lock);
203 #ifdef AFS_PTHREAD_ENV
204 assert(pthread_attr_init(&tattr) == 0);
205 assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
206 assert(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
207 #else /* AFS_PTHREAD_ENV */
208 assert(LWP_CreateProcess
209 (FSYNC_sync, USUAL_STACK_SIZE, USUAL_PRIORITY, (void *)0,
210 "FSYNC_sync", &pid) == LWP_SUCCESS);
211 #endif /* AFS_PTHREAD_ENV */
214 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
215 static struct pollfd FSYNC_readfds[MAXHANDLERS];
217 static fd_set FSYNC_readfds;
222 FSYNC_sync(void * args)
224 #ifdef USE_UNIX_SOCKETS
225 char tbuffer[AFSDIR_PATH_MAX];
226 #endif /* USE_UNIX_SOCKETS */
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;
239 SYNC_getAddr(&state->endpoint, &state->addr);
240 SYNC_cleanupSock(state);
243 (void)signal(SIGPIPE, SIG_IGN);
246 #ifdef AFS_PTHREAD_ENV
247 /* set our 'thread-id' so that the host hold table works */
248 MUTEX_ENTER(&rx_stats_mutex); /* protects rxi_pthread_hinum */
249 tid = ++rxi_pthread_hinum;
250 MUTEX_EXIT(&rx_stats_mutex);
251 pthread_setspecific(rx_thread_id_key, (void *)tid);
252 Log("Set thread id %d for FSYNC_sync\n", tid);
253 #endif /* AFS_PTHREAD_ENV */
256 /* Let somebody else run until level > 0. That doesn't mean that
257 * all volumes have been attached. */
258 #ifdef AFS_PTHREAD_ENV
260 #else /* AFS_PTHREAD_ENV */
261 LWP_DispatchProcess();
262 #endif /* AFS_PTHREAD_ENV */
264 state->fd = SYNC_getSock(&state->endpoint);
265 code = SYNC_bindSock(state);
268 #ifdef AFS_DEMAND_ATTACH_FS
270 * make sure the volume package is incapable of recursively executing
271 * salvsync calls on this thread, since there is a possibility of
274 thread_opts = malloc(sizeof(VThreadOptions_t));
275 if (thread_opts == NULL) {
276 Log("failed to allocate memory for thread-specific volume package options structure\n");
279 memcpy(thread_opts, &VThread_defaults, sizeof(VThread_defaults));
280 thread_opts->disallow_salvsync = 1;
281 assert(pthread_setspecific(VThread_key, thread_opts) == 0);
288 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
290 GetHandler(FSYNC_readfds, MAXHANDLERS, POLLIN|POLLPRI, &nfds);
291 if (poll(FSYNC_readfds, nfds, -1) >=1)
292 CallHandler(FSYNC_readfds, nfds, POLLIN|POLLPRI);
295 GetHandler(&FSYNC_readfds, &maxfd);
296 /* Note: check for >= 1 below is essential since IOMGR_select
297 * doesn't have exactly same semantics as select.
299 #ifdef AFS_PTHREAD_ENV
300 if (select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
301 #else /* AFS_PTHREAD_ENV */
302 if (IOMGR_Select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
303 #endif /* AFS_PTHREAD_ENV */
304 CallHandler(&FSYNC_readfds);
310 FSYNC_newconnection(int afd)
312 #ifdef USE_UNIX_SOCKETS
313 struct sockaddr_un other;
314 #else /* USE_UNIX_SOCKETS */
315 struct sockaddr_in other;
318 junk = sizeof(other);
319 fd = accept(afd, (struct sockaddr *)&other, &junk);
321 Log("FSYNC_newconnection: accept failed, errno==%d\n", errno);
323 } else if (!AddHandler(fd, FSYNC_com)) {
325 assert(AddHandler(fd, FSYNC_com));
329 /* this function processes commands from an fssync file descriptor (fd) */
330 afs_int32 FS_cnt = 0;
336 SYNC_PROTO_BUF_DECL(com_buf);
337 SYNC_PROTO_BUF_DECL(res_buf);
339 memset(&res.hdr, 0, sizeof(res.hdr));
341 com.payload.buf = (void *)com_buf;
342 com.payload.len = SYNC_PROTO_MAX_LEN;
343 res.hdr.response_len = sizeof(res.hdr);
344 res.payload.len = SYNC_PROTO_MAX_LEN;
345 res.payload.buf = (void *)res_buf;
348 if (SYNC_getCom(&fssync_server_state, fd, &com)) {
349 Log("FSYNC_com: read failed; dropping connection (cnt=%d)\n", FS_cnt);
354 if (com.recv_len < sizeof(com.hdr)) {
355 Log("FSSYNC_com: invalid protocol message length (%u)\n", com.recv_len);
356 res.hdr.response = SYNC_COM_ERROR;
357 res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
358 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
362 if (com.hdr.proto_version != FSYNC_PROTO_VERSION) {
363 Log("FSYNC_com: invalid protocol version (%u)\n", com.hdr.proto_version);
364 res.hdr.response = SYNC_COM_ERROR;
365 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
369 if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
370 res.hdr.response = SYNC_OK;
371 res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
375 res.hdr.com_seq = com.hdr.com_seq;
378 switch (com.hdr.command) {
380 case FSYNC_VOL_ATTACH:
381 case FSYNC_VOL_LEAVE_OFF:
383 case FSYNC_VOL_FORCE_ERROR:
384 case FSYNC_VOL_LISTVOLUMES:
385 case FSYNC_VOL_NEEDVOLUME:
387 case FSYNC_VOL_BREAKCBKS:
389 case FSYNC_VOL_QUERY:
390 case FSYNC_VOL_QUERY_HDR:
391 case FSYNC_VOL_QUERY_VOP:
392 res.hdr.response = FSYNC_com_VolOp(fd, &com, &res);
394 case FSYNC_VOL_STATS_GENERAL:
395 case FSYNC_VOL_STATS_VICEP:
396 case FSYNC_VOL_STATS_HASH:
397 case FSYNC_VOL_STATS_HDR:
398 case FSYNC_VOL_STATS_VLRU:
399 res.hdr.response = FSYNC_com_StatsOp(fd, &com, &res);
401 case FSYNC_VOL_QUERY_VNODE:
402 res.hdr.response = FSYNC_com_VnQry(fd, &com, &res);
405 res.hdr.response = SYNC_BAD_COMMAND;
411 SYNC_putRes(&fssync_server_state, fd, &res);
412 if (res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN) {
418 FSYNC_com_VolOp(int fd, SYNC_command * com, SYNC_response * res)
421 afs_int32 code = SYNC_OK;
422 FSSYNC_VolOp_command vcom;
424 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VolOp_hdr))) {
425 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
426 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
427 return SYNC_COM_ERROR;
430 vcom.hdr = &com->hdr;
431 vcom.vop = (FSSYNC_VolOp_hdr *) com->payload.buf;
434 vcom.volumes = OfflineVolumes[FindHandler(fd)];
435 for (vcom.v = NULL, i = 0; i < MAXOFFLINEVOLUMES; i++) {
436 if ((vcom.volumes[i].volumeID == vcom.vop->volume) &&
437 (strncmp(vcom.volumes[i].partName, vcom.vop->partName,
438 sizeof(vcom.volumes[i].partName)) == 0)) {
439 vcom.v = &vcom.volumes[i];
444 switch (com->hdr.command) {
446 case FSYNC_VOL_ATTACH:
447 case FSYNC_VOL_LEAVE_OFF:
448 code = FSYNC_com_VolOn(&vcom, res);
451 case FSYNC_VOL_NEEDVOLUME:
452 code = FSYNC_com_VolOff(&vcom, res);
454 case FSYNC_VOL_LISTVOLUMES:
458 code = FSYNC_com_VolMove(&vcom, res);
460 case FSYNC_VOL_BREAKCBKS:
461 code = FSYNC_com_VolBreakCBKs(&vcom, res);
464 code = FSYNC_com_VolDone(&vcom, res);
466 case FSYNC_VOL_QUERY:
467 code = FSYNC_com_VolQuery(&vcom, res);
469 case FSYNC_VOL_QUERY_HDR:
470 code = FSYNC_com_VolHdrQuery(&vcom, res);
472 #ifdef AFS_DEMAND_ATTACH_FS
473 case FSYNC_VOL_FORCE_ERROR:
474 code = FSYNC_com_VolError(&vcom, res);
476 case FSYNC_VOL_QUERY_VOP:
477 code = FSYNC_com_VolOpQuery(&vcom, res);
479 #endif /* AFS_DEMAND_ATTACH_FS */
481 code = SYNC_BAD_COMMAND;
488 * service an FSYNC request to bring a volume online.
490 * @param[in] vcom pointer command object
491 * @param[out] res object in which to store response packet
493 * @return operation status
494 * @retval SYNC_OK volume transitioned online
495 * @retval SYNC_FAILED invalid command protocol message
496 * @retval SYNC_DENIED operation could not be completed
498 * @note this is an FSYNC RPC server stub
500 * @note this procedure handles the following FSSYNC command codes:
503 * - FSYNC_VOL_LEAVE_OFF
505 * @note the supplementary reason code contains additional details.
506 * When SYNC_DENIED is returned, the specific reason is
507 * placed in the response packet reason field.
512 FSYNC_com_VolOn(FSSYNC_VolOp_command * vcom, SYNC_response * res)
514 afs_int32 code = SYNC_OK;
515 char tvolName[VMAXPATHLEN];
519 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
520 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
525 /* so, we need to attach the volume */
527 #ifdef AFS_DEMAND_ATTACH_FS
528 /* check DAFS permissions */
529 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
531 FSYNC_partMatch(vcom, vp, 1) &&
532 vp->pending_vol_op &&
533 (vcom->hdr->programType != vp->pending_vol_op->com.programType)) {
534 /* a different program has this volume checked out. deny. */
535 Log("FSYNC_VolOn: WARNING: program type %u has attempted to manipulate "
536 "state for volume %u using command code %u while the volume is "
537 "checked out by program type %u for command code %u.\n",
538 vcom->hdr->programType,
541 vp->pending_vol_op->com.programType,
542 vp->pending_vol_op->com.command);
544 res->hdr.reason = FSYNC_EXCLUSIVE;
550 vcom->v->volumeID = 0;
553 if (vcom->hdr->command == FSYNC_VOL_LEAVE_OFF) {
554 /* nothing much to do if we're leaving the volume offline */
555 #ifdef AFS_DEMAND_ATTACH_FS
557 if (FSYNC_partMatch(vcom, vp, 1)) {
558 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
559 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
560 VChangeState_r(vp, VOL_STATE_UNATTACHED);
561 VDeregisterVolOp_r(vp);
564 res->hdr.reason = FSYNC_BAD_STATE;
568 res->hdr.reason = FSYNC_WRONG_PART;
572 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
578 #ifdef AFS_DEMAND_ATTACH_FS
579 /* first, check to see whether we have such a volume defined */
580 vp = VPreAttachVolumeById_r(&error,
584 VDeregisterVolOp_r(vp);
586 #else /* !AFS_DEMAND_ATTACH_FS */
588 snprintf(&tvolName[1], sizeof(tvolName)-1, VFORMAT, vcom->vop->volume);
589 tvolName[sizeof(tvolName)-1] = '\0';
591 vp = VAttachVolumeByName_r(&error, vcom->vop->partName, tvolName,
597 res->hdr.reason = error;
599 #endif /* !AFS_DEMAND_ATTACH_FS */
606 * service an FSYNC request to take a volume offline.
608 * @param[in] vcom pointer command object
609 * @param[out] res object in which to store response packet
611 * @return operation status
612 * @retval SYNC_OK volume transitioned offline
613 * @retval SYNC_FAILED invalid command protocol message
614 * @retval SYNC_DENIED operation could not be completed
616 * @note this is an FSYNC RPC server stub
618 * @note this procedure handles the following FSSYNC command codes:
620 * - FSYNC_VOL_NEEDVOLUME
622 * @note the supplementary reason code contains additional details.
623 * When SYNC_DENIED is returned, the specific reason is
624 * placed in the response packet reason field.
629 FSYNC_com_VolOff(FSSYNC_VolOp_command * vcom, SYNC_response * res)
631 FSSYNC_VolOp_info info;
632 afs_int32 code = SYNC_OK;
636 #ifdef AFS_DEMAND_ATTACH_FS
640 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
641 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
646 /* not already offline, we need to find a slot for newly offline volume */
647 if (vcom->hdr->programType == debugUtility) {
648 /* debug utilities do not have their operations tracked */
652 for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
653 if (vcom->volumes[i].volumeID == 0) {
654 vcom->v = &vcom->volumes[i];
664 FSYNC_com_to_info(vcom, &info);
666 #ifdef AFS_DEMAND_ATTACH_FS
667 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
669 vp = VGetVolume_r(&error, vcom->vop->volume);
673 if (!FSYNC_partMatch(vcom, vp, 1)) {
674 /* volume on desired partition is not online, so we
675 * should treat this as an offline volume.
677 #ifndef AFS_DEMAND_ATTACH_FS
685 #ifdef AFS_DEMAND_ATTACH_FS
687 ProgramType type = (ProgramType) vcom->hdr->programType;
689 /* do initial filtering of requests */
691 /* enforce mutual exclusion for volume ops */
692 if (vp->pending_vol_op) {
693 if (vp->pending_vol_op->com.programType != type) {
694 Log("volume %u already checked out\n", vp->hashid);
696 Log("vp->vop = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x }, vop = { vol=%u, part='%s' } }\n",
697 vp->pending_vol_op->com.proto_version,
698 vp->pending_vol_op->com.programType,
699 vp->pending_vol_op->com.command,
700 vp->pending_vol_op->com.reason,
701 vp->pending_vol_op->com.command_len,
702 vp->pending_vol_op->com.flags,
703 vp->pending_vol_op->vop.volume,
704 vp->pending_vol_op->vop.partName );
705 Log("vcom = { com = { ver=%u, prog=%d, com=%d, reason=%d, len=%u, flags=0x%x } , vop = { vol=%u, part='%s' } }\n",
706 vcom->hdr->proto_version,
707 vcom->hdr->programType,
710 vcom->hdr->command_len,
713 vcom->vop->partName);
714 res->hdr.reason = FSYNC_EXCLUSIVE;
717 Log("warning: volume %u recursively checked out by programType id %d\n",
718 vp->hashid, vcom->hdr->programType);
722 /* filter based upon requestor
724 * volume utilities are not allowed to check out volumes
725 * which are in an error state
727 * unknown utility programs will be denied on principal
731 /* it is possible for the salvageserver to checkout a
732 * volume for salvage before its scheduling request
733 * has been sent to the salvageserver */
734 if (vp->salvage.requested && !vp->salvage.scheduled) {
735 vp->salvage.scheduled = 1;
741 if (VIsErrorState(V_attachState(vp))) {
747 Log("bad program type passed to FSSYNC\n");
751 /* short circuit for offline volume states
752 * so we can avoid I/O penalty of attachment */
753 switch (V_attachState(vp)) {
754 case VOL_STATE_UNATTACHED:
755 case VOL_STATE_PREATTACHED:
756 case VOL_STATE_SALVAGING:
757 case VOL_STATE_ERROR:
758 /* register the volume operation metadata with the volume
760 * if the volume is currently pre-attached, attach2()
761 * will evaluate the vol op metadata to determine whether
762 * attaching the volume would be safe */
763 VRegisterVolOp_r(vp, &info);
769 /* convert to heavyweight ref */
770 nvp = VGetVolumeByVp_r(&error, vp);
773 Log("FSYNC_com_VolOff: failed to get heavyweight reference to volume %u\n",
775 res->hdr.reason = FSYNC_VOL_PKG_ERROR;
777 } else if (nvp != vp) {
778 /* i don't think this should ever happen, but just in case... */
779 Log("FSYNC_com_VolOff: warning: potentially dangerous race detected\n");
783 /* register the volume operation metadata with the volume */
784 VRegisterVolOp_r(vp, &info);
787 #endif /* AFS_DEMAND_ATTACH_FS */
790 if (VVolOpLeaveOnline_r(vp, &info)) {
791 VUpdateVolume_r(&error, vp, VOL_UPDATE_WAIT); /* At least get volume stats right */
793 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n",
794 V_id(vp), V_name(vp),
795 vcom->hdr->reason == V_CLONE ? "clone" :
796 vcom->hdr->reason == V_READONLY ? "readonly" :
797 vcom->hdr->reason == V_DUMP ? "dump" :
802 if (VVolOpSetVBusy_r(vp, &info)) {
803 vp->specialStatus = VBUSY;
806 /* remember what volume we got, so we can keep track of how
807 * many volumes the volserver or whatever is using. Note that
808 * vp is valid since leaveonline is only set when vp is valid.
811 vcom->v->volumeID = vcom->vop->volume;
812 strlcpy(vcom->v->partName, vp->partition->name, sizeof(vcom->v->partName));
815 VOffline_r(vp, "A volume utility is running.");
828 * service an FSYNC request to mark a volume as moved.
830 * @param[in] vcom pointer command object
831 * @param[out] res object in which to store response packet
833 * @return operation status
834 * @retval SYNC_OK volume marked as moved to a remote server
835 * @retval SYNC_FAILED invalid command protocol message
836 * @retval SYNC_DENIED current volume state does not permit this operation
838 * @note this is an FSYNC RPC server stub
840 * @note this operation also breaks all callbacks for the given volume
842 * @note this procedure handles the following FSSYNC command codes:
845 * @note the supplementary reason code contains additional details. For
846 * instance, SYNC_OK is still returned when the partition specified
847 * does not match the one registered in the volume object -- reason
848 * will be FSYNC_WRONG_PART in this case.
853 FSYNC_com_VolMove(FSSYNC_VolOp_command * vcom, SYNC_response * res)
855 afs_int32 code = SYNC_DENIED;
859 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
860 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
865 /* Yuch: the "reason" for the move is the site it got moved to... */
866 /* still set specialStatus so we stop sending back VBUSY.
867 * also should still break callbacks. Note that I don't know
868 * how to tell if we should break all or not, so we just do it
869 * since it doesn't matter much if we do an extra break
870 * volume callbacks on a volume move within the same server */
871 #ifdef AFS_DEMAND_ATTACH_FS
872 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
874 vp = VGetVolume_r(&error, vcom->vop->volume);
877 if (FSYNC_partMatch(vcom, vp, 1)) {
878 #ifdef AFS_DEMAND_ATTACH_FS
879 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
880 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
883 vp->specialStatus = VMOVED;
884 #ifdef AFS_DEMAND_ATTACH_FS
886 res->hdr.reason = FSYNC_BAD_STATE;
890 res->hdr.reason = FSYNC_WRONG_PART;
894 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
897 if ((code == SYNC_OK) && (V_BreakVolumeCallbacks != NULL)) {
898 Log("fssync: volume %u moved to %x; breaking all call backs\n",
899 vcom->vop->volume, vcom->hdr->reason);
901 (*V_BreakVolumeCallbacks) (vcom->vop->volume);
911 * service an FSYNC request to mark a volume as destroyed.
913 * @param[in] vcom pointer command object
914 * @param[out] res object in which to store response packet
916 * @return operation status
917 * @retval SYNC_OK volume marked as destroyed
918 * @retval SYNC_FAILED invalid command protocol message
919 * @retval SYNC_DENIED current volume state does not permit this operation
921 * @note this is an FSYNC RPC server stub
923 * @note this procedure handles the following FSSYNC command codes:
926 * @note the supplementary reason code contains additional details. For
927 * instance, SYNC_OK is still returned when the partition specified
928 * does not match the one registered in the volume object -- reason
929 * will be FSYNC_WRONG_PART in this case.
934 FSYNC_com_VolDone(FSSYNC_VolOp_command * vcom, SYNC_response * res)
936 afs_int32 code = SYNC_FAILED;
937 #ifdef AFS_DEMAND_ATTACH_FS
942 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
943 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
947 /* don't try to put online, this call is made only after deleting
948 * a volume, in which case we want to remove the vol # from the
949 * OfflineVolumes array only */
951 vcom->v->volumeID = 0;
953 #ifdef AFS_DEMAND_ATTACH_FS
954 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
956 if (FSYNC_partMatch(vcom, vp, 1)) {
957 if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
958 (V_attachState(vp) == VOL_STATE_PREATTACHED)) {
959 VChangeState_r(vp, VOL_STATE_UNATTACHED);
960 VDeregisterVolOp_r(vp);
964 res->hdr.reason = FSYNC_BAD_STATE;
967 code = SYNC_OK; /* XXX is this really a good idea? */
968 res->hdr.reason = FSYNC_WRONG_PART;
971 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
979 #ifdef AFS_DEMAND_ATTACH_FS
981 * service an FSYNC request to transition a volume to the hard error state.
983 * @param[in] vcom pointer command object
984 * @param[out] res object in which to store response packet
986 * @return operation status
987 * @retval SYNC_OK volume transitioned to hard error state
988 * @retval SYNC_FAILED invalid command protocol message
989 * @retval SYNC_DENIED (see note)
991 * @note this is an FSYNC RPC server stub
993 * @note this procedure handles the following FSSYNC command codes:
994 * - FSYNC_VOL_FORCE_ERROR
996 * @note SYNC_DENIED is returned in the following cases:
997 * - no partition name is specified (reason field set to
999 * - volume id not known to fileserver (reason field set
1000 * to FSYNC_UNKNOWN_VOLID).
1002 * @note demand attach fileserver only
1007 FSYNC_com_VolError(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1011 afs_int32 code = SYNC_FAILED;
1013 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1014 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1018 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1020 if (FSYNC_partMatch(vcom, vp, 0)) {
1021 /* null out salvsync control state, as it's no longer relevant */
1022 memset(&vp->salvage, 0, sizeof(vp->salvage));
1023 VChangeState_r(vp, VOL_STATE_ERROR);
1026 res->hdr.reason = FSYNC_WRONG_PART;
1029 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1035 #endif /* AFS_DEMAND_ATTACH_FS */
1038 * service an FSYNC request to break all callbacks for this volume.
1040 * @param[in] vcom pointer command object
1041 * @param[out] res object in which to store response packet
1043 * @return operation status
1044 * @retval SYNC_OK callback breaks scheduled for volume
1046 * @note this is an FSYNC RPC server stub
1048 * @note this procedure handles the following FSSYNC command codes:
1049 * - FSYNC_VOL_BREAKCBKS
1051 * @note demand attach fileserver only
1053 * @todo should do partition matching
1058 FSYNC_com_VolBreakCBKs(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1060 /* if the volume is being restored, break all callbacks on it */
1061 if (V_BreakVolumeCallbacks) {
1062 Log("fssync: breaking all call backs for volume %u\n",
1065 (*V_BreakVolumeCallbacks) (vcom->vop->volume);
1072 * service an FSYNC request to return the Volume object.
1074 * @param[in] vcom pointer command object
1075 * @param[out] res object in which to store response packet
1077 * @return operation status
1078 * @retval SYNC_OK volume object returned to caller
1079 * @retval SYNC_FAILED bad command packet, or failed to locate volume object
1081 * @note this is an FSYNC RPC server stub
1083 * @note this procedure handles the following FSSYNC command codes:
1089 FSYNC_com_VolQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1091 afs_int32 code = SYNC_FAILED;
1095 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1096 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1100 #ifdef AFS_DEMAND_ATTACH_FS
1101 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1102 #else /* !AFS_DEMAND_ATTACH_FS */
1103 vp = VGetVolume_r(&error, vcom->vop->volume);
1104 #endif /* !AFS_DEMAND_ATTACH_FS */
1107 if (FSYNC_partMatch(vcom, vp, 1)) {
1108 if (res->payload.len >= sizeof(Volume)) {
1109 memcpy(res->payload.buf, vp, sizeof(Volume));
1110 res->hdr.response_len += sizeof(Volume);
1113 res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1116 res->hdr.reason = FSYNC_WRONG_PART;
1118 #ifndef AFS_DEMAND_ATTACH_FS
1122 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1130 * service an FSYNC request to return the Volume header.
1132 * @param[in] vcom pointer command object
1133 * @param[out] res object in which to store response packet
1135 * @return operation status
1136 * @retval SYNC_OK volume header returned to caller
1137 * @retval SYNC_FAILED bad command packet, or failed to locate volume header
1139 * @note this is an FSYNC RPC server stub
1141 * @note this procedure handles the following FSSYNC command codes:
1142 * - FSYNC_VOL_QUERY_HDR
1147 FSYNC_com_VolHdrQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1149 afs_int32 code = SYNC_FAILED;
1154 if (SYNC_verifyProtocolString(vcom->vop->partName, sizeof(vcom->vop->partName))) {
1155 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1158 if (res->payload.len < sizeof(VolumeDiskData)) {
1159 res->hdr.reason = SYNC_REASON_PAYLOAD_TOO_BIG;
1163 #ifdef AFS_DEMAND_ATTACH_FS
1164 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1165 #else /* !AFS_DEMAND_ATTACH_FS */
1166 vp = VGetVolume_r(&error, vcom->vop->volume);
1170 if (FSYNC_partMatch(vcom, vp, 1)) {
1171 #ifdef AFS_DEMAND_ATTACH_FS
1172 if ((vp->header == NULL) ||
1173 !(V_attachFlags(vp) & VOL_HDR_ATTACHED) ||
1174 !(V_attachFlags(vp) & VOL_HDR_LOADED)) {
1175 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1178 #else /* !AFS_DEMAND_ATTACH_FS */
1179 if (!vp || !vp->header) {
1180 res->hdr.reason = FSYNC_HDR_NOT_ATTACHED;
1183 #endif /* !AFS_DEMAND_ATTACH_FS */
1185 res->hdr.reason = FSYNC_WRONG_PART;
1189 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1194 memcpy(res->payload.buf, &V_disk(vp), sizeof(VolumeDiskData));
1195 res->hdr.response_len += sizeof(VolumeDiskData);
1196 #ifndef AFS_DEMAND_ATTACH_FS
1205 #ifdef AFS_DEMAND_ATTACH_FS
1207 FSYNC_com_VolOpQuery(FSSYNC_VolOp_command * vcom, SYNC_response * res)
1209 afs_int32 code = SYNC_OK;
1213 vp = VLookupVolume_r(&error, vcom->vop->volume, NULL);
1215 if (vp && vp->pending_vol_op) {
1216 assert(sizeof(FSSYNC_VolOp_info) <= res->payload.len);
1217 memcpy(res->payload.buf, vp->pending_vol_op, sizeof(FSSYNC_VolOp_info));
1218 res->hdr.response_len += sizeof(FSSYNC_VolOp_info);
1221 res->hdr.reason = FSYNC_NO_PENDING_VOL_OP;
1223 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1229 #endif /* AFS_DEMAND_ATTACH_FS */
1232 FSYNC_com_VnQry(int fd, SYNC_command * com, SYNC_response * res)
1234 afs_int32 code = SYNC_OK;
1235 FSSYNC_VnQry_hdr * qry = com->payload.buf;
1240 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_VnQry_hdr))) {
1241 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1242 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1243 return SYNC_COM_ERROR;
1246 #ifdef AFS_DEMAND_ATTACH_FS
1247 vp = VLookupVolume_r(&error, qry->volume, NULL);
1248 #else /* !AFS_DEMAND_ATTACH_FS */
1249 vp = VGetVolume_r(&error, qry->volume);
1250 #endif /* !AFS_DEMAND_ATTACH_FS */
1253 res->hdr.reason = FSYNC_UNKNOWN_VOLID;
1258 vnp = VLookupVnode(vp, qry->vnode);
1260 res->hdr.reason = FSYNC_UNKNOWN_VNID;
1265 if (Vn_class(vnp)->residentSize > res->payload.len) {
1266 res->hdr.reason = SYNC_REASON_ENCODING_ERROR;
1271 memcpy(res->payload.buf, vnp, Vn_class(vnp)->residentSize);
1272 res->hdr.response_len += Vn_class(vnp)->residentSize;
1275 #ifndef AFS_DEMAND_ATTACH_FS
1284 FSYNC_com_StatsOp(int fd, SYNC_command * com, SYNC_response * res)
1286 afs_int32 code = SYNC_OK;
1287 FSSYNC_StatsOp_command scom;
1289 if (com->recv_len != (sizeof(com->hdr) + sizeof(FSSYNC_StatsOp_hdr))) {
1290 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1291 res->hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
1292 return SYNC_COM_ERROR;
1295 scom.hdr = &com->hdr;
1296 scom.sop = (FSSYNC_StatsOp_hdr *) com->payload.buf;
1299 switch (com->hdr.command) {
1300 case FSYNC_VOL_STATS_GENERAL:
1301 code = FSYNC_com_StatsOpGeneral(&scom, res);
1303 #ifdef AFS_DEMAND_ATTACH_FS
1304 /* statistics for the following subsystems are only tracked
1305 * for demand attach fileservers */
1306 case FSYNC_VOL_STATS_VICEP:
1307 code = FSYNC_com_StatsOpViceP(&scom, res);
1309 case FSYNC_VOL_STATS_HASH:
1310 code = FSYNC_com_StatsOpHash(&scom, res);
1312 case FSYNC_VOL_STATS_HDR:
1313 code = FSYNC_com_StatsOpHdr(&scom, res);
1315 case FSYNC_VOL_STATS_VLRU:
1316 code = FSYNC_com_StatsOpVLRU(&scom, res);
1318 #endif /* AFS_DEMAND_ATTACH_FS */
1320 code = SYNC_BAD_COMMAND;
1327 FSYNC_com_StatsOpGeneral(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1329 afs_int32 code = SYNC_OK;
1331 memcpy(res->payload.buf, &VStats, sizeof(VStats));
1332 res->hdr.response_len += sizeof(VStats);
1337 #ifdef AFS_DEMAND_ATTACH_FS
1339 FSYNC_com_StatsOpViceP(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1341 afs_int32 code = SYNC_OK;
1342 struct DiskPartition64 * dp;
1343 struct DiskPartitionStats64 * stats;
1345 if (SYNC_verifyProtocolString(scom->sop->args.partName, sizeof(scom->sop->args.partName))) {
1346 res->hdr.reason = SYNC_REASON_MALFORMED_PACKET;
1351 dp = VGetPartition_r(scom->sop->args.partName, 0);
1355 stats = (struct DiskPartitionStats64 *) res->payload.buf;
1356 stats->free = dp->free;
1357 stats->totalUsable = dp->totalUsable;
1358 stats->minFree = dp->minFree;
1359 stats->f_files = dp->f_files;
1360 stats->vol_list_len = dp->vol_list.len;
1362 res->hdr.response_len += sizeof(struct DiskPartitionStats64);
1370 FSYNC_com_StatsOpHash(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1372 afs_int32 code = SYNC_OK;
1373 struct VolumeHashChainStats * stats;
1374 struct VolumeHashChainHead * head;
1376 if (scom->sop->args.hash_bucket >= VolumeHashTable.Size) {
1380 head = &VolumeHashTable.Table[scom->sop->args.hash_bucket];
1381 stats = (struct VolumeHashChainStats *) res->payload.buf;
1382 stats->table_size = VolumeHashTable.Size;
1383 stats->chain_len = head->len;
1384 stats->chain_cacheCheck = head->cacheCheck;
1385 stats->chain_busy = head->busy;
1386 AssignInt64(head->looks, &stats->chain_looks);
1387 AssignInt64(head->gets, &stats->chain_gets);
1388 AssignInt64(head->reorders, &stats->chain_reorders);
1390 res->hdr.response_len += sizeof(struct VolumeHashChainStats);
1396 FSYNC_com_StatsOpHdr(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1398 afs_int32 code = SYNC_OK;
1400 memcpy(res->payload.buf, &volume_hdr_LRU.stats, sizeof(volume_hdr_LRU.stats));
1401 res->hdr.response_len += sizeof(volume_hdr_LRU.stats);
1407 FSYNC_com_StatsOpVLRU(FSSYNC_StatsOp_command * scom, SYNC_response * res)
1409 afs_int32 code = SYNC_OK;
1411 code = SYNC_BAD_COMMAND;
1415 #endif /* AFS_DEMAND_ATTACH_FS */
1418 * populate an FSSYNC_VolOp_info object from a command packet object.
1420 * @param[in] vcom pointer to command packet
1421 * @param[out] info pointer to info object which will be populated
1423 * @note FSSYNC_VolOp_info objects are attached to Volume objects when
1424 * a volume operation is commenced.
1429 FSYNC_com_to_info(FSSYNC_VolOp_command * vcom, FSSYNC_VolOp_info * info)
1431 memcpy(&info->com, vcom->hdr, sizeof(SYNC_command_hdr));
1432 memcpy(&info->vop, vcom->vop, sizeof(FSSYNC_VolOp_hdr));
1436 * check whether command packet partition name matches volume
1437 * object's partition name.
1439 * @param[in] vcom pointer to command packet
1440 * @param[in] vp pointer to volume object
1441 * @param[in] match_anon anon matching control flag (see note below)
1443 * @return whether partitions match
1444 * @retval 0 partitions do NOT match
1445 * @retval 1 partitions match
1447 * @note if match_anon is non-zero, then this function will return a
1448 * positive match for a zero-length partition string in the
1454 FSYNC_partMatch(FSSYNC_VolOp_command * vcom, Volume * vp, int match_anon)
1456 return ((match_anon && vcom->vop->partName[0] == 0) ||
1457 (strncmp(vcom->vop->partName, V_partition(vp)->name,
1458 sizeof(vcom->vop->partName)) == 0));
1465 struct offlineInfo *p;
1468 char tvolName[VMAXPATHLEN];
1471 p = OfflineVolumes[FindHandler(fd)];
1472 for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
1473 if (p[i].volumeID) {
1478 sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
1479 vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
1496 static int AcceptHandler = -1; /* handler id for accept, if turned on */
1501 if (AcceptHandler == -1) {
1502 assert(AddHandler(fssync_server_state.fd, FSYNC_newconnection));
1503 AcceptHandler = FindHandler(fssync_server_state.fd);
1510 if (AcceptHandler != -1) {
1511 assert(RemoveHandler(fssync_server_state.fd));
1516 /* The multiple FD handling code. */
1518 static int HandlerFD[MAXHANDLERS];
1519 static int (*HandlerProc[MAXHANDLERS]) ();
1525 ObtainWriteLock(&FSYNC_handler_lock);
1526 for (i = 0; i < MAXHANDLERS; i++) {
1530 ReleaseWriteLock(&FSYNC_handler_lock);
1533 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1535 CallHandler(struct pollfd *fds, int nfds, int mask)
1539 ObtainReadLock(&FSYNC_handler_lock);
1540 for (i = 0; i < nfds; i++) {
1541 if (fds[i].revents & mask) {
1542 handler = FindHandler_r(fds[i].fd);
1543 ReleaseReadLock(&FSYNC_handler_lock);
1544 (*HandlerProc[handler]) (fds[i].fd);
1545 ObtainReadLock(&FSYNC_handler_lock);
1548 ReleaseReadLock(&FSYNC_handler_lock);
1552 CallHandler(fd_set * fdsetp)
1555 ObtainReadLock(&FSYNC_handler_lock);
1556 for (i = 0; i < MAXHANDLERS; i++) {
1557 if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
1558 ReleaseReadLock(&FSYNC_handler_lock);
1559 (*HandlerProc[i]) (HandlerFD[i]);
1560 ObtainReadLock(&FSYNC_handler_lock);
1563 ReleaseReadLock(&FSYNC_handler_lock);
1568 AddHandler(int afd, int (*aproc) ())
1571 ObtainWriteLock(&FSYNC_handler_lock);
1572 for (i = 0; i < MAXHANDLERS; i++)
1573 if (HandlerFD[i] == -1)
1575 if (i >= MAXHANDLERS) {
1576 ReleaseWriteLock(&FSYNC_handler_lock);
1580 HandlerProc[i] = aproc;
1581 ReleaseWriteLock(&FSYNC_handler_lock);
1586 FindHandler(register int afd)
1589 ObtainReadLock(&FSYNC_handler_lock);
1590 for (i = 0; i < MAXHANDLERS; i++)
1591 if (HandlerFD[i] == afd) {
1592 ReleaseReadLock(&FSYNC_handler_lock);
1595 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
1597 return -1; /* satisfy compiler */
1601 FindHandler_r(register int afd)
1604 for (i = 0; i < MAXHANDLERS; i++)
1605 if (HandlerFD[i] == afd) {
1609 return -1; /* satisfy compiler */
1613 RemoveHandler(register int afd)
1615 ObtainWriteLock(&FSYNC_handler_lock);
1616 HandlerFD[FindHandler_r(afd)] = -1;
1617 ReleaseWriteLock(&FSYNC_handler_lock);
1621 #if defined(HAVE_POLL) && defined(AFS_PTHREAD_ENV)
1623 GetHandler(struct pollfd *fds, int maxfds, int events, int *nfds)
1627 ObtainReadLock(&FSYNC_handler_lock);
1628 for (i = 0; i < MAXHANDLERS; i++)
1629 if (HandlerFD[i] != -1) {
1631 fds[fdi].fd = HandlerFD[i];
1632 fds[fdi].events = events;
1633 fds[fdi].revents = 0;
1637 ReleaseReadLock(&FSYNC_handler_lock);
1641 GetHandler(fd_set * fdsetp, int *maxfdp)
1644 register int maxfd = -1;
1646 ObtainReadLock(&FSYNC_handler_lock); /* just in case */
1647 for (i = 0; i < MAXHANDLERS; i++)
1648 if (HandlerFD[i] != -1) {
1649 FD_SET(HandlerFD[i], fdsetp);
1650 if (maxfd < HandlerFD[i])
1651 maxfd = HandlerFD[i];
1654 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
1656 #endif /* HAVE_POLL && AFS_PTHREAD_ENV */
1658 #endif /* FSSYNC_BUILD_SERVER */