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 */
64 #include <afs/afsint.h>
66 #include <afs/errors.h>
70 #include <afs/afssyscalls.h>
74 #include "partition.h"
76 extern int LogLevel; /* Vice loglevel */
77 int (*V_BreakVolumeCallbacks)();
79 #define MAXHANDLERS 4 /* Up to 4 clients; must be at least 2, so that
80 move = dump+restore can run on single server */
81 #define MAXOFFLINEVOLUMES 30 /* This needs to be as big as the maximum
82 number that would be offline for 1 operation.
83 Current winner is salvage, which needs all
84 cloned read-only copies offline when salvaging
85 a single read-write volume */
87 #define MAX_BIND_TRIES 5 /* Number of times to retry socket bind */
95 static struct offlineInfo OfflineVolumes[MAXHANDLERS][MAXOFFLINEVOLUMES];
97 static FS_sd = -1; /* Client socket for talking to file server */
98 static AcceptSd = -1; /* Socket used by server for accepting connections */
100 static int getport();
106 char partName[16]; /* partition name, e.g. /vicepa */
110 /* Forward declarations */
111 static int getport();
112 static void FSYNC_sync();
113 static void FSYNC_newconnection();
114 static void FSYNC_com();
115 static void FSYNC_Drop();
116 static void AcceptOn();
117 static void AcceptOff();
118 static void InitHandler();
119 static void CallHandler(fd_set *fdsetp);
120 static int AddHandler();
121 static int FindHandler();
122 static int FindHandler_r();
123 static int RemoveHandler();
124 static void GetHandler(fd_set *fdsetp, int *maxfdp);
127 * This lock controls access to the handler array. The overhead
128 * is minimal in non-preemptive environments.
130 struct Lock FSYNC_handler_lock;
132 int FSYNC_clientInit(void)
134 struct sockaddr_in addr;
135 /* I can't believe the following is needed for localhost connections!! */
136 static backoff[] = {3,3,3,5,5,5,7,15,16,24,32,40,48,0};
137 int *timeout = &backoff[0];
140 FS_sd = getport(&addr);
141 if (connect(FS_sd, (struct sockaddr *) &addr, sizeof(addr)) >= 0)
143 #if defined(AFS_SGI_ENV)
144 /* down with worthless error messages! */
146 perror("FSYNC_clientInit failed (after many retries)");
153 perror("FSYNC_clientInit temporary failure (will retry)");
158 perror("FSYNC_clientInit failed (giving up!)");
162 void FSYNC_clientFinis(void)
170 Lock_Destroy(&FSYNC_handler_lock);
173 int FSYNC_askfs(VolumeId volume, char *partName, int com, int reason)
176 struct command command;
178 command.volume = volume;
179 command.command = com;
180 command.reason = reason;
182 strcpy(command.partName, partName);
184 command.partName[0] = 0;
187 if (send(FS_sd, (char*)&command, sizeof(command), 0) != sizeof(command)) {
188 printf("FSYNC_askfs: write to file server failed\n");
191 while ((n = recv(FS_sd, &response, 1, 0)) != 1) {
192 if (n == 0 || WSAEINTR != WSAGetLastError()) {
193 printf("FSYNC_askfs: No response from file server\n");
198 if (write(FS_sd, &command, sizeof(command)) != sizeof(command)) {
199 printf("FSYNC_askfs: write to file server failed\n");
202 while ((n = read(FS_sd, &response, 1)) != 1) {
203 if (n == 0 || errno != EINTR) {
204 printf("FSYNC_askfs: No response from file server\n");
210 printf("FSYNC_askfs: negative response from file server; volume %u, command %d\n", command.volume, command.command);
216 void FSYNC_fsInit(void)
218 #ifdef AFS_PTHREAD_ENV
220 pthread_attr_t tattr;
221 assert(pthread_attr_init(&tattr) == 0);
222 assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
223 assert(pthread_create(&tid, &tattr, FSYNC_sync, NULL) == 0);
224 #else /* AFS_PTHREAD_ENV */
226 assert (LWP_CreateProcess(FSYNC_sync, USUAL_STACK_SIZE,
228 "FSYNC_sync", &pid) == LWP_SUCCESS);
229 #endif /* AFS_PTHREAD_ENV */
232 static int getport(addr)
233 struct sockaddr_in *addr;
237 memset(addr, 0, sizeof(*addr));
238 assert((sd = socket(AF_INET, SOCK_STREAM, 0)) >= 0);
239 addr->sin_addr.s_addr = htonl(0x7f000001);
240 addr->sin_family = AF_INET; /* was localhost->h_addrtype */
241 addr->sin_port = htons(2040); /* XXXX htons not _really_ neccessary */
245 static void FSYNC_sync() {
246 struct sockaddr_in addr;
253 signal(SIGPIPE, SIG_IGN);
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 AcceptSd = getport(&addr);
265 /* Reuseaddr needed because system inexplicably leaves crud lying around */
266 code = setsockopt(AcceptSd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
267 if (code) Log("FSYNC_sync: setsockopt failed with (%d)\n",errno);
269 for (numTries=0; numTries < MAX_BIND_TRIES; numTries++) {
270 if ((code = bind(AcceptSd, (struct sockaddr *) &addr, sizeof(addr))) == 0) break;
271 Log("FSYNC_sync: bind failed with (%d), will sleep and retry\n",errno);
275 listen(AcceptSd,100);
281 GetHandler(&readfds, &maxfd);
282 /* Note: check for >= 1 below is essential since IOMGR_select
283 * doesn't have exactly same semantics as select.
285 #ifdef AFS_PTHREAD_ENV
286 if (select(maxfd+1, &readfds, NULL, NULL, NULL) >= 1)
287 #else /* AFS_PTHREAD_ENV */
288 if (IOMGR_Select(maxfd+1, &readfds, NULL, NULL, NULL) >= 1)
289 #endif /* AFS_PTHREAD_ENV */
290 CallHandler(&readfds);
294 static void FSYNC_newconnection(afd)
297 struct sockaddr_in other;
299 junk = sizeof(other);
300 fd = accept(afd, (struct sockaddr *) &other, &junk);
302 Log("FSYNC_newconnection: accept failed, errno==%d\n", errno);
305 else if (!AddHandler(fd, FSYNC_com)) {
307 assert(AddHandler(fd, FSYNC_com));
315 afs_int32 FS_cnt = 0;
316 static void FSYNC_com(fd)
322 struct command command;
324 register struct offlineInfo *volumes, *v;
326 char tvolName[VMAXPATHLEN];
330 n = recv(fd, &command, sizeof (command), 0);
332 n = read(fd, &command, sizeof (command));
338 if (n < sizeof(command)) {
339 Log("FSYNC_com: partial read (%d instead of %d); dropping connection (cnt=%d)\n", n, sizeof(command), FS_cnt);
345 volumes = OfflineVolumes[FindHandler(fd)];
346 for (v = 0, i = 0; i<MAXOFFLINEVOLUMES; i++) {
347 if (volumes[i].volumeID == command.volume
348 && strcmp(volumes[i].partName, command.partName)==0) {
353 switch (command.command) {
355 /* don't try to put online, this call is made only after deleting
356 a volume, in which case we want to remove the vol # from the
357 OfflineVolumes array only */
358 if (v) v->volumeID = 0;
363 This is where a detatched volume gets reattached. However in the
364 special case where the volume is merely busy, it is already
365 attatched and it is only necessary to clear the busy flag. See
366 defect #2080 for details.
369 /* is the volume already attatched? */
372 * XXX With the following enabled we had bizarre problems where the backup id would
373 * be reset to 0; that was due to the interaction between fileserver/volserver in that they
374 * both keep volumes in memory and the changes wouldn't be made to the fileserver. Some of
375 * the problems were due to refcnt changes as result of VGetVolume/VPutVolume which would call
376 * VOffline, etc. when we don't want to; someday the whole #2080 issue should be revisited to
379 vp=VGetVolume_r(&error,command.volume);
381 /* yep, is the BUSY flag set? */
382 if(vp->specialStatus==VBUSY) {
383 /* test harness for defect #2081 */
387 test #2081 by releasing TEST.2081,
388 so leave it alone here, zap it after
391 if(strcmp(vp->header->diskstuff.name,"TEST.2081")==0)
394 /* yep, clear BUSY flag */
397 /* make sure vol is online */
400 V_inUse(vp)=1; /* online */
409 /* so, we need to attach the volume */
414 sprintf(&tvolName[1], VFORMAT, command.volume);
416 vp = VAttachVolumeByName_r(&error, command.partName, tvolName, V_UPDATE);
421 case FSYNC_NEEDVOLUME: {
423 /* not already offline, we need to find a slot for newly offline volume */
425 for (i = 0; i<MAXOFFLINEVOLUMES; i++) {
426 if (volumes[i].volumeID == 0) {
436 vp = VGetVolume_r(&error, command.volume);
438 if (command.partName[0] != 0
439 && strcmp(command.partName, vp->partition->name) != 0) {
440 /* volume on desired partition is not online, so we
441 * should treat this as an offline volume.
449 command.command==FSYNC_NEEDVOLUME
450 && (command.reason==V_READONLY
451 || (!VolumeWriteable(vp)
452 && (command.reason==V_CLONE || command.reason==V_DUMP))
456 if (command.command==FSYNC_NEEDVOLUME
457 && (command.reason==V_CLONE || command.reason==V_DUMP)) {
458 vp->specialStatus = VBUSY;
460 /* remember what volume we got, so we can keep track of how
461 * many volumes the volserver or whatever is using. Note that
462 * vp is valid since leaveonline is only set when vp is valid.
464 v->volumeID = command.volume;
465 strcpy(v->partName, vp->partition->name);
467 /* in this case, VOffline just returns sans decrementing
468 * ref count. We could try to fix it, but it has lots of
474 VOffline_r(vp, "A volume utility is running.");
479 VUpdateVolume_r(&error, vp); /* At least get volume stats right */
481 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n",
482 V_id(vp), V_name(vp),
483 command.reason == V_CLONE? "clone":
484 command.reason == V_READONLY? "readonly":
485 command.reason == V_DUMP? "dump" : "UNKNOWN");
494 case FSYNC_MOVEVOLUME:
495 /* Yuch: the "reason" for the move is the site it got moved to... */
496 /* still set specialStatus so we stop sending back VBUSY.
497 also should still break callbacks. Note that I don't know
498 how to tell if we should break all or not, so we just do it
499 since it doesn't matter much if we do an extra break
500 volume callbacks on a volume move within the same server */
501 vp = VGetVolume_r(&error, command.volume);
503 vp->specialStatus = VMOVED;
506 if (V_BreakVolumeCallbacks) {
507 Log("fssync: volume %u moved to %x; breaking all call backs\n",
508 command.volume, command.reason);
511 (*V_BreakVolumeCallbacks)(command.volume);
516 case FSYNC_RESTOREVOLUME:
517 /* if the volume is being restored, break all callbacks on it*/
518 if (V_BreakVolumeCallbacks) {
521 (*V_BreakVolumeCallbacks)(command.volume);
539 static void FSYNC_Drop(fd)
542 struct offlineInfo *p;
545 char tvolName[VMAXPATHLEN];
549 p = OfflineVolumes[FindHandler(fd)];
550 for (i = 0; i<MAXOFFLINEVOLUMES; i++) {
555 sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
556 vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName, V_UPDATE);
573 static int AcceptHandler = -1; /* handler id for accept, if turned on */
575 static void AcceptOn() {
576 if (AcceptHandler == -1) {
577 assert(AddHandler(AcceptSd, FSYNC_newconnection));
578 AcceptHandler = FindHandler(AcceptSd);
582 static void AcceptOff() {
583 if (AcceptHandler != -1) {
584 assert(RemoveHandler(AcceptSd));
589 /* The multiple FD handling code. */
591 static int HandlerFD[MAXHANDLERS];
592 static int (*HandlerProc[MAXHANDLERS])();
594 static void InitHandler ()
597 ObtainWriteLock(&FSYNC_handler_lock);
598 for(i=0;i<MAXHANDLERS;i++)
602 ReleaseWriteLock(&FSYNC_handler_lock);
605 static void CallHandler(fd_set *fdsetp)
608 ObtainReadLock(&FSYNC_handler_lock);
609 for(i=0;i<MAXHANDLERS;i++) {
610 if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
611 ReleaseReadLock(&FSYNC_handler_lock);
612 (*HandlerProc[i])(HandlerFD[i]);
613 ObtainReadLock(&FSYNC_handler_lock);
616 ReleaseReadLock(&FSYNC_handler_lock);
619 static int AddHandler (afd, aproc)
624 ObtainWriteLock(&FSYNC_handler_lock);
625 for(i=0;i<MAXHANDLERS;i++)
626 if (HandlerFD[i] == -1) break;
627 if (i>=MAXHANDLERS) {
628 ReleaseWriteLock(&FSYNC_handler_lock);
632 HandlerProc[i] = aproc;
633 ReleaseWriteLock(&FSYNC_handler_lock);
637 static int FindHandler (afd)
641 ObtainReadLock(&FSYNC_handler_lock);
642 for(i=0;i<MAXHANDLERS;i++)
643 if (HandlerFD[i] == afd) {
644 ReleaseReadLock(&FSYNC_handler_lock);
647 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
649 return -1; /* satisfy compiler */
652 static int FindHandler_r (afd)
656 for(i=0;i<MAXHANDLERS;i++)
657 if (HandlerFD[i] == afd) {
661 return -1; /* satisfy compiler */
664 static int RemoveHandler (afd)
667 ObtainWriteLock(&FSYNC_handler_lock);
668 HandlerFD[FindHandler_r(afd)] = -1;
669 ReleaseWriteLock(&FSYNC_handler_lock);
673 static void GetHandler (fd_set *fdsetp, int *maxfdp)
676 register int maxfd = -1;
678 ObtainReadLock(&FSYNC_handler_lock); /* just in case */
679 for(i=0;i<MAXHANDLERS;i++)
680 if (HandlerFD[i] != -1) {
681 FD_SET(HandlerFD[i], fdsetp);
682 if (maxfd < HandlerFD[i])
683 maxfd = HandlerFD[i];
686 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */