On 28 May 2015 at 19:52, Ivan Zhakov <i...@visualsvn.com> wrote: > On 28 May 2015 at 19:25, Stefan Fuhrmann <stefan.fuhrm...@wandisco.com> wrote: >> On Thu, May 28, 2015 at 5:54 PM, Ivan Zhakov <i...@visualsvn.com> wrote: >>> >>> On 28 May 2015 at 18:45, <stef...@apache.org> wrote: >>> > Author: stefan2 >>> > Date: Thu May 28 15:45:55 2015 >>> > New Revision: 1682265 >>> > >>> > URL: http://svn.apache.org/r1682265 >>> > Log: >>> > Correctly fsync() after renames in FSFS on Win32. We must flush the >>> > disk >>> > buffers after the rename, otherwise the metadata may not be persistent. >>> > Moreover, if the rename is degraded to a copy by Win32, we won't even >>> > have >>> > the complete file contents on disk without a buffer flush. >>> > >>> Are you sure about this change? >> >> >> Yes. APR calls MoveFileEx with MOVEFILE_COPY_ALLOWED >> but not with MOVEFILE_WRITE_THROUGH. If your txn folder >> points to a different volume than the repo, *no* data will be fsync'ed. >> > Using MOVEFILE_COPY_ALLOWED without MOVEFILE_WRITE_THROUGH is a > problem. But it could be easily fixed, without open+flush+close file > on every move. > > Also moving txn folder on different volume already creates risk of > repository corruption, because svn_io_copy_file() is not atomic > operation, i.e. destination file could be deleted/empty/contain > partial content when svn_io_file_rename() degrades to copy. But we > need to improve svn_fs_fs__move_into_place() code in different way: > 1. Make svn_io_file_name() consistently return error for cross volume > renames by fixing APR or using platform specific code. I've prepared a patch that fixes svn_io_file_rename() to consistently return error for cross volume renames on Windows using platform specific code. See svn-rename-no-copy-allowed-v1.patch.txt. Review/testing will be really appreciated since it contains platform specific code.
While I think that we should generally avoid platform specific code, in this case using the native API gives us an opportunity to use MOVEFILE_WRITE_THROUGH flag for MoveFileEx later to avoid potential problems on network shares and non-NTFS filesystems. I've also prepared patch for APR that changes apr_file_rename() behavior to fail for cross-volume renames on Windows (see apr-file-rename-no-copy-allowed-v1.patch), but I'm not sure that it could be committed to APR (and backported to release branches) since it changes behavior and some APR users may depend on current behavior. -- Ivan Zhakov
Index: subversion/libsvn_subr/io.c =================================================================== --- subversion/libsvn_subr/io.c (revision 1687052) +++ subversion/libsvn_subr/io.c (working copy) @@ -4024,7 +4024,25 @@ return SVN_NO_ERROR; } +#if defined(WIN32) +/* Compatibility wrapper around apr_file_rename() to workaround + APR problems on Windows. */ +static apr_status_t +win32_file_rename(const WCHAR *from_path_w, + const WCHAR *to_path_w, + apr_pool_t *pool) +{ + /* APR calls MoveFileExW() with MOVEFILE_COPY_ALLOWED, while we rely + * that rename is atomic operation. Use MoveFileEx directly on Windows + * without MOVEFILE_COPY_ALLOWED flag to workaround it. + */ + if (!MoveFileExW(from_path_w, to_path_w, MOVEFILE_REPLACE_EXISTING)) + return apr_get_os_error(); + return APR_SUCCESS; +} +#endif + svn_error_t * svn_io_file_rename(const char *from_path, const char *to_path, apr_pool_t *pool) @@ -4031,13 +4049,19 @@ { apr_status_t status = APR_SUCCESS; const char *from_path_apr, *to_path_apr; +#if defined(WIN32) + WCHAR *from_path_w; + WCHAR *to_path_w; +#endif SVN_ERR(cstring_from_utf8(&from_path_apr, from_path, pool)); SVN_ERR(cstring_from_utf8(&to_path_apr, to_path, pool)); - status = apr_file_rename(from_path_apr, to_path_apr, pool); +#if defined(WIN32) + SVN_ERR(svn_io__utf8_to_unicode_longpath(&from_path_w, from_path_apr, pool)); + SVN_ERR(svn_io__utf8_to_unicode_longpath(&to_path_w, to_path_apr, pool)); + status = win32_file_rename(from_path_w, to_path_w, pool); -#if defined(WIN32) || defined(__OS2__) /* If the target file is read only NTFS reports EACCESS and FAT/FAT32 reports EEXIST */ if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status)) @@ -4047,9 +4071,23 @@ allow renaming when from_path is read only. */ SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool)); + status = win32_file_rename(from_path_w, to_path_w, pool); + } + WIN32_RETRY_LOOP(status, win32_file_rename(from_path_w, to_path_w, pool)); +#elif defined(__OS2__) + /* If the target file is read only NTFS reports EACCESS and + FAT/FAT32 reports EEXIST */ + if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status)) + { + /* Set the destination file writable because OS/2 will not + allow us to rename when to_path is read-only, but will + allow renaming when from_path is read only. */ + SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool)); + status = apr_file_rename(from_path_apr, to_path_apr, pool); } - WIN32_RETRY_LOOP(status, apr_file_rename(from_path_apr, to_path_apr, pool)); +#else + status = apr_file_rename(from_path_apr, to_path_apr, pool); #endif /* WIN32 || __OS2__ */ if (status)
Index: file_io/win32/open.c =================================================================== --- file_io/win32/open.c (revision 1687097) +++ file_io/win32/open.c (working copy) @@ -548,15 +548,13 @@ return rv; } #ifndef _WIN32_WCE - if (MoveFileExW(wfrompath, wtopath, MOVEFILE_REPLACE_EXISTING | - MOVEFILE_COPY_ALLOWED)) + if (MoveFileExW(wfrompath, wtopath, MOVEFILE_REPLACE_EXISTING)) #else if (MoveFileW(wfrompath, wtopath)) #endif return APR_SUCCESS; #else - if (MoveFileEx(frompath, topath, MOVEFILE_REPLACE_EXISTING | - MOVEFILE_COPY_ALLOWED)) + if (MoveFileEx(frompath, topath, MOVEFILE_REPLACE_EXISTING)) return APR_SUCCESS; #endif }