15e134da0SJan Kneschke #define _GNU_SOURCE 25e134da0SJan Kneschke 35e134da0SJan Kneschke #include <sys/types.h> 45e134da0SJan Kneschke #include <sys/stat.h> 55e134da0SJan Kneschke 65e134da0SJan Kneschke #include <stdlib.h> 75e134da0SJan Kneschke #include <string.h> 85e134da0SJan Kneschke #include <errno.h> 95e134da0SJan Kneschke #include <unistd.h> 105e134da0SJan Kneschke #include <stdio.h> 115e134da0SJan Kneschke #include <fcntl.h> 125e134da0SJan Kneschke 135e134da0SJan Kneschke #include "log.h" 145e134da0SJan Kneschke #include "stat_cache.h" 155e134da0SJan Kneschke #include "fdevent.h" 165e134da0SJan Kneschke #include "etag.h" 175e134da0SJan Kneschke 185e134da0SJan Kneschke #ifdef HAVE_ATTR_ATTRIBUTES_H 195e134da0SJan Kneschke #include <attr/attributes.h> 205e134da0SJan Kneschke #endif 215e134da0SJan Kneschke 225e134da0SJan Kneschke #ifdef HAVE_FAM_H 235e134da0SJan Kneschke # include <fam.h> 245e134da0SJan Kneschke #endif 255e134da0SJan Kneschke 265e134da0SJan Kneschke #include "sys-mmap.h" 275e134da0SJan Kneschke 285e134da0SJan Kneschke /* NetBSD 1.3.x needs it */ 295e134da0SJan Kneschke #ifndef MAP_FAILED 305e134da0SJan Kneschke # define MAP_FAILED -1 315e134da0SJan Kneschke #endif 325e134da0SJan Kneschke 335e134da0SJan Kneschke #ifndef O_LARGEFILE 345e134da0SJan Kneschke # define O_LARGEFILE 0 355e134da0SJan Kneschke #endif 365e134da0SJan Kneschke 375e134da0SJan Kneschke #ifndef HAVE_LSTAT 385e134da0SJan Kneschke #define lstat stat 395e134da0SJan Kneschke #endif 405e134da0SJan Kneschke 415e134da0SJan Kneschke /* 425e134da0SJan Kneschke * stat-cache 435e134da0SJan Kneschke * 445e134da0SJan Kneschke * we cache the stat() calls in our own storage 455e134da0SJan Kneschke * the directories are cached in FAM 465e134da0SJan Kneschke * 475e134da0SJan Kneschke * if we get a change-event from FAM, we increment the version in the FAM->dir mapping 485e134da0SJan Kneschke * 495e134da0SJan Kneschke * if the stat()-cache is queried we check if the version id for the directory is the 505e134da0SJan Kneschke * same and return immediatly. 515e134da0SJan Kneschke * 525e134da0SJan Kneschke * 535e134da0SJan Kneschke * What we need: 545e134da0SJan Kneschke * 555e134da0SJan Kneschke * - for each stat-cache entry we need a fast indirect lookup on the directory name 565e134da0SJan Kneschke * - for each FAMRequest we have to find the version in the directory cache (index as userdata) 575e134da0SJan Kneschke * 585e134da0SJan Kneschke * stat <<-> directory <-> FAMRequest 595e134da0SJan Kneschke * 605e134da0SJan Kneschke * if file is deleted, directory is dirty, file is rechecked ... 615e134da0SJan Kneschke * if directory is deleted, directory mapping is removed 625e134da0SJan Kneschke * 635e134da0SJan Kneschke * */ 645e134da0SJan Kneschke 655e134da0SJan Kneschke #ifdef HAVE_FAM_H 665e134da0SJan Kneschke typedef struct { 675e134da0SJan Kneschke FAMRequest *req; 685e134da0SJan Kneschke FAMConnection *fc; 695e134da0SJan Kneschke 705e134da0SJan Kneschke buffer *name; 715e134da0SJan Kneschke 725e134da0SJan Kneschke int version; 735e134da0SJan Kneschke } fam_dir_entry; 745e134da0SJan Kneschke #endif 755e134da0SJan Kneschke 765e134da0SJan Kneschke /* the directory name is too long to always compare on it 775e134da0SJan Kneschke * - we need a hash 785e134da0SJan Kneschke * - the hash-key is used as sorting criteria for a tree 795e134da0SJan Kneschke * - a splay-tree is used as we can use the caching effect of it 805e134da0SJan Kneschke */ 815e134da0SJan Kneschke 825e134da0SJan Kneschke /* we want to cleanup the stat-cache every few seconds, let's say 10 835e134da0SJan Kneschke * 845e134da0SJan Kneschke * - remove entries which are outdated since 30s 855e134da0SJan Kneschke * - remove entries which are fresh but havn't been used since 60s 865e134da0SJan Kneschke * - if we don't have a stat-cache entry for a directory, release it from the monitor 875e134da0SJan Kneschke */ 885e134da0SJan Kneschke 895e134da0SJan Kneschke stat_cache *stat_cache_init(void) { 905e134da0SJan Kneschke stat_cache *fc = NULL; 915e134da0SJan Kneschke 925e134da0SJan Kneschke fc = calloc(1, sizeof(*fc)); 935e134da0SJan Kneschke 945e134da0SJan Kneschke fc->dir_name = buffer_init(); 955e134da0SJan Kneschke #ifdef HAVE_FAM_H 965e134da0SJan Kneschke fc->fam = calloc(1, sizeof(*fc->fam)); 975e134da0SJan Kneschke 985e134da0SJan Kneschke if (0 != FAMOpen2(fc->fam, "lighttpd")) { 995e134da0SJan Kneschke return NULL; 1005e134da0SJan Kneschke } 1015e134da0SJan Kneschke 1025e134da0SJan Kneschke FAMNoExists(fc->fam); 1035e134da0SJan Kneschke #endif 1045e134da0SJan Kneschke 1055e134da0SJan Kneschke return fc; 1065e134da0SJan Kneschke } 1075e134da0SJan Kneschke 1085e134da0SJan Kneschke static stat_cache_entry * stat_cache_entry_init(void) { 1095e134da0SJan Kneschke stat_cache_entry *sce = NULL; 1105e134da0SJan Kneschke 1115e134da0SJan Kneschke sce = calloc(1, sizeof(*sce)); 1125e134da0SJan Kneschke 1135e134da0SJan Kneschke sce->name = buffer_init(); 1145e134da0SJan Kneschke sce->etag = buffer_init(); 1155e134da0SJan Kneschke sce->content_type = buffer_init(); 1165e134da0SJan Kneschke 1175e134da0SJan Kneschke return sce; 1185e134da0SJan Kneschke } 1195e134da0SJan Kneschke 1205e134da0SJan Kneschke static void stat_cache_entry_free(void *data) { 1215e134da0SJan Kneschke stat_cache_entry *sce = data; 1225e134da0SJan Kneschke if (!sce) return; 1235e134da0SJan Kneschke 1245e134da0SJan Kneschke buffer_free(sce->etag); 1255e134da0SJan Kneschke buffer_free(sce->name); 1265e134da0SJan Kneschke buffer_free(sce->content_type); 1275e134da0SJan Kneschke 1285e134da0SJan Kneschke free(sce); 1295e134da0SJan Kneschke } 1305e134da0SJan Kneschke 1315e134da0SJan Kneschke static void splaytree_delete_tree(splay_tree *t, void (*data_free)(void *)) { 1325e134da0SJan Kneschke if (!t) return; 1335e134da0SJan Kneschke 1345e134da0SJan Kneschke splaytree_delete_tree(t->left, data_free); 1355e134da0SJan Kneschke splaytree_delete_tree(t->right, data_free); 1365e134da0SJan Kneschke 1375e134da0SJan Kneschke if (data_free) { 1385e134da0SJan Kneschke data_free(t->data); 1395e134da0SJan Kneschke } 1405e134da0SJan Kneschke 1415e134da0SJan Kneschke free(t); 1425e134da0SJan Kneschke } 1435e134da0SJan Kneschke 1445e134da0SJan Kneschke #ifdef HAVE_FAM_H 1455e134da0SJan Kneschke static fam_dir_entry * fam_dir_entry_init(void) { 1465e134da0SJan Kneschke fam_dir_entry *fam_dir = NULL; 1475e134da0SJan Kneschke 1485e134da0SJan Kneschke fam_dir = calloc(1, sizeof(*fam_dir)); 1495e134da0SJan Kneschke 1505e134da0SJan Kneschke fam_dir->name = buffer_init(); 1515e134da0SJan Kneschke 1525e134da0SJan Kneschke return fam_dir; 1535e134da0SJan Kneschke } 1545e134da0SJan Kneschke 1555e134da0SJan Kneschke static void fam_dir_entry_free(void *data) { 1565e134da0SJan Kneschke fam_dir_entry *fam_dir = data; 1575e134da0SJan Kneschke 1585e134da0SJan Kneschke if (!fam_dir) return; 1595e134da0SJan Kneschke 1605e134da0SJan Kneschke FAMCancelMonitor(fam_dir->fc, fam_dir->req); 1615e134da0SJan Kneschke 1625e134da0SJan Kneschke buffer_free(fam_dir->name); 1635e134da0SJan Kneschke free(fam_dir->req); 1645e134da0SJan Kneschke 1655e134da0SJan Kneschke free(fam_dir); 1665e134da0SJan Kneschke } 1675e134da0SJan Kneschke #endif 1685e134da0SJan Kneschke 1695e134da0SJan Kneschke void stat_cache_free(stat_cache *fc) { 1705e134da0SJan Kneschke splaytree_delete_tree(fc->files, stat_cache_entry_free); 1715e134da0SJan Kneschke 1725e134da0SJan Kneschke buffer_free(fc->dir_name); 1735e134da0SJan Kneschke 1745e134da0SJan Kneschke #ifdef HAVE_FAM_H 1755e134da0SJan Kneschke splaytree_delete_tree(fc->dirs, fam_dir_entry_free); 1765e134da0SJan Kneschke 1775e134da0SJan Kneschke FAMClose(fc->fam); 1785e134da0SJan Kneschke free(fc->fam); 1795e134da0SJan Kneschke #endif 1805e134da0SJan Kneschke free(fc); 1815e134da0SJan Kneschke } 1825e134da0SJan Kneschke 1835e134da0SJan Kneschke #ifdef HAVE_XATTR 184*30b19732SJan Kneschke static int stat_cache_attr_get(buffer *buf, char *name) { 1855e134da0SJan Kneschke int attrlen; 1865e134da0SJan Kneschke int ret; 1875e134da0SJan Kneschke 1885e134da0SJan Kneschke attrlen = 1024; 1895e134da0SJan Kneschke buffer_prepare_copy(buf, attrlen); 1905e134da0SJan Kneschke attrlen--; 1915e134da0SJan Kneschke if(0 == (ret = attr_get(name, "Content-Type", buf->ptr, &attrlen, 0))) { 1925e134da0SJan Kneschke buf->used = attrlen + 1; 1935e134da0SJan Kneschke buf->ptr[attrlen] = '\0'; 1945e134da0SJan Kneschke } 1955e134da0SJan Kneschke return ret; 1965e134da0SJan Kneschke } 1975e134da0SJan Kneschke #endif 1985e134da0SJan Kneschke 1995e134da0SJan Kneschke static int hashme(buffer *str) { 2005e134da0SJan Kneschke int hash = 0; 2015e134da0SJan Kneschke const char *s; 2025e134da0SJan Kneschke for (s = str->ptr; *s; s++) { 2035e134da0SJan Kneschke hash = hash * 53 + *s; 2045e134da0SJan Kneschke } 2055e134da0SJan Kneschke 2065e134da0SJan Kneschke return hash; 2075e134da0SJan Kneschke } 2085e134da0SJan Kneschke 2095e134da0SJan Kneschke #ifdef HAVE_FAM_H 2105e134da0SJan Kneschke handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) { 2115e134da0SJan Kneschke size_t i; 2125e134da0SJan Kneschke server *srv = _srv; 2135e134da0SJan Kneschke stat_cache *sc = srv->stat_cache; 2145e134da0SJan Kneschke size_t events; 2155e134da0SJan Kneschke 2165e134da0SJan Kneschke 2175e134da0SJan Kneschke UNUSED(revent); 2185e134da0SJan Kneschke /* */ 2195e134da0SJan Kneschke 2205e134da0SJan Kneschke events = FAMPending(sc->fam); 2215e134da0SJan Kneschke 2225e134da0SJan Kneschke for (i = 0; i < events; i++) { 2235e134da0SJan Kneschke FAMEvent fe; 2245e134da0SJan Kneschke fam_dir_entry *fam_dir; 2255e134da0SJan Kneschke splay_tree *node; 2265e134da0SJan Kneschke int ndx; 2275e134da0SJan Kneschke 2285e134da0SJan Kneschke FAMNextEvent(sc->fam, &fe); 2295e134da0SJan Kneschke 2305e134da0SJan Kneschke /* handle event */ 2315e134da0SJan Kneschke 2325e134da0SJan Kneschke switch(fe.code) { 2335e134da0SJan Kneschke case FAMChanged: 2345e134da0SJan Kneschke case FAMDeleted: 2355e134da0SJan Kneschke case FAMMoved: 2365e134da0SJan Kneschke /* if the filename is a directory remove the entry */ 2375e134da0SJan Kneschke 2385e134da0SJan Kneschke fam_dir = fe.userdata; 2395e134da0SJan Kneschke fam_dir->version++; 2405e134da0SJan Kneschke 2415e134da0SJan Kneschke /* file/dir is still here */ 2425e134da0SJan Kneschke if (fe.code == FAMChanged) break; 2435e134da0SJan Kneschke 2445e134da0SJan Kneschke buffer_copy_string(sc->dir_name, fe.filename); 2455e134da0SJan Kneschke 2465e134da0SJan Kneschke ndx = hashme(sc->dir_name); 2475e134da0SJan Kneschke 2485e134da0SJan Kneschke sc->dirs = splaytree_splay(sc->dirs, ndx); 2495e134da0SJan Kneschke node = sc->dirs; 2505e134da0SJan Kneschke 2515e134da0SJan Kneschke if (node && (node->key == ndx)) { 2525e134da0SJan Kneschke fam_dir_entry_free(node->data); 2535e134da0SJan Kneschke sc->dirs = splaytree_delete(sc->dirs, ndx); 2545e134da0SJan Kneschke } 2555e134da0SJan Kneschke break; 2565e134da0SJan Kneschke default: 2575e134da0SJan Kneschke break; 2585e134da0SJan Kneschke } 2595e134da0SJan Kneschke } 2605e134da0SJan Kneschke 2615e134da0SJan Kneschke return HANDLER_GO_ON; 2625e134da0SJan Kneschke } 2635e134da0SJan Kneschke 2645e134da0SJan Kneschke static int buffer_copy_dirname(buffer *dst, buffer *file) { 2655e134da0SJan Kneschke size_t i; 2665e134da0SJan Kneschke 2675e134da0SJan Kneschke if (buffer_is_empty(file)) return -1; 2685e134da0SJan Kneschke 2695e134da0SJan Kneschke for (i = file->used - 1; i+1 > 0; i--) { 2705e134da0SJan Kneschke if (file->ptr[i] == '/') { 2715e134da0SJan Kneschke buffer_copy_string_len(dst, file->ptr, i); 2725e134da0SJan Kneschke return 0; 2735e134da0SJan Kneschke } 2745e134da0SJan Kneschke } 2755e134da0SJan Kneschke 2765e134da0SJan Kneschke return -1; 2775e134da0SJan Kneschke } 2785e134da0SJan Kneschke #endif 2795e134da0SJan Kneschke 2805e134da0SJan Kneschke /*** 2815e134da0SJan Kneschke * 2825e134da0SJan Kneschke * 2835e134da0SJan Kneschke * 2845e134da0SJan Kneschke * returns: 2855e134da0SJan Kneschke * - HANDLER_FINISHED on cache-miss (don't forget to reopen the file) 2865e134da0SJan Kneschke * - HANDLER_ERROR on stat() failed -> see errno for problem 2875e134da0SJan Kneschke */ 2885e134da0SJan Kneschke 2895e134da0SJan Kneschke handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **ret_sce) { 2905e134da0SJan Kneschke #ifdef HAVE_FAM_H 2915e134da0SJan Kneschke fam_dir_entry *fam_dir = NULL; 2925e134da0SJan Kneschke int dir_ndx = -1; 2935e134da0SJan Kneschke splay_tree *dir_node = NULL; 2945e134da0SJan Kneschke #endif 2955e134da0SJan Kneschke stat_cache_entry *sce = NULL; 2965e134da0SJan Kneschke stat_cache *sc; 2975e134da0SJan Kneschke struct stat st; 2985e134da0SJan Kneschke 2995e134da0SJan Kneschke int file_ndx; 3005e134da0SJan Kneschke splay_tree *file_node = NULL; 3015e134da0SJan Kneschke 3025e134da0SJan Kneschke *ret_sce = NULL; 3035e134da0SJan Kneschke 3045e134da0SJan Kneschke /* 3055e134da0SJan Kneschke * check if the directory for this file has changed 3065e134da0SJan Kneschke */ 3075e134da0SJan Kneschke 3085e134da0SJan Kneschke sc = srv->stat_cache; 3095e134da0SJan Kneschke 3105e134da0SJan Kneschke file_ndx = hashme(name); 3115e134da0SJan Kneschke sc->files = splaytree_splay(sc->files, file_ndx); 3125e134da0SJan Kneschke 3135e134da0SJan Kneschke if (sc->files && (sc->files->key == file_ndx)) { 3145e134da0SJan Kneschke /* we have seen this file already and 3155e134da0SJan Kneschke * don't stat() it again in the same second */ 3165e134da0SJan Kneschke 3175e134da0SJan Kneschke file_node = sc->files; 3185e134da0SJan Kneschke 3195e134da0SJan Kneschke sce = file_node->data; 3205e134da0SJan Kneschke 3215e134da0SJan Kneschke if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) { 3225e134da0SJan Kneschke if (sce->stat_ts == srv->cur_ts) { 3235e134da0SJan Kneschke *ret_sce = sce; 3245e134da0SJan Kneschke return HANDLER_GO_ON; 3255e134da0SJan Kneschke } 3265e134da0SJan Kneschke } 3275e134da0SJan Kneschke } 3285e134da0SJan Kneschke 3295e134da0SJan Kneschke #ifdef HAVE_FAM_H 3305e134da0SJan Kneschke /* dir-check */ 3315e134da0SJan Kneschke if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { 3325e134da0SJan Kneschke if (0 != buffer_copy_dirname(sc->dir_name, name)) { 3335e134da0SJan Kneschke SEGFAULT(); 3345e134da0SJan Kneschke } 3355e134da0SJan Kneschke 3365e134da0SJan Kneschke dir_ndx = hashme(sc->dir_name); 3375e134da0SJan Kneschke 3385e134da0SJan Kneschke sc->dirs = splaytree_splay(sc->dirs, dir_ndx); 3395e134da0SJan Kneschke 3405e134da0SJan Kneschke if (sc->dirs && (sc->dirs->key == dir_ndx)) { 3415e134da0SJan Kneschke dir_node = sc->dirs; 3425e134da0SJan Kneschke } 3435e134da0SJan Kneschke 3445e134da0SJan Kneschke if (dir_node && file_node) { 3455e134da0SJan Kneschke /* we found a file */ 3465e134da0SJan Kneschke 3475e134da0SJan Kneschke sce = file_node->data; 3485e134da0SJan Kneschke fam_dir = dir_node->data; 3495e134da0SJan Kneschke 3505e134da0SJan Kneschke if (fam_dir->version == sce->dir_version) { 3515e134da0SJan Kneschke /* the stat()-cache entry is still ok */ 3525e134da0SJan Kneschke 3535e134da0SJan Kneschke *ret_sce = sce; 3545e134da0SJan Kneschke return HANDLER_GO_ON; 3555e134da0SJan Kneschke } 3565e134da0SJan Kneschke } 3575e134da0SJan Kneschke } 3585e134da0SJan Kneschke #endif 3595e134da0SJan Kneschke if (-1 == (con->conf.follow_symlink ? stat(name->ptr, &st) : lstat(name->ptr, &st))) { 3605e134da0SJan Kneschke /* stat() failed, ENOENT, ... and so on */ 3615e134da0SJan Kneschke return HANDLER_ERROR; 3625e134da0SJan Kneschke } 3635e134da0SJan Kneschke 3645e134da0SJan Kneschke if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) { 3655e134da0SJan Kneschke size_t k; 3665e134da0SJan Kneschke 3675e134da0SJan Kneschke if (NULL == sce) { 3685e134da0SJan Kneschke sce = stat_cache_entry_init(); 3695e134da0SJan Kneschke buffer_copy_string_buffer(sce->name, name); 3705e134da0SJan Kneschke 3715e134da0SJan Kneschke sc->files = splaytree_insert(sc->files, file_ndx, sce); 3725e134da0SJan Kneschke } 3735e134da0SJan Kneschke 3745e134da0SJan Kneschke sce->st = st; 3755e134da0SJan Kneschke sce->stat_ts = srv->cur_ts; 3765e134da0SJan Kneschke 3775e134da0SJan Kneschke if (S_ISREG(st.st_mode)) { 3785e134da0SJan Kneschke /* determine mimetype */ 3795e134da0SJan Kneschke buffer_reset(sce->content_type); 3805e134da0SJan Kneschke 3815e134da0SJan Kneschke for (k = 0; k < con->conf.mimetypes->used; k++) { 3825e134da0SJan Kneschke data_string *ds = (data_string *)con->conf.mimetypes->data[k]; 3835e134da0SJan Kneschke 3845e134da0SJan Kneschke if (ds->key->used == 0) continue; 3855e134da0SJan Kneschke 3865e134da0SJan Kneschke if (buffer_is_equal_right_len(name, ds->key, ds->key->used - 1)) { 3875e134da0SJan Kneschke buffer_copy_string_buffer(sce->content_type, ds->value); 3885e134da0SJan Kneschke break; 3895e134da0SJan Kneschke } 3905e134da0SJan Kneschke } 3915e134da0SJan Kneschke etag_create(sce->etag, &(sce->st)); 3925e134da0SJan Kneschke #ifdef HAVE_XATTR 3935e134da0SJan Kneschke if (buffer_is_empty(sce->content_type)) { 3945e134da0SJan Kneschke stat_cache_attr_get(sce->content_type, name->ptr); 3955e134da0SJan Kneschke } 3965e134da0SJan Kneschke #endif 3975e134da0SJan Kneschke } 3985e134da0SJan Kneschke 3995e134da0SJan Kneschke #ifdef HAVE_FAM_H 4005e134da0SJan Kneschke if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { 4015e134da0SJan Kneschke /* is this directory already registered ? */ 4025e134da0SJan Kneschke if (!dir_node) { 4035e134da0SJan Kneschke fam_dir = fam_dir_entry_init(); 4045e134da0SJan Kneschke fam_dir->fc = sc->fam; 4055e134da0SJan Kneschke 4065e134da0SJan Kneschke buffer_copy_string_buffer(fam_dir->name, sc->dir_name); 4075e134da0SJan Kneschke 4085e134da0SJan Kneschke fam_dir->version = 1; 4095e134da0SJan Kneschke 4105e134da0SJan Kneschke fam_dir->req = calloc(1, sizeof(FAMRequest)); 4115e134da0SJan Kneschke 4125e134da0SJan Kneschke if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, 4135e134da0SJan Kneschke fam_dir->req, fam_dir)) { 4145e134da0SJan Kneschke 4155e134da0SJan Kneschke log_error_write(srv, __FILE__, __LINE__, "sbs", 4165e134da0SJan Kneschke "monitoring dir failed:", 4175e134da0SJan Kneschke fam_dir->name, 4185e134da0SJan Kneschke FamErrlist[FAMErrno]); 4195e134da0SJan Kneschke 4205e134da0SJan Kneschke fam_dir_entry_free(fam_dir); 4215e134da0SJan Kneschke } else { 4225e134da0SJan Kneschke sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); 4235e134da0SJan Kneschke } 4245e134da0SJan Kneschke } else { 4255e134da0SJan Kneschke fam_dir = dir_node->data; 4265e134da0SJan Kneschke } 4275e134da0SJan Kneschke 4285e134da0SJan Kneschke /* bind the fam_fc to the stat() cache entry */ 4295e134da0SJan Kneschke 4305e134da0SJan Kneschke if (fam_dir) { 4315e134da0SJan Kneschke sce->dir_version = fam_dir->version; 4325e134da0SJan Kneschke sce->dir_ndx = dir_ndx; 4335e134da0SJan Kneschke } 4345e134da0SJan Kneschke } 4355e134da0SJan Kneschke #endif 4365e134da0SJan Kneschke } 4375e134da0SJan Kneschke *ret_sce = sce; 4385e134da0SJan Kneschke 4395e134da0SJan Kneschke return HANDLER_GO_ON; 4405e134da0SJan Kneschke } 4415e134da0SJan Kneschke 4425e134da0SJan Kneschke /** 4435e134da0SJan Kneschke * remove stat() from cache which havn't been stat()ed for 4445e134da0SJan Kneschke * more than 10 seconds 4455e134da0SJan Kneschke * 4465e134da0SJan Kneschke * 4475e134da0SJan Kneschke * walk though the stat-cache, collect the ids which are too old 4485e134da0SJan Kneschke * and remove them in a second loop 4495e134da0SJan Kneschke */ 4505e134da0SJan Kneschke 4515e134da0SJan Kneschke static int stat_cache_tag_old_entries(server *srv, splay_tree *t, int *keys, size_t *ndx) { 4525e134da0SJan Kneschke stat_cache_entry *sce; 4535e134da0SJan Kneschke 4545e134da0SJan Kneschke if (!t) return 0; 4555e134da0SJan Kneschke 4565e134da0SJan Kneschke stat_cache_tag_old_entries(srv, t->left, keys, ndx); 4575e134da0SJan Kneschke stat_cache_tag_old_entries(srv, t->right, keys, ndx); 4585e134da0SJan Kneschke 4595e134da0SJan Kneschke sce = t->data; 4605e134da0SJan Kneschke 4615e134da0SJan Kneschke if (srv->cur_ts - sce->stat_ts > 10) { 4625e134da0SJan Kneschke keys[(*ndx)++] = t->key; 4635e134da0SJan Kneschke } 4645e134da0SJan Kneschke 4655e134da0SJan Kneschke return 0; 4665e134da0SJan Kneschke } 4675e134da0SJan Kneschke 4685e134da0SJan Kneschke int stat_cache_trigger_cleanup(server *srv) { 4695e134da0SJan Kneschke stat_cache *sc; 4705e134da0SJan Kneschke size_t max_ndx = 0, i; 4715e134da0SJan Kneschke int *keys; 4725e134da0SJan Kneschke 4735e134da0SJan Kneschke sc = srv->stat_cache; 4745e134da0SJan Kneschke 4755e134da0SJan Kneschke if (!sc->files) return 0; 4765e134da0SJan Kneschke 4775e134da0SJan Kneschke keys = calloc(1, sizeof(size_t) * sc->files->size); 4785e134da0SJan Kneschke 4795e134da0SJan Kneschke stat_cache_tag_old_entries(srv, sc->files, keys, &max_ndx); 4805e134da0SJan Kneschke 4815e134da0SJan Kneschke for (i = 0; i < max_ndx; i++) { 4825e134da0SJan Kneschke int ndx = keys[i]; 4835e134da0SJan Kneschke splay_tree *node; 4845e134da0SJan Kneschke 4855e134da0SJan Kneschke sc->files = splaytree_splay(sc->files, ndx); 4865e134da0SJan Kneschke 4875e134da0SJan Kneschke node = sc->files; 4885e134da0SJan Kneschke 4895e134da0SJan Kneschke if (node && (node->key == ndx)) { 4905e134da0SJan Kneschke stat_cache_entry_free(node->data); 4915e134da0SJan Kneschke sc->files = splaytree_delete(sc->files, ndx); 4925e134da0SJan Kneschke } 4935e134da0SJan Kneschke } 4945e134da0SJan Kneschke 4955e134da0SJan Kneschke free(keys); 4965e134da0SJan Kneschke 4975e134da0SJan Kneschke return 0; 4985e134da0SJan Kneschke } 499