]> arthur.barton.de Git - netatalk.git/commitdiff
Fix a race condition on reading and writing data to the same fork. Also,
authorjmarcus <jmarcus>
Sun, 3 Feb 2002 04:57:38 +0000 (04:57 +0000)
committerjmarcus <jmarcus>
Sun, 3 Feb 2002 04:57:38 +0000 (04:57 +0000)
correct a lock contention issue where one afpd process could lock a
byte region, and then only unlock part of that region.  The next afpd
process to access the same reason would receive AFPERR_LOCK.  Submitted by
didier <dgautheron@magic.fr>.

etc/afpd/fork.c

index 291972d0192f8c3cec0d9ded0a79b73e3c3f7c52..dc64e90f5ab13ad1111e6c550568681c7ff27237 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.c,v 1.20 2002-02-02 19:11:34 jmarcus Exp $
+ * $Id: fork.c,v 1.21 2002-02-03 04:57:38 jmarcus Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -790,8 +790,8 @@ int         ibuflen, *rbuflen;
 {
     struct ofork       *ofork;
     off_t              size;
-    int32_t            offset, saveoff, reqcount;
-    int                        cc, err, eid, xlate = 0;
+    int32_t            offset, saveoff, reqcount, savereqcount;
+    int                        cc, err, saveerr, eid, xlate = 0;
     u_int16_t          ofrefnum;
     u_char             nlmask, nlchar;
 
@@ -839,42 +839,50 @@ int               ibuflen, *rbuflen;
     }
 
     /* zero request count */
+    err = AFP_OK;
     if (!reqcount) {
-        err = AFP_OK;
         goto afp_read_err;
     }
 
     /* reqcount isn't always truthful. we need to deal with that. */
-    if ((size = ad_size(ofork->of_ad, eid)) == 0) {
+    size = ad_size(ofork->of_ad, eid);
+
+    if (offset >= size) {
         err = AFPERR_EOF;
         goto afp_read_err;
     }
 
+    /* subtract off the offset */
+    size -= offset;
+    savereqcount = reqcount;
+    if (reqcount > size) {
+       reqcount = size;
+        err = AFPERR_EOF;
+    }
+
     saveoff = offset;
-    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) {
+    /* if EOF lock on the old reqcount, some prg may need it */
+    if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) {
         err = AFPERR_LOCK;
         goto afp_read_err;
     }
 
 #define min(a,b)       ((a)<(b)?(a):(b))
     *rbuflen = min( reqcount, *rbuflen );
+    saveerr = err;
     err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen,
                     xlate);
     if (err < 0)
         goto afp_read_done;
-
+    if (saveerr < 0) {
+       err = saveerr;
+       goto afp_read_done;
+    }
     /* dsi can stream requests. we can only do this if we're not checking
      * for an end-of-line character. oh well. */
     if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) {
         DSI *dsi = obj->handle;
 
-        /* subtract off the offset */
-        size -= offset;
-        if (reqcount > size) {
-            reqcount = size;
-            err = AFPERR_EOF;
-        }
-
         if (obj->options.flags & OPTION_DEBUG) {
             printf( "(read) reply: %d/%d, %d\n", *rbuflen,
                     reqcount, dsi->clientID);
@@ -935,12 +943,12 @@ afp_read_loop:
 afp_read_exit:
         LOG(log_error, logtype_default, "afp_read: %s", strerror(errno));
         dsi_readdone(dsi);
-        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
+        ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
         obj->exit(1);
     }
 
 afp_read_done:
-    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount);
+    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount);
     return err;
 
 afp_read_err: