mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
smbd: Remove write cache
Since this was written, our write path has changed significantly. In particular we have gained very flexible support for async I/O, with the linux io_uring in the pipeline. Caching stuff in main memory and then doing a blocking pwrite nowadays does not belong into the core smbd code. If someone wants it back, it should be doable in a VFS module. Removes: "write cache size" parameter. Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Autobuild-User(master): Jeremy Allison <jra@samba.org> Autobuild-Date(master): Wed Nov 13 00:20:55 UTC 2019 on sn-devel-184
This commit is contained in:
parent
a0aaf5c334
commit
3fea05e01f
18
WHATSNEW.txt
18
WHATSNEW.txt
@ -56,6 +56,23 @@ applies.
|
||||
REMOVED FEATURES
|
||||
================
|
||||
|
||||
The smb.conf parameter "write cache size" has been removed.
|
||||
|
||||
Since the in-memory write caching code was written, our write path has
|
||||
changed significantly. In particular we have gained very flexible
|
||||
support for async I/O, with the new linux io_uring interface in
|
||||
development. The old write cache concept which cached data in main
|
||||
memory followed by a blocking pwrite no longer gives any improvement
|
||||
on modern systems, and may make performance worse on memory-contrained
|
||||
systems, so this functionality should not be enabled in core smbd
|
||||
code.
|
||||
|
||||
In addition, it complicated the write code, which is a performance
|
||||
critical code path.
|
||||
|
||||
If required for specialist purposes, it can be recreated as a VFS
|
||||
module.
|
||||
|
||||
BIND9_FLATFILE deprecated
|
||||
-------------------------
|
||||
|
||||
@ -77,6 +94,7 @@ smb.conf changes
|
||||
|
||||
nfs4:acedup Changed default merge
|
||||
rndc command Removed
|
||||
write cache size Removed
|
||||
|
||||
KNOWN ISSUES
|
||||
============
|
||||
|
@ -1,33 +0,0 @@
|
||||
<samba:parameter name="write cache size"
|
||||
context="S"
|
||||
type="bytes"
|
||||
xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
|
||||
<description>
|
||||
<para>If this integer parameter is set to non-zero value,
|
||||
Samba will create an in-memory cache for each oplocked file
|
||||
(it does <emphasis>not</emphasis> do this for
|
||||
non-oplocked files). All writes that the client does not request
|
||||
to be flushed directly to disk will be stored in this cache if possible.
|
||||
The cache is flushed onto disk when a write comes in whose offset
|
||||
would not fit into the cache or when the file is closed by the client.
|
||||
Reads for the file are also served from this cache if the data is stored
|
||||
within it.</para>
|
||||
|
||||
<para>This cache allows Samba to batch client writes into a more
|
||||
efficient write size for RAID disks (i.e. writes may be tuned to
|
||||
be the RAID stripe size) and can improve performance on systems
|
||||
where the disk subsystem is a bottleneck but there is free
|
||||
memory for userspace programs.</para>
|
||||
|
||||
<para>The integer parameter specifies the size of this cache
|
||||
(per oplocked file) in bytes.</para>
|
||||
|
||||
<para>Note that the write cache won't be used for file handles with a smb2 write lease.</para>
|
||||
</description>
|
||||
|
||||
<related>aio read size</related>
|
||||
<related>aio write size</related>
|
||||
<related>smb2 leases</related>
|
||||
<value type="default">0</value>
|
||||
<value type="example">262144<comment> for a 256k cache size per file</comment></value>
|
||||
</samba:parameter>
|
@ -749,19 +749,4 @@ struct smb_extended_info {
|
||||
char samba_version_string[SAMBA_EXTENDED_INFO_VERSION_STRING_LENGTH];
|
||||
};
|
||||
|
||||
/*
|
||||
* Reasons for cache flush.
|
||||
*/
|
||||
|
||||
enum flush_reason_enum {
|
||||
SAMBA_SEEK_FLUSH,
|
||||
SAMBA_READ_FLUSH,
|
||||
SAMBA_WRITE_FLUSH,
|
||||
SAMBA_READRAW_FLUSH,
|
||||
SAMBA_OPLOCK_RELEASE_FLUSH,
|
||||
SAMBA_CLOSE_FLUSH,
|
||||
SAMBA_SYNC_FLUSH,
|
||||
SAMBA_SIZECHANGE_FLUSH,
|
||||
};
|
||||
|
||||
#endif /* _SMB_H */
|
||||
|
@ -108,27 +108,6 @@ struct tevent_context;
|
||||
SMBPROFILE_STATS_COUNT(statcache_hits) \
|
||||
SMBPROFILE_STATS_SECTION_END \
|
||||
\
|
||||
SMBPROFILE_STATS_SECTION_START(writecache, "Write Cache") \
|
||||
SMBPROFILE_STATS_COUNT(writecache_allocations) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_deallocations) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_cached_reads) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_total_writes) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_init_writes) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_abutted_writes) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_non_oplock_writes) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_direct_writes) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_cached_writes) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_perfect_writes) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_flush_reason_seek) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_flush_reason_read) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_flush_reason_readraw) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_flush_reason_write) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_flush_reason_oplock) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_flush_reason_close) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_flush_reason_sync) \
|
||||
SMBPROFILE_STATS_COUNT(writecache_flush_reason_sizechange) \
|
||||
SMBPROFILE_STATS_SECTION_END \
|
||||
\
|
||||
SMBPROFILE_STATS_SECTION_START(SMB, "SMB Calls") \
|
||||
SMBPROFILE_STATS_BASIC(SMBmkdir) \
|
||||
SMBPROFILE_STATS_BASIC(SMBrmdir) \
|
||||
|
@ -286,6 +286,7 @@
|
||||
/* Version 42 - Remove SMB_VFS_RMDIR.
|
||||
Use SMB_VFS_UNLINKAT(.., AT_REMOVEDIR) instead. */
|
||||
/* Version 42 - Remove SMB_VFS_CHOWN */
|
||||
/* Version 42 - Remove struct write_cache *wcp from files_struct */
|
||||
|
||||
#define SMB_VFS_INTERFACE_VERSION 42
|
||||
|
||||
@ -347,7 +348,6 @@ typedef struct files_struct {
|
||||
uint64_t initial_allocation_size; /* Faked up initial allocation on disk. */
|
||||
uint16_t file_pid;
|
||||
uint64_t vuid; /* SMB2 compat */
|
||||
struct write_cache *wcp;
|
||||
struct timeval open_time;
|
||||
uint32_t access_mask; /* NTCreateX access bits (FILE_READ_DATA etc.) */
|
||||
bool kernel_share_modes_taken;
|
||||
|
@ -160,7 +160,6 @@ static const struct loadparm_service _sDefault =
|
||||
.min_print_space = 0,
|
||||
.max_print_jobs = 1000,
|
||||
.max_reported_print_jobs = 0,
|
||||
.write_cache_size = 0,
|
||||
.create_mask = 0744,
|
||||
.force_create_mode = 0,
|
||||
.directory_mask = 0755,
|
||||
|
@ -172,9 +172,8 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn,
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
||||
/* Only do this on non-chained and non-chaining reads not using the
|
||||
* write cache. */
|
||||
if (req_is_in_chain(smbreq) || (lp_write_cache_size(SNUM(conn)) != 0)) {
|
||||
/* Only do this on non-chained and non-chaining reads */
|
||||
if (req_is_in_chain(smbreq)) {
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
||||
@ -428,9 +427,8 @@ NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
||||
/* Only do this on non-chained and non-chaining writes not using the
|
||||
* write cache. */
|
||||
if (req_is_in_chain(smbreq) || (lp_write_cache_size(SNUM(conn)) != 0)) {
|
||||
/* Only do this on non-chained and non-chaining writes */
|
||||
if (req_is_in_chain(smbreq)) {
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
||||
@ -673,11 +671,6 @@ NTSTATUS schedule_smb2_aio_read(connection_struct *conn,
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
||||
/* Only do this on reads not using the write cache. */
|
||||
if (lp_write_cache_size(SNUM(conn)) != 0) {
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
||||
if (smbd_smb2_is_compound(smbreq->smb2req)) {
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
@ -813,11 +806,6 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
||||
/* Only do this on writes not using the write cache. */
|
||||
if (lp_write_cache_size(SNUM(conn)) != 0) {
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
||||
if (smbd_smb2_is_compound(smbreq->smb2req)) {
|
||||
return NT_STATUS_RETRY;
|
||||
}
|
||||
|
@ -140,24 +140,6 @@ static NTSTATUS check_magic(struct files_struct *fsp)
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Common code to close a file or a directory.
|
||||
****************************************************************************/
|
||||
|
||||
static NTSTATUS close_filestruct(files_struct *fsp)
|
||||
{
|
||||
NTSTATUS status = NT_STATUS_OK;
|
||||
|
||||
if (fsp->fh->fd != -1) {
|
||||
if(flush_write_cache(fsp, SAMBA_CLOSE_FLUSH) == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
}
|
||||
delete_write_cache(fsp);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Delete all streams
|
||||
****************************************************************************/
|
||||
@ -715,9 +697,6 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
|
||||
* error here, we must remember this.
|
||||
*/
|
||||
|
||||
tmp = close_filestruct(fsp);
|
||||
status = ntstatus_keeperror(status, tmp);
|
||||
|
||||
if (NT_STATUS_IS_OK(status) && fsp->op != NULL) {
|
||||
is_durable = fsp->op->global->durable;
|
||||
}
|
||||
@ -1182,7 +1161,6 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
|
||||
if (lck == NULL) {
|
||||
DEBUG(0, ("close_directory: Could not get share mode lock for "
|
||||
"%s\n", fsp_str_dbg(fsp)));
|
||||
close_filestruct(fsp);
|
||||
file_free(req, fsp);
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
@ -1242,7 +1220,6 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(5, ("delete_all_streams failed: %s\n",
|
||||
nt_errstr(status)));
|
||||
close_filestruct(fsp);
|
||||
file_free(req, fsp);
|
||||
return status;
|
||||
}
|
||||
@ -1287,7 +1264,6 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
|
||||
/*
|
||||
* Do the code common to files and directories.
|
||||
*/
|
||||
close_filestruct(fsp);
|
||||
file_free(req, fsp);
|
||||
|
||||
if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
|
||||
|
@ -25,39 +25,6 @@
|
||||
#include "smbd/globals.h"
|
||||
#include "smbprofile.h"
|
||||
|
||||
struct write_cache {
|
||||
off_t file_size;
|
||||
off_t offset;
|
||||
size_t alloc_size;
|
||||
size_t data_size;
|
||||
char *data;
|
||||
};
|
||||
|
||||
static bool setup_write_cache(files_struct *, off_t);
|
||||
|
||||
/****************************************************************************
|
||||
Read from write cache if we can.
|
||||
****************************************************************************/
|
||||
|
||||
static bool read_from_write_cache(files_struct *fsp,char *data,off_t pos,size_t n)
|
||||
{
|
||||
struct write_cache *wcp = fsp->wcp;
|
||||
|
||||
if(!wcp) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if( n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) {
|
||||
return False;
|
||||
}
|
||||
|
||||
memcpy(data, wcp->data + (pos - wcp->offset), n);
|
||||
|
||||
DO_PROFILE_INC(writecache_cached_reads);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Read from a file.
|
||||
****************************************************************************/
|
||||
@ -72,18 +39,6 @@ ssize_t read_file(files_struct *fsp,char *data,off_t pos,size_t n)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serve from write cache if we can.
|
||||
*/
|
||||
|
||||
if(read_from_write_cache(fsp, data, pos, n)) {
|
||||
fsp->fh->pos = pos + n;
|
||||
fsp->fh->position_information = fsp->fh->pos;
|
||||
return n;
|
||||
}
|
||||
|
||||
flush_write_cache(fsp, SAMBA_READ_FLUSH);
|
||||
|
||||
fsp->fh->pos = pos;
|
||||
|
||||
if (n > 0) {
|
||||
@ -140,26 +95,6 @@ static ssize_t real_write_file(struct smb_request *req,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
File size cache change.
|
||||
Updates size on disk but doesn't flush the cache.
|
||||
****************************************************************************/
|
||||
|
||||
static int wcp_file_size_change(files_struct *fsp)
|
||||
{
|
||||
int ret;
|
||||
struct write_cache *wcp = fsp->wcp;
|
||||
|
||||
wcp->file_size = wcp->offset + wcp->data_size;
|
||||
ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size);
|
||||
if (ret == -1) {
|
||||
DEBUG(0,("wcp_file_size_change (%s): ftruncate of size %.0f "
|
||||
"error %s\n", fsp_str_dbg(fsp),
|
||||
(double)wcp->file_size, strerror(errno)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fsp_flush_write_time_update(struct files_struct *fsp)
|
||||
{
|
||||
/*
|
||||
@ -314,9 +249,7 @@ ssize_t write_file(struct smb_request *req,
|
||||
off_t pos,
|
||||
size_t n)
|
||||
{
|
||||
struct write_cache *wcp = fsp->wcp;
|
||||
ssize_t total_written = 0;
|
||||
int write_path = -1;
|
||||
|
||||
if (fsp->print_file) {
|
||||
uint32_t t;
|
||||
@ -335,30 +268,8 @@ ssize_t write_file(struct smb_request *req,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is the first write and we have an exclusive oplock
|
||||
* then setup the write cache.
|
||||
*/
|
||||
|
||||
if (!fsp->modified &&
|
||||
EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) &&
|
||||
(wcp == NULL)) {
|
||||
/*
|
||||
* Note: no write cache with leases!
|
||||
* as the handles would have to share the write cache
|
||||
* that's possible but an improvement for another day...
|
||||
*/
|
||||
setup_write_cache(fsp, fsp->fsp_name->st.st_ex_size);
|
||||
wcp = fsp->wcp;
|
||||
}
|
||||
|
||||
mark_file_modified(fsp);
|
||||
|
||||
DO_PROFILE_INC(writecache_total_writes);
|
||||
if (!fsp->oplock_type) {
|
||||
DO_PROFILE_INC(writecache_non_oplock_writes);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this file is level II oplocked then we need
|
||||
* to grab the shared memory lock and inform all
|
||||
@ -371,681 +282,10 @@ ssize_t write_file(struct smb_request *req,
|
||||
contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
|
||||
contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);
|
||||
|
||||
if (wcp && req->unread_bytes) {
|
||||
/* If we're using receivefile don't
|
||||
* deal with a write cache.
|
||||
*/
|
||||
flush_write_cache(fsp, SAMBA_WRITE_FLUSH);
|
||||
delete_write_cache(fsp);
|
||||
wcp = NULL;
|
||||
}
|
||||
|
||||
if(!wcp) {
|
||||
DO_PROFILE_INC(writecache_direct_writes);
|
||||
total_written = real_write_file(req, fsp, data, pos, n);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
DEBUG(9,("write_file (%s)(fd=%d pos=%.0f size=%u) wcp->offset=%.0f "
|
||||
"wcp->data_size=%u\n", fsp_str_dbg(fsp), fsp->fh->fd,
|
||||
(double)pos, (unsigned int)n, (double)wcp->offset,
|
||||
(unsigned int)wcp->data_size));
|
||||
|
||||
fsp->fh->pos = pos + n;
|
||||
|
||||
if ((n == 1) && (data[0] == '\0') && (pos > wcp->file_size)) {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* This is a 1-byte write of a 0 beyond the EOF and
|
||||
* thus implicitly also beyond the current active
|
||||
* write cache, the typical file-extending (and
|
||||
* allocating, but we're using the write cache here)
|
||||
* write done by Windows. We just have to ftruncate
|
||||
* the file and rely on posix semantics to return
|
||||
* zeros for non-written file data that is within the
|
||||
* file length.
|
||||
*
|
||||
* We can not use wcp_file_size_change here because we
|
||||
* might have an existing write cache, and
|
||||
* wcp_file_size_change assumes a change to just the
|
||||
* end of the current write cache.
|
||||
*/
|
||||
|
||||
wcp->file_size = pos + 1;
|
||||
ret = SMB_VFS_FTRUNCATE(fsp, wcp->file_size);
|
||||
if (ret == -1) {
|
||||
DEBUG(0, ("wcp_file_size_change (%s): ftruncate of "
|
||||
"size %.0f error %s\n", fsp_str_dbg(fsp),
|
||||
(double)wcp->file_size, strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If we have active cache and it isn't contiguous then we flush.
|
||||
* NOTE: There is a small problem with running out of disk ....
|
||||
*/
|
||||
|
||||
if (wcp->data_size) {
|
||||
bool cache_flush_needed = False;
|
||||
|
||||
if ((pos >= wcp->offset) &&
|
||||
(pos <= wcp->offset + wcp->data_size)) {
|
||||
|
||||
/* ASCII art.... JRA.
|
||||
|
||||
+--------------+-----
|
||||
| Cached data | Rest of allocated cache buffer....
|
||||
+--------------+-----
|
||||
|
||||
+-------------------+
|
||||
| Data to write |
|
||||
+-------------------+
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Start of write overlaps or abutts the existing data.
|
||||
*/
|
||||
|
||||
size_t data_used;
|
||||
|
||||
data_used = MIN((wcp->alloc_size - (pos - wcp->offset)),
|
||||
n);
|
||||
|
||||
memcpy(wcp->data + (pos - wcp->offset), data,
|
||||
data_used);
|
||||
|
||||
/*
|
||||
* Update the current buffer size with the new data.
|
||||
*/
|
||||
|
||||
if(pos + data_used > wcp->offset + wcp->data_size) {
|
||||
wcp->data_size = pos + data_used - wcp->offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the file size if changed.
|
||||
*/
|
||||
|
||||
if (wcp->offset + wcp->data_size > wcp->file_size) {
|
||||
if (wcp_file_size_change(fsp) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we used all the data then
|
||||
* return here.
|
||||
*/
|
||||
|
||||
if(n == data_used) {
|
||||
return n;
|
||||
} else {
|
||||
cache_flush_needed = True;
|
||||
}
|
||||
/*
|
||||
* Move the start of data forward by the amount used,
|
||||
* cut down the amount left by the same amount.
|
||||
*/
|
||||
|
||||
data += data_used;
|
||||
pos += data_used;
|
||||
n -= data_used;
|
||||
|
||||
DO_PROFILE_INC(writecache_abutted_writes);
|
||||
total_written = data_used;
|
||||
|
||||
write_path = 1;
|
||||
|
||||
} else if ((pos < wcp->offset) &&
|
||||
(pos + n > wcp->offset) &&
|
||||
(pos + n <= wcp->offset + wcp->alloc_size)) {
|
||||
|
||||
/* ASCII art.... JRA.
|
||||
|
||||
+---------------+
|
||||
| Cache buffer |
|
||||
+---------------+
|
||||
|
||||
+-------------------+
|
||||
| Data to write |
|
||||
+-------------------+
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* End of write overlaps the existing data.
|
||||
*/
|
||||
|
||||
size_t data_used = pos + n - wcp->offset;
|
||||
|
||||
memcpy(wcp->data, data + n - data_used, data_used);
|
||||
|
||||
/*
|
||||
* Update the current buffer size with the new data.
|
||||
*/
|
||||
|
||||
if(pos + n > wcp->offset + wcp->data_size) {
|
||||
wcp->data_size = pos + n - wcp->offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the file size if changed.
|
||||
*/
|
||||
|
||||
if (wcp->offset + wcp->data_size > wcp->file_size) {
|
||||
if (wcp_file_size_change(fsp) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need to move the start of data, but we
|
||||
* cut down the amount left by the amount used.
|
||||
*/
|
||||
|
||||
n -= data_used;
|
||||
|
||||
/*
|
||||
* We cannot have used all the data here.
|
||||
*/
|
||||
|
||||
cache_flush_needed = True;
|
||||
|
||||
DO_PROFILE_INC(writecache_abutted_writes);
|
||||
total_written = data_used;
|
||||
|
||||
write_path = 2;
|
||||
|
||||
} else if ((pos >= wcp->file_size) &&
|
||||
(wcp->offset + wcp->data_size == wcp->file_size) &&
|
||||
(pos > wcp->offset + wcp->data_size) &&
|
||||
(pos < wcp->offset + wcp->alloc_size) ) {
|
||||
|
||||
/* ASCII art.... JRA.
|
||||
|
||||
End of file ---->|
|
||||
|
||||
+---------------+---------------+
|
||||
| Cached data | Cache buffer |
|
||||
+---------------+---------------+
|
||||
|
||||
+-------------------+
|
||||
| Data to write |
|
||||
+-------------------+
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Non-contiguous write part of which fits within
|
||||
* the cache buffer and is extending the file
|
||||
* and the cache contents reflect the current
|
||||
* data up to the current end of the file.
|
||||
*/
|
||||
|
||||
size_t data_used;
|
||||
|
||||
if(pos + n <= wcp->offset + wcp->alloc_size) {
|
||||
data_used = n;
|
||||
} else {
|
||||
data_used = wcp->offset+wcp->alloc_size-pos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the non-continuous area with zeros.
|
||||
*/
|
||||
|
||||
memset(wcp->data + wcp->data_size, '\0',
|
||||
pos - (wcp->offset + wcp->data_size) );
|
||||
|
||||
memcpy(wcp->data + (pos - wcp->offset), data,
|
||||
data_used);
|
||||
|
||||
/*
|
||||
* Update the current buffer size with the new data.
|
||||
*/
|
||||
|
||||
if(pos + data_used > wcp->offset + wcp->data_size) {
|
||||
wcp->data_size = pos + data_used - wcp->offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the file size if changed.
|
||||
*/
|
||||
|
||||
if (wcp->offset + wcp->data_size > wcp->file_size) {
|
||||
if (wcp_file_size_change(fsp) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we used all the data then
|
||||
* return here.
|
||||
*/
|
||||
|
||||
if(n == data_used) {
|
||||
return n;
|
||||
} else {
|
||||
cache_flush_needed = True;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the start of data forward by the amount used,
|
||||
* cut down the amount left by the same amount.
|
||||
*/
|
||||
|
||||
data += data_used;
|
||||
pos += data_used;
|
||||
n -= data_used;
|
||||
|
||||
DO_PROFILE_INC(writecache_abutted_writes);
|
||||
total_written = data_used;
|
||||
|
||||
write_path = 3;
|
||||
|
||||
} else if ( (pos >= wcp->file_size) &&
|
||||
(n == 1) &&
|
||||
(wcp->file_size == wcp->offset + wcp->data_size) &&
|
||||
(pos < wcp->file_size + wcp->alloc_size)) {
|
||||
|
||||
/*
|
||||
|
||||
End of file ---->|
|
||||
|
||||
+---------------+---------------+
|
||||
| Cached data | Cache buffer |
|
||||
+---------------+---------------+
|
||||
|
||||
|<------- allocated size ---------------->|
|
||||
|
||||
+--------+
|
||||
| 1 Byte |
|
||||
+--------+
|
||||
|
||||
MS-Office seems to do this a lot to determine if
|
||||
there's enough space on the filesystem to write a new
|
||||
file.
|
||||
|
||||
Change to :
|
||||
|
||||
End of file ---->|
|
||||
+-----------------------+--------+
|
||||
| Zeroed Cached data | 1 Byte |
|
||||
+-----------------------+--------+
|
||||
*/
|
||||
|
||||
flush_write_cache(fsp, SAMBA_WRITE_FLUSH);
|
||||
wcp->offset = wcp->file_size;
|
||||
wcp->data_size = pos - wcp->file_size + 1;
|
||||
memset(wcp->data, '\0', wcp->data_size);
|
||||
memcpy(wcp->data + wcp->data_size-1, data, 1);
|
||||
|
||||
/*
|
||||
* Update the file size if changed.
|
||||
*/
|
||||
|
||||
if (wcp->offset + wcp->data_size > wcp->file_size) {
|
||||
if (wcp_file_size_change(fsp) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
|
||||
} else {
|
||||
|
||||
/* ASCII art..... JRA.
|
||||
|
||||
Case 1).
|
||||
|
||||
+---------------+---------------+
|
||||
| Cached data | Cache buffer |
|
||||
+---------------+---------------+
|
||||
|
||||
+---------------+
|
||||
| Data to write |
|
||||
+---------------+
|
||||
|
||||
Case 2).
|
||||
|
||||
+---------------+---------------+
|
||||
| Cached data | Cache buffer |
|
||||
+---------------+---------------+
|
||||
|
||||
+-------------------+
|
||||
| Data to write |
|
||||
+-------------------+
|
||||
|
||||
Case 3).
|
||||
|
||||
+---------------+---------------+
|
||||
| Cached data | Cache buffer |
|
||||
+---------------+---------------+
|
||||
|
||||
+-----------------------------------------------------+
|
||||
| Data to write |
|
||||
+-----------------------------------------------------+
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Write is bigger than buffer, or there is no
|
||||
* overlap on the low or high ends.
|
||||
*/
|
||||
|
||||
DEBUG(9,("write_file: non cacheable write : fd = %d, "
|
||||
"pos = %.0f, len = %u, "
|
||||
"current cache pos = %.0f len = %u\n",
|
||||
fsp->fh->fd, (double)pos, (unsigned int)n,
|
||||
(double)wcp->offset,
|
||||
(unsigned int)wcp->data_size ));
|
||||
|
||||
/*
|
||||
* If write would fit in the cache, and is
|
||||
* larger than the data already in the cache,
|
||||
* flush the cache and preferentially copy the
|
||||
* data new data into it. Otherwise just write
|
||||
* the data directly.
|
||||
*/
|
||||
|
||||
if ( n <= wcp->alloc_size && n > wcp->data_size) {
|
||||
cache_flush_needed = True;
|
||||
} else {
|
||||
ssize_t ret = real_write_file(NULL, fsp, data,
|
||||
pos, n);
|
||||
|
||||
/*
|
||||
* If the write overlaps the entire
|
||||
* cache, then discard the current
|
||||
* contents of the cache. Fix from
|
||||
* Rasmus Borup Hansen rbh@math.ku.dk.
|
||||
*/
|
||||
|
||||
if ((pos <= wcp->offset) &&
|
||||
(pos + n >= wcp->offset+wcp->data_size)) {
|
||||
DEBUG(9,("write_file: discarding "
|
||||
"overwritten write cache: "
|
||||
"fd = %d, off=%.0f, "
|
||||
"size=%u\n", fsp->fh->fd,
|
||||
(double)wcp->offset,
|
||||
(unsigned)wcp->data_size));
|
||||
wcp->data_size = 0;
|
||||
}
|
||||
|
||||
DO_PROFILE_INC(writecache_direct_writes);
|
||||
if (ret == -1) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pos + ret > wcp->file_size) {
|
||||
wcp->file_size = pos + ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
write_path = 4;
|
||||
|
||||
}
|
||||
|
||||
if (cache_flush_needed) {
|
||||
DEBUG(3, ("SAMBA_WRITE_FLUSH:%d: due to noncontinuous "
|
||||
"write: fd = %d, size = %.0f, pos = %.0f, "
|
||||
"n = %u, wcp->offset=%.0f, "
|
||||
"wcp->data_size=%u\n",
|
||||
write_path, fsp->fh->fd,
|
||||
(double)wcp->file_size, (double)pos,
|
||||
(unsigned int)n, (double)wcp->offset,
|
||||
(unsigned int)wcp->data_size ));
|
||||
|
||||
flush_write_cache(fsp, SAMBA_WRITE_FLUSH);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the write request is bigger than the cache
|
||||
* size, write it all out.
|
||||
*/
|
||||
|
||||
if (n > wcp->alloc_size ) {
|
||||
ssize_t ret = real_write_file(NULL,fsp, data, pos, n);
|
||||
if (ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pos + ret > wcp->file_size) {
|
||||
wcp->file_size = pos + n;
|
||||
}
|
||||
|
||||
DO_PROFILE_INC(writecache_direct_writes);
|
||||
return total_written + n;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there's any data left, cache it.
|
||||
*/
|
||||
|
||||
if (n) {
|
||||
DO_PROFILE_INC(writecache_cached_writes);
|
||||
if (wcp->data_size) {
|
||||
DO_PROFILE_INC(writecache_abutted_writes);
|
||||
} else {
|
||||
DO_PROFILE_INC(writecache_init_writes);
|
||||
}
|
||||
|
||||
if ((wcp->data_size == 0)
|
||||
&& (pos > wcp->file_size)
|
||||
&& (pos + n <= wcp->file_size + wcp->alloc_size)) {
|
||||
/*
|
||||
* This is a write completely beyond the
|
||||
* current EOF, but within reach of the write
|
||||
* cache. We expect fill-up writes pretty
|
||||
* soon, so it does not make sense to start
|
||||
* the write cache at the current
|
||||
* offset. These fill-up writes would trigger
|
||||
* separate pwrites or even unnecessary cache
|
||||
* flushes because they overlap if this is a
|
||||
* one-byte allocating write.
|
||||
*/
|
||||
wcp->offset = wcp->file_size;
|
||||
wcp->data_size = pos - wcp->file_size;
|
||||
memset(wcp->data, 0, wcp->data_size);
|
||||
}
|
||||
|
||||
memcpy(wcp->data+wcp->data_size, data, n);
|
||||
if (wcp->data_size == 0) {
|
||||
wcp->offset = pos;
|
||||
}
|
||||
wcp->data_size += n;
|
||||
|
||||
/*
|
||||
* Update the file size if changed.
|
||||
*/
|
||||
|
||||
if (wcp->offset + wcp->data_size > wcp->file_size) {
|
||||
if (wcp_file_size_change(fsp) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
DEBUG(9, ("wcp->offset = %.0f wcp->data_size = %u cache "
|
||||
"return %u\n",
|
||||
(double)wcp->offset, (unsigned int)wcp->data_size,
|
||||
(unsigned int)n));
|
||||
|
||||
total_written += n;
|
||||
return total_written; /* .... that's a write :) */
|
||||
}
|
||||
|
||||
total_written = real_write_file(req, fsp, data, pos, n);
|
||||
return total_written;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Delete the write cache structure.
|
||||
****************************************************************************/
|
||||
|
||||
void delete_write_cache(files_struct *fsp)
|
||||
{
|
||||
struct write_cache *wcp;
|
||||
|
||||
if(!fsp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(wcp = fsp->wcp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DO_PROFILE_INC(writecache_deallocations);
|
||||
allocated_write_caches--;
|
||||
|
||||
SMB_ASSERT(wcp->data_size == 0);
|
||||
|
||||
SAFE_FREE(wcp->data);
|
||||
SAFE_FREE(fsp->wcp);
|
||||
|
||||
DEBUG(10,("delete_write_cache: File %s deleted write cache\n",
|
||||
fsp_str_dbg(fsp)));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Setup the write cache structure.
|
||||
****************************************************************************/
|
||||
|
||||
static bool setup_write_cache(files_struct *fsp, off_t file_size)
|
||||
{
|
||||
ssize_t alloc_size = lp_write_cache_size(SNUM(fsp->conn));
|
||||
struct write_cache *wcp;
|
||||
|
||||
if (allocated_write_caches >= MAX_WRITE_CACHES) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if(alloc_size == 0 || fsp->wcp) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if((wcp = SMB_MALLOC_P(struct write_cache)) == NULL) {
|
||||
DEBUG(0,("setup_write_cache: malloc fail.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
wcp->file_size = file_size;
|
||||
wcp->offset = 0;
|
||||
wcp->alloc_size = alloc_size;
|
||||
wcp->data_size = 0;
|
||||
if((wcp->data = (char *)SMB_MALLOC(wcp->alloc_size)) == NULL) {
|
||||
DEBUG(0,("setup_write_cache: malloc fail for buffer size %u.\n",
|
||||
(unsigned int)wcp->alloc_size ));
|
||||
SAFE_FREE(wcp);
|
||||
return False;
|
||||
}
|
||||
|
||||
memset(wcp->data, '\0', wcp->alloc_size );
|
||||
|
||||
fsp->wcp = wcp;
|
||||
DO_PROFILE_INC(writecache_allocations);
|
||||
allocated_write_caches++;
|
||||
|
||||
DEBUG(10,("setup_write_cache: File %s allocated write cache size %lu\n",
|
||||
fsp_str_dbg(fsp), (unsigned long)wcp->alloc_size));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Cope with a size change.
|
||||
****************************************************************************/
|
||||
|
||||
void set_filelen_write_cache(files_struct *fsp, off_t file_size)
|
||||
{
|
||||
if(fsp->wcp) {
|
||||
/* The cache *must* have been flushed before we do this. */
|
||||
if (fsp->wcp->data_size != 0) {
|
||||
char *msg;
|
||||
if (asprintf(&msg, "set_filelen_write_cache: size change "
|
||||
"on file %s with write cache size = %lu\n",
|
||||
fsp->fsp_name->base_name,
|
||||
(unsigned long)fsp->wcp->data_size) != -1) {
|
||||
smb_panic(msg);
|
||||
} else {
|
||||
smb_panic("set_filelen_write_cache");
|
||||
}
|
||||
}
|
||||
fsp->wcp->file_size = file_size;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Flush a write cache struct to disk.
|
||||
********************************************************************/
|
||||
|
||||
ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason)
|
||||
{
|
||||
struct write_cache *wcp = fsp->wcp;
|
||||
size_t data_size;
|
||||
ssize_t ret;
|
||||
|
||||
if(!wcp || !wcp->data_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
data_size = wcp->data_size;
|
||||
wcp->data_size = 0;
|
||||
|
||||
switch (reason) {
|
||||
case SAMBA_SEEK_FLUSH:
|
||||
DO_PROFILE_INC(writecache_flush_reason_seek);
|
||||
break;
|
||||
case SAMBA_READ_FLUSH:
|
||||
DO_PROFILE_INC(writecache_flush_reason_read);
|
||||
break;
|
||||
case SAMBA_WRITE_FLUSH:
|
||||
DO_PROFILE_INC(writecache_flush_reason_write);;
|
||||
break;
|
||||
case SAMBA_READRAW_FLUSH:
|
||||
DO_PROFILE_INC(writecache_flush_reason_readraw);
|
||||
break;
|
||||
case SAMBA_OPLOCK_RELEASE_FLUSH:
|
||||
DO_PROFILE_INC(writecache_flush_reason_oplock);
|
||||
break;
|
||||
case SAMBA_CLOSE_FLUSH:
|
||||
DO_PROFILE_INC(writecache_flush_reason_close);
|
||||
break;
|
||||
case SAMBA_SYNC_FLUSH:
|
||||
DO_PROFILE_INC(writecache_flush_reason_sync);
|
||||
break;
|
||||
case SAMBA_SIZECHANGE_FLUSH:
|
||||
DO_PROFILE_INC(writecache_flush_reason_sizechange);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG(9,("flushing write cache: fd = %d, off=%.0f, size=%u\n",
|
||||
fsp->fh->fd, (double)wcp->offset, (unsigned int)data_size));
|
||||
|
||||
if(data_size == wcp->alloc_size) {
|
||||
DO_PROFILE_INC(writecache_perfect_writes);
|
||||
}
|
||||
|
||||
ret = real_write_file(NULL, fsp, wcp->data, wcp->offset, data_size);
|
||||
|
||||
/*
|
||||
* Ensure file size if kept up to date if write extends file.
|
||||
*/
|
||||
|
||||
if ((ret != -1) && (wcp->offset + ret > wcp->file_size)) {
|
||||
wcp->file_size = wcp->offset + ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
sync a file
|
||||
********************************************************************/
|
||||
@ -1057,10 +297,7 @@ NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_throug
|
||||
|
||||
if (lp_strict_sync(SNUM(conn)) &&
|
||||
(lp_sync_always(SNUM(conn)) || write_through)) {
|
||||
int ret = flush_write_cache(fsp, SAMBA_SYNC_FLUSH);
|
||||
if (ret == -1) {
|
||||
return map_nt_error_from_unix(errno);
|
||||
}
|
||||
int ret;
|
||||
ret = smb_vfs_fsync_sync(fsp);
|
||||
if (ret == -1) {
|
||||
return map_nt_error_from_unix(errno);
|
||||
|
@ -28,9 +28,6 @@
|
||||
struct smbd_dmapi_context *dmapi_ctx = NULL;
|
||||
#endif
|
||||
|
||||
/* how many write cache buffers have been allocated */
|
||||
unsigned int allocated_write_caches = 0;
|
||||
|
||||
const struct mangle_fns *mangle_fns = NULL;
|
||||
|
||||
unsigned char *chartest = NULL;
|
||||
|
@ -30,9 +30,6 @@ struct smbd_dmapi_context;
|
||||
extern struct smbd_dmapi_context *dmapi_ctx;
|
||||
#endif
|
||||
|
||||
/* how many write cache buffers have been allocated */
|
||||
extern unsigned int allocated_write_caches;
|
||||
|
||||
/* A singleton cache to speed up searching by dev/inode. */
|
||||
struct fsp_singleton_cache {
|
||||
files_struct *fsp;
|
||||
|
@ -1451,8 +1451,6 @@ static NTSTATUS open_file(files_struct *fsp,
|
||||
fsp->aio_write_behind = True;
|
||||
}
|
||||
|
||||
fsp->wcp = NULL; /* Write cache pointer. */
|
||||
|
||||
DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
|
||||
conn->session_info->unix_info->unix_name,
|
||||
smb_fname_str_dbg(smb_fname),
|
||||
|
@ -139,9 +139,6 @@ static void release_file_oplock(files_struct *fsp)
|
||||
fsp->oplock_type = NO_OPLOCK;
|
||||
fsp->sent_oplock_break = NO_BREAK_SENT;
|
||||
|
||||
flush_write_cache(fsp, SAMBA_OPLOCK_RELEASE_FLUSH);
|
||||
delete_write_cache(fsp);
|
||||
|
||||
TALLOC_FREE(fsp->oplock_timeout);
|
||||
}
|
||||
|
||||
@ -169,9 +166,6 @@ static void downgrade_file_oplock(files_struct *fsp)
|
||||
sconn->oplocks.level_II_open++;
|
||||
fsp->sent_oplock_break = NO_BREAK_SENT;
|
||||
|
||||
flush_write_cache(fsp, SAMBA_OPLOCK_RELEASE_FLUSH);
|
||||
delete_write_cache(fsp);
|
||||
|
||||
TALLOC_FREE(fsp->oplock_timeout);
|
||||
}
|
||||
|
||||
|
@ -330,9 +330,6 @@ ssize_t write_file(struct smb_request *req,
|
||||
const char *data,
|
||||
off_t pos,
|
||||
size_t n);
|
||||
void delete_write_cache(files_struct *fsp);
|
||||
void set_filelen_write_cache(files_struct *fsp, off_t file_size);
|
||||
ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason);
|
||||
NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through);
|
||||
|
||||
/* The following definitions come from smbd/filename.c */
|
||||
|
@ -3643,7 +3643,6 @@ static void send_file_readbraw(connection_struct *conn,
|
||||
*/
|
||||
|
||||
if ( !req_is_in_chain(req) && (nread > 0) && (fsp->base_fsp == NULL) &&
|
||||
(fsp->wcp == NULL) &&
|
||||
lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
|
||||
ssize_t sendfile_read = -1;
|
||||
char header[4];
|
||||
@ -3827,8 +3826,6 @@ void reply_readbraw(struct smb_request *req)
|
||||
return;
|
||||
}
|
||||
|
||||
flush_write_cache(fsp, SAMBA_READRAW_FLUSH);
|
||||
|
||||
startpos = IVAL_TO_SMB_OFF_T(req->vwv+1, 0);
|
||||
if(req->wct == 10) {
|
||||
/*
|
||||
@ -4215,7 +4212,6 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
|
||||
if (!req_is_in_chain(req) &&
|
||||
!req->encrypted &&
|
||||
(fsp->base_fsp == NULL) &&
|
||||
(fsp->wcp == NULL) &&
|
||||
lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) {
|
||||
uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */];
|
||||
DATA_BLOB header;
|
||||
@ -5446,8 +5442,6 @@ void reply_lseek(struct smb_request *req)
|
||||
return;
|
||||
}
|
||||
|
||||
flush_write_cache(fsp, SAMBA_SEEK_FLUSH);
|
||||
|
||||
mode = SVAL(req->vwv+1, 0) & 3;
|
||||
/* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
|
||||
startpos = (off_t)IVALS(req->vwv+2, 0);
|
||||
|
@ -125,7 +125,6 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_req *subreq;
|
||||
struct smbd_smb2_flush_state *state;
|
||||
struct smb_request *smbreq;
|
||||
int ret;
|
||||
|
||||
req = tevent_req_create(mem_ctx, &state,
|
||||
struct smbd_smb2_flush_state);
|
||||
@ -187,12 +186,6 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
ret = flush_write_cache(fsp, SAMBA_SYNC_FLUSH);
|
||||
if (ret == -1) {
|
||||
tevent_req_nterror(req, map_nt_error_from_unix(errno));
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
|
@ -355,7 +355,6 @@ static NTSTATUS schedule_smb2_sendfile_read(struct smbd_smb2_request *smb2req,
|
||||
smb2req->do_encryption ||
|
||||
smbd_smb2_is_compound(smb2req) ||
|
||||
(fsp->base_fsp != NULL) ||
|
||||
(fsp->wcp != NULL) ||
|
||||
(!S_ISREG(fsp->fsp_name->st.st_ex_mode)) ||
|
||||
(state->in_offset >= fsp->fsp_name->st.st_ex_size) ||
|
||||
(fsp->fsp_name->st.st_ex_size < state->in_offset + state->in_length))
|
||||
|
@ -515,10 +515,7 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
|
||||
|
||||
contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
|
||||
|
||||
flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
|
||||
if ((ret = SMB_VFS_FTRUNCATE(fsp, (off_t)len)) != -1) {
|
||||
set_filelen_write_cache(fsp, len);
|
||||
}
|
||||
ret = SMB_VFS_FTRUNCATE(fsp, (off_t)len);
|
||||
|
||||
contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);
|
||||
|
||||
@ -585,9 +582,7 @@ int vfs_set_filelen(files_struct *fsp, off_t len)
|
||||
|
||||
DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n",
|
||||
fsp_str_dbg(fsp), (double)len));
|
||||
flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
|
||||
if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
|
||||
set_filelen_write_cache(fsp, len);
|
||||
notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
|
||||
FILE_NOTIFY_CHANGE_SIZE
|
||||
| FILE_NOTIFY_CHANGE_ATTRIBUTES,
|
||||
@ -676,8 +671,6 @@ int vfs_fill_sparse(files_struct *fsp, off_t len)
|
||||
|
||||
contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);
|
||||
|
||||
flush_write_cache(fsp, SAMBA_SIZECHANGE_FLUSH);
|
||||
|
||||
offset = fsp->fsp_name->st.st_ex_size;
|
||||
num_to_write = len - fsp->fsp_name->st.st_ex_size;
|
||||
|
||||
@ -703,10 +696,6 @@ int vfs_fill_sparse(files_struct *fsp, off_t len)
|
||||
|
||||
out:
|
||||
|
||||
if (ret == 0) {
|
||||
set_filelen_write_cache(fsp, len);
|
||||
}
|
||||
|
||||
contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_FILL_SPARSE);
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user