LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
AfpNum2name(function), AfpErr2name(err));
+
+ dir_free_invalid_q();
+
#ifdef FORCE_UIDGID
/* bring everything back to old euid, egid */
if (obj->force_uid)
dircache_stat.hits++;
} else {
LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {not in cache}", ntohl(cnid));
- dircache_stat.hits++;
+ dircache_stat.misses++;
}
return cdir;
else
queue_count = 0;
+ /* Initialize index queue */
+ if ((invalid_dircache_entries = queue_init()) == NULL)
+ return -1;
+
/* As long as directory.c hasn't got its own initializer call, we do it for it */
rootParent.d_did = DIRDID_ROOT_PARENT;
rootParent.d_fullpath = bfromcstr("ROOT_PARENT");
{0} /* struct stat */
};
+/*
+ * dir_remove queues struct dirs to be freed here. We can't just delete them immeidately
+ * eg in dircache_search_by_id, because a caller somewhere up the stack might be
+ * referencing it.
+ * So instead:
+ * - we mark it as invalid by setting d_did to CNID_INVALID (ie 0)
+ * - queue it in "invalid_dircache_entries" queue
+ * - which is finally freed at the end of every AFP func in afp_dsi.c.
+ */
+q_t *invalid_dircache_entries;
+
/*******************************************************************************************
* Locals
}
/*!
- * @brief Remove a dir from a cache and free it and any ressources with it
+ * Free the queue with invalid struct dirs
+ *
+ * This gets called at the end of every AFP func.
+ */
+void dir_free_invalid_q(void)
+{
+ struct dir *dir;
+ while (dir = (struct dir *)dequeue(invalid_dircache_entries))
+ dir_free(dir);
+}
+
+/*!
+ * @brief Remove a dir from a cache and queue it for freeing
*
* 1. Check if the dir is locked or has opened forks
* 2. If it's a request to remove curdir, just chdir to volume root
* 3. Remove it from the cache
- * 4. Remove the dir plus any allocated resources it references
+ * 4. Queue it for removal
+ * 5. Mark it as invalid
*
* @param (r) pointer to struct vol
* @param (rw) pointer to struct dir
ntohl(dir->d_did), cfrombstr(dir->d_u_name));
dircache_remove(vol, dir, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX); /* 3 */
- dir_free(dir); /* 4 */
-
+ enqueue(invalid_dircache_entries, dir); /* 4 */
+ dir->d_did = CNID_INVALID; /* 5 */
return 0;
}
/*
- * $Id: directory.h,v 1.34 2010/03/12 15:16:49 franklahm Exp $
- *
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*
#define AR_UWRITE (1<<2)
#define AR_UOWN (1<<7)
+q_t *invalid_dircache_entries;
+
typedef int (*dir_loop)(struct dirent *, char *, void *);
-extern struct dir *dir_new(const char *mname, const char *uname, const struct vol *,
- cnid_t pdid, cnid_t did, bstring fullpath, time_t ctime);
+extern void dir_free_invalid_q(void);
+extern struct dir *dir_new(const char *mname, const char *uname, const struct vol *,
+ cnid_t pdid, cnid_t did, bstring fullpath, time_t ctime);
extern void dir_free (struct dir *);
extern struct dir *dir_add(struct vol *, const struct dir *, struct path *, int);
extern int dir_modify(const struct vol *vol, struct dir *dir, cnid_t pdid, cnid_t did,