]> arthur.barton.de Git - netatalk.git/commitdiff
dircache: support locking of dirs which prevent cache removal.
authorfranklahm <franklahm>
Fri, 5 Feb 2010 10:27:58 +0000 (10:27 +0000)
committerfranklahm <franklahm>
Fri, 5 Feb 2010 10:27:58 +0000 (10:27 +0000)
etc/afpd/afp_options.c
etc/afpd/catsearch.c
etc/afpd/dircache.c
etc/afpd/dircache.h
etc/afpd/directory.c
etc/afpd/directory.h

index 8930422689bd87cc45b47d376b10cd9dd633444c..f23c370b3319842ea7f00b03464d29500583abb3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_options.c,v 1.51.4.1 2010-02-04 14:34:31 franklahm Exp $
+ * $Id: afp_options.c,v 1.51.4.2 2010-02-05 10:27:58 franklahm Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -49,6 +49,7 @@ char *strchr (), *strrchr ();
 #include "globals.h"
 #include "status.h"
 #include "auth.h"
+#include "dircache.h"
 
 #include <atalk/compat.h>
 
@@ -195,7 +196,7 @@ void afp_options_init(struct afp_options *options)
     /* don't advertize slp by default */
     options->flags |= OPTION_NOSLP;
 #endif
-    options->dircachesize = 8192;
+    options->dircachesize = DEFAULT_MAX_DIRCACHE_SIZE;
 }
 
 /* parse an afpd.conf line. i'm doing it this way because it's
index d85f25cbf995ea377c1f41a1ec92498173bbe2fb..4a1d229f59e13c1036d9b5d974edb8a58ab249af 100644 (file)
@@ -49,6 +49,8 @@
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 #endif /* CNID_DB */
+#include <atalk/bstradd.h>
+
 #include "desktop.h"
 #include "directory.h"
 #include "dircache.h"
@@ -145,6 +147,7 @@ static int addstack(char *uname, struct dir *dir, int pidx)
        /* Put new element. Allocate and copy lname and path. */
        ds = dstack + dsidx++;
        ds->dir = dir;
