home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / unix / question / 10833 < prev    next >
Encoding:
Text File  |  1992-09-08  |  4.3 KB  |  126 lines

  1. Xref: sparky comp.unix.questions:10833 comp.sys.sgi:13388 comp.unix.misc:3586
  2. Newsgroups: comp.unix.questions,comp.sys.sgi,comp.unix.misc
  3. Path: sparky!uunet!stanford.edu!microunity!brendan
  4. From: brendan@microunity.com (Brendan Eich)
  5. Subject: Re: File Locking across NFS mounts
  6. Message-ID: <1992Sep8.210250.7387@microunity.com>
  7. Sender: usenet@microunity.com (news)
  8. Nntp-Posting-Host: acteon.microunity.com
  9. Organization: MicroUnity Systems Engineering, Inc.
  10. References: <9209080829.PN04389@LL.MIT.EDU>
  11. Distribution: comp
  12. Date: Tue, 8 Sep 1992 21:02:50 GMT
  13. Lines: 111
  14.  
  15. In article <9209080829.PN04389@LL.MIT.EDU> lebrun@ll.mit.edu (Steven F. LeBrun) writes:
  16. >I am looking for a method of file locking what works across NFS
  17. >mounted directories and am interested on what methods other 
  18. >people are using.
  19. >
  20. >I tried flock() and discovered a bug that only exists if the file 
  21. >being locked is a remote (NFS) file.  If a program terminates without 
  22. >unlocking an NFS file (due to a system reboot, user abort, program 
  23. >bug [this is how I discovered the problem -- bugs can be useful at 
  24. >times :-) etc.] the file remains locked so that no other programs 
  25. >can access the file.
  26.  
  27. First let me say that this lockd bug may well be fixed in a release
  28. that's available now to customers on support.  It was a known bug within
  29. SGI last I heard, and I believe the fix was in hand.  With that in mind,
  30. here's a homebrew locking scheme.
  31.  
  32. Try using a symlink (which is created exclusively and can contain an
  33. arbitrary NUL-free string) as a locking device (these functions return
  34. 0 on success and an errno on failure):
  35.  
  36. int
  37. lockit(char *lockname)
  38. {
  39.     int pid, timeout, cc, lockpid;
  40.     char hostname[MAXHOSTNAMELEN], lockhost[MAXHOSTNAMELEN];
  41.     char signature[BIGENOUGH], locksig[BIGENOUGH];
  42.  
  43.     pid = getpid();
  44.     (void) gethostname(hostname, sizeof hostname);
  45.     sprintf(signature, "%s:%d.%ld", hostname, pid, time(0));
  46.     for (timeout = 1; symlink(lockname, signature) < 0; timeout <<= 1) {
  47.         if (errno != EEXIST)
  48.             return errno;
  49.         cc = readlink(lockname, locksig, sizeof locksig);
  50.         if (cc < 0)
  51.             return errno;
  52.         locksig[cc] = '\0';
  53.         if (sscanf(locksig, "%s:%d", lockhost, &lockpid) != 2)
  54.             return EINVAL;
  55.         if (strcmp(lockhost, hostname) == 0) {
  56.             /*
  57.              * If we already own the lock, succeed.
  58.              */
  59.             if (lockpid == pid)
  60.                 break;
  61.             /*
  62.              * Probe for a dead process that failed to unlock.
  63.              */
  64.             if (kill(lockpid, 0) < 0 && errno == ESRCH) {
  65.                 (void) unlink(lockname);
  66.                 continue;
  67.             }
  68.         } else {
  69.             /*
  70.              * A process on another host claims the lock.
  71.              * Do something fancy, perhaps with rcmd, kill -0,
  72.              * and error-message echoing, to verify that the
  73.              * process exists.
  74.              */
  75.             . . .
  76.         }
  77.         if (timeout >= BIGTIMEOUT)
  78.             return ETIMEDOUT;
  79.         sleep(timeout);
  80.     }
  81.     return 0;
  82. }
  83.  
  84. int
  85. unlockit(char *lockname)
  86. {
  87. #ifdef DEBUG
  88.     /*
  89.      * Use readlink to sanity-check that we claim the lock.
  90.      */
  91.     . . .
  92. #endif
  93.     return (unlink(lockname) < 0) ? errno : 0;
  94. }
  95.  
  96. Remember that NFS lacks reliable transactions, so under very heavy load
  97. involving a congested internet between client and server and bad delays,
  98. or with old NFS servers that fail to use the "idempotency cache" (a weak
  99. at-most-once NFS transaction mechanism) for symlink and unlink, several
  100. processes can get the lock by mistake, because a delayed unlink request
  101. retransmission removed someone else's lock.
  102.  
  103. If the lock ever gets "stuck" you can use `ls -l` to find out who claims
  104. it and kill the process or remove the symlink, as appropriate.  I added
  105. the initial time to the lock signature so you can see how old and bogus
  106. a suspicious lock might be.
  107.  
  108. On SGI servers, you can increase MAXDUPREQS in /usr/sysgen/master.d/snfs
  109. and '/etc/init.d/autoconfig; answer y; reboot' to get a bigger idempotency
  110. cache.  In 4.0.5 and later, you can use `nfsstat -sr` to get server-side
  111. RPC statistics including "dupage", which gives a smoothed average of the
  112. age of the least-recently-used idempotency cache entry that was recycled.
  113. This should be a larger number than BIGTIMEOUT (I forget whether the units
  114. have to be converted to seconds) for the above scheme to work reliably.
  115.  
  116. On a single Ethernet with few clients, this scheme should work well (the
  117. probing for a remote process, not shown above, can be slow if done using
  118. rcmd(3N) and kill(1)).
  119.  
  120. /be
  121. --
  122. Brendan Eich
  123. MicroUnity Systems Engineering, Inc.
  124. brendan@microunity.com
  125. Any opinions above are mine.
  126.