1
0
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:
Volker Lendecke 2019-05-27 11:24:14 +02:00 committed by Jeremy Allison
parent a0aaf5c334
commit 3fea05e01f
18 changed files with 26 additions and 919 deletions

View File

@ -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
============

View File

@ -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>

View File

@ -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 */

View File

@ -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) \

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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),

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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))

View File

@ -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;
}