+    dir->d_flags |= DIRF_CACHELOCK;
        ds->pidx = pidx;
        ds->checked = 0;
        if (pidx >= 0) {
@@ -177,6 +180,7 @@ static int reducestack(void)
        while (dsidx > 0) {
                if (dstack[dsidx-1].checked) {
                        dsidx--;
+            dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
                        free(dstack[dsidx].path);
                } else
                        return dsidx - 1;
@@ -190,6 +194,7 @@ static void clearstack(void)
        save_cidx = -1;
        while (dsidx > 0) {
                dsidx--;
+        dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
                free(dstack[dsidx].path);
        }
 } 
@@ -500,7 +505,6 @@ static int catsearch(struct vol *vol, struct dir *dir,
        char *rrbuf = rbuf;
     time_t start_time;
     int num_rounds = NUM_ROUNDS;
-    int cached;
     int cwd = -1;
         
        if (*pos != 0 && *pos != cur_pos) {
@@ -535,11 +539,8 @@ static int catsearch(struct vol *vol, struct dir *dir,
     }
        
        while ((cidx = reducestack()) != -1) {
-               cached = 1;
                if (dirpos == NULL) {
                        dirpos = opendir(dstack[cidx].path);
-// FIXME dircache rewrite
-//                     cached = (dstack[cidx].dir->d_child != NULL);
                }
                if (dirpos == NULL) {
                        switch (errno) {
@@ -558,8 +559,11 @@ static int catsearch(struct vol *vol, struct dir *dir,
                        } /* switch (errno) */
                        goto catsearch_end;
                }
-               /* FIXME error in chdir, what do we do? */
-               chdir(dstack[cidx].path);
+
+               if (chdir(dstack[cidx].path) != 0) {
+                               result = AFPERR_NFILE;
+                goto catsearch_end;
+        }
                
 
                while ((entry=readdir(dirpos)) != NULL) {
@@ -591,18 +595,15 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                   ALL dirsearch_byname will fail.
                                */
                 int unlen = strlen(path.u_name);
-                               if (cached)
-                       path.d_dir = dircache_search_by_name(vol, dstack[cidx].dir, path.u_name, unlen);
-               else
-                       path.d_dir = NULL;
-               if (!path.d_dir) {
+                path.d_dir = dircache_search_by_name(vol, dstack[cidx].dir, path.u_name, unlen);
+               if (path.d_dir == NULL) {
                        /* path.m_name is set by adddir */
                    if (NULL == (path.d_dir = dir_add( vol, dstack[cidx].dir, &path, unlen) ) ) {
                                                result = AFPERR_MISC;
                                                goto catsearch_end;
                                        }
                 }
-                path.m_name = (char *)path.d_dir->d_m_name->data;
+                path.m_name = cfrombstring(path.d_dir->d_m_name);
                        
                                if (addstack(path.u_name, path.d_dir, cidx) == -1) {
                                        result = AFPERR_MISC;
index 7059f6284363210d2e3e8ec69cc5b3998fd3eec9..43c7c90a7efe2591757ea641d0f06acc29a36e6a 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  $Id: dircache.c,v 1.1.2.3 2010-02-04 14:34:31 franklahm Exp $
+  $Id: dircache.c,v 1.1.2.4 2010-02-05 10:27:58 franklahm Exp $
   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -47,6 +47,8 @@
  * We have/need two indexes:
  * - a DID/name index on the main dircache, another hashtable
  * - a queue index on the dircache, for evicting the oldest entries
+ * The cache supports locking of struct dir elements through the DIRF_CACHELOCK flag. A dir
+ * locked this way wont ever be removed from the cache, so be careful.
  */
 
 /********************************************************
 /*****************************
  *       THE dircache        */
 
-/* Maximum size of the dircache hashtable */
-#define DEFAULT_MAX_DIRCACHE_SIZE 8192 /* FIXME: make it a afpd.conf option */
-#define MAX_POSSIBLE_DIRCACHE_SIZE 131072
-
 static hash_t       *dircache;        /* The actual cache */
 static unsigned int dircache_maxsize; /* cache maximum size */
 
@@ -179,7 +177,8 @@ static const int dircache_free_quantum = 256; /* number of entries to free */
  *
  * The default is to remove the 256 oldest entries from the cache.
  * 1. Get the oldest entry
- * 2. If it's in use ie open forks reference it or it's curdir requeue it, dont remove it
+ * 2. If it's in use ie open forks reference it or it's curdir requeue it,
+ *    or it's locked (from catsearch) dont remove it
  * 3. Remove the dir from the main cache and the didname index
  * 4. Free the struct dir structure and all its members
  */
@@ -197,7 +196,9 @@ static void dircache_evict(void)
         }
         queue_count--;
 
-        if (curdir == dir || dir->d_ofork) {     /* 2 */
+        if (curdir == dir
+            || dir->d_ofork
+            || (dir->d_flags & DIRF_CACHELOCK)) {     /* 2 */
             if ((dir->qidx_node = enqueue(index_queue, dir)) == NULL) {
                 dircache_dump();
                 exit(EXITERR_SYS);
@@ -360,6 +361,9 @@ void dircache_remove(const struct vol *vol _U_, struct dir *dir, int flags)
     assert(dir);
     assert((flags & ~(QUEUE_INDEX | DIDNAME_INDEX | DIRCACHE)) == 0);
 
+    if (dir->d_flags & DIRF_CACHELOCK)
+        return;
+
     if (flags & QUEUE_INDEX) {
         /* remove it from the queue index */
         dequeue(dir->qidx_node->prev); /* this effectively deletes the dequeued node */
@@ -440,11 +444,7 @@ int dircache_init(int reqsize)
 }
 
 /*!
-
-   FIXME: TO DO !!!
-
  * @brief Dump dircache to /tmp/dircache.PID
-
  */
 void dircache_dump(void)
 {
@@ -470,8 +470,9 @@ void dircache_dump(void)
         if (n == index_queue)
             break;
         dir = (struct dir *)n->data;
-        fprintf(dump, "%05u: vid:%u, pdid:%u, did:%u, path:%s\n",
-                i, ntohs(dir->d_vid), ntohl(dir->d_pdid), ntohl(dir->d_did), cfrombstring(dir->d_fullpath));
+        fprintf(dump, "%05u: vid:%u, pdid:%6u, did:%6u, path:%s, locked:%s\n",
+                i, ntohs(dir->d_vid), ntohl(dir->d_pdid), ntohl(dir->d_did), cfrombstring(dir->d_fullpath),
+                (dir->d_flags & DIRF_CACHELOCK) ? "yes" : "no");
         n = n->next;
     }
 
index 2a99c2a203b00c6c5ac0a8214fb7ec5ed4aa9426..70e8f8d50131faacb1e7fa78c650c4860890456c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   $Id: dircache.h,v 1.1.2.2 2010-02-04 14:34:31 franklahm Exp $
+   $Id: dircache.h,v 1.1.2.3 2010-02-05 10:27:58 franklahm Exp $
    Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
 #include <atalk/volume.h>
 #include <atalk/directory.h>
 
+/* Maximum size of the dircache hashtable */
+#define DEFAULT_MAX_DIRCACHE_SIZE 8192
+#define MAX_POSSIBLE_DIRCACHE_SIZE 131072
+
 /* flags for dircache_remove */
 #define DIRCACHE      (1 << 0)
 #define DIDNAME_INDEX (1 << 1)
index 43ef8a9196e01e5ec8fe12e44d1a732717fa168b..29cc3f1b39e59c911721657eeae802f0f6e4d766 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.131.2.9 2010-02-04 14:34:31 franklahm Exp $
+ * $Id: directory.c,v 1.131.2.10 2010-02-05 10:27:58 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -49,11 +49,8 @@ extern void addir_inherit_acl(const struct vol *vol);
 
 /*
  * FIXMEs, loose ends after the dircache rewrite:
- * o dircache aging, place dirlookup'ed dirs on front of queue ??
  * o merge dircache_search_by_name and dir_add ??
  * o case-insensitivity is gone from cname
- * o catsearch doesn't work, see FIXMEs in catsearch.c
- * o curdir per volume caching is gone
  * o directory offspring count calculation probably broken
  * o doesn't work with CNID backend last and the like,
  *   CNID backend must support persistent CNIDs.
@@ -341,23 +338,25 @@ static int cname_mtouname(const struct vol *vol, const struct dir *dir, struct p
  *
  * The final movecwd in cname failed, possibly with EPERM or ENOENT. We:
  * 1. move cwd into parent dir (we're often already there, but not always)
+ * 2. set struct path to the dirname
+ * 3. in case of
+ *    AFPERR_ACCESS: the dir is there, we just cant chdir into it
+ *    AFPERR_NOOBJ: the dir was there when we stated it in cname, so we have a race
+ *                  4. indicate there's no dir for this path
+ *                  5. remove the dir
  */
 static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path *ret)
 {
-    /*
-     * it's tricky: movecwd failed some of dir path are not there anymore.
-     * FIXME: Is it true with other errors?
-     */
     if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
         return NULL;
 
     switch (afp_errno) {
 
     case AFPERR_ACCESS:
-        if (movecwd( vol, dirlookup(vol, dir->d_pdid)) < 0 )
+        if (movecwd( vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */
             return NULL;
 
-        memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1);
+        memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1); /* 3 */
         if (dir->d_m_name == dir->d_u_name) {
             ret->u_name = ret->m_name;
         } else {
@@ -366,12 +365,8 @@ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path
         }
 
         ret->d_dir = dir;
-#if 0
-        ret->st_valid = 1;
-        ret->st_errno = EACCES;
-#endif
 
-        LOG(log_debug, logtype_afpd, "cname(AFPERR_ACCESS:'%s') {path-from-dir: curdir:'%s', path:'%s'}",
+        LOG(log_debug, logtype_afpd, "cname('%s') {path-from-dir: AFPERR_ACCESS. curdir:'%s', path:'%s'}",
             cfrombstring(dir->d_fullpath),
             cfrombstring(curdir->d_fullpath),
             ret->u_name);
@@ -379,7 +374,7 @@ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path
         return ret;
 
     case AFPERR_NOOBJ:
-        if (movecwd(vol, dirlookup(vol, dir->d_pdid)) < 0 )
+        if (movecwd(vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */
             return NULL;
 
         memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1);
@@ -390,12 +385,8 @@ static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path
             memcpy(ret->u_name, cfrombstring(dir->d_u_name), blength(dir->d_u_name) + 1);
         }
 
-#if 0
-        ret->st_valid = 1;
-        ret->st_errno = ENOENT;
-#endif
-        ret->d_dir = NULL;
-        dir_remove(vol, dir);
+        ret->d_dir = NULL;      /* 4 */
+        dir_remove(vol, dir);   /* 5 */
         return ret;
 
     default:
@@ -878,6 +869,9 @@ exit:
 }
 
 /*!
+
+  FIXME: open forks ??!!!
+
  * @brief Remove a dir from a cache and free it and any ressources with it
  *
  * @param (r) pointer to struct vol
@@ -891,13 +885,18 @@ int dir_remove(const struct vol *vol, struct dir *dir)
     if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
         return 0;
 
+    if (dir->d_flags & DIRF_CACHELOCK) {
+        LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): attempt to remove a locked dir",
+            ntohl(dir->d_did), cfrombstring(dir->d_fullpath));
+        return 0;
+    }
+
     if (curdir == dir) {
         if (movecwd(vol, vol->v_root) < 0) {
             LOG(log_error, logtype_afpd, "dir_remove: can't chdir to : %s", vol->v_root);
         }
     }
 
-
     LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}",
         ntohl(dir->d_did), cfrombstring(dir->d_fullpath));
 
index dd14692faf7a910b89cc4a6b7a0d78b71c445316..852d5343ddd06c4e8acd6eb2df381ac063c36e8f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.h,v 1.33.4.1 2010-02-01 10:56:08 franklahm Exp $
+ * $Id: directory.h,v 1.33.4.2 2010-02-05 10:27:59 franklahm Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -48,8 +48,9 @@
 #define DIRF_AFS       (1<<0)
 #define DIRF_UFS       (2<<0)
 
-#define DIRF_OFFCNT     (1<<4) /* offsprings count is valid */
-#define DIRF_CNID      (1<<5)  /* renumerate id */
+#define DIRF_OFFCNT    (1<<4) /* offsprings count is valid */
+#define DIRF_CNID         (1<<5) /* renumerate id */
+#define DIRF_CACHELOCK (1<<6) /* lock in cache, don't remove in dircache_eviction, for catsearch */
 
 #define AFPDIR_READ    (1<<0)