bus: mhi: core: Fix some error return code
[linux/fpc-iii.git] / fs / exfat / cache.c
blob03d0824fc368a5b10241082e271dd4bfefd26ada
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * linux/fs/fat/cache.c
5 * Written 1992,1993 by Werner Almesberger
7 * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead
8 * of inode number.
9 * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
10 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
13 #include <linux/slab.h>
14 #include <asm/unaligned.h>
15 #include <linux/buffer_head.h>
17 #include "exfat_raw.h"
18 #include "exfat_fs.h"
20 #define EXFAT_CACHE_VALID 0
21 #define EXFAT_MAX_CACHE 16
23 struct exfat_cache {
24 struct list_head cache_list;
25 unsigned int nr_contig; /* number of contiguous clusters */
26 unsigned int fcluster; /* cluster number in the file. */
27 unsigned int dcluster; /* cluster number on disk. */
30 struct exfat_cache_id {
31 unsigned int id;
32 unsigned int nr_contig;
33 unsigned int fcluster;
34 unsigned int dcluster;
37 static struct kmem_cache *exfat_cachep;
39 static void exfat_cache_init_once(void *c)
41 struct exfat_cache *cache = (struct exfat_cache *)c;
43 INIT_LIST_HEAD(&cache->cache_list);
46 int exfat_cache_init(void)
48 exfat_cachep = kmem_cache_create("exfat_cache",
49 sizeof(struct exfat_cache),
50 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
51 exfat_cache_init_once);
52 if (!exfat_cachep)
53 return -ENOMEM;
54 return 0;
57 void exfat_cache_shutdown(void)
59 if (!exfat_cachep)
60 return;
61 kmem_cache_destroy(exfat_cachep);
64 void exfat_cache_init_inode(struct inode *inode)
66 struct exfat_inode_info *ei = EXFAT_I(inode);
68 spin_lock_init(&ei->cache_lru_lock);
69 ei->nr_caches = 0;
70 ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
71 INIT_LIST_HEAD(&ei->cache_lru);
74 static inline struct exfat_cache *exfat_cache_alloc(void)
76 return kmem_cache_alloc(exfat_cachep, GFP_NOFS);
79 static inline void exfat_cache_free(struct exfat_cache *cache)
81 WARN_ON(!list_empty(&cache->cache_list));
82 kmem_cache_free(exfat_cachep, cache);
85 static inline void exfat_cache_update_lru(struct inode *inode,
86 struct exfat_cache *cache)
88 struct exfat_inode_info *ei = EXFAT_I(inode);
90 if (ei->cache_lru.next != &cache->cache_list)
91 list_move(&cache->cache_list, &ei->cache_lru);
94 static unsigned int exfat_cache_lookup(struct inode *inode,
95 unsigned int fclus, struct exfat_cache_id *cid,
96 unsigned int *cached_fclus, unsigned int *cached_dclus)
98 struct exfat_inode_info *ei = EXFAT_I(inode);
99 static struct exfat_cache nohit = { .fcluster = 0, };
100 struct exfat_cache *hit = &nohit, *p;
101 unsigned int offset = EXFAT_EOF_CLUSTER;
103 spin_lock(&ei->cache_lru_lock);
104 list_for_each_entry(p, &ei->cache_lru, cache_list) {
105 /* Find the cache of "fclus" or nearest cache. */
106 if (p->fcluster <= fclus && hit->fcluster < p->fcluster) {
107 hit = p;
108 if (hit->fcluster + hit->nr_contig < fclus) {
109 offset = hit->nr_contig;
110 } else {
111 offset = fclus - hit->fcluster;
112 break;
116 if (hit != &nohit) {
117 exfat_cache_update_lru(inode, hit);
119 cid->id = ei->cache_valid_id;
120 cid->nr_contig = hit->nr_contig;
121 cid->fcluster = hit->fcluster;
122 cid->dcluster = hit->dcluster;
123 *cached_fclus = cid->fcluster + offset;
124 *cached_dclus = cid->dcluster + offset;
126 spin_unlock(&ei->cache_lru_lock);
128 return offset;
131 static struct exfat_cache *exfat_cache_merge(struct inode *inode,
132 struct exfat_cache_id *new)
134 struct exfat_inode_info *ei = EXFAT_I(inode);
135 struct exfat_cache *p;
137 list_for_each_entry(p, &ei->cache_lru, cache_list) {
138 /* Find the same part as "new" in cluster-chain. */
139 if (p->fcluster == new->fcluster) {
140 if (new->nr_contig > p->nr_contig)
141 p->nr_contig = new->nr_contig;
142 return p;
145 return NULL;
148 static void exfat_cache_add(struct inode *inode,
149 struct exfat_cache_id *new)
151 struct exfat_inode_info *ei = EXFAT_I(inode);
152 struct exfat_cache *cache, *tmp;
154 if (new->fcluster == EXFAT_EOF_CLUSTER) /* dummy cache */
155 return;
157 spin_lock(&ei->cache_lru_lock);
158 if (new->id != EXFAT_CACHE_VALID &&
159 new->id != ei->cache_valid_id)
160 goto unlock; /* this cache was invalidated */
162 cache = exfat_cache_merge(inode, new);
163 if (cache == NULL) {
164 if (ei->nr_caches < EXFAT_MAX_CACHE) {
165 ei->nr_caches++;
166 spin_unlock(&ei->cache_lru_lock);
168 tmp = exfat_cache_alloc();
169 if (!tmp) {
170 spin_lock(&ei->cache_lru_lock);
171 ei->nr_caches--;
172 spin_unlock(&ei->cache_lru_lock);
173 return;
176 spin_lock(&ei->cache_lru_lock);
177 cache = exfat_cache_merge(inode, new);
178 if (cache != NULL) {
179 ei->nr_caches--;
180 exfat_cache_free(tmp);
181 goto out_update_lru;
183 cache = tmp;
184 } else {
185 struct list_head *p = ei->cache_lru.prev;
187 cache = list_entry(p,
188 struct exfat_cache, cache_list);
190 cache->fcluster = new->fcluster;
191 cache->dcluster = new->dcluster;
192 cache->nr_contig = new->nr_contig;
194 out_update_lru:
195 exfat_cache_update_lru(inode, cache);
196 unlock:
197 spin_unlock(&ei->cache_lru_lock);
201 * Cache invalidation occurs rarely, thus the LRU chain is not updated. It
202 * fixes itself after a while.
204 static void __exfat_cache_inval_inode(struct inode *inode)
206 struct exfat_inode_info *ei = EXFAT_I(inode);
207 struct exfat_cache *cache;
209 while (!list_empty(&ei->cache_lru)) {
210 cache = list_entry(ei->cache_lru.next,
211 struct exfat_cache, cache_list);
212 list_del_init(&cache->cache_list);
213 ei->nr_caches--;
214 exfat_cache_free(cache);
216 /* Update. The copy of caches before this id is discarded. */
217 ei->cache_valid_id++;
218 if (ei->cache_valid_id == EXFAT_CACHE_VALID)
219 ei->cache_valid_id++;
222 void exfat_cache_inval_inode(struct inode *inode)
224 struct exfat_inode_info *ei = EXFAT_I(inode);
226 spin_lock(&ei->cache_lru_lock);
227 __exfat_cache_inval_inode(inode);
228 spin_unlock(&ei->cache_lru_lock);
231 static inline int cache_contiguous(struct exfat_cache_id *cid,
232 unsigned int dclus)
234 cid->nr_contig++;
235 return cid->dcluster + cid->nr_contig == dclus;
238 static inline void cache_init(struct exfat_cache_id *cid,
239 unsigned int fclus, unsigned int dclus)
241 cid->id = EXFAT_CACHE_VALID;
242 cid->fcluster = fclus;
243 cid->dcluster = dclus;
244 cid->nr_contig = 0;
247 int exfat_get_cluster(struct inode *inode, unsigned int cluster,
248 unsigned int *fclus, unsigned int *dclus,
249 unsigned int *last_dclus, int allow_eof)
251 struct super_block *sb = inode->i_sb;
252 struct exfat_sb_info *sbi = EXFAT_SB(sb);
253 unsigned int limit = sbi->num_clusters;
254 struct exfat_inode_info *ei = EXFAT_I(inode);
255 struct exfat_cache_id cid;
256 unsigned int content;
258 if (ei->start_clu == EXFAT_FREE_CLUSTER) {
259 exfat_fs_error(sb,
260 "invalid access to exfat cache (entry 0x%08x)",
261 ei->start_clu);
262 return -EIO;
265 *fclus = 0;
266 *dclus = ei->start_clu;
267 *last_dclus = *dclus;
270 * Don`t use exfat_cache if zero offset or non-cluster allocation
272 if (cluster == 0 || *dclus == EXFAT_EOF_CLUSTER)
273 return 0;
275 cache_init(&cid, EXFAT_EOF_CLUSTER, EXFAT_EOF_CLUSTER);
277 if (exfat_cache_lookup(inode, cluster, &cid, fclus, dclus) ==
278 EXFAT_EOF_CLUSTER) {
280 * dummy, always not contiguous
281 * This is reinitialized by cache_init(), later.
283 WARN_ON(cid.id != EXFAT_CACHE_VALID ||
284 cid.fcluster != EXFAT_EOF_CLUSTER ||
285 cid.dcluster != EXFAT_EOF_CLUSTER ||
286 cid.nr_contig != 0);
289 if (*fclus == cluster)
290 return 0;
292 while (*fclus < cluster) {
293 /* prevent the infinite loop of cluster chain */
294 if (*fclus > limit) {
295 exfat_fs_error(sb,
296 "detected the cluster chain loop (i_pos %u)",
297 (*fclus));
298 return -EIO;
301 if (exfat_ent_get(sb, *dclus, &content))
302 return -EIO;
304 *last_dclus = *dclus;
305 *dclus = content;
306 (*fclus)++;
308 if (content == EXFAT_EOF_CLUSTER) {
309 if (!allow_eof) {
310 exfat_fs_error(sb,
311 "invalid cluster chain (i_pos %u, last_clus 0x%08x is EOF)",
312 *fclus, (*last_dclus));
313 return -EIO;
316 break;
319 if (!cache_contiguous(&cid, *dclus))
320 cache_init(&cid, *fclus, *dclus);
323 exfat_cache_add(inode, &cid);
324 return 0;