b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * linux/fs/fat/cache.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * Written 1992,1993 by Werner Almesberger
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) * of inode number.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11)
5a0e3ad6af866 (Tejun Heo 2010-03-24 17:04:11 +0900 12) #include <linux/slab.h>
9e975dae2970d (OGAWA Hirofumi 2008-11-06 12:53:46 -0800 13) #include "fat.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) /* this must be > 0. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16) #define FAT_MAX_CACHE 8
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) struct fat_cache {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19) struct list_head cache_list;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) int nr_contig; /* number of contiguous clusters */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) int fcluster; /* cluster number in the file. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22) int dcluster; /* cluster number on disk. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 24)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 25) struct fat_cache_id {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 26) unsigned int id;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27) int nr_contig;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28) int fcluster;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) int dcluster;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32) static inline int fat_max_cache(struct inode *inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 33) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34) return FAT_MAX_CACHE;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36)
e18b890bb0881 (Christoph Lameter 2006-12-06 20:33:20 -0800 37) static struct kmem_cache *fat_cache_cachep;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 38)
51cc50685a427 (Alexey Dobriyan 2008-07-25 19:45:34 -0700 39) static void init_once(void *foo)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 40) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41) struct fat_cache *cache = (struct fat_cache *)foo;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 42)
a35afb830f8d7 (Christoph Lameter 2007-05-16 22:10:57 -0700 43) INIT_LIST_HEAD(&cache->cache_list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 45)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46) int __init fat_cache_init(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 47) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 48) fat_cache_cachep = kmem_cache_create("fat_cache",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 49) sizeof(struct fat_cache),
4b6a9316fab51 (Paul Jackson 2006-03-24 03:16:05 -0800 50) 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
20c2df83d25c6 (Paul Mundt 2007-07-20 10:11:58 +0900 51) init_once);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 52) if (fat_cache_cachep == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 53) return -ENOMEM;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 54) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 56)
ef6689eff4b58 (Andrew Morton 2005-06-30 22:13:14 -0700 57) void fat_cache_destroy(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 58) {
1a1d92c10dd24 (Alexey Dobriyan 2006-09-27 01:49:40 -0700 59) kmem_cache_destroy(fat_cache_cachep);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 61)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 62) static inline struct fat_cache *fat_cache_alloc(struct inode *inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 63) {
8f5934278d1d8 (Linus Torvalds 2008-05-19 19:53:01 -0700 64) return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 65) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 66)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 67) static inline void fat_cache_free(struct fat_cache *cache)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 68) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 69) BUG_ON(!list_empty(&cache->cache_list));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 70) kmem_cache_free(fat_cache_cachep, cache);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) static inline void fat_cache_update_lru(struct inode *inode,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) struct fat_cache *cache)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 76) if (MSDOS_I(inode)->cache_lru.next != &cache->cache_list)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 77) list_move(&cache->cache_list, &MSDOS_I(inode)->cache_lru);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 78) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 79)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 80) static int fat_cache_lookup(struct inode *inode, int fclus,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 81) struct fat_cache_id *cid,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 82) int *cached_fclus, int *cached_dclus)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 83) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 84) static struct fat_cache nohit = { .fcluster = 0, };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 85)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86) struct fat_cache *hit = &nohit, *p;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 87) int offset = -1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 88)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 89) spin_lock(&MSDOS_I(inode)->cache_lru_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 90) list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 91) /* Find the cache of "fclus" or nearest cache. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92) if (p->fcluster <= fclus && hit->fcluster < p->fcluster) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93) hit = p;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 94) if ((hit->fcluster + hit->nr_contig) < fclus) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) offset = hit->nr_contig;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97) offset = fclus - hit->fcluster;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 100) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 101) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 102) if (hit != &nohit) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 103) fat_cache_update_lru(inode, hit);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 104)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 105) cid->id = MSDOS_I(inode)->cache_valid_id;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 106) cid->nr_contig = hit->nr_contig;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 107) cid->fcluster = hit->fcluster;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108) cid->dcluster = hit->dcluster;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 109) *cached_fclus = cid->fcluster + offset;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110) *cached_dclus = cid->dcluster + offset;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 111) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 112) spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 113)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 114) return offset;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 115) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 116)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 117) static struct fat_cache *fat_cache_merge(struct inode *inode,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 118) struct fat_cache_id *new)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 119) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 120) struct fat_cache *p;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 121)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 122) list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 123) /* Find the same part as "new" in cluster-chain. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 124) if (p->fcluster == new->fcluster) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 125) BUG_ON(p->dcluster != new->dcluster);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 126) if (new->nr_contig > p->nr_contig)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 127) p->nr_contig = new->nr_contig;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 128) return p;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 129) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 130) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 131) return NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 132) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 133)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 134) static void fat_cache_add(struct inode *inode, struct fat_cache_id *new)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 135) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 136) struct fat_cache *cache, *tmp;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 137)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 138) if (new->fcluster == -1) /* dummy cache */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 139) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 140)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 141) spin_lock(&MSDOS_I(inode)->cache_lru_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 142) if (new->id != FAT_CACHE_VALID &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 143) new->id != MSDOS_I(inode)->cache_valid_id)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 144) goto out; /* this cache was invalidated */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 145)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 146) cache = fat_cache_merge(inode, new);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 147) if (cache == NULL) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 148) if (MSDOS_I(inode)->nr_caches < fat_max_cache(inode)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 149) MSDOS_I(inode)->nr_caches++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 150) spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 151)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 152) tmp = fat_cache_alloc(inode);
700309295551e (OGAWA Hirofumi 2011-04-12 21:08:38 +0900 153) if (!tmp) {
700309295551e (OGAWA Hirofumi 2011-04-12 21:08:38 +0900 154) spin_lock(&MSDOS_I(inode)->cache_lru_lock);
700309295551e (OGAWA Hirofumi 2011-04-12 21:08:38 +0900 155) MSDOS_I(inode)->nr_caches--;
700309295551e (OGAWA Hirofumi 2011-04-12 21:08:38 +0900 156) spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
700309295551e (OGAWA Hirofumi 2011-04-12 21:08:38 +0900 157) return;
700309295551e (OGAWA Hirofumi 2011-04-12 21:08:38 +0900 158) }
700309295551e (OGAWA Hirofumi 2011-04-12 21:08:38 +0900 159)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 160) spin_lock(&MSDOS_I(inode)->cache_lru_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 161) cache = fat_cache_merge(inode, new);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162) if (cache != NULL) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 163) MSDOS_I(inode)->nr_caches--;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 164) fat_cache_free(tmp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 165) goto out_update_lru;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 166) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 167) cache = tmp;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 168) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 169) struct list_head *p = MSDOS_I(inode)->cache_lru.prev;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 170) cache = list_entry(p, struct fat_cache, cache_list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 171) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 172) cache->fcluster = new->fcluster;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 173) cache->dcluster = new->dcluster;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 174) cache->nr_contig = new->nr_contig;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 175) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 176) out_update_lru:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 177) fat_cache_update_lru(inode, cache);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 178) out:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 179) spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 180) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 181)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 182) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 183) * Cache invalidation occurs rarely, thus the LRU chain is not updated. It
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 184) * fixes itself after a while.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 185) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 186) static void __fat_cache_inval_inode(struct inode *inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 187) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 188) struct msdos_inode_info *i = MSDOS_I(inode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 189) struct fat_cache *cache;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 190)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 191) while (!list_empty(&i->cache_lru)) {
c90518290ec88 (Cruz Julian Bishop 2012-10-04 17:14:53 -0700 192) cache = list_entry(i->cache_lru.next,
c90518290ec88 (Cruz Julian Bishop 2012-10-04 17:14:53 -0700 193) struct fat_cache, cache_list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 194) list_del_init(&cache->cache_list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 195) i->nr_caches--;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 196) fat_cache_free(cache);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 197) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 198) /* Update. The copy of caches before this id is discarded. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 199) i->cache_valid_id++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 200) if (i->cache_valid_id == FAT_CACHE_VALID)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 201) i->cache_valid_id++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 202) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 203)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 204) void fat_cache_inval_inode(struct inode *inode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 205) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 206) spin_lock(&MSDOS_I(inode)->cache_lru_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 207) __fat_cache_inval_inode(inode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 208) spin_unlock(&MSDOS_I(inode)->cache_lru_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 209) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 210)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 211) static inline int cache_contiguous(struct fat_cache_id *cid, int dclus)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 212) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 213) cid->nr_contig++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 214) return ((cid->dcluster + cid->nr_contig) == dclus);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 215) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 216)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 217) static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 218) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 219) cid->id = FAT_CACHE_VALID;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 220) cid->fcluster = fclus;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 221) cid->dcluster = dclus;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 222) cid->nr_contig = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 223) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 224)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 225) int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 226) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 227) struct super_block *sb = inode->i_sb;
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 228) struct msdos_sb_info *sbi = MSDOS_SB(sb);
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 229) const int limit = sb->s_maxbytes >> sbi->cluster_bits;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 230) struct fat_entry fatent;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 231) struct fat_cache_id cid;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 232) int nr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 233)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 234) BUG_ON(MSDOS_I(inode)->i_start == 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 235)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 236) *fclus = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 237) *dclus = MSDOS_I(inode)->i_start;
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 238) if (!fat_valid_entry(sbi, *dclus)) {
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 239) fat_fs_error_ratelimit(sb,
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 240) "%s: invalid start cluster (i_pos %lld, start %08x)",
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 241) __func__, MSDOS_I(inode)->i_pos, *dclus);
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 242) return -EIO;
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 243) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 244) if (cluster == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 245) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 246)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 247) if (fat_cache_lookup(inode, cluster, &cid, fclus, dclus) < 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 248) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 249) * dummy, always not contiguous
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 250) * This is reinitialized by cache_init(), later.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 251) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 252) cache_init(&cid, -1, -1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 253) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 254)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 255) fatent_init(&fatent);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 256) while (*fclus < cluster) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 257) /* prevent the infinite loop of cluster chain */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 258) if (*fclus > limit) {
aaa04b4875f30 (OGAWA Hirofumi 2010-05-24 14:33:12 -0700 259) fat_fs_error_ratelimit(sb,
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 260) "%s: detected the cluster chain loop (i_pos %lld)",
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 261) __func__, MSDOS_I(inode)->i_pos);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 262) nr = -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 263) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 264) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 265)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 266) nr = fat_ent_read(inode, &fatent, *dclus);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 267) if (nr < 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 268) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 269) else if (nr == FAT_ENT_FREE) {
c90518290ec88 (Cruz Julian Bishop 2012-10-04 17:14:53 -0700 270) fat_fs_error_ratelimit(sb,
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 271) "%s: invalid cluster chain (i_pos %lld)",
0afa9626667c3 (OGAWA Hirofumi 2018-08-21 21:59:44 -0700 272) __func__, MSDOS_I(inode)->i_pos);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 273) nr = -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 274) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 275) } else if (nr == FAT_ENT_EOF) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 276) fat_cache_add(inode, &cid);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 277) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 278) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 279) (*fclus)++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 280) *dclus = nr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 281) if (!cache_contiguous(&cid, *dclus))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 282) cache_init(&cid, *fclus, *dclus);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 283) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 284) nr = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 285) fat_cache_add(inode, &cid);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 286) out:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 287) fatent_brelse(&fatent);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 288) return nr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 289) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 290)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 291) static int fat_bmap_cluster(struct inode *inode, int cluster)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 292) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 293) struct super_block *sb = inode->i_sb;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 294) int ret, fclus, dclus;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 295)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 296) if (MSDOS_I(inode)->i_start == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 297) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 298)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 299) ret = fat_get_cluster(inode, cluster, &fclus, &dclus);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 300) if (ret < 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 301) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 302) else if (ret == FAT_ENT_EOF) {
85c7859190c41 (Denis Karpov 2009-06-04 02:34:22 +0900 303) fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)",
8e24eea728068 (Harvey Harrison 2008-04-30 00:55:09 -0700 304) __func__, MSDOS_I(inode)->i_pos);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 305) return -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 306) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 307) return dclus;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 308) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 309)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 310) int fat_get_mapped_cluster(struct inode *inode, sector_t sector,
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 311) sector_t last_block,
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 312) unsigned long *mapped_blocks, sector_t *bmap)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 313) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 314) struct super_block *sb = inode->i_sb;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 315) struct msdos_sb_info *sbi = MSDOS_SB(sb);
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 316) int cluster, offset;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 317)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 318) cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 319) offset = sector & (sbi->sec_per_clus - 1);
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 320) cluster = fat_bmap_cluster(inode, cluster);
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 321) if (cluster < 0)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 322) return cluster;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 323) else if (cluster) {
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 324) *bmap = fat_clus_to_blknr(sbi, cluster) + offset;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 325) *mapped_blocks = sbi->sec_per_clus - offset;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 326) if (*mapped_blocks > last_block - sector)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 327) *mapped_blocks = last_block - sector;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 328) }
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 329)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 330) return 0;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 331) }
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 332)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 333) static int is_exceed_eof(struct inode *inode, sector_t sector,
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 334) sector_t *last_block, int create)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 335) {
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 336) struct super_block *sb = inode->i_sb;
2bdf67eb1631f (OGAWA Hirofumi 2008-11-06 12:53:57 -0800 337) const unsigned long blocksize = sb->s_blocksize;
2bdf67eb1631f (OGAWA Hirofumi 2008-11-06 12:53:57 -0800 338) const unsigned char blocksize_bits = sb->s_blocksize_bits;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 339)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 340) *last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 341) if (sector >= *last_block) {
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 342) if (!create)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 343) return 1;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 344)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 345) /*
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 346) * ->mmu_private can access on only allocation path.
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 347) * (caller must hold ->i_mutex)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 348) */
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 349) *last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1))
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 350) >> blocksize_bits;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 351) if (sector >= *last_block)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 352) return 1;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 353) }
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 354)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 355) return 0;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 356) }
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 357)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 358) int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 359) unsigned long *mapped_blocks, int create, bool from_bmap)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 360) {
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 361) struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 362) sector_t last_block;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 363)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 364) *phys = 0;
e5174baaea758 (OGAWA Hirofumi 2006-01-08 01:02:11 -0800 365) *mapped_blocks = 0;
306790f75ac2f (Carmeli Tamir 2019-01-03 15:28:00 -0800 366) if (!is_fat32(sbi) && (inode->i_ino == MSDOS_ROOT_INO)) {
e5174baaea758 (OGAWA Hirofumi 2006-01-08 01:02:11 -0800 367) if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 368) *phys = sector + sbi->dir_start;
e5174baaea758 (OGAWA Hirofumi 2006-01-08 01:02:11 -0800 369) *mapped_blocks = 1;
e5174baaea758 (OGAWA Hirofumi 2006-01-08 01:02:11 -0800 370) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 371) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 372) }
2bdf67eb1631f (OGAWA Hirofumi 2008-11-06 12:53:57 -0800 373)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 374) if (!from_bmap) {
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 375) if (is_exceed_eof(inode, sector, &last_block, create))
2bdf67eb1631f (OGAWA Hirofumi 2008-11-06 12:53:57 -0800 376) return 0;
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 377) } else {
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 378) last_block = inode->i_blocks >>
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 379) (inode->i_sb->s_blocksize_bits - 9);
2bdf67eb1631f (OGAWA Hirofumi 2008-11-06 12:53:57 -0800 380) if (sector >= last_block)
2bdf67eb1631f (OGAWA Hirofumi 2008-11-06 12:53:57 -0800 381) return 0;
2bdf67eb1631f (OGAWA Hirofumi 2008-11-06 12:53:57 -0800 382) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 383)
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 384) return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks,
16fab2015099a (Namjae Jeon 2016-01-20 14:59:46 -0800 385) phys);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 386) }