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 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
240 addr->sin_len = sizeof(struct sockaddr_in);
242 addr->sin_addr.s_addr = htonl(0x7f000001);
243 addr->sin_family = AF_INET; /* was localhost->h_addrtype */
244 addr->sin_port = htons(2040); /* XXXX htons not _really_ neccessary */
249 static void FSYNC_sync() {
250 struct sockaddr_in addr;
257 signal(SIGPIPE, SIG_IGN);
260 /* Let somebody else run until level > 0. That doesn't mean that
261 * all volumes have been attached. */
262 #ifdef AFS_PTHREAD_ENV
264 #else /* AFS_PTHREAD_ENV */
265 LWP_DispatchProcess();
266 #endif /* AFS_PTHREAD_ENV */
268 AcceptSd = getport(&addr);
269 /* Reuseaddr needed because system inexplicably leaves crud lying around */
270 code = setsockopt(AcceptSd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
271 if (code) Log("FSYNC_sync: setsockopt failed with (%d)\n",errno);
273 for (numTries=0; numTries < MAX_BIND_TRIES; numTries++) {
274 if ((code = bind(AcceptSd, (struct sockaddr *) &addr, sizeof(addr))) == 0) break;
275 Log("FSYNC_sync: bind failed with (%d), will sleep and retry\n",errno);
279 listen(AcceptSd,100);
285 GetHandler(&readfds, &maxfd);
286 /* Note: check for >= 1 below is essential since IOMGR_select
287 * doesn't have exactly same semantics as select.
289 #ifdef AFS_PTHREAD_ENV
290 if (select(maxfd+1, &readfds, NULL, NULL, NULL) >= 1)
291 #else /* AFS_PTHREAD_ENV */
292 if (IOMGR_Select(maxfd+1, &readfds, NULL, NULL, NULL) >= 1)
293 #endif /* AFS_PTHREAD_ENV */
294 CallHandler(&readfds);
298 static void FSYNC_newconnection(afd)
301 struct sockaddr_in other;
303 junk = sizeof(other);
304 fd = accept(afd, (struct sockaddr *) &other, &junk);
306 Log("FSYNC_newconnection: accept failed, errno==%d\n", errno);
309 else if (!AddHandler(fd, FSYNC_com)) {
311 assert(AddHandler(fd, FSYNC_com));
319 afs_int32 FS_cnt = 0;
320 static void FSYNC_com(fd)
326 struct command command;
328 register struct offlineInfo *volumes, *v;
330 char tvolName[VMAXPATHLEN];
334 n = recv(fd, &command, sizeof (command), 0);
336 n = read(fd, &command, sizeof (command));
342 if (n < sizeof(command)) {
343 Log("FSYNC_com: partial read (%d instead of %d); dropping connection (cnt=%d)\n", n, sizeof(command), FS_cnt);
349 volumes = OfflineVolumes[FindHandler(fd)];
350 for (v = 0, i = 0; i<MAXOFFLINEVOLUMES; i++) {
351 if (volumes[i].volumeID == command.volume
352 && strcmp(volumes[i].partName, command.partName)==0) {
357 switch (command.command) {
359 /* don't try to put online, this call is made only after deleting
360 a volume, in which case we want to remove the vol # from the
361 OfflineVolumes array only */
362 if (v) v->volumeID = 0;
367 This is where a detatched volume gets reattached. However in the
368 special case where the volume is merely busy, it is already
369 attatched and it is only necessary to clear the busy flag. See
370 defect #2080 for details.
373 /* is the volume already attatched? */
376 * XXX With the following enabled we had bizarre problems where the backup id would
377 * be reset to 0; that was due to the interaction between fileserver/volserver in that they
378 * both keep volumes in memory and the changes wouldn't be made to the fileserver. Some of
379 * the problems were due to refcnt changes as result of VGetVolume/VPutVolume which would call
380 * VOffline, etc. when we don't want to; someday the whole #2080 issue should be revisited to
383 vp=VGetVolume_r(&error,command.volume);
385 /* yep, is the BUSY flag set? */
386 if(vp->specialStatus==VBUSY) {
387 /* test harness for defect #2081 */
391 test #2081 by releasing TEST.2081,
392 so leave it alone here, zap it after
395 if(strcmp(vp->header->diskstuff.name,"TEST.2081")==0)
398 /* yep, clear BUSY flag */
401 /* make sure vol is online */
404 V_inUse(vp)=1; /* online */
413 /* so, we need to attach the volume */
418 sprintf(&tvolName[1], VFORMAT, command.volume);
420 vp = VAttachVolumeByName_r(&error, command.partName, tvolName, V_UPDATE);
425 case FSYNC_NEEDVOLUME: {
427 /* not already offline, we need to find a slot for newly offline volume */
429 for (i = 0; i<MAXOFFLINEVOLUMES; i++) {
430 if (volumes[i].volumeID == 0) {
440 vp = VGetVolume_r(&error, command.volume);
442 if (command.partName[0] != 0
443 && strcmp(command.partName, vp->partition->name) != 0) {
444 /* volume on desired partition is not online, so we
445 * should treat this as an offline volume.
453 command.command==FSYNC_NEEDVOLUME
454 && (command.reason==V_READONLY
455 || (!VolumeWriteable(vp)
456 && (command.reason==V_CLONE || command.reason==V_DUMP))
460 if (command.command==FSYNC_NEEDVOLUME
461 && (command.reason==V_CLONE || command.reason==V_DUMP)) {
462 vp->specialStatus = VBUSY;
464 /* remember what volume we got, so we can keep track of how
465 * many volumes the volserver or whatever is using. Note that
466 * vp is valid since leaveonline is only set when vp is valid.
468 v->volumeID = command.volume;
469 strcpy(v->partName, vp->partition->name);
471 /* in this case, VOffline just returns sans decrementing
472 * ref count. We could try to fix it, but it has lots of
478 VOffline_r(vp, "A volume utility is running.");
483 VUpdateVolume_r(&error, vp); /* At least get volume stats right */
485 Log("FSYNC: Volume %u (%s) was left on line for an external %s request\n",
486 V_id(vp), V_name(vp),
487 command.reason == V_CLONE? "clone":
488 command.reason == V_READONLY? "readonly":
489 command.reason == V_DUMP? "dump" : "UNKNOWN");
498 case FSYNC_MOVEVOLUME:
499 /* Yuch: the "reason" for the move is the site it got moved to... */
500 /* still set specialStatus so we stop sending back VBUSY.
501 also should still break callbacks. Note that I don't know
502 how to tell if we should break all or not, so we just do it
503 since it doesn't matter much if we do an extra break
504 volume callbacks on a volume move within the same server */
505 vp = VGetVolume_r(&error, command.volume);
507 vp->specialStatus = VMOVED;
516 if (V_BreakVolumeCallbacks) {
517 Log("fssync: volume %u moved to %x; breaking all call backs\n",
518 command.volume, command.reason);
521 (*V_BreakVolumeCallbacks)(command.volume);
526 case FSYNC_RESTOREVOLUME:
527 /* if the volume is being restored, break all callbacks on it*/
534 if (V_BreakVolumeCallbacks) {
537 (*V_BreakVolumeCallbacks)(command.volume);
557 static void FSYNC_Drop(fd)
560 struct offlineInfo *p;
563 char tvolName[VMAXPATHLEN];
567 p = OfflineVolumes[FindHandler(fd)];
568 for (i = 0; i<MAXOFFLINEVOLUMES; i++) {
573 sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
574 vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName, V_UPDATE);
591 static int AcceptHandler = -1; /* handler id for accept, if turned on */
593 static void AcceptOn() {
594 if (AcceptHandler == -1) {
595 assert(AddHandler(AcceptSd, FSYNC_newconnection));
596 AcceptHandler = FindHandler(AcceptSd);
600 static void AcceptOff() {
601 if (AcceptHandler != -1) {
602 assert(RemoveHandler(AcceptSd));
607 /* The multiple FD handling code. */
609 static int HandlerFD[MAXHANDLERS];
610 static int (*HandlerProc[MAXHANDLERS])();
612 static void InitHandler ()
615 ObtainWriteLock(&FSYNC_handler_lock);
616 for(i=0;i<MAXHANDLERS;i++)
620 ReleaseWriteLock(&FSYNC_handler_lock);
623 static void CallHandler(fd_set *fdsetp)
626 ObtainReadLock(&FSYNC_handler_lock);
627 for(i=0;i<MAXHANDLERS;i++) {
628 if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
629 ReleaseReadLock(&FSYNC_handler_lock);
630 (*HandlerProc[i])(HandlerFD[i]);
631 ObtainReadLock(&FSYNC_handler_lock);
634 ReleaseReadLock(&FSYNC_handler_lock);
637 static int AddHandler (afd, aproc)
642 ObtainWriteLock(&FSYNC_handler_lock);
643 for(i=0;i<MAXHANDLERS;i++)
644 if (HandlerFD[i] == -1) break;
645 if (i>=MAXHANDLERS) {
646 ReleaseWriteLock(&FSYNC_handler_lock);
650 HandlerProc[i] = aproc;
651 ReleaseWriteLock(&FSYNC_handler_lock);
655 static int FindHandler (afd)
659 ObtainReadLock(&FSYNC_handler_lock);
660 for(i=0;i<MAXHANDLERS;i++)
661 if (HandlerFD[i] == afd) {
662 ReleaseReadLock(&FSYNC_handler_lock);
665 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
667 return -1; /* satisfy compiler */
670 static int FindHandler_r (afd)
674 for(i=0;i<MAXHANDLERS;i++)
675 if (HandlerFD[i] == afd) {
679 return -1; /* satisfy compiler */
682 static int RemoveHandler (afd)
685 ObtainWriteLock(&FSYNC_handler_lock);
686 HandlerFD[FindHandler_r(afd)] = -1;
687 ReleaseWriteLock(&FSYNC_handler_lock);
691 static void GetHandler (fd_set *fdsetp, int *maxfdp)
694 register int maxfd = -1;
696 ObtainReadLock(&FSYNC_handler_lock); /* just in case */
697 for(i=0;i<MAXHANDLERS;i++)
698 if (HandlerFD[i] != -1) {
699 FD_SET(HandlerFD[i], fdsetp);
700 if (maxfd < HandlerFD[i])
701 maxfd = HandlerFD[i];
704 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */