]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - include/linux/lru_cache.h
Merge branch 'for-3.8/drivers' of git://git.kernel.dk/linux-block
[karo-tx-linux.git] / include / linux / lru_cache.h
index cafc7f99e124ec0c5a39743f048527a9875a3b55..4019013c6593b90adebe0760b344e57a76afaa50 100644 (file)
@@ -166,9 +166,11 @@ struct lc_element {
        /* if we want to track a larger set of objects,
         * it needs to become arch independend u64 */
        unsigned lc_number;
-
        /* special label when on free list */
 #define LC_FREE (~0U)
+
+       /* for pending changes */
+       unsigned lc_new_number;
 };
 
 struct lru_cache {
@@ -176,6 +178,7 @@ struct lru_cache {
        struct list_head lru;
        struct list_head free;
        struct list_head in_use;
+       struct list_head to_be_changed;
 
        /* the pre-created kmem cache to allocate the objects from */
        struct kmem_cache *lc_cache;
@@ -186,7 +189,7 @@ struct lru_cache {
        size_t element_off;
 
        /* number of elements (indices) */
-       unsigned int  nr_elements;
+       unsigned int nr_elements;
        /* Arbitrary limit on maximum tracked objects. Practical limit is much
         * lower due to allocation failures, probably. For typical use cases,
         * nr_elements should be a few thousand at most.
@@ -194,18 +197,19 @@ struct lru_cache {
         * 8 high bits of .lc_index to be overloaded with flags in the future. */
 #define LC_MAX_ACTIVE  (1<<24)
 
+       /* allow to accumulate a few (index:label) changes,
+        * but no more than max_pending_changes */
+       unsigned int max_pending_changes;
+       /* number of elements currently on to_be_changed list */
+       unsigned int pending_changes;
+
        /* statistics */
-       unsigned used; /* number of lelements currently on in_use list */
-       unsigned long hits, misses, starving, dirty, changed;
+       unsigned used; /* number of elements currently on in_use list */
+       unsigned long hits, misses, starving, locked, changed;
 
        /* see below: flag-bits for lru_cache */
        unsigned long flags;
 
-       /* when changing the label of an index element */
-       unsigned int  new_number;
-
-       /* for paranoia when changing the label of an index element */
-       struct lc_element *changing_element;
 
        void  *lc_private;
        const char *name;
@@ -221,10 +225,15 @@ enum {
        /* debugging aid, to catch concurrent access early.
         * user needs to guarantee exclusive access by proper locking! */
        __LC_PARANOIA,
-       /* if we need to change the set, but currently there is a changing
-        * transaction pending, we are "dirty", and must deferr further
-        * changing requests */
+
+       /* annotate that the set is "dirty", possibly accumulating further
+        * changes, until a transaction is finally triggered */
        __LC_DIRTY,
+
+       /* Locked, no further changes allowed.
+        * Also used to serialize changing transactions. */
+       __LC_LOCKED,
+
        /* if we need to change the set, but currently there is no free nor
         * unused element available, we are "starving", and must not give out
         * further references, to guarantee that eventually some refcnt will
@@ -236,9 +245,11 @@ enum {
 };
 #define LC_PARANOIA (1<<__LC_PARANOIA)
 #define LC_DIRTY    (1<<__LC_DIRTY)
+#define LC_LOCKED   (1<<__LC_LOCKED)
 #define LC_STARVING (1<<__LC_STARVING)
 
 extern struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
+               unsigned max_pending_changes,
                unsigned e_count, size_t e_size, size_t e_off);
 extern void lc_reset(struct lru_cache *lc);
 extern void lc_destroy(struct lru_cache *lc);
@@ -249,7 +260,7 @@ extern struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr);
 extern struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr);
 extern struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr);
 extern unsigned int lc_put(struct lru_cache *lc, struct lc_element *e);
-extern void lc_changed(struct lru_cache *lc, struct lc_element *e);
+extern void lc_committed(struct lru_cache *lc);
 
 struct seq_file;
 extern size_t lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc);
@@ -258,17 +269,29 @@ extern void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char
                                void (*detail) (struct seq_file *, struct lc_element *));
 
 /**
- * lc_try_lock - can be used to stop lc_get() from changing the tracked set
+ * lc_try_lock_for_transaction - can be used to stop lc_get() from changing the tracked set
  * @lc: the lru cache to operate on
  *
- * Note that the reference counts and order on the active and lru lists may
- * still change.  Returns true if we acquired the lock.
+ * Allows (expects) the set to be "dirty".  Note that the reference counts and
+ * order on the active and lru lists may still change.  Used to serialize
+ * changing transactions.  Returns true if we aquired the lock.
  */
-static inline int lc_try_lock(struct lru_cache *lc)
+static inline int lc_try_lock_for_transaction(struct lru_cache *lc)
 {
-       return !test_and_set_bit(__LC_DIRTY, &lc->flags);
+       return !test_and_set_bit(__LC_LOCKED, &lc->flags);
 }
 
+/**
+ * lc_try_lock - variant to stop lc_get() from changing the tracked set
+ * @lc: the lru cache to operate on
+ *
+ * Note that the reference counts and order on the active and lru lists may
+ * still change.  Only works on a "clean" set.  Returns true if we aquired the
+ * lock, which means there are no pending changes, and any further attempt to
+ * change the set will not succeed until the next lc_unlock().
+ */
+extern int lc_try_lock(struct lru_cache *lc);
+
 /**
  * lc_unlock - unlock @lc, allow lc_get() to change the set again
  * @lc: the lru cache to operate on
@@ -276,14 +299,10 @@ static inline int lc_try_lock(struct lru_cache *lc)
 static inline void lc_unlock(struct lru_cache *lc)
 {
        clear_bit(__LC_DIRTY, &lc->flags);
-       smp_mb__after_clear_bit();
+       clear_bit_unlock(__LC_LOCKED, &lc->flags);
 }
 
-static inline int lc_is_used(struct lru_cache *lc, unsigned int enr)
-{
-       struct lc_element *e = lc_find(lc, enr);
-       return e && e->refcnt;
-}
+extern bool lc_is_used(struct lru_cache *lc, unsigned int enr);
 
 #define lc_entry(ptr, type, member) \
        container_of(ptr, type, member)