diff options
-rw-r--r-- | source3/include/proto.h | 1 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 26 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 79 |
3 files changed, 50 insertions, 56 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 85a7294d1a..19c693b252 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -5562,6 +5562,7 @@ ssize_t vfs_pwrite_data(struct smb_request *req, SMB_OFF_T offset); int vfs_allocate_file_space(files_struct *fsp, uint64_t len); int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len); +int vfs_slow_fallocate(files_struct *fsp, SMB_OFF_T offset, SMB_OFF_T len); int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len); SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n); const char *vfs_readdirname(connection_struct *conn, void *p, diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 0ec5b66df3..79f66db6d9 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -822,16 +822,11 @@ static int vfswrap_ntimes(vfs_handle_struct *handle, static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T len) { SMB_STRUCT_STAT st; - SMB_OFF_T currpos = SMB_VFS_LSEEK(fsp, 0, SEEK_CUR); - unsigned char zero_space[4096]; SMB_OFF_T space_to_write; uint64_t space_avail; uint64_t bsize,dfree,dsize; int ret; - if (currpos == -1) - return -1; - if (SMB_VFS_FSTAT(fsp, &st) == -1) return -1; @@ -877,25 +872,12 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs } /* Write out the real space on disk. */ - if (SMB_VFS_LSEEK(fsp, st.st_ex_size, SEEK_SET) != st.st_ex_size) - return -1; - - memset(zero_space, '\0', sizeof(zero_space)); - while ( space_to_write > 0) { - SMB_OFF_T retlen; - SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),space_to_write); - - retlen = SMB_VFS_WRITE(fsp,(char *)zero_space,current_len_to_write); - if (retlen <= 0) - return -1; - - space_to_write -= retlen; + ret = vfs_slow_fallocate(fsp, st.st_ex_size, space_to_write); + if (ret != 0) { + errno = ret; + ret = -1; } - /* Seek to where we were */ - if (SMB_VFS_LSEEK(fsp, currpos, SEEK_SET) != currpos) - return -1; - return 0; } diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 1829e3ae42..a35142eab1 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -558,22 +558,56 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) } /**************************************************************************** + A slow version of posix_fallocate. Fallback code if SMB_VFS_POSIX_FALLOCATE + fails. Needs to be outside of the default version of SMB_VFS_POSIX_FALLOCATE + as this is also called from the default SMB_VFS_FTRUNCATE code. + Returns 0 on success, errno on failure. +****************************************************************************/ + +#define SPARSE_BUF_WRITE_SIZE (32*1024) + +int vfs_slow_fallocate(files_struct *fsp, SMB_OFF_T offset, SMB_OFF_T len) +{ + ssize_t pwrite_ret; + size_t total = 0; + + if (!sparse_buf) { + sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE); + if (!sparse_buf) { + errno = ENOMEM; + return ENOMEM; + } + } + + while (total < len) { + size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (len - total)); + + pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total); + if (pwrite_ret == -1) { + DEBUG(10,("vfs_slow_fallocate: SMB_VFS_PWRITE for file " + "%s failed with error %s\n", + fsp_str_dbg(fsp), strerror(errno))); + return errno; + } + total += pwrite_ret; + } + + return 0; +} + +/**************************************************************************** A vfs fill sparse call. Writes zeros from the end of file to len, if len is greater than EOF. Used only by strict_sync. Returns 0 on success, -1 on failure. ****************************************************************************/ -#define SPARSE_BUF_WRITE_SIZE (32*1024) - int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) { int ret; SMB_STRUCT_STAT st; SMB_OFF_T offset; - size_t total; size_t num_to_write; - ssize_t pwrite_ret; ret = SMB_VFS_FSTAT(fsp, &st); if (ret == -1) { @@ -616,47 +650,24 @@ int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len) goto out; } if (ret == 0) { - set_filelen_write_cache(fsp, len); goto out; } DEBUG(10,("vfs_fill_sparse: SMB_VFS_POSIX_FALLOCATE failed with " "error %d. Falling back to slow manual allocation\n", ret)); } - if (!sparse_buf) { - sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE); - if (!sparse_buf) { - errno = ENOMEM; - ret = -1; - goto out; - } + ret = vfs_slow_fallocate(fsp, offset, num_to_write); + if (ret != 0) { + errno = ret; + ret = -1; } - total = 0; - - while (total < num_to_write) { - size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total)); - - pwrite_ret = SMB_VFS_PWRITE(fsp, sparse_buf, curr_write_size, offset + total); - if (pwrite_ret == -1) { - DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file " - "%s failed with error %s\n", - fsp_str_dbg(fsp), strerror(errno))); - ret = -1; - goto out; - } - if (pwrite_ret == 0) { - ret = 0; - goto out; - } + out: - total += pwrite_ret; + if (ret == 0) { + set_filelen_write_cache(fsp, len); } - set_filelen_write_cache(fsp, len); - - ret = 0; - out: contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE); return ret; } |