fs/exfat/cache.c

Source file repositories/reference/linux-study-clean/fs/exfat/cache.c

File Facts

System
Linux kernel
Corpus path
fs/exfat/cache.c
Extension
.c
Size
8772 bytes
Lines
358
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct exfat_cache {
	struct list_head cache_list;
	unsigned int nr_contig;	/* number of contiguous clusters */
	unsigned int fcluster;	/* cluster number in the file. */
	unsigned int dcluster;	/* cluster number on disk. */
};

struct exfat_cache_id {
	unsigned int id;
	unsigned int nr_contig;
	unsigned int fcluster;
	unsigned int dcluster;
};

static struct kmem_cache *exfat_cachep;

static void exfat_cache_init_once(void *c)
{
	struct exfat_cache *cache = (struct exfat_cache *)c;

	INIT_LIST_HEAD(&cache->cache_list);
}

int exfat_cache_init(void)
{
	exfat_cachep = kmem_cache_create("exfat_cache",
				sizeof(struct exfat_cache),
				0, SLAB_RECLAIM_ACCOUNT,
				exfat_cache_init_once);
	if (!exfat_cachep)
		return -ENOMEM;
	return 0;
}

void exfat_cache_shutdown(void)
{
	if (!exfat_cachep)
		return;
	kmem_cache_destroy(exfat_cachep);
}

static inline struct exfat_cache *exfat_cache_alloc(void)
{
	return kmem_cache_alloc(exfat_cachep, GFP_NOFS);
}

static inline void exfat_cache_free(struct exfat_cache *cache)
{
	WARN_ON(!list_empty(&cache->cache_list));
	kmem_cache_free(exfat_cachep, cache);
}

static inline void exfat_cache_update_lru(struct inode *inode,
		struct exfat_cache *cache)
{
	struct exfat_inode_info *ei = EXFAT_I(inode);

	if (ei->cache_lru.next != &cache->cache_list)
		list_move(&cache->cache_list, &ei->cache_lru);
}

/*
 * Find the cache that covers or precedes 'fclus' and return the last
 * cluster before the next cache range.
 */
static inline unsigned int
exfat_cache_lookup(struct inode *inode, struct exfat_cache_id *cid,
		unsigned int fclus, unsigned int end,
		unsigned int *cached_fclus, unsigned int *cached_dclus)
{
	struct exfat_inode_info *ei = EXFAT_I(inode);
	static struct exfat_cache nohit = { .fcluster = 0, };
	struct exfat_cache *hit = &nohit, *p;
	unsigned int tail = 0;		/* End boundary of hit cache */

	/*
	 * Search range [fclus, end]. Stop early if:
	 * 1. Cache covers entire range, or
	 * 2. Next cache starts at current cache tail
	 */
	spin_lock(&ei->cache_lru_lock);
	list_for_each_entry(p, &ei->cache_lru, cache_list) {
		/* Find the cache of "fclus" or nearest cache. */
		if (p->fcluster <= fclus) {
			if (p->fcluster < hit->fcluster)
				continue;

			hit = p;
			tail = hit->fcluster + hit->nr_contig;

Annotation

Implementation Notes