0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/slab.h>
0014 #include <asm/unaligned.h>
0015 #include <linux/buffer_head.h>
0016
0017 #include "exfat_raw.h"
0018 #include "exfat_fs.h"
0019
0020 #define EXFAT_MAX_CACHE 16
0021
0022 struct exfat_cache {
0023 struct list_head cache_list;
0024 unsigned int nr_contig;
0025 unsigned int fcluster;
0026 unsigned int dcluster;
0027 };
0028
0029 struct exfat_cache_id {
0030 unsigned int id;
0031 unsigned int nr_contig;
0032 unsigned int fcluster;
0033 unsigned int dcluster;
0034 };
0035
0036 static struct kmem_cache *exfat_cachep;
0037
0038 static void exfat_cache_init_once(void *c)
0039 {
0040 struct exfat_cache *cache = (struct exfat_cache *)c;
0041
0042 INIT_LIST_HEAD(&cache->cache_list);
0043 }
0044
0045 int exfat_cache_init(void)
0046 {
0047 exfat_cachep = kmem_cache_create("exfat_cache",
0048 sizeof(struct exfat_cache),
0049 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
0050 exfat_cache_init_once);
0051 if (!exfat_cachep)
0052 return -ENOMEM;
0053 return 0;
0054 }
0055
0056 void exfat_cache_shutdown(void)
0057 {
0058 if (!exfat_cachep)
0059 return;
0060 kmem_cache_destroy(exfat_cachep);
0061 }
0062
0063 static inline struct exfat_cache *exfat_cache_alloc(void)
0064 {
0065 return kmem_cache_alloc(exfat_cachep, GFP_NOFS);
0066 }
0067
0068 static inline void exfat_cache_free(struct exfat_cache *cache)
0069 {
0070 WARN_ON(!list_empty(&cache->cache_list));
0071 kmem_cache_free(exfat_cachep, cache);
0072 }
0073
0074 static inline void exfat_cache_update_lru(struct inode *inode,
0075 struct exfat_cache *cache)
0076 {
0077 struct exfat_inode_info *ei = EXFAT_I(inode);
0078
0079 if (ei->cache_lru.next != &cache->cache_list)
0080 list_move(&cache->cache_list, &ei->cache_lru);
0081 }
0082
0083 static unsigned int exfat_cache_lookup(struct inode *inode,
0084 unsigned int fclus, struct exfat_cache_id *cid,
0085 unsigned int *cached_fclus, unsigned int *cached_dclus)
0086 {
0087 struct exfat_inode_info *ei = EXFAT_I(inode);
0088 static struct exfat_cache nohit = { .fcluster = 0, };
0089 struct exfat_cache *hit = &nohit, *p;
0090 unsigned int offset = EXFAT_EOF_CLUSTER;
0091
0092 spin_lock(&ei->cache_lru_lock);
0093 list_for_each_entry(p, &ei->cache_lru, cache_list) {
0094
0095 if (p->fcluster <= fclus && hit->fcluster < p->fcluster) {
0096 hit = p;
0097 if (hit->fcluster + hit->nr_contig < fclus) {
0098 offset = hit->nr_contig;
0099 } else {
0100 offset = fclus - hit->fcluster;
0101 break;
0102 }
0103 }
0104 }
0105 if (hit != &nohit) {
0106 exfat_cache_update_lru(inode, hit);
0107
0108 cid->id = ei->cache_valid_id;
0109 cid->nr_contig = hit->nr_contig;
0110 cid->fcluster = hit->fcluster;
0111 cid->dcluster = hit->dcluster;
0112 *cached_fclus = cid->fcluster + offset;
0113 *cached_dclus = cid->dcluster + offset;
0114 }
0115 spin_unlock(&ei->cache_lru_lock);
0116
0117 return offset;
0118 }
0119
0120 static struct exfat_cache *exfat_cache_merge(struct inode *inode,
0121 struct exfat_cache_id *new)
0122 {
0123 struct exfat_inode_info *ei = EXFAT_I(inode);
0124 struct exfat_cache *p;
0125
0126 list_for_each_entry(p, &ei->cache_lru, cache_list) {
0127
0128 if (p->fcluster == new->fcluster) {
0129 if (new->nr_contig > p->nr_contig)
0130 p->nr_contig = new->nr_contig;
0131 return p;
0132 }
0133 }
0134 return NULL;
0135 }
0136
0137 static void exfat_cache_add(struct inode *inode,
0138 struct exfat_cache_id *new)
0139 {
0140 struct exfat_inode_info *ei = EXFAT_I(inode);
0141 struct exfat_cache *cache, *tmp;
0142
0143 if (new->fcluster == EXFAT_EOF_CLUSTER)
0144 return;
0145
0146 spin_lock(&ei->cache_lru_lock);
0147 if (new->id != EXFAT_CACHE_VALID &&
0148 new->id != ei->cache_valid_id)
0149 goto unlock;
0150
0151 cache = exfat_cache_merge(inode, new);
0152 if (cache == NULL) {
0153 if (ei->nr_caches < EXFAT_MAX_CACHE) {
0154 ei->nr_caches++;
0155 spin_unlock(&ei->cache_lru_lock);
0156
0157 tmp = exfat_cache_alloc();
0158 if (!tmp) {
0159 spin_lock(&ei->cache_lru_lock);
0160 ei->nr_caches--;
0161 spin_unlock(&ei->cache_lru_lock);
0162 return;
0163 }
0164
0165 spin_lock(&ei->cache_lru_lock);
0166 cache = exfat_cache_merge(inode, new);
0167 if (cache != NULL) {
0168 ei->nr_caches--;
0169 exfat_cache_free(tmp);
0170 goto out_update_lru;
0171 }
0172 cache = tmp;
0173 } else {
0174 struct list_head *p = ei->cache_lru.prev;
0175
0176 cache = list_entry(p,
0177 struct exfat_cache, cache_list);
0178 }
0179 cache->fcluster = new->fcluster;
0180 cache->dcluster = new->dcluster;
0181 cache->nr_contig = new->nr_contig;
0182 }
0183 out_update_lru:
0184 exfat_cache_update_lru(inode, cache);
0185 unlock:
0186 spin_unlock(&ei->cache_lru_lock);
0187 }
0188
0189
0190
0191
0192
0193 static void __exfat_cache_inval_inode(struct inode *inode)
0194 {
0195 struct exfat_inode_info *ei = EXFAT_I(inode);
0196 struct exfat_cache *cache;
0197
0198 while (!list_empty(&ei->cache_lru)) {
0199 cache = list_entry(ei->cache_lru.next,
0200 struct exfat_cache, cache_list);
0201 list_del_init(&cache->cache_list);
0202 ei->nr_caches--;
0203 exfat_cache_free(cache);
0204 }
0205
0206 ei->cache_valid_id++;
0207 if (ei->cache_valid_id == EXFAT_CACHE_VALID)
0208 ei->cache_valid_id++;
0209 }
0210
0211 void exfat_cache_inval_inode(struct inode *inode)
0212 {
0213 struct exfat_inode_info *ei = EXFAT_I(inode);
0214
0215 spin_lock(&ei->cache_lru_lock);
0216 __exfat_cache_inval_inode(inode);
0217 spin_unlock(&ei->cache_lru_lock);
0218 }
0219
0220 static inline int cache_contiguous(struct exfat_cache_id *cid,
0221 unsigned int dclus)
0222 {
0223 cid->nr_contig++;
0224 return cid->dcluster + cid->nr_contig == dclus;
0225 }
0226
0227 static inline void cache_init(struct exfat_cache_id *cid,
0228 unsigned int fclus, unsigned int dclus)
0229 {
0230 cid->id = EXFAT_CACHE_VALID;
0231 cid->fcluster = fclus;
0232 cid->dcluster = dclus;
0233 cid->nr_contig = 0;
0234 }
0235
0236 int exfat_get_cluster(struct inode *inode, unsigned int cluster,
0237 unsigned int *fclus, unsigned int *dclus,
0238 unsigned int *last_dclus, int allow_eof)
0239 {
0240 struct super_block *sb = inode->i_sb;
0241 struct exfat_sb_info *sbi = EXFAT_SB(sb);
0242 unsigned int limit = sbi->num_clusters;
0243 struct exfat_inode_info *ei = EXFAT_I(inode);
0244 struct exfat_cache_id cid;
0245 unsigned int content;
0246
0247 if (ei->start_clu == EXFAT_FREE_CLUSTER) {
0248 exfat_fs_error(sb,
0249 "invalid access to exfat cache (entry 0x%08x)",
0250 ei->start_clu);
0251 return -EIO;
0252 }
0253
0254 *fclus = 0;
0255 *dclus = ei->start_clu;
0256 *last_dclus = *dclus;
0257
0258
0259
0260
0261 if (cluster == 0 || *dclus == EXFAT_EOF_CLUSTER)
0262 return 0;
0263
0264 cache_init(&cid, EXFAT_EOF_CLUSTER, EXFAT_EOF_CLUSTER);
0265
0266 if (exfat_cache_lookup(inode, cluster, &cid, fclus, dclus) ==
0267 EXFAT_EOF_CLUSTER) {
0268
0269
0270
0271
0272 WARN_ON(cid.id != EXFAT_CACHE_VALID ||
0273 cid.fcluster != EXFAT_EOF_CLUSTER ||
0274 cid.dcluster != EXFAT_EOF_CLUSTER ||
0275 cid.nr_contig != 0);
0276 }
0277
0278 if (*fclus == cluster)
0279 return 0;
0280
0281 while (*fclus < cluster) {
0282
0283 if (*fclus > limit) {
0284 exfat_fs_error(sb,
0285 "detected the cluster chain loop (i_pos %u)",
0286 (*fclus));
0287 return -EIO;
0288 }
0289
0290 if (exfat_ent_get(sb, *dclus, &content))
0291 return -EIO;
0292
0293 *last_dclus = *dclus;
0294 *dclus = content;
0295 (*fclus)++;
0296
0297 if (content == EXFAT_EOF_CLUSTER) {
0298 if (!allow_eof) {
0299 exfat_fs_error(sb,
0300 "invalid cluster chain (i_pos %u, last_clus 0x%08x is EOF)",
0301 *fclus, (*last_dclus));
0302 return -EIO;
0303 }
0304
0305 break;
0306 }
0307
0308 if (!cache_contiguous(&cid, *dclus))
0309 cache_init(&cid, *fclus, *dclus);
0310 }
0311
0312 exfat_cache_add(inode, &cid);
0313 return 0;
0314 }