Yaffs: Change cache policy
authorCharles Manning <cdhmanning@gmail.com>
Tue, 22 Jul 2014 21:33:04 +0000 (09:33 +1200)
committerCharles Manning <cdhmanning@gmail.com>
Tue, 22 Jul 2014 21:33:04 +0000 (09:33 +1200)
When the cache is full and a new cache entry is needed, then space has
to be made. This is sometimes termed push out.

Until now, the push out involved finding the least recently used cache
entry then pushing out all entries in the same file.

This had the unintended consequence of making "bursty" writes and forcing
extra reads under some conditions.

Since the same code path was being used for fsync() and flushing, this
also meant that flushing a file caused the file to be thrown out of the
cache. That is not a very useful thing to do.

These changes are twofold:

1. Only push out the LRU cache entry, rather than the whole file. This
makes for a "smoother" push out. It also saves some reads.

2. Flushing a file no longer invalidates the file in cache, it just writes
dirty cache entries. This makes better use of the cache.

Signed-off-by: Charles Manning <cdhmanning@gmail.com>
yaffs_guts.c
yaffs_guts.h

index 1de2817356c29030bb85ae616908a37ff77488c5..6a12aba23ebdaf89543980b3cf0fda1c4805a9ba 100644 (file)
@@ -1377,56 +1377,49 @@ static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
        return 0;
 }
 
        return 0;
 }
 
-static void yaffs_flush_file_cache(struct yaffs_obj *obj)
+static void yaffs_flush_single_cache(struct yaffs_cache *cache, int discard)
+{
+
+       if (!cache || cache->locked)
+               return;
+
+       /* Write it out and free it up  if need be.*/
+       if (cache->dirty) {
+               yaffs_wr_data_obj(cache->object,
+                                 cache->chunk_id,
+                                 cache->data,
+                                 cache->n_bytes,
+                                 1);
+
+               cache->dirty = 0;
+       }
+
+       if (discard)
+               cache->object = NULL;
+}
+
+static void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard)
 {
        struct yaffs_dev *dev = obj->my_dev;
 {
        struct yaffs_dev *dev = obj->my_dev;
-       int lowest = -99;       /* Stop compiler whining. */
        int i;
        struct yaffs_cache *cache;
        int i;
        struct yaffs_cache *cache;
-       int chunk_written = 0;
        int n_caches = obj->my_dev->param.n_caches;
 
        if (n_caches < 1)
                return;
        int n_caches = obj->my_dev->param.n_caches;
 
        if (n_caches < 1)
                return;
-       do {
-               cache = NULL;
-
-               /* Find the lowest dirty chunk for this object */
-               for (i = 0; i < n_caches; i++) {
-                       if (dev->cache[i].object == obj &&
-                           dev->cache[i].dirty) {
-                               if (!cache ||
-                                   dev->cache[i].chunk_id < lowest) {
-                                       cache = &dev->cache[i];
-                                       lowest = cache->chunk_id;
-                               }
-                       }
-               }
 
 
-               if (cache && !cache->locked) {
-                       /* Write it out and free it up */
-                       chunk_written =
-                           yaffs_wr_data_obj(cache->object,
-                                             cache->chunk_id,
-                                             cache->data,
-                                             cache->n_bytes, 1);
-                       cache->dirty = 0;
-                       cache->object = NULL;
-               }
-       } while (cache && chunk_written > 0);
 
 
-       if (cache)
-               /* Hoosterman, disk full while writing cache out. */
-               yaffs_trace(YAFFS_TRACE_ERROR,
-                       "yaffs tragedy: no space during cache write");
+       /* Find the chunks for this object and flush them. */
+       for (i = 0; i < n_caches; i++) {
+               cache = &dev->cache[i];
+               if (cache->object == obj)
+                       yaffs_flush_single_cache(cache, discard);
+       }
+
 }
 
 }
 
-/*yaffs_flush_whole_cache(dev)
- *
- *
- */
 
 
-void yaffs_flush_whole_cache(struct yaffs_dev *dev)
+void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard)
 {
        struct yaffs_obj *obj;
        int n_caches = dev->param.n_caches;
 {
        struct yaffs_obj *obj;
        int n_caches = dev->param.n_caches;
@@ -1442,12 +1435,12 @@ void yaffs_flush_whole_cache(struct yaffs_dev *dev)
                                obj = dev->cache[i].object;
                }
                if (obj)
                                obj = dev->cache[i].object;
                }
                if (obj)
-                       yaffs_flush_file_cache(obj);
+                       yaffs_flush_file_cache(obj, discard);
        } while (obj);
 
 }
 
        } while (obj);
 
 }
 
