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_UPDATE);
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;
525 if (V_BreakVolumeCallbacks) {
526 Log("fssync: volume %u moved to %x; breaking all call backs\n",
527 command.volume, command.reason);
530 (*V_BreakVolumeCallbacks)(command.volume);
535 case FSYNC_RESTOREVOLUME:
536 /* if the volume is being restored, break all callbacks on it*/
543 if (V_BreakVolumeCallbacks) {
546 (*V_BreakVolumeCallbacks)(command.volume);
566 static void FSYNC_Drop(fd)
569 struct offlineInfo *p;
572 char tvolName[VMAXPATHLEN];
576 p = OfflineVolumes[FindHandler(fd)];
577 for (i = 0; i<MAXOFFLINEVOLUMES; i++) {
582 sprintf(&tvolName[1], VFORMAT, p[i].volumeID);
583 vp = VAttachVolumeByName_r(&error, p[i].partName, tvolName, V_UPDATE);
600 static int AcceptHandler = -1; /* handler id for accept, if turned on */
602 static void AcceptOn() {
603 if (AcceptHandler == -1) {
604 assert(AddHandler(AcceptSd, FSYNC_newconnection));
605 AcceptHandler = FindHandler(AcceptSd);
609 static void AcceptOff() {
610 if (AcceptHandler != -1) {
611 assert(RemoveHandler(AcceptSd));
616 /* The multiple FD handling code. */
618 static int HandlerFD[MAXHANDLERS];
619 static int (*HandlerProc[MAXHANDLERS])();
621 static void InitHandler ()
624 ObtainWriteLock(&FSYNC_handler_lock);
625 for(i=0;i<MAXHANDLERS;i++)
629 ReleaseWriteLock(&FSYNC_handler_lock);
632 static void CallHandler(fd_set *fdsetp)
635 ObtainReadLock(&FSYNC_handler_lock);
636 for(i=0;i<MAXHANDLERS;i++) {
637 if (HandlerFD[i] >= 0 && FD_ISSET(HandlerFD[i], fdsetp)) {
638 ReleaseReadLock(&FSYNC_handler_lock);
639 (*HandlerProc[i])(HandlerFD[i]);
640 ObtainReadLock(&FSYNC_handler_lock);
643 ReleaseReadLock(&FSYNC_handler_lock);
646 static int AddHandler (afd, aproc)
651 ObtainWriteLock(&FSYNC_handler_lock);
652 for(i=0;i<MAXHANDLERS;i++)
653 if (HandlerFD[i] == -1) break;
654 if (i>=MAXHANDLERS) {
655 ReleaseWriteLock(&FSYNC_handler_lock);
659 HandlerProc[i] = aproc;
660 ReleaseWriteLock(&FSYNC_handler_lock);
664 static int FindHandler (afd)
668 ObtainReadLock(&FSYNC_handler_lock);
669 for(i=0;i<MAXHANDLERS;i++)
670 if (HandlerFD[i] == afd) {
671 ReleaseReadLock(&FSYNC_handler_lock);
674 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */
676 return -1; /* satisfy compiler */
679 static int FindHandler_r (afd)
683 for(i=0;i<MAXHANDLERS;i++)
684 if (HandlerFD[i] == afd) {
688 return -1; /* satisfy compiler */
691 static int RemoveHandler (afd)
694 ObtainWriteLock(&FSYNC_handler_lock);
695 HandlerFD[FindHandler_r(afd)] = -1;
696 ReleaseWriteLock(&FSYNC_handler_lock);
700 static void GetHandler (fd_set *fdsetp, int *maxfdp)
703 register int maxfd = -1;
705 ObtainReadLock(&FSYNC_handler_lock); /* just in case */
706 for(i=0;i<MAXHANDLERS;i++)
707 if (HandlerFD[i] != -1) {
708 FD_SET(HandlerFD[i], fdsetp);
709 if (maxfd < HandlerFD[i])
710 maxfd = HandlerFD[i];
713 ReleaseReadLock(&FSYNC_handler_lock); /* just in case */