Author: ivan
Date: Tue Sep  3 09:52:47 2013
New Revision: 1519624

URL: http://svn.apache.org/r1519624
Log:
Fix potential FSFS transaction corruption issue. The issue could happen 
only if processes are writing to the same transaction and using extremely 
large path.

* subversion/libsvn_fs_fs/low_level.c
  (write_change_entry): Collect all change info in stringbuf and write in one
   atomic write call.
* subversion/libsvn_fs_fs/transaction.c
  (svn_fs_fs__add_change): Remove APR_BUFFERED flag when opening changes 
   file for appending.

Modified:
    subversion/trunk/subversion/libsvn_fs_fs/low_level.c
    subversion/trunk/subversion/libsvn_fs_fs/transaction.c

Modified: subversion/trunk/subversion/libsvn_fs_fs/low_level.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/low_level.c?rev=1519624&r1=1519623&r2=1519624&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/low_level.c Tue Sep  3 09:52:47 
2013
@@ -350,9 +350,11 @@ write_change_entry(svn_stream_t *stream,
                    svn_boolean_t include_node_kind,
                    apr_pool_t *pool)
 {
-  const char *idstr, *buf;
+  const char *idstr;
   const char *change_string = NULL;
   const char *kind_string = "";
+  svn_stringbuf_t *buf;
+  apr_size_t len;
 
   switch (change->change_kind)
     {
@@ -391,22 +393,24 @@ write_change_entry(svn_stream_t *stream,
                                  ? SVN_FS_FS__KIND_DIR
                                   : SVN_FS_FS__KIND_FILE);
     }
-  buf = apr_psprintf(pool, "%s %s%s %s %s %s\n",
-                     idstr, change_string, kind_string,
-                     change->text_mod ? FLAG_TRUE : FLAG_FALSE,
-                     change->prop_mod ? FLAG_TRUE : FLAG_FALSE,
-                     path);
-
-  SVN_ERR(svn_stream_puts(stream, buf));
+  buf = svn_stringbuf_createf(pool, "%s %s%s %s %s %s\n",
+                              idstr, change_string, kind_string,
+                              change->text_mod ? FLAG_TRUE : FLAG_FALSE,
+                              change->prop_mod ? FLAG_TRUE : FLAG_FALSE,
+                              path);
 
   if (SVN_IS_VALID_REVNUM(change->copyfrom_rev))
     {
-      buf = apr_psprintf(pool, "%ld %s", change->copyfrom_rev,
-                         change->copyfrom_path);
-      SVN_ERR(svn_stream_puts(stream, buf));
+      svn_stringbuf_appendcstr(buf, apr_psprintf(pool, "%ld %s",
+                                                 change->copyfrom_rev,
+                                                 change->copyfrom_path));
     }
 
-  return svn_error_trace(svn_stream_puts(stream, "\n"));
+   svn_stringbuf_appendbyte(buf, '\n');
+
+   /* Write all change info in one write call. */
+   len = buf->len;
+   return svn_error_trace(svn_stream_write(stream, buf->data, &len));
 }
 
 svn_error_t *

Modified: subversion/trunk/subversion/libsvn_fs_fs/transaction.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/transaction.c?rev=1519624&r1=1519623&r2=1519624&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/transaction.c Tue Sep  3 09:52:47 
2013
@@ -1518,9 +1518,10 @@ svn_fs_fs__add_change(svn_fs_t *fs,
   svn_fs_path_change2_t *change;
   apr_hash_t *changes = apr_hash_make(pool);
 
+  /* Not using APR_BUFFERED to append change in one atomic write operation. */
   SVN_ERR(svn_io_file_open(&file, path_txn_changes(fs, txn_id, pool),
-                           APR_APPEND | APR_WRITE | APR_CREATE
-                           | APR_BUFFERED, APR_OS_DEFAULT, pool));
+                           APR_APPEND | APR_WRITE | APR_CREATE,
+                           APR_OS_DEFAULT, pool));
 
   change = svn_fs__path_change_create_internal(id, change_kind, pool);
   change->text_mod = text_mod;


Reply via email to