mirror of
https://github.com/samba-team/samba.git
synced 2025-03-20 22:50:26 +03:00
smbd: Cache dfree information based on query path
Sub directories in a SMB share can have different free space information (e.g. when a different file system is mounted there). Caching the dfree information per SMB share will return invalid data. Address this by switching to memcache and store the cached data based on the query path. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13446 Signed-off-by: Christof Schmitt <cs@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> (cherry picked from commit 8f121747b06ca78cf51801a3931b2ddd1a424c77)
This commit is contained in:
parent
3fd685e71a
commit
f7e53f864b
@ -343,4 +343,3 @@
|
||||
# Disabling NTLM means you can't use samr to change the password
|
||||
^samba.tests.ntlmdisabled.python\(ktest\).ntlmdisabled.NtlmDisabledTests.test_samr_change_password\(ktest\)
|
||||
^samba.tests.ntlmdisabled.python\(ad_dc_no_ntlm\).ntlmdisabled.NtlmDisabledTests.test_ntlm_connection\(ad_dc_no_ntlm\)
|
||||
^samba3.blackbox.dfree_quota \(fileserver\).Test dfree cache\(fileserver\)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "smbd/smbd.h"
|
||||
#include "smbd/globals.h"
|
||||
#include "lib/util_file.h"
|
||||
#include "lib/util/memcache.h"
|
||||
|
||||
/****************************************************************************
|
||||
Normalise for DOS usage.
|
||||
@ -167,48 +168,108 @@ dfree_done:
|
||||
|
||||
/****************************************************************************
|
||||
Potentially returned cached dfree info.
|
||||
|
||||
Depending on the file system layout and file system features, the free space
|
||||
information can be different for different sub directories underneath a SMB
|
||||
share. Store the cache information in memcache using the query path as the
|
||||
key to accomodate this.
|
||||
****************************************************************************/
|
||||
|
||||
uint64_t get_dfree_info(connection_struct *conn, struct smb_filename *fname,
|
||||
uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
|
||||
{
|
||||
int dfree_cache_time = lp_dfree_cache_time(SNUM(conn));
|
||||
struct dfree_cached_info *dfc = conn->dfree_info;
|
||||
struct dfree_cached_info *dfc = NULL;
|
||||
struct dfree_cached_info dfc_new = { 0 };
|
||||
uint64_t dfree_ret;
|
||||
char tmpbuf[PATH_MAX];
|
||||
char *full_path = NULL;
|
||||
char *to_free = NULL;
|
||||
char *key_path = NULL;
|
||||
size_t len;
|
||||
DATA_BLOB key, value;
|
||||
bool found;
|
||||
|
||||
if (!dfree_cache_time) {
|
||||
return sys_disk_free(conn, fname, bsize, dfree, dsize);
|
||||
}
|
||||
|
||||
len = full_path_tos(conn->connectpath,
|
||||
fname->base_name,
|
||||
tmpbuf,
|
||||
sizeof(tmpbuf),
|
||||
&full_path,
|
||||
&to_free);
|
||||
if (len == -1) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (VALID_STAT(fname->st) && S_ISREG(fname->st.st_ex_mode)) {
|
||||
/*
|
||||
* In case of a file use the parent directory to reduce number
|
||||
* of cache entries.
|
||||
*/
|
||||
bool ok;
|
||||
|
||||
ok = parent_dirname(talloc_tos(),
|
||||
full_path,
|
||||
&key_path,
|
||||
NULL);
|
||||
TALLOC_FREE(to_free); /* We're done with full_path */
|
||||
|
||||
if (!ok) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_path is always a talloced object.
|
||||
*/
|
||||
to_free = key_path;
|
||||
} else {
|
||||
/*
|
||||
* key_path might not be a talloced object; rely on
|
||||
* to_free set from full_path_tos.
|
||||
*/
|
||||
key_path = full_path;
|
||||
}
|
||||
|
||||
key = data_blob_const(key_path, strlen(key_path));
|
||||
found = memcache_lookup(smbd_memcache(),
|
||||
DFREE_CACHE,
|
||||
key,
|
||||
&value);
|
||||
dfc = found ? (struct dfree_cached_info *)value.data : NULL;
|
||||
|
||||
if (dfc && (conn->lastused - dfc->last_dfree_time < dfree_cache_time)) {
|
||||
/* Return cached info. */
|
||||
DBG_DEBUG("Returning dfree cache entry for %s\n", key_path);
|
||||
*bsize = dfc->bsize;
|
||||
*dfree = dfc->dfree;
|
||||
*dsize = dfc->dsize;
|
||||
return dfc->dfree_ret;
|
||||
dfree_ret = dfc->dfree_ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dfree_ret = sys_disk_free(conn, fname, bsize, dfree, dsize);
|
||||
|
||||
if (dfree_ret == (uint64_t)-1) {
|
||||
/* Don't cache bad data. */
|
||||
return dfree_ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* No cached info or time to refresh. */
|
||||
if (!dfc) {
|
||||
dfc = talloc(conn, struct dfree_cached_info);
|
||||
if (!dfc) {
|
||||
return dfree_ret;
|
||||
}
|
||||
conn->dfree_info = dfc;
|
||||
}
|
||||
|
||||
dfc->bsize = *bsize;
|
||||
dfc->dfree = *dfree;
|
||||
dfc->dsize = *dsize;
|
||||
dfc->dfree_ret = dfree_ret;
|
||||
dfc->last_dfree_time = conn->lastused;
|
||||
DBG_DEBUG("Creating dfree cache entry for %s\n", key_path);
|
||||
dfc_new.bsize = *bsize;
|
||||
dfc_new.dfree = *dfree;
|
||||
dfc_new.dsize = *dsize;
|
||||
dfc_new.dfree_ret = dfree_ret;
|
||||
dfc_new.last_dfree_time = conn->lastused;
|
||||
memcache_add(smbd_memcache(),
|
||||
DFREE_CACHE,
|
||||
key,
|
||||
data_blob_const(&dfc_new, sizeof(dfc_new)));
|
||||
|
||||
out:
|
||||
TALLOC_FREE(to_free);
|
||||
return dfree_ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user