From ace4006c9f7ac16b3c09b1b2222f607bccfa040e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 26 Jan 2000 21:25:35 +0000 Subject: Added hash-based stat cache code from Ying Chen. Jeremy. (This used to be commit b62a1bd6328f5894ae1a2fef3ef6fc66304ade52) --- source3/Makefile.in | 2 +- source3/include/hash.h | 75 +++++++++++ source3/include/includes.h | 1 + source3/include/proto.h | 10 ++ source3/lib/hash.c | 320 ++++++++++++++++++++++++++++++++++++++++++++ source3/script/mkproto.awk | 2 +- source3/smbd/filename.c | 173 +++++++++++++----------- source3/smbd/server.c | 1 + source3/ubiqx/sys_include.h | 1 + 9 files changed, 502 insertions(+), 83 deletions(-) create mode 100644 source3/include/hash.h create mode 100644 source3/lib/hash.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 31594bbc8f..fd736fd5d5 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -99,7 +99,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \ lib/util_array.o lib/util_str.o lib/util_sid.o \ lib/util_unistr.o lib/util_file.o \ lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o lib/fnmatch.o \ - tdb/tdb.o lib/talloc.o + tdb/tdb.o lib/talloc.o lib/hash.o UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \ ubiqx/ubi_dLinkList.o ubiqx/ubi_sLinkList.o ubiqx/debugparse.o diff --git a/source3/include/hash.h b/source3/include/hash.h new file mode 100644 index 0000000000..2de7031855 --- /dev/null +++ b/source3/include/hash.h @@ -0,0 +1,75 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Copyright (C) Ying Chen 2000. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _HASH_H_ +#define _HASH_H_ + +#define MAX_HASH_TABLE_SIZE 32768 +#define HASH_TABLE_INCREMENT 2 + +typedef int (*compare_function)(char *, char *); +typedef int (*hash_function)(int, char *); + +/* + * lru_link: links the node to the LRU list. + * hash_elem: the pointer to the element that is tied onto the link. + */ +typedef struct lru_node { + ubi_dlNode lru_link; + void *hash_elem; +} lru_node; + +/* + * bucket_link: link the hash element to the bucket chain that it belongs to. + * lru_link: this element ties the hash element to the lru list. + * bucket: a pointer to the hash bucket that this element belongs to. + * value: a pointer to the hash element content. It can be anything. + * key: stores the string key. The hash_element is always allocated with + * more memory space than the structure shown below to accomodate the space + * used for the whole string. But the memory is always appended at the + * end of the structure, so keep "key" at the end of the structure. + * Don't move it. + */ +typedef struct hash_element { + ubi_dlNode bucket_link; + lru_node lru_link; + ubi_dlList *bucket; + void *value; + char key[1]; +} hash_element; + +/* + * buckets: a list of buckets, implemented as a dLinkList. + * lru_chain: the lru list of all the hash elements. + * num_elements: the # of elements in the hash table. + * size: the hash table size. + * comp_func: the compare function used during hash key comparisons. + */ + +typedef struct hash_table { + ubi_dlList *buckets; + ubi_dlList lru_chain; + int num_elements; + int size; + compare_function comp_func; +} hash_table; + +#endif /* _HASH_H_ */ diff --git a/source3/include/includes.h b/source3/include/includes.h index a872c1d306..a049b725c4 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -619,6 +619,7 @@ extern int errno; #include "../tdb/tdb.h" #include "talloc.h" #include "interfaces.h" +#include "hash.h" #ifdef HAVE_FNMATCH #include diff --git a/source3/include/proto.h b/source3/include/proto.h index 03fc5b1353..205031a2a8 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -97,6 +97,15 @@ void generate_random_buffer( unsigned char *out, int len, BOOL re_seed); char *getsmbpass(char *prompt) ; +/*The following definitions come from lib/hash.c */ + +BOOL hash_table_init(hash_table *table, int num_buckets, compare_function compare_func); +int string_hash(int hash_size, const char *key); +hash_element *hash_lookup(hash_table *table, char *key); +hash_element *hash_insert(hash_table *table, char *value, char *key); +void hash_remove(hash_table *table, hash_element *hash_elem); +void hash_clear(hash_table *table); + /*The following definitions come from lib/interface.c */ void load_interfaces(void); @@ -2636,6 +2645,7 @@ void print_stat_cache_statistics(void); BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, BOOL *bad_path, SMB_STRUCT_STAT *pst); BOOL check_name(char *name,connection_struct *conn); +BOOL reset_stat_cache( void ); /*The following definitions come from smbd/files.c */ diff --git a/source3/lib/hash.c b/source3/lib/hash.c new file mode 100644 index 0000000000..ccaf65b55a --- /dev/null +++ b/source3/lib/hash.c @@ -0,0 +1,320 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + + Copyright (C) Ying Chen 2000. + Copyright (C) Jeremy Allison 2000. + - added some defensive programming. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * NB. We may end up replacing this functionality in a future 2.x + * release to reduce the number of hashing/lookup methods we support. JRA. + */ + +#include "includes.h" + +extern int DEBUGLEVEL; + +#define NUM_PRIMES 11 + +static BOOL enlarge_hash_table(hash_table *table); +static int primes[NUM_PRIMES] = + {17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209, 16411}; + +/**************************************************************************** + * This function initializes the hash table. + * This hash function hashes on string keys. + * This number of hash buckets is always rounded up to a power of + * 2 first, then to a prime number that is large than the power of two. + * Input: + * table -- the hash table pointer. + * num_buckets -- the number of buckets to be allocated. This + * hash function can dynamically increase its size when the + * the hash table size becomes small. There is a MAX hash table + * size defined in hash.h. + * compare_func -- the function pointer to a comparison function + * used by the hash key comparison. + **************************************************************************** + */ + +BOOL hash_table_init(hash_table *table, int num_buckets, compare_function compare_func) +{ + int i; + ubi_dlList *bucket; + + table->num_elements = 0; + table->size = 2; + table->comp_func = compare_func; + while (table->size < num_buckets) + table->size <<= 1; + for (i = 0; i < NUM_PRIMES; i++) { + if (primes[i] > table->size) { + table->size = primes[i]; + break; + } + } + + DEBUG(5, ("Hash size = %d.\n", table->size)); + + if(!(table->buckets = (ubi_dlList *) malloc(sizeof(ubi_dlList) * table->size))) { + DEBUG(0,("hash_table_init: malloc fail !\n")); + return False; + } + ubi_dlInitList(&(table->lru_chain)); + for (i=0, bucket = table->buckets; i < table->size; i++, bucket++) + ubi_dlInitList(bucket); + + return True; +} + +/* + ************************************************************** + * Compute a hash value based on a string key value. + * Make the string key into an array of int's if possible. + * For the last few chars that cannot be int'ed, use char instead. + * The function returns the bucket index number for the hashed + * key. + ************************************************************** + */ + +int string_hash(int hash_size, const char *key) +{ + int j=0; + while (*key) + j = j*10 + *key++; + return(((j>=0)?j:(-j)) % hash_size); +} + +/* ************************************************************************* + * Search the hash table for the entry in the hash chain. + * The function returns the pointer to the + * element found in the chain or NULL if none is found. + * If the element is found, the element is also moved to + * the head of the LRU list. + * + * Input: + * table -- The hash table where the element is stored in. + * hash_chain -- The pointer to the bucket that stores the + * element to be found. + * key -- The hash key to be found. + *************************************************************************** + */ + +static hash_element *hash_chain_find(hash_table *table, ubi_dlList *hash_chain, char *key) +{ + hash_element *hash_elem; + ubi_dlNodePtr lru_item; + int i = 0; + + for (hash_elem = (hash_element *)(ubi_dlFirst(hash_chain)); i < hash_chain->count; + i++, hash_elem = (hash_element *)(ubi_dlNext(hash_elem))) { + if ((table->comp_func)(hash_elem->key, key) == 0) { + /* Move to the head of the lru List. */ + lru_item = ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); + ubi_dlAddHead(&(table->lru_chain), lru_item); + return(hash_elem); + } + } + return ((hash_element *) NULL); +} + +/* *************************************************************************** + * + * Lookup a hash table for an element with key. + * The function returns a pointer to the hash element. + * If no element is found, the function returns NULL. + * + * Input: + * table -- The hash table to be searched on. + * key -- The key to be found. + ***************************************************************************** + */ + +hash_element *hash_lookup(hash_table *table, char *key) +{ + return (hash_chain_find(table, &(table->buckets[string_hash(table->size, key)]), key)); +} + +/* *************************************************************** + * + * This function first checks if an element with key "key" + * exists in the hash table. If so, the function moves the + * element to the front of the LRU list. Otherwise, a new + * hash element corresponding to "value" and "key" is allocated + * and inserted into the hash table. The new elements are + * always inserted in the LRU order to the LRU list as well. + * + * Input: + * table -- The hash table to be inserted in. + * value -- The content of the element to be inserted. + * key -- The key of the new element to be inserted. + * + **************************************************************** + */ + +hash_element *hash_insert(hash_table *table, char *value, char *key) +{ + hash_element *hash_elem; + ubi_dlNodePtr lru_item; + ubi_dlList *bucket; + + /* + * If the hash table size has not reached the MAX_HASH_TABLE_SIZE, + * the hash table may be enlarged if the current hash table is full. + * If the hash table size has reached the MAX_HASH_TABLE_SIZE, + * use LRU to remove the oldest element from the hash table. + */ + + if ((table->num_elements >= table->size) && + (table->num_elements < MAX_HASH_TABLE_SIZE)) { + if(!enlarge_hash_table(table)) + return (hash_element *)NULL; + table->num_elements += 1; + } else if (table->num_elements >= MAX_HASH_TABLE_SIZE) { + /* Do an LRU replacement. */ + lru_item = ubi_dlLast(&(table->lru_chain)); + hash_elem = (hash_element *)(((lru_node *)lru_item)->hash_elem); + bucket = hash_elem->bucket; + ubi_dlRemThis(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); + ubi_dlRemThis(bucket, (ubi_dlNodePtr)hash_elem); + free((char*)(hash_elem->value)); + free(hash_elem); + } else { + table->num_elements += 1; + } + + bucket = &(table->buckets[string_hash(table->size, key)]); + + /* Since we only have 1-byte for the key string, we need to + * allocate extra space in the hash_element to store the entire key + * string. + */ + + if(!(hash_elem = (hash_element *) malloc(sizeof(hash_element) + strlen(key)))) { + DEBUG(0,("hash_insert: malloc fail !\n")); + return (hash_element *)NULL; + } + + safe_strcpy((char *) hash_elem->key, key, strlen(key)+1); + + hash_elem->value = (char *)value; + hash_elem->bucket = bucket; + /* Insert in front of the lru list and the bucket list. */ + ubi_dlAddHead(bucket, hash_elem); + hash_elem->lru_link.hash_elem = hash_elem; + ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); + + return(hash_elem); +} + +/* ************************************************************************** + * + * Remove a hash element from the hash table. The hash element is + * removed from both the LRU list and the hash bucket chain. + * + * Input: + * table -- the hash table to be manipulated on. + * hash_elem -- the element to be removed. + ************************************************************************** + */ + +void hash_remove(hash_table *table, hash_element *hash_elem) +{ + if (hash_elem) { + ubi_dlRemove(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); + ubi_dlRemove(hash_elem->bucket, (ubi_dlNodePtr) hash_elem); + if(hash_elem->value) + free((char *)(hash_elem->value)); + if(hash_elem) + free((char *) hash_elem); + table->num_elements--; + } +} + +/* ****************************************************************** + * Increase the hash table size if it is too small. + * The hash table size is increased by the HASH_TABLE_INCREMENT + * ratio. + * Input: + * table -- the hash table to be enlarged. + ****************************************************************** + */ + +static BOOL enlarge_hash_table(hash_table *table) +{ + hash_element *hash_elem; + int size, hash_value; + ubi_dlList *buckets; + ubi_dlList *old_bucket; + ubi_dlList *bucket; + ubi_dlList lru_chain; + + buckets = table->buckets; + lru_chain = table->lru_chain; + size = table->size; + + /* Reinitialize the hash table. */ + if(!hash_table_init(table, table->size * HASH_TABLE_INCREMENT, table->comp_func)) + return False; + + for (old_bucket = buckets; size > 0; size--, old_bucket++) { + while (old_bucket->count != 0) { + hash_elem = (hash_element *) ubi_dlRemHead(old_bucket); + ubi_dlRemove(&lru_chain, &(hash_elem->lru_link.lru_link)); + hash_value = string_hash(table->size, (char *) hash_elem->key); + bucket = &(table->buckets[hash_value]); + ubi_dlAddHead(bucket, hash_elem); + ubi_dlAddHead(&(table->lru_chain), &(hash_elem->lru_link.lru_link)); + hash_elem->bucket = bucket; + hash_elem->lru_link.hash_elem = hash_elem; + table->num_elements++; + } + } + if(buckets) + free((char *) buckets); + + return True; +} + +/* ********************************************************************** + * + * Remove everything from a hash table and free up the memory it + * occupies. + * Input: + * table -- the hash table to be cleared. + * + ************************************************************************* + */ + +void hash_clear(hash_table *table) +{ + int i; + ubi_dlList *bucket = table->buckets; + hash_element *hash_elem; + for (i = 0; i < table->size; bucket++, i++) { + while (bucket->count != 0) { + hash_elem = (hash_element *) ubi_dlRemHead(bucket); + if(hash_elem->value) + free((char *)(hash_elem->value)); + if(hash_elem) + free((char *)hash_elem); + } + } + if(table->buckets) + free((char *) table->buckets); +} diff --git a/source3/script/mkproto.awk b/source3/script/mkproto.awk index 8ef414266a..a8c807a10c 100644 --- a/source3/script/mkproto.awk +++ b/source3/script/mkproto.awk @@ -98,7 +98,7 @@ END { gotstart = 1; } - if( $0 ~ /^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX/ ) { + if( $0 ~ /^TDB_CONTEXT|^TDB_DATA|^smb_ucs2_t|^TALLOC_CTX|^hash_element/ ) { gotstart = 1; } diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 64f63805f3..2f8e92d98e 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -3,6 +3,8 @@ Version 1.9. filename handling routines Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 1999-200 + Copyright (C) Ying Chen 2000 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,6 +21,10 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * New hash table stat cache code added by Ying Chen. + */ + #include "includes.h" extern int DEBUGLEVEL; @@ -109,15 +115,12 @@ stat cache was %f%% effective.\n", global_stat_cache_lookups, } typedef struct { - ubi_dlNode link; int name_len; - pstring orig_name; - pstring translated_name; + char names[2]; /* This is extended via malloc... */ } stat_cache_entry; -#define MAX_STAT_CACHE_SIZE 50 - -static ubi_dlList stat_cache = { NULL, (ubi_dlNodePtr)&stat_cache, 0}; +#define INIT_STAT_CACHE_SIZE 512 +static hash_table stat_cache; /**************************************************************************** Compare a pathname to a name in the stat cache - of a given length. @@ -144,9 +147,11 @@ static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len) static void stat_cache_add( char *full_orig_name, char *orig_translated_path) { stat_cache_entry *scp; + stat_cache_entry *found_scp; pstring orig_name; pstring translated_path; int namelen; + hash_element *hash_elem; if (!lp_stat_cache()) return; @@ -194,39 +199,39 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path) * add it. */ - for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp; - scp = (stat_cache_entry *)ubi_dlNext( scp )) { - if((strcmp( scp->orig_name, orig_name) == 0) && - (strcmp( scp->translated_name, translated_path) == 0)) { - /* - * Name does exist - promote it. - */ - if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != scp ) { - ubi_dlRemThis( &stat_cache, scp); - ubi_dlAddHead( &stat_cache, scp); - } + if (hash_elem = hash_lookup(&stat_cache, orig_name)) { + found_scp = (stat_cache_entry *)(hash_elem->value); + if (strcmp((found_scp->names+found_scp->name_len+1), translated_path) == 0) { return; + } else { + hash_remove(&stat_cache, hash_elem); + if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) { + DEBUG(0,("stat_cache_add: Out of memory !\n")); + return; + } + pstrcpy(scp->names, orig_name); + pstrcpy((scp->names+namelen+1), translated_path); + scp->name_len = namelen; + hash_insert(&stat_cache, (char *)scp, orig_name); } - } - - if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry))) == NULL) { - DEBUG(0,("stat_cache_add: Out of memory !\n")); return; - } - - pstrcpy(scp->orig_name, orig_name); - pstrcpy(scp->translated_name, translated_path); - scp->name_len = namelen; - - ubi_dlAddHead( &stat_cache, scp); + } else { - DEBUG(10,("stat_cache_add: Added entry %s -> %s\n", scp->orig_name, scp->translated_name )); + /* + * New entry. + */ - if(ubi_dlCount(&stat_cache) > lp_stat_cache_size()) { - scp = (stat_cache_entry *)ubi_dlRemTail( &stat_cache ); - free((char *)scp); - return; + if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry)+2*namelen)) == NULL) { + DEBUG(0,("stat_cache_add: Out of memory !\n")); + return; + } + pstrcpy(scp->names, orig_name); + pstrcpy(scp->names+namelen+1, translated_path); + scp->name_len = namelen; + hash_insert(&stat_cache, (char *)scp, orig_name); } + + DEBUG(5,("stat_cache_add: Added entry %s -> %s\n", scp->names, (scp->names+scp->name_len+1))); } /**************************************************************************** @@ -238,10 +243,14 @@ static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRU { stat_cache_entry *scp; stat_cache_entry *longest_hit = NULL; + char *trans_name; pstring chk_name; int namelen; + hash_element *hash_elem; + char *sp; - if (!lp_stat_cache()) return False; + if (!lp_stat_cache()) + return False; namelen = strlen(name); @@ -260,55 +269,44 @@ static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRU if(!case_sensitive) strupper( chk_name ); - for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp; - scp = (stat_cache_entry *)ubi_dlNext( scp )) { - if(scp->name_len <= namelen) { - if(stat_name_equal_len(scp->orig_name, chk_name, scp->name_len)) { - if((longest_hit == NULL) || (longest_hit->name_len <= scp->name_len)) - longest_hit = scp; + while (1) { + hash_elem = hash_lookup(&stat_cache, chk_name); + if(hash_elem == NULL) { + /* + * Didn't find it - remove last component for next try. + */ + sp = strrchr(chk_name, '/'); + if (sp) { + *sp = '\0'; + } else { + /* + * We reached the end of the name - no match. + */ + global_stat_cache_misses++; + return False; } + if((*chk_name == '\0') || (strcmp(chk_name, ".") == 0) + || (strcmp(chk_name, "..") == 0)) { + global_stat_cache_misses++; + return False; + } + } else { + scp = (stat_cache_entry *)(hash_elem->value); + global_stat_cache_hits++; + trans_name = scp->names+scp->name_len+1; + if(dos_stat( trans_name, pst) != 0) { + /* Discard this entry - it doesn't exist in the filesystem. */ + hash_remove(&stat_cache, hash_elem); + return False; + } + memcpy(name, trans_name, scp->name_len); + *start = &name[scp->name_len]; + if(**start == '/') + ++*start; + StrnCpy( dirpath, trans_name, name - (*start)); + return (namelen == scp->name_len); } } - - if(longest_hit == NULL) { - DEBUG(10,("stat_cache_lookup: cache miss on %s\n", name)); - global_stat_cache_misses++; - return False; - } - - global_stat_cache_hits++; - - DEBUG(10,("stat_cache_lookup: cache hit for name %s. %s -> %s\n", - name, longest_hit->orig_name, longest_hit->translated_name )); - - /* - * longest_hit is the longest match we got in the list. - * Check it exists - if so, overwrite the original name - * and then promote it to the top. - */ - - if(dos_stat( longest_hit->translated_name, pst) != 0) { - /* - * Discard this entry. - */ - ubi_dlRemThis( &stat_cache, longest_hit); - free((char *)longest_hit); - return False; - } - - memcpy(name, longest_hit->translated_name, longest_hit->name_len); - if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != longest_hit ) { - ubi_dlRemThis( &stat_cache, longest_hit); - ubi_dlAddHead( &stat_cache, longest_hit); - } - - *start = &name[longest_hit->name_len]; - if(**start == '/') - ++*start; - - StrnCpy( dirpath, longest_hit->translated_name, name - (*start)); - - return (namelen == longest_hit->name_len); } /**************************************************************************** @@ -352,7 +350,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, *dirpath = 0; *bad_path = False; if(pst) { - ZERO_STRUCTP(pst); + ZERO_STRUCTP(pst); } if(saved_last_component) @@ -744,3 +742,16 @@ static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL d CloseDir(cur_dir); return(False); } + +/*************************************************************************** ** + * Initializes or clears the stat cache. + * + * Input: none. + * Output: none. + * + * ************************************************************************** ** + */ +BOOL reset_stat_cache( void ) +{ + return hash_table_init( &stat_cache, INIT_STAT_CACHE_SIZE, (compare_function)(strcmp)); +} /* reset_stat_cache */ diff --git a/source3/smbd/server.c b/source3/smbd/server.c index bd07ed8458..0e9675076f 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -320,6 +320,7 @@ BOOL reload_services(BOOL test) } reset_mangled_cache(); + reset_stat_cache(); /* this forces service parameters to be flushed */ become_service(NULL,True); diff --git a/source3/ubiqx/sys_include.h b/source3/ubiqx/sys_include.h index acfa5cdb84..8ff270afe8 100644 --- a/source3/ubiqx/sys_include.h +++ b/source3/ubiqx/sys_include.h @@ -40,6 +40,7 @@ */ #define _PROTO_H_ #define _NAMESERV_H_ +#define _HASH_H_ /* The main Samba system-adaptive header file. */ -- cgit