kernel Makefile won't work after moving cache handling into a separated file.
[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_manager *mgr = &dev->cache_mgr;
33
34         for (i = 0; i < mgr->n_caches; i++) {
35                 struct yaffs_cache *cache = &mgr->cache[i];
36
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_manager *mgr = &dev->cache_mgr;
70
71         if (mgr->n_caches < 1)
72                 return;
73
74
75         /* Find the chunks for this object and flush them. */
76         for (i = 0; i < mgr->n_caches; i++) {
77                 struct yaffs_cache *cache = &mgr->cache[i];
78
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_cache_manager *mgr = &dev->cache_mgr;
89         struct yaffs_obj *obj;
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 < mgr->n_caches && !obj; i++) {
98                         struct yaffs_cache *cache = &mgr->cache[i];
99                         if (cache->object && cache->dirty)
100                                 obj = cache->object;
101                 }
102                 if (obj)
103                         yaffs_flush_file_cache(obj, discard);
104         } while (obj);
105
106 }
107
108 /* Grab us an unused cache chunk for use.
109  * First look for an empty one.
110  * Then look for the least recently used non-dirty one.
111  * Then look for the least recently used dirty one...., flush and look again.
112  */
113 static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
114 {
115         struct yaffs_cache_manager *mgr = &dev->cache_mgr;
116         int i;
117
118         for (i = 0; i < mgr->n_caches; i++) {
119                 struct yaffs_cache *cache = &mgr->cache[i];
120                 if (!cache->object)
121                         return cache;
122         }
123
124         return NULL;
125 }
126
127 struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
128 {
129         struct yaffs_cache_manager *mgr = &dev->cache_mgr;
130         struct yaffs_cache *cache;
131         int usage;
132         int i;
133
134         if (mgr->n_caches < 1)
135                 return NULL;
136
137         /* First look for an unused cache */
138
139         cache = yaffs_grab_chunk_worker(dev);
140
141         if (cache)
142                 return cache;
143
144         /*
145          * Thery were all in use.
146          * Find the LRU cache and flush it if it is dirty.
147          */
148
149         usage = -1;
150         cache = NULL;
151
152         for (i = 0; i < mgr->n_caches; i++) {
153                 struct yaffs_cache *this_cache = &mgr->cache[i];
154
155                 if (this_cache->object &&
156                     !this_cache->locked &&
157                     (this_cache->last_use < usage || !cache)) {
158                                 usage = this_cache->last_use;
159                                 cache = this_cache;
160                 }
161         }
162
163 #if 1
164         yaffs_flush_single_cache(cache, 1);
165 #else
166         yaffs_flush_file_cache(cache->object, 1);
167         cache = yaffs_grab_chunk_worker(dev);
168 #endif
169
170         return cache;
171 }
172
173 /* Find a cached chunk */
174 struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
175                                                   int chunk_id)
176 {
177         struct yaffs_dev *dev = obj->my_dev;
178         struct yaffs_cache_manager *mgr = &dev->cache_mgr;
179         int i;
180
181         if (mgr->n_caches < 1)
182                 return NULL;
183
184         for (i = 0; i < mgr->n_caches; i++) {
185                 struct yaffs_cache *cache = &mgr->cache[i];
186
187                 if (cache->object == obj &&
188                     cache->chunk_id == chunk_id) {
189                         dev->cache_hits++;
190                         return cache;
191                 }
192         }
193         return NULL;
194 }
195
196 /* Mark the chunk for the least recently used algorithym */
197 void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
198                             int is_write)
199 {
200         struct yaffs_cache_manager *mgr = &dev->cache_mgr;
201         int i;
202
203         if (mgr->n_caches < 1)
204                 return;
205
206         if (mgr->cache_last_use < 0 ||
207                 mgr->cache_last_use > 100000000) {
208                 /* Reset the cache usages */
209                 for (i = 1; i < mgr->n_caches; i++)
210                         mgr->cache[i].last_use = 0;
211
212                 mgr->cache_last_use = 0;
213         }
214         mgr->cache_last_use++;
215         cache->last_use = mgr->cache_last_use;
216
217         if (is_write)
218                 cache->dirty = 1;
219 }
220
221 /* Invalidate a single cache page.
222  * Do this when a whole page gets written,
223  * ie the short cache for this page is no longer valid.
224  */
225 void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
226 {
227         struct yaffs_cache *cache;
228
229         cache = yaffs_find_chunk_cache(object, chunk_id);
230         if (cache)
231                 cache->object = NULL;
232 }
233
234 /* Invalidate all the cache pages associated with this object
235  * Do this whenever the file is deleted or resized.
236  */
237 void yaffs_invalidate_file_cache(struct yaffs_obj *in)
238 {
239         int i;
240         struct yaffs_dev *dev = in->my_dev;
241         struct yaffs_cache_manager *mgr = &dev->cache_mgr;
242
243         /* Invalidate it. */
244         for (i = 0; i < mgr->n_caches; i++) {
245                 struct yaffs_cache *cache = &mgr->cache[i];
246
247                 if (cache->object == in)
248                         cache->object = NULL;
249         }
250 }
251
252 int yaffs_count_dirty_caches(struct yaffs_dev *dev)
253 {
254         int n_dirty;
255         int i;
256         struct yaffs_cache_manager *mgr = &dev->cache_mgr;
257
258         for (n_dirty= 0, i = 0; i < mgr->n_caches; i++) {
259                 if (mgr->cache[i].dirty)
260                         n_dirty++;
261         }
262
263         return n_dirty;
264 }
265
266 int yaffs_cache_init(struct yaffs_dev *dev)
267 {
268         struct yaffs_cache_manager *mgr = &dev->cache_mgr;
269         int init_failed = 0;
270
271         if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
272                         dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
273
274         mgr->n_caches = dev->param.n_caches;
275         if (mgr->n_caches > 0) {
276                 int i;
277                 void *buf;
278                 u32 cache_bytes =
279                     mgr->n_caches * sizeof(struct yaffs_cache);
280
281
282
283                 mgr->cache = kmalloc(cache_bytes, GFP_NOFS);
284
285                 buf = (u8 *) mgr->cache;
286
287                 if (mgr->cache)
288                         memset(mgr->cache, 0, cache_bytes);
289
290                 for (i = 0; i < mgr->n_caches && buf; i++) {
291                         struct yaffs_cache *cache = &mgr->cache[i];
292
293                         cache->object = NULL;
294                         cache->last_use = 0;
295                         cache->dirty = 0;
296                         cache->data = buf =
297                             kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
298                 }
299                 if (!buf)
300                         init_failed = 1;
301
302                 mgr->cache_last_use = 0;
303         }
304
305         return init_failed ? -1 : 0;
306 }
307
308 void yaffs_cache_deinit(struct yaffs_dev *dev)
309 {
310         struct yaffs_cache_manager *mgr = &dev->cache_mgr;
311         int i;
312
313         if (mgr->n_caches < 1 || !mgr->cache)
314                 return;
315
316         for (i = 0; i < mgr->n_caches; i++) {
317
318                 struct yaffs_cache *cache = &mgr->cache[i];
319                 kfree(cache->data);
320                 cache->data = NULL;
321         }
322
323         kfree(mgr->cache);
324         mgr->cache = NULL;
325 }