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;
24 #ifndef AFS_PTHREAD_ENV
25 #define USUAL_PRIORITY (LWP_MAX_PRIORITY - 2)
28 * stack size increased from 8K because the HP machine seemed to have trouble
29 * with the smaller stack
31 #define USUAL_STACK_SIZE (24 * 1024)
32 #endif /* !AFS_PTHREAD_ENV */
36 File server synchronization with external volume utilities.
38 #include <afsconfig.h>
39 #include <afs/param.h>
43 #include <sys/types.h>
49 #include <sys/param.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
56 #ifdef AFS_PTHREAD_ENV
58 #else /* AFS_PTHREAD_ENV */
59 #include <afs/assert.h>
60 #endif /* AFS_PTHREAD_ENV */
73 #include <afs/afsint.h>
75 #include <afs/errors.h>
79 #include <afs/afssyscalls.h>
83 #include "partition.h"
85 extern int LogLevel; /* Vice loglevel */
86 int (*V_BreakVolumeCallbacks)();
88 #define MAXHANDLERS 4 /* Up to 4 clients; must be at least 2, so that
89 move = dump+restore can run on single server */
90 #define MAXOFFLINEVOLUMES 30 /* This needs to be as big as the maximum
91 number that would be offline for 1 operation.
92 Current winner is salvage, which needs all
93 cloned read-only copies offline when salvaging
94 a single read-write volume */
96 #define MAX_BIND_TRIES 5 /* Number of times to retry socket bind */
104 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
106 static FS_sd = -1; /* Client socket for talking to file server */
107 static AcceptSd = -1; /* Socket used by server for accepting connections */
109 static int getport();
115 char partName[16]; /* partition name, e.g. /vicepa */
119 /* Forward declarations */
120 static int getport();
121 static void FSYNC_sync();
122 static void FSYNC_newconnection();
123 static void FSYNC_com();
124 static void FSYNC_Drop();
125 static void AcceptOn();
126 static void AcceptOff();
127 static void InitHandler();
128 static void CallHandler(fd_set *fdsetp);
129 static int AddHandler();
130 static int FindHandler();
131 static int FindHandler_r();
132 static int RemoveHandler();
133 static void GetHandler(fd_set *fdsetp, int *maxfdp);
136 * This lock controls access to the handler array. The overhead
137 * is minimal in non-preemptive environments.
139 struct Lock FSYNC_handler_lock;
141 int FSYNC_clientInit(void)
143 struct sockaddr_in addr;
144 /* I can't believe the following is needed for localhost connections!! */
145 static backoff[] = {3,3,3,5,5,5,7,15,16,24,32,40,48,0};
146 int *timeout = &backoff[0];
149 FS_sd = getport(&addr);
150 if (connect(FS_sd, (struct sockaddr *) &addr, sizeof(addr)) >= 0)
152 #if defined(AFS_SGI_ENV)
153 /* down with worthless error messages! */
155 perror("FSYNC_clientInit failed (after many retries)");
162 perror("FSYNC_clientInit temporary failure (will retry)");
167 perror("FSYNC_clientInit failed (giving up!)");
171 void FSYNC_clientFinis(void)
179 Lock_Destroy(&FSYNC_handler_lock);
182 int FSYNC_askfs(VolumeId volume, char *partName, int com, int reason)
185 struct command command;
187 command.volume = volume;
188 command.command = com;
189 command.reason = reason;
191 strcpy(command.partName, partName);
193 command.partName[0] = 0;
196 if (send(FS_sd, (char*)&command, sizeof(command), 0) != sizeof(command)) {
197 printf("FSYNC_askfs: write to file server failed\n");
200 while ((n = recv(FS_sd, &response, 1, 0)) != 1) {
201 if (n == 0 || WSAEINTR != WSAGetLastError()) {
202 printf("FSYNC_askfs: No response from file server\n");
207 if (write(FS_sd, &command, sizeof(command)) != sizeof(command)) {
208 printf("FSYNC_askfs: write to file server failed\n");
211 while ((n = read(FS_sd, &response, 1)) != 1) {
212 if (n == 0 || errno != EINTR) {
213 printf("FSYNC_askfs: No response from file server\n");
219 printf("FSYNC_askfs: negative response from file server; volume %u, command %d\n", command.volume, command.command);
225 void FSYNC_fsInit(void)
227 #ifdef AFS_PTHREAD_ENV
229 pthread_attr_t tattr;
230 assert(pthread_attr_init(&tattr) == 0);
231 assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
232 assert(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
233 #else /* AFS_PTHREAD_ENV */
235 assert (LWP_CreateProcess(FSYNC_sync, USUAL_STACK_SIZE,
236 USUAL_PRIORITY, (void *) 0,
237 "FSYNC_sync", &pid) == LWP_SUCCESS);
238 #endif /* AFS_PTHREAD_ENV */
241 static int getport(addr)
242 struct sockaddr_in *addr;
246 memset(addr, 0, sizeof(*addr));
247 assert((sd = socket(AF_INET, SOCK_STREAM, 0)) >= 0);
248 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
249 addr->sin_len = sizeof(struct sockaddr_in);
251 addr->sin_addr.s_addr = htonl(0x7f000001);
252 addr->sin_family = AF_INET; /* was localhost->h_addrtype */
253 addr->sin_port = htons(2040); /* XXXX htons not _really_ neccessary */
258 static void FSYNC_sync() {
259 struct sockaddr_in addr;
266 signal(SIGPIPE, SIG_IGN);
269 /* Let somebody else run until level > 0. That doesn't mean that
270 * all volumes have been attached. */
271 #ifdef AFS_PTHREAD_ENV
273 #else /* AFS_PTHREAD_ENV */
274 LWP_DispatchProcess();
275 #endif /* AFS_PTHREAD_ENV */
277 AcceptSd = getport(&addr);
278 /* Reuseaddr needed because system inexplicably leaves crud lying around */
279 code = setsockopt(AcceptSd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
280 if (code) Log("FSYNC_sync: setsockopt failed with (%d)\n",errno);
282 for (numTries=0; numTries < MAX_BIND_TRIES; numTries++) {
283 if ((code = bind(AcceptSd, (struct sockaddr *) &addr, sizeof(addr))) == 0) break;
284 Log("FSYNC_sync: bind failed with (%d), will sleep and retry\n",errno);
288 listen(AcceptSd,100);
294 GetHandler(&readfds, &maxfd);
295 /* Note: check for >= 1 below is essential since IOMGR_select
296 * doesn't have exactly same semantics as select.
298 #ifdef AFS_PTHREAD_ENV
299 if (select(maxfd+1, &readfds, NULL, NULL, NULL) >= 1)
300 #else /* AFS_PTHREAD_ENV */
301 if (IOMGR_Select(maxfd+1, &readfds, NULL, NULL, NULL) >= 1)
302 #endif /* AFS_PTHREAD_ENV */
303 CallHandler(&readfds);
307 static void FSYNC_newconnection(afd)
310 struct sockaddr_in other;
312 junk = sizeof(other);
313 fd = accept(afd, (struct sockaddr *) &other, &junk);
315 Log("FSYNC_newconnection: accept failed, errno==%d\n", errno);
318 else if (!AddHandler(fd, FSYNC_com)) {
320 assert(AddHandler(fd, FSYNC_com));
328 afs_int32 FS_cnt = 0;
329 static void FSYNC_com(fd)
335 struct command command;
337 register struct offlineInfo *volumes, *v;
339 char tvolName[VMAXPATHLEN];
343 n = recv(fd, &command, sizeof (command), 0);
345 n = read(fd, &command, sizeof (command));
351 if (n < sizeof(command)) {
352 Log("FSYNC_com: partial read (%d instead of %d); dropping connection (cnt=%d)\n", n, sizeof(command), FS_cnt);
358 volumes = OfflineVolumes[FindHandler(fd)];
359 for (v = 0, i = 0; i<MAXOFFLINEVOLUMES; i++) {
360 if (volumes[i].volumeID == command.volume
361 && strcmp(volumes[i].partName, command.partName)==0) {
366 switch (command.command) {
368 /* don't try to put online, this call is made only after deleting
369 a volume, in which case we want to remove the vol # from the
370 OfflineVolumes array only */
371 if (v) v->volumeID = 0;
376 This is where a detatched volume gets reattached. However in the
377 special case where the volume is merely busy, it is already
378 attatched and it is only necessary to clear the busy flag. See
379 defect #2080 for details.
382 /* is the volume already attatched? */
385 * XXX With the following enabled we had bizarre problems where the backup id would
386 * be reset to 0; that was due to the interaction between fileserver/volserver in that they
387 * both keep volumes in memory and the changes wouldn't be made to the fileserver. Some of
388 * the problems were due to refcnt changes as result of VGetVolume/VPutVolume which would call
389 * VOffline, etc. when we don't want to; someday the whole #2080 issue should be revisited to
392 vp=VGetVolume_r(&error,command.volume);
394 /* yep, is the BUSY flag set? */
395 if(vp->specialStatus==VBUSY) {
396 /* test harness for defect #2081 */
400 test #2081 by releasing TEST.2081,
401 so leave it alone here, zap it after
404 if(strcmp(vp->header->diskstuff.name,"TEST.2081")==0)
407 /* yep, clear BUSY flag */
410 /* make sure vol is online */
413 V_inUse(vp)=1; /* online */
422 /* so, we need to attach the volume */
427 sprintf(&tvolName[1], VFORMAT, command.volume);
429 vp = VAttachVolumeByName_r(&error, command.partName, tvolName, V_VOLUPD);
434 case FSYNC_NEEDVOLUME: {
436 /* not already offline, we need to find a slot for newly offline volume */
438 for (i = 0; i<MAXOFFLINEVOLUMES; i++) {
439 if (volumes[i].volumeID == 0) {
449 vp = VGetVolume_r(&error, command.volume);
451 if (command.partName[0] != 0
452 && strcmp(command.partName, vp->partition->name) != 0) {
453 /* volume on desired partition is not online, so we
454 * should treat this as an offline volume.
462 command.command==FSYNC_NEEDVOLUME
463 && (command.reason==V_READONLY
464 || (!VolumeWriteable(vp)
465 && (command.reason==V_CLONE || command.reason==V_DUMP))
469 if (command.command==FSYNC_NEEDVOLUME
470 && (command.reason==V_CLONE || command.reason==V_DUMP)) {
471 vp->specialStatus = VBUSY;
473 /* remember what volume we got, so we can keep track of how
474 * many volumes the volserver or whatever is using. Note that
475 * vp is valid since leaveonline is only set when vp is valid.
477 v->volumeID = command.volume;
478 strcpy(v->partName, vp->partition->name);
480 /* in this case, VOffline just returns sans decrementing
481 * ref count. We could try to fix it, but it has lots of
487 VOffline_r(vp, "A volume utility is running.");
492 VUpdateVolume_r(&error, vp); /* At least get volume stats right */
494 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n",
495 V_id(vp), V_name(vp),
496 command.reason == V_CLONE? "clone":
497 command.reason == V_READONLY? "readonly":
498 command.reason == V_DUMP? "dump" : "UNKNOWN");
507 case FSYNC_MOVEVOLUME:
508 /* Yuch: the "reason" for the move is the site it got moved to... */
509 /* still set specialStatus so we stop sending back VBUSY.
510 also should still break callbacks. Note that I don't know
511 how to tell if we should break all or not, so we just do it
512 since it doesn't matter much if we do an extra break
513 volume callbacks on a volume move within the same server */
514 vp = VGetVolume_r(&error, command.volume);
516 vp->specialStatus = VMOVED;
520 if (V_BreakVolumeCallbacks) {
521 Log("fssync: volume %u moved to %x; breaking all call backs\n",
522 command.volume, command.reason);
525 (*V_BreakVolumeCallbacks)(command.volume);
530 case FSYNC_RESTOREVOLUME:
531 /* if the volume is being restored, break all callbacks on it*/
532 if (V_BreakVolumeCallbacks) {
533 Log("fssync: volume %u restored; breaking all call backs\n",
537 (*V_BreakVolumeCallbacks)(command.volume);
555 static void FSYNC_Drop(fd)
558 struct offlineInfo *p;
561 char tvolName[VMAXPATHLEN];
565 p = OfflineVolumes[FindHandler(fd)];
566 for (i = 0; i<MAXOFFLINEVOLUMES; i++) {
571 sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
572 vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName, V_VOLUPD);
589 static int AcceptHandler = -1; /* handler id for accept, if turned on */
591 static void AcceptOn() {
592 if (AcceptHandler == -1) {
593 assert(AddHandler(AcceptSd, FSYNC_newconnection));
594 AcceptHandler = FindHandler(AcceptSd);
598 static void AcceptOff() {
599 if (AcceptHandler != -1) {
600 assert(RemoveHandler(AcceptSd));
605 /* The multiple FD handling code. */
607 static int HandlerFD[MAXHANDLERS];
608 static int (*HandlerProc[MAXHANDLERS])();
610 static void InitHandler ()
613 ObtainWriteLock(&FSYNC_handler_lock);
614 for(i=0;i<MAXHANDLERS;i++)
618 ReleaseWriteLock(&FSYNC_handler_lock);
621 static void CallHandler(fd_set *fdsetp)
624 ObtainReadLock(&FSYNC_handler_lock);
625 for(i=0;i<MAXHANDLERS;i++) {
626 if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
627 ReleaseReadLock(&FSYNC_handler_lock);
628 (*HandlerProc[i])(HandlerFD[i]);
629 ObtainReadLock(&FSYNC_handler_lock);
632 ReleaseReadLock(&FSYNC_handler_lock);
635 static int AddHandler (afd, aproc)
640 ObtainWriteLock(&FSYNC_handler_lock);
641 for(i=0;i<MAXHANDLERS;i++)
642 if (HandlerFD[i] == -1) break;
643 if (i>=MAXHANDLERS) {
644 ReleaseWriteLock(&FSYNC_handler_lock);
648 HandlerProc[i] = aproc;
649 ReleaseWriteLock(&FSYNC_handler_lock);
653 static int FindHandler (afd)
657 ObtainReadLock(&FSYNC_handler_lock);
658 for(i=0;i<MAXHANDLERS;i++)
659 if (HandlerFD[i] == afd) {
660 ReleaseReadLock(&FSYNC_handler_lock);
663 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
665 return -1; /* satisfy compiler */
668 static int FindHandler_r (afd)
672 for(i=0;i<MAXHANDLERS;i++)
673 if (HandlerFD[i] == afd) {
677 return -1; /* satisfy compiler */
680 static int RemoveHandler (afd)
683 ObtainWriteLock(&FSYNC_handler_lock);
684 HandlerFD[FindHandler_r(afd)] = -1;
685 ReleaseWriteLock(&FSYNC_handler_lock);
689 static void GetHandler (fd_set *fdsetp, int *maxfdp)
692 register int maxfd = -1;
694 ObtainReadLock(&FSYNC_handler_lock); /* just in case */
695 for(i=0;i<MAXHANDLERS;i++)
696 if (HandlerFD[i] != -1) {
697 FD_SET(HandlerFD[i], fdsetp);
698 if (maxfd < HandlerFD[i])
699 maxfd = HandlerFD[i];
702 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */