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
13 Institution: The Information Technology Center, Carnegie-Mellon University
18 /* All this is going away in early 1989 */
19 int newVLDB; /* Compatibility flag */
22 static int newVLDB = 1;
25 #ifndef AFS_PTHREAD_ENV
26 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
29 * stack size increased from 8K because the HP machine seemed to have trouble
30 * with the smaller stack
32 #define USUAL_STACK_SIZE (24 * 1024)
33 #endif /* !AFS_PTHREAD_ENV */
37 File server synchronization with external volume utilities.
40 /* This controls the size of an fd_set; it must be defined early before
41 * the system headers define that type and the macros that operate on it.
42 * Its value should be as large as the maximum file descriptor limit we
43 * are likely to run into on any platform. Right now, that is 65536
44 * which is the default hard fd limit on Solaris 9 */
45 #define FD_SETSIZE 65536
47 #include <afsconfig.h>
48 #include <afs/param.h>
53 #include <sys/types.h>
59 #include <sys/param.h>
60 #include <sys/socket.h>
61 #include <netinet/in.h>
66 #ifdef AFS_PTHREAD_ENV
68 #else /* AFS_PTHREAD_ENV */
69 #include <afs/assert.h>
70 #endif /* AFS_PTHREAD_ENV */
83 #include <afs/afsint.h>
85 #include <afs/errors.h>
89 #include <afs/afssyscalls.h>
93 #include "partition.h"
95 /*@printflike@*/ extern void Log(const char *format, ...);
100 #define osi_Assert(e) (void)(e)
102 int (*V_BreakVolumeCallbacks) ();
104 #define MAXHANDLERS 4 /* Up to 4 clients; must be at least 2, so that
105 * move = dump+restore can run on single server */
106 #define MAXOFFLINEVOLUMES 30 /* This needs to be as big as the maximum
107 * number that would be offline for 1 operation.
108 * Current winner is salvage, which needs all
109 * cloned read-only copies offline when salvaging
110 * a single read-write volume */
112 #define MAX_BIND_TRIES 5 /* Number of times to retry socket bind */
120 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
122 static FS_sd = -1; /* Client socket for talking to file server */
123 static AcceptSd = -1; /* Socket used by server for accepting connections */
125 static int getport();
131 char partName[16]; /* partition name, e.g. /vicepa */
134 /* Forward declarations */
135 static void FSYNC_sync();
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 void CallHandler(fd_set * fdsetp);
143 static int AddHandler();
144 static int FindHandler();
145 static int FindHandler_r();
146 static int RemoveHandler();
147 static void GetHandler(fd_set * fdsetp, int *maxfdp);
152 * This lock controls access to the handler array. The overhead
153 * is minimal in non-preemptive environments.
155 struct Lock FSYNC_handler_lock;
158 FSYNC_clientInit(void)
160 struct sockaddr_in addr;
161 /* I can't believe the following is needed for localhost connections!! */
162 static time_t backoff[] =
163 { 3, 3, 3, 5, 5, 5, 7, 15, 16, 24, 32, 40, 48, 0 };
164 time_t *timeout = &backoff[0];
167 FS_sd = getport(&addr);
168 if (connect(FS_sd, (struct sockaddr *)&addr, sizeof(addr)) >= 0)
170 #if defined(AFS_SGI_ENV)
171 /* down with worthless error messages! */
173 perror("FSYNC_clientInit failed (after many retries)");
180 perror("FSYNC_clientInit temporary failure (will retry)");
185 perror("FSYNC_clientInit failed (giving up!)");
190 FSYNC_clientFinis(void)
198 Lock_Destroy(&FSYNC_handler_lock);
202 FSYNC_askfs(VolumeId volume, char *partName, int com, int reason)
205 struct command command;
207 command.volume = volume;
208 command.command = com;
209 command.reason = reason;
211 strcpy(command.partName, partName);
213 command.partName[0] = 0;
217 if (send(FS_sd, (char *)&command, sizeof(command), 0) != sizeof(command)) {
218 printf("FSYNC_askfs: write to file server failed\n");
219 response = FSYNC_DENIED;
222 while ((n = recv(FS_sd, &response, 1, 0)) != 1) {
223 if (n == 0 || WSAEINTR != WSAGetLastError()) {
224 printf("FSYNC_askfs: No response from file server\n");
225 response = FSYNC_DENIED;
230 if (write(FS_sd, &command, sizeof(command)) != sizeof(command)) {
231 printf("FSYNC_askfs: write to file server failed\n");
232 response = FSYNC_DENIED;
235 while ((n = read(FS_sd, &response, 1)) != 1) {
236 if (n == 0 || errno != EINTR) {
237 printf("FSYNC_askfs: No response from file server\n");
238 response = FSYNC_DENIED;
245 ("FSYNC_askfs: negative response from file server; volume %u, command %d\n",
246 command.volume, (int)command.command);
257 #ifdef AFS_PTHREAD_ENV
259 pthread_attr_t tattr;
260 assert(pthread_attr_init(&tattr) == 0);
261 assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
262 assert(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
263 #else /* AFS_PTHREAD_ENV */
265 assert(LWP_CreateProcess
266 (FSYNC_sync, USUAL_STACK_SIZE, USUAL_PRIORITY, (void *)0,
267 "FSYNC_sync", &pid) == LWP_SUCCESS);
268 #endif /* AFS_PTHREAD_ENV */
272 getport(struct sockaddr_in *addr)
276 memset(addr, 0, sizeof(*addr));
277 assert((sd = socket(AF_INET, SOCK_STREAM, 0)) >= 0);
278 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
279 addr->sin_len = sizeof(struct sockaddr_in);
281 addr->sin_addr.s_addr = htonl(0x7f000001);
282 addr->sin_family = AF_INET; /* was localhost->h_addrtype */
283 addr->sin_port = htons(2040); /* XXXX htons not _really_ neccessary */
288 static fd_set FSYNC_readfds;
293 struct sockaddr_in addr;
298 #ifdef AFS_PTHREAD_ENV
303 (void)signal(SIGPIPE, SIG_IGN);
306 #ifdef AFS_PTHREAD_ENV
307 /* set our 'thread-id' so that the host hold table works */
308 MUTEX_ENTER(&rx_stats_mutex); /* protects rxi_pthread_hinum */
309 tid = ++rxi_pthread_hinum;
310 MUTEX_EXIT(&rx_stats_mutex);
311 pthread_setspecific(rx_thread_id_key, (void *)tid);
312 Log("Set thread id %d for FSYNC_sync\n", tid);
313 #endif /* AFS_PTHREAD_ENV */
316 /* Let somebody else run until level > 0. That doesn't mean that
317 * all volumes have been attached. */
318 #ifdef AFS_PTHREAD_ENV
320 #else /* AFS_PTHREAD_ENV */
321 LWP_DispatchProcess();
322 #endif /* AFS_PTHREAD_ENV */
324 AcceptSd = getport(&addr);
325 /* Reuseaddr needed because system inexplicably leaves crud lying around */
327 setsockopt(AcceptSd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
330 Log("FSYNC_sync: setsockopt failed with (%d)\n", errno);
332 for (numTries = 0; numTries < MAX_BIND_TRIES; numTries++) {
334 bind(AcceptSd, (struct sockaddr *)&addr, sizeof(addr))) == 0)
336 Log("FSYNC_sync: bind failed with (%d), will sleep and retry\n",
341 listen(AcceptSd, 100);
346 GetHandler(&FSYNC_readfds, &maxfd);
347 /* Note: check for >= 1 below is essential since IOMGR_select
348 * doesn't have exactly same semantics as select.
350 #ifdef AFS_PTHREAD_ENV
351 if (select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
352 #else /* AFS_PTHREAD_ENV */
353 if (IOMGR_Select(maxfd + 1, &FSYNC_readfds, NULL, NULL, NULL) >= 1)
354 #endif /* AFS_PTHREAD_ENV */
355 CallHandler(&FSYNC_readfds);
360 FSYNC_newconnection(int afd)
362 struct sockaddr_in other;
364 junk = sizeof(other);
365 fd = accept(afd, (struct sockaddr *)&other, &junk);
367 Log("FSYNC_newconnection: accept failed, errno==%d\n", errno);
369 } else if (!AddHandler(fd, FSYNC_com)) {
371 assert(AddHandler(fd, FSYNC_com));
379 afs_int32 FS_cnt = 0;
386 struct command command;
388 register struct offlineInfo *volumes, *v;
390 char tvolName[VMAXPATHLEN];
394 n = recv(fd, &command, sizeof(command), 0);
396 n = read(fd, &command, sizeof(command));
402 if (n < sizeof(command)) {
403 Log("FSYNC_com: partial read (%d instead of %d); dropping connection (cnt=%d)\n", n, sizeof(command), FS_cnt);
407 VATTACH_LOCK VOL_LOCK volumes = OfflineVolumes[FindHandler(fd)];
408 for (v = 0, i = 0; i < MAXOFFLINEVOLUMES; i++) {
409 if (volumes[i].volumeID == command.volume
410 && strcmp(volumes[i].partName, command.partName) == 0) {
415 switch (command.command) {
417 /* don't try to put online, this call is made only after deleting
418 * a volume, in which case we want to remove the vol # from the
419 * OfflineVolumes array only */
426 This is where a detatched volume gets reattached. However in the
427 special case where the volume is merely busy, it is already
428 attatched and it is only necessary to clear the busy flag. See
429 defect #2080 for details.
432 /* is the volume already attatched? */
435 * XXX With the following enabled we had bizarre problems where the backup id would
436 * be reset to 0; that was due to the interaction between fileserver/volserver in that they
437 * both keep volumes in memory and the changes wouldn't be made to the fileserver. Some of
438 * the problems were due to refcnt changes as result of VGetVolume/VPutVolume which would call
439 * VOffline, etc. when we don't want to; someday the whole #2080 issue should be revisited to
442 vp = VGetVolume_r(&error, command.volume);
444 /* yep, is the BUSY flag set? */
445 if (vp->specialStatus == VBUSY) {
446 /* test harness for defect #2081 */
450 * test #2081 by releasing TEST.2081,
451 * so leave it alone here, zap it after
454 if (strcmp(vp->header->diskstuff.name, "TEST.2081") == 0)
457 /* yep, clear BUSY flag */
459 vp->specialStatus = 0;
460 /* make sure vol is online */
463 V_inUse(vp) = 1; /* online */
472 /* so, we need to attach the volume */
477 sprintf(&tvolName[1], VFORMAT, command.volume);
479 vp = VAttachVolumeByName_r(&error, command.partName, tvolName,
485 case FSYNC_NEEDVOLUME:{
487 /* not already offline, we need to find a slot for newly offline volume */
489 for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
490 if (volumes[i].volumeID == 0) {
500 vp = VGetVolume_r(&error, command.volume);
502 if (command.partName[0] != 0
503 && strcmp(command.partName, vp->partition->name) != 0) {
504 /* volume on desired partition is not online, so we
505 * should treat this as an offline volume.
512 leaveonline = (command.command == FSYNC_NEEDVOLUME
513 && (command.reason == V_READONLY
514 || (!VolumeWriteable(vp)
515 && (command.reason == V_CLONE
516 || command.reason == V_DUMP))
520 if (command.command == FSYNC_NEEDVOLUME
521 && (command.reason == V_CLONE
522 || command.reason == V_DUMP)) {
523 vp->specialStatus = VBUSY;
525 /* remember what volume we got, so we can keep track of how
526 * many volumes the volserver or whatever is using. Note that
527 * vp is valid since leaveonline is only set when vp is valid.
529 v->volumeID = command.volume;
530 strcpy(v->partName, vp->partition->name);
532 /* in this case, VOffline just returns sans decrementing
533 * ref count. We could try to fix it, but it has lots of
538 VOffline_r(vp, "A volume utility is running.");
542 VUpdateVolume_r(&error, vp); /* At least get volume stats right */
544 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n", V_id(vp), V_name(vp), command.reason == V_CLONE ? "clone" : command.reason == V_READONLY ? "readonly" : command.reason == V_DUMP ? "dump" : "UNKNOWN");
553 case FSYNC_MOVEVOLUME:
554 /* Yuch: the "reason" for the move is the site it got moved to... */
555 /* still set specialStatus so we stop sending back VBUSY.
556 * also should still break callbacks. Note that I don't know
557 * how to tell if we should break all or not, so we just do it
558 * since it doesn't matter much if we do an extra break
559 * volume callbacks on a volume move within the same server */
560 vp = VGetVolume_r(&error, command.volume);
562 vp->specialStatus = VMOVED;
566 if (V_BreakVolumeCallbacks) {
567 Log("fssync: volume %u moved to %x; breaking all call backs\n",
568 command.volume, command.reason);
569 VOL_UNLOCK VATTACH_UNLOCK(*V_BreakVolumeCallbacks) (command.
571 VATTACH_LOCK VOL_LOCK}
573 case FSYNC_RESTOREVOLUME:
574 /* if the volume is being restored, break all callbacks on it */
575 if (V_BreakVolumeCallbacks) {
576 Log("fssync: volume %u restored; breaking all call backs\n",
578 VOL_UNLOCK VATTACH_UNLOCK(*V_BreakVolumeCallbacks) (command.
580 VATTACH_LOCK VOL_LOCK}
586 VOL_UNLOCK VATTACH_UNLOCK
588 (void) send(fd, &rc, 1, 0);
590 (void) write(fd, &rc, 1);
597 struct offlineInfo *p;
600 char tvolName[VMAXPATHLEN];
602 VATTACH_LOCK VOL_LOCK p = OfflineVolumes[FindHandler(fd)];
603 for (i = 0; i < MAXOFFLINEVOLUMES; i++) {
608 sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
609 vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName,
616 VOL_UNLOCK VATTACH_UNLOCK RemoveHandler(fd);
625 static int AcceptHandler = -1; /* handler id for accept, if turned on */
630 if (AcceptHandler == -1) {
631 assert(AddHandler(AcceptSd, FSYNC_newconnection));
632 AcceptHandler = FindHandler(AcceptSd);
639 if (AcceptHandler != -1) {
640 assert(RemoveHandler(AcceptSd));
645 /* The multiple FD handling code. */
647 static int HandlerFD[MAXHANDLERS];
648 static int (*HandlerProc[MAXHANDLERS]) ();
654 ObtainWriteLock(&FSYNC_handler_lock);
655 for (i = 0; i < MAXHANDLERS; i++) {
659 ReleaseWriteLock(&FSYNC_handler_lock);
663 CallHandler(fd_set * fdsetp)
666 ObtainReadLock(&FSYNC_handler_lock);
667 for (i = 0; i < MAXHANDLERS; i++) {
668 if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
669 ReleaseReadLock(&FSYNC_handler_lock);
670 (*HandlerProc[i]) (HandlerFD[i]);
671 ObtainReadLock(&FSYNC_handler_lock);
674 ReleaseReadLock(&FSYNC_handler_lock);
678 AddHandler(int afd, int (*aproc) ())
681 ObtainWriteLock(&FSYNC_handler_lock);
682 for (i = 0; i < MAXHANDLERS; i++)
683 if (HandlerFD[i] == -1)
685 if (i >= MAXHANDLERS) {
686 ReleaseWriteLock(&FSYNC_handler_lock);
690 HandlerProc[i] = aproc;
691 ReleaseWriteLock(&FSYNC_handler_lock);
696 FindHandler(register int afd)
699 ObtainReadLock(&FSYNC_handler_lock);
700 for (i = 0; i < MAXHANDLERS; i++)
701 if (HandlerFD[i] == afd) {
702 ReleaseReadLock(&FSYNC_handler_lock);
705 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
707 return -1; /* satisfy compiler */
711 FindHandler_r(register int afd)
714 for (i = 0; i < MAXHANDLERS; i++)
715 if (HandlerFD[i] == afd) {
719 return -1; /* satisfy compiler */
723 RemoveHandler(register int afd)
725 ObtainWriteLock(&FSYNC_handler_lock);
726 HandlerFD[FindHandler_r(afd)] = -1;
727 ReleaseWriteLock(&FSYNC_handler_lock);
732 GetHandler(fd_set * fdsetp, int *maxfdp)
735 register int maxfd = -1;
737 ObtainReadLock(&FSYNC_handler_lock); /* just in case */
738 for (i = 0; i < MAXHANDLERS; i++)
739 if (HandlerFD[i] != -1) {
740 FD_SET(HandlerFD[i], fdsetp);
741 if (maxfd < HandlerFD[i])
742 maxfd = HandlerFD[i];
745 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */