PATCH samba cache and read-ahead

Amin Azez azez at
Mon Nov 12 14:24:20 GMT 2007

Attached is proof-of-concept caching and read-ahead for Samba to
optimize WAN scenarios.
It applies to Friday's SVN.
They are distributed here under GPL3

The proof of concept provides extra functionality to the cifs proxy.


It supports configurable read-ahead.

In a simple scenario where only one proxy is used on the client side of
the WAN, if the read-ahead window is a little more than the WAN
bandwidth multiplied by the round-trip time, then the WAN link should be
fully utilized. On a 100ms RTT WAN link, this can reduce the time to
load a large file by 25%; and even better when there is higher latency.


It supports simple caching when an op-lock is obtained, intended to
manage better caching than the client might, but the caching is
currently a bit simple, supporting only a linear extent from offset zero.


Where there is a proxy on both sides of the WAN it can also negotiate
compression, which combined with read-ahead can reduce time to load a
big file to 25% of normal, if the file compresses at around 25%.


There is also basic cache-revalidation if there is an existing cache
file, where the client proxy can provide a md5 checksum of what is in
the cache as part of a read-request, and the server proxy just confirms
this. Currently re-validation is done as compressible read-ahead, which
means the client cannot gauge downstream bandwidth usage better than it
can guess cache-hits, so I think I must introduce a streaming
revalidation where the server sends unsolicited updates based on the
compressed response size.

A pre-cached 10MB file 25% compressible took:

Normal: 470 seconds
read-ahead: 367 seconds
zlib + read-ahead: 97 seconds
zlib + read-ahead+cache-validation: 9 seconds

or down to around 2% of the transfer time.

The code is ugly; I'm still working out which layers of Samba I should
be tainting.

Mapping generic operations

I had some trouble with cvfs; CIFS_MAP_GENERIC_DEFAULT was set to false
yet all the handler functions were written assuming it was true, but
also, having a union to hold the different smb_read structs turned out
to be less helpful than it first seemed.

I tried adding some extra accessor macros in interfaces.h but I find the
whole thing unsatisfactory. I've been toying with generics of various
kinds, including multiple invocations of the C pre-processor on
vfs_cifs.c so we can write the function once but implement it for all
the various smb_read structs involved. Anybody think it might be nicer
to consider converting to vala? Me neither but I don't like managing
this hard work be hand. Passing round a union* in this fashion is as bad
as passing round a void* except we don't get the compiler warnings. I
think the void* would make me feel happier as we could cast it with a
protective macro that checked the level, what we have now is plain

New operations

I defined a SAMBA wire-protocol operation SMBreadMagic but it's
currently really just SMBreadx with compression support added. I'm
agreed that a new operation needed adding here, but I'm not totally
certain that I needed a new samba-level operation SMB_READ_CACHE. It's
so similar to SMB_READ_READX that the code that handles it is nearly the
same, only can't quite be because they use different members of the
smb_read union (bah!) and I don't think much of my accessor macros.

Advertising capabilities

I also took the liberty of:
#define CAP_CACHE              0x00100000

so client and server could tell if they supported the caching and
compression stuff. I'm not sure about this being the best way, I don't
feel good stealing one of these bits, maybe we need an
extra_capabilities field to use when talking to samba servers?


The smb.conf file has to look something like this:

        ntvfs handler = cifs
        cifs:server =
        cifs:share = myshare
        cifs:cache-enabled = FALSE
        cifs:cache-readahead = 8192
        # I think these next two are not used, now we have MAGIC_CA
        cifs:server-compression = FALSE
        cifs:client-compression = TRUE

        cifs:user = USERNAME
        cifs:password = PASSWORD
        cifs:domain = DOMAIN

I'm now trying to find out how to get the cifs-proxy to proxy the
connecting users credentials. Any help would be appreciated.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: samba_cache.patch
Type: text/x-patch
Size: 80112 bytes
Desc: not available
Url :

More information about the samba-technical mailing list