-/* Grab us a cache chunk for use.
+/* Grab us an unused cache chunk for use.
  * First look for an empty one.
  * Then look for the least recently used non-dirty one.
  * Then look for the least recently used dirty one...., flush and look again.
  * First look for an empty one.
  * Then look for the least recently used non-dirty one.
  * Then look for the least recently used dirty one...., flush and look again.
@@ -1462,56 +1455,50 @@ static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
                                return &dev->cache[i];
                }
        }
                                return &dev->cache[i];
                }
        }
+
        return NULL;
 }
 
 static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
 {
        struct yaffs_cache *cache;
        return NULL;
 }
 
 static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
 {
        struct yaffs_cache *cache;
-       struct yaffs_obj *the_obj;
        int usage;
        int i;
        int usage;
        int i;
-       int pushout;
 
        if (dev->param.n_caches < 1)
                return NULL;
 
 
        if (dev->param.n_caches < 1)
                return NULL;
 
-       /* Try find a non-dirty one... */
+       /* First look for an unused cache */
 
        cache = yaffs_grab_chunk_worker(dev);
 
 
        cache = yaffs_grab_chunk_worker(dev);
 
-       if (!cache) {
-               /* They were all dirty, find the LRU object and flush
-                * its cache, then  find again.
-                * NB what's here is not very accurate,
-                * we actually flush the object with the LRU chunk.
-                */
+       if (cache)
+               return cache;
 
 
-               /* With locking we can't assume we can use entry zero,
-                * Set the_obj to a valid pointer for Coverity. */
-               the_obj = dev->cache[0].object;
-               usage = -1;
-               cache = NULL;
-               pushout = -1;
+       /*
+        * Thery were all in use.
+        * Find the LRU cache and flush it if it is dirty.
+        */
 
 
-               for (i = 0; i < dev->param.n_caches; i++) {
-                       if (dev->cache[i].object &&
-                           !dev->cache[i].locked &&
-                           (dev->cache[i].last_use < usage ||
-                           !cache)) {
+       usage = -1;
+       cache = NULL;
+
+       for (i = 0; i < dev->param.n_caches; i++) {
+               if (dev->cache[i].object &&
+                   !dev->cache[i].locked &&
+                   (dev->cache[i].last_use < usage || !cache)) {
                                usage = dev->cache[i].last_use;
                                usage = dev->cache[i].last_use;
-                               the_obj = dev->cache[i].object;
                                cache = &dev->cache[i];
                                cache = &dev->cache[i];
-                               pushout = i;
-                       }
-               }
-
-               if (!cache || cache->dirty) {
-                       /* Flush and try again */
-                       yaffs_flush_file_cache(the_obj);
-                       cache = yaffs_grab_chunk_worker(dev);
                }
        }
                }
        }
+
+#if 1
+       yaffs_flush_single_cache(cache, 1);
+#else
+       yaffs_flush_file_cache(cache->object, 1);
+       cache = yaffs_grab_chunk_worker(dev);
+#endif
+
        return cache;
 }
 
        return cache;
 }
 
@@ -3765,7 +3752,7 @@ int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
        struct yaffs_dev *dev = in->my_dev;
        loff_t old_size = in->variant.file_variant.file_size;
 
        struct yaffs_dev *dev = in->my_dev;
        loff_t old_size = in->variant.file_variant.file_size;
 
-       yaffs_flush_file_cache(in);
+       yaffs_flush_file_cache(in, 1);
        yaffs_invalidate_whole_cache(in);
 
        yaffs_check_gc(dev, 0);
        yaffs_invalidate_whole_cache(in);
 
        yaffs_check_gc(dev, 0);
@@ -3798,12 +3785,15 @@ int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
        return YAFFS_OK;
 }
 
        return YAFFS_OK;
 }
 
-int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
+int yaffs_flush_file(struct yaffs_obj *in,
+                    int update_time,
+                    int data_sync,
+                    int discard_cache)
 {
        if (!in->dirty)
                return YAFFS_OK;
 
 {
        if (!in->dirty)
                return YAFFS_OK;
 
-       yaffs_flush_file_cache(in);
+       yaffs_flush_file_cache(in, discard_cache);
 
        if (data_sync)
                return YAFFS_OK;
 
        if (data_sync)
                return YAFFS_OK;
index 77bc7e9968c386612d951f818f9e1e627f69c386..231f8ac567eb86e3583f4c1fc436e9c89a4ca2c8 100644 (file)
@@ -876,10 +876,13 @@ struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
                                    const YCHAR *name, u32 mode, u32 uid,
                                    u32 gid);
 
                                    const YCHAR *name, u32 mode, u32 uid,
                                    u32 gid);
 
-int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
+int yaffs_flush_file(struct yaffs_obj *in,
+                    int update_time,
+                    int data_sync,
+                    int discard_cache);
 
 /* Flushing and checkpointing */
 
 /* Flushing and checkpointing */
-void yaffs_flush_whole_cache(struct yaffs_dev *dev);
+void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard);
 
 int yaffs_checkpoint_save(struct yaffs_dev *dev);
 int yaffs_checkpoint_restore(struct yaffs_dev *dev);
 
 int yaffs_checkpoint_save(struct yaffs_dev *dev);
 int yaffs_checkpoint_restore(struct yaffs_dev *dev);