Author: obnox
Date: 2007-07-20 14:23:12 +0000 (Fri, 20 Jul 2007)
New Revision: 23977

WebSVN: 
http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=23977

Log:
Im prove the pwrite-patch to tdb_expand_file of r23972:

* prevent infinite loops due to 0 bytes written:
  try once more. if we still get 0 as return,
  set errno to ENOSPC and return -1 (error)

* replace int by correct types (ssize_t and size_t).

* print a warning log message in case "written < requested to write"
  usually this means, that the next call to pwrite will fail
  with return value -1 and set errno accordingly.

  Note that the former error condition "written != requested to write"
  is not a correct error condition of write/pwrite. If this is due
  to an error, a subsequent call to (p)write will reveal the cause
  (typically "no space left on device" - ENOSPC).

Michael


Modified:
   branches/SAMBA_3_2/source/lib/tdb/common/io.c
   branches/SAMBA_3_2_0/source/lib/tdb/common/io.c
   branches/SAMBA_4_0/source/lib/tdb/common/io.c


Changeset:
Modified: branches/SAMBA_3_2/source/lib/tdb/common/io.c
===================================================================
--- branches/SAMBA_3_2/source/lib/tdb/common/io.c       2007-07-19 14:49:08 UTC 
(rev 23976)
+++ branches/SAMBA_3_2/source/lib/tdb/common/io.c       2007-07-20 14:23:12 UTC 
(rev 23977)
@@ -232,15 +232,28 @@
           disk. This must be done with write, not via mmap */
        memset(buf, TDB_PAD_BYTE, sizeof(buf));
        while (addition) {
-               int n = addition>sizeof(buf)?sizeof(buf):addition;
-               int ret = pwrite(tdb->fd, buf, n, size);
-               if (ret == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of %d 
failed (%s)\n", 
-                                  n, strerror(errno)));
+               size_t n = addition>sizeof(buf)?sizeof(buf):addition;
+               ssize_t written = pwrite(tdb->fd, buf, n, size);
+               if (written == 0) {
+                       /* prevent infinite loops: try _once_ more */
+                       written = pwrite(tdb->fd, buf, n, size);
+               }
+               if (written == 0) {
+                       /* give up, trying to provide a useful errno */
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
+                               "returned 0 twice: giving up!\n"));
+                       errno = ENOSPC;
                        return -1;
+               } else if (written == -1) {
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
+                               "%d bytes failed (%s)\n", n, strerror(errno)));
+                       return -1;
+               } else if (written != n) {
+                       TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
+                               "only %d of %d bytes - retrying\n", written,n));
                }
-               addition -= ret;
-               size += ret;
+               addition -= written;
+               size += written;
        }
        return 0;
 }

Modified: branches/SAMBA_3_2_0/source/lib/tdb/common/io.c
===================================================================
--- branches/SAMBA_3_2_0/source/lib/tdb/common/io.c     2007-07-19 14:49:08 UTC 
(rev 23976)
+++ branches/SAMBA_3_2_0/source/lib/tdb/common/io.c     2007-07-20 14:23:12 UTC 
(rev 23977)
@@ -232,15 +232,28 @@
           disk. This must be done with write, not via mmap */
        memset(buf, TDB_PAD_BYTE, sizeof(buf));
        while (addition) {
-               int n = addition>sizeof(buf)?sizeof(buf):addition;
-               int ret = pwrite(tdb->fd, buf, n, size);
-               if (ret == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of %d 
failed (%s)\n", 
-                                  n, strerror(errno)));
+               size_t n = addition>sizeof(buf)?sizeof(buf):addition;
+               ssize_t written = pwrite(tdb->fd, buf, n, size);
+               if (written == 0) {
+                       /* prevent infinite loops: try _once_ more */
+                       written = pwrite(tdb->fd, buf, n, size);
+               }
+               if (written == 0) {
+                       /* give up, trying to provide a useful errno */
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
+                               "returned 0 twice: giving up!\n"));
+                       errno = ENOSPC;
                        return -1;
+               } else if (written == -1) {
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
+                               "%d bytes failed (%s)\n", n, strerror(errno)));
+                       return -1;
+               } else if (written != n) {
+                       TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
+                               "only %d of %d bytes - retrying\n", written,n));
                }
-               addition -= ret;
-               size += ret;
+               addition -= written;
+               size += written;
        }
        return 0;
 }

Modified: branches/SAMBA_4_0/source/lib/tdb/common/io.c
===================================================================
--- branches/SAMBA_4_0/source/lib/tdb/common/io.c       2007-07-19 14:49:08 UTC 
(rev 23976)
+++ branches/SAMBA_4_0/source/lib/tdb/common/io.c       2007-07-20 14:23:12 UTC 
(rev 23977)
@@ -232,15 +232,28 @@
           disk. This must be done with write, not via mmap */
        memset(buf, TDB_PAD_BYTE, sizeof(buf));
        while (addition) {
-               int n = addition>sizeof(buf)?sizeof(buf):addition;
-               int ret = pwrite(tdb->fd, buf, n, size);
-               if (ret == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of %d 
failed (%s)\n", 
-                                  n, strerror(errno)));
+               size_t n = addition>sizeof(buf)?sizeof(buf):addition;
+               ssize_t written = pwrite(tdb->fd, buf, n, size);
+               if (written == 0) {
+                       /* prevent infinite loops: try _once_ more */
+                       written = pwrite(tdb->fd, buf, n, size);
+               }
+               if (written == 0) {
+                       /* give up, trying to provide a useful errno */
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write "
+                               "returned 0 twice: giving up!\n"));
+                       errno = ENOSPC;
                        return -1;
+               } else if (written == -1) {
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "expand_file write of "
+                               "%d bytes failed (%s)\n", n, strerror(errno)));
+                       return -1;
+               } else if (written != n) {
+                       TDB_LOG((tdb, TDB_DEBUG_WARNING, "expand_file: wrote "
+                               "only %d of %d bytes - retrying\n", written,n));
                }
-               addition -= ret;
-               size += ret;
+               addition -= written;
+               size += written;
        }
        return 0;
 }

Reply via email to