27f54e2c602b1abab1337dd569278f2664261c7a
[yaffs2.git] / yaffs_cache.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2018 Aleph One Ltd.
5  *
6  * Created by Charles Manning <charles@aleph1.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include "yaffs_cache.h"
14
15 /*------------------------ Short Operations Cache ------------------------------
16  *   In many situations where there is no high level buffering  a lot of
17  *   reads might be short sequential reads, and a lot of writes may be short
18  *   sequential writes. eg. scanning/writing a jpeg file.
19  *   In these cases, a short read/write cache can provide a huge perfomance
20  *   benefit with dumb-as-a-rock code.
21  *   In Linux, the page cache provides read buffering and the short op cache
22  *   provides write buffering.
23  *
24  *   There are a small number (~10) of cache chunks per device so that we don't
25  *   need a very intelligent search.
26  */
27
28 int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
29 {
30         struct yaffs_dev *dev = obj->my_dev;
31         int i;
32         struct yaffs_cache *cache;
33         int n_caches = obj->my_dev->param.n_caches;
34
35         for (i = 0; i < n_caches; i++) {
36                 cache = &dev->cache[i];
37                 if (cache->object == obj && cache->dirty)
38                         return 1;
39         }
40
41         return 0;
42 }
43
44 void yaffs_flush_single_cache(struct yaffs_cache *cache, int discard)
45 {
46
47         if (!cache || cache->locked)
48                 return;
49
50         /* Write it out and free it up  if need be.*/
51         if (cache->dirty) {
52                 yaffs_wr_data_obj(cache->object,
53                                   cache->chunk_id,
54                                   cache->data,
55                                   cache->n_bytes,
56                                   1);
57
58                 cache->dirty = 0;
59         }
60
61         if (discard)
62                 cache->object = NULL;
63 }
64
65 void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard)
66 {
67         struct yaffs_dev *dev = obj->my_dev;
68         int i;
69         struct yaffs_cache *cache;
70         int n_caches = obj->my_dev->param.n_caches;
71
72         if (n_caches < 1)
73                 return;
74
75
76         /* Find the chunks for this object and flush them. */
77         for (i = 0; i < n_caches; i++) {
78                 cache = &dev->cache[i];
79                 if (cache->object == obj)
80                         yaffs_flush_single_cache(cache, discard);
81         }
82
83 }
84
85
86 void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard)
87 {
88         struct yaffs_obj *obj;
89         int n_caches = dev->param.n_caches;
90         int i;
91
92         /* Find a dirty object in the cache and flush it...
93          * until there are no further dirty objects.
94          */
95         do {
96                 obj = NULL;
97                 for (i = 0; i < n_caches && !obj; i++) {
98                         if (dev->cache[i].object && dev->cache[i].dirty)
99                                 obj = dev->cache[i].object;
100                 }
101                 if (obj)
102                         yaffs_flush_file_cache(obj, discard);
103         } while (obj);
104
105 }
106
107 /* Grab us an unused cache chunk for use.
108  * First look for an empty one.
109  * Then look for the least recently used non-dirty one.
110  * Then look for the least recently used dirty one...., flush and look again.
111  */
112 static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
113 {
114         u32 i;
115
116         if (dev->param.n_caches > 0) {
117                 for (i = 0; i < dev->param.n_caches; i++) {
118                         if (!dev->cache[i].object)
119                                 return &dev->cache[i];
120                 }
121         }
122
123         return NULL;
124 }
125
126 struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
127 {
128         struct yaffs_cache *cache;
129         int usage;
130         u32 i;
131
132         if (dev->param.n_caches < 1)
133                 return NULL;
134
135         /* First look for an unused cache */
136
137         cache = yaffs_grab_chunk_worker(dev);
138
139         if (cache)
140                 return cache;
141
142         /*
143          * Thery were all in use.
144          * Find the LRU cache and flush it if it is dirty.
145          */
146
147         usage = -1;
148         cache = NULL;
149
150         for (i = 0; i < dev->param.n_caches; i++) {
151                 if (dev->cache[i].object &&
152                     !dev->cache[i].locked &&
153                     (dev->cache[i].last_use < usage || !cache)) {
154                                 usage = dev->cache[i].last_use;
155                                 cache = &dev->cache[i];
156                 }
157         }
158
159 #if 1
160         yaffs_flush_single_cache(cache, 1);
161 #else
162         yaffs_flush_file_cache(cache->object, 1);
163         cache = yaffs_grab_chunk_worker(dev);
164 #endif
165
166         return cache;
167 }
168
169 /* Find a cached chunk */
170 struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
171                                                   int chunk_id)
172 {
173         struct yaffs_dev *dev = obj->my_dev;
174         u32 i;
175
176         if (dev->param.n_caches < 1)
177                 return NULL;
178
179         for (i = 0; i < dev->param.n_caches; i++) {
180                 if (dev->cache[i].object == obj &&
181                     dev->cache[i].chunk_id == chunk_id) {
182                         dev->cache_hits++;
183
184                         return &dev->cache[i];
185                 }
186         }
187         return NULL;
188 }
189
190 /* Mark the chunk for the least recently used algorithym */
191 void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
192                             int is_write)
193 {
194         u32 i;
195
196         if (dev->param.n_caches < 1)
197                 return;
198
199         if (dev->cache_last_use < 0 ||
200                 dev->cache_last_use > 100000000) {
201                 /* Reset the cache usages */
202                 for (i = 1; i < dev->param.n_caches; i++)
203                         dev->cache[i].last_use = 0;
204
205                 dev->cache_last_use = 0;
206         }
207         dev->cache_last_use++;
208         cache->last_use = dev->cache_last_use;
209
210         if (is_write)
211                 cache->dirty = 1;
212 }
213
214 /* Invalidate a single cache page.
215  * Do this when a whole page gets written,
216  * ie the short cache for this page is no longer valid.
217  */
218 void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
219 {
220         struct yaffs_cache *cache;
221
222         if (object->my_dev->param.n_caches > 0) {
223                 cache = yaffs_find_chunk_cache(object, chunk_id);
224
225                 if (cache)
226                         cache->object = NULL;
227         }
228 }
229
230 /* Invalidate all the cache pages associated with this object
231  * Do this whenever ther file is deleted or resized.
232  */
233 void yaffs_invalidate_file_cache(struct yaffs_obj *in)
234 {
235         u32 i;
236         struct yaffs_dev *dev = in->my_dev;
237
238         if (dev->param.n_caches > 0) {
239                 /* Invalidate it. */
240                 for (i = 0; i < dev->param.n_caches; i++) {
241                         if (dev->cache[i].object == in)
242                                 dev->cache[i].object = NULL;
243                 }
244         }
245 }
246
247
248 int yaffs_cache_init(struct yaffs_dev *dev)
249 {
250         int init_failed;
251
252         if (dev->param.n_caches > 0) {
253                 u32 i;
254                 void *buf;
255                 u32 cache_bytes =
256                     dev->param.n_caches * sizeof(struct yaffs_cache);
257
258                 if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
259                         dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
260
261                 dev->cache = kmalloc(cache_bytes, GFP_NOFS);
262
263                 buf = (u8 *) dev->cache;
264
265                 if (dev->cache)
266                         memset(dev->cache, 0, cache_bytes);
267
268                 for (i = 0; i < dev->param.n_caches && buf; i++) {
269                         dev->cache[i].object = NULL;
270                         dev->cache[i].last_use = 0;
271                         dev->cache[i].dirty = 0;
272                         dev->cache[i].data = buf =
273                             kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
274                 }
275                 if (!buf)
276                         init_failed = 1;
277
278                 dev->cache_last_use = 0;
279         }
280
281         return init_failed ? -1 : 0;
282 }
283
284 void yaffs_cache_deinit(struct yaffs_dev *dev)
285 {
286
287         if (dev->param.n_caches > 0 && dev->cache) {
288                 u32 i;
289
290                 for (i = 0; i < dev->param.n_caches; i++) {
291                         kfree(dev->cache[i].data);
292                         dev->cache[i].data = NULL;
293                 }
294
295                 kfree(dev->cache);
296                 dev->cache = NULL;
297         }
298 }