Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 140199
b: refs/heads/master
c: 0e04d4c
h: refs/heads/master
i:
  140197: 4660a87
  140195: 68d2fc0
  140191: 1997a2b
v: v3
  • Loading branch information
David Howells committed Apr 3, 2009
1 parent 7fa6c76 commit cf86d9a
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a6891645cf2ddd4778096848a864580e7258faba
refs/heads/master: 0e04d4cefcf4d8fbbdb2c50e93ad541582933fd2
1 change: 1 addition & 0 deletions trunk/fs/fscache/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#

fscache-y := \
cache.o \
fsdef.o \
main.o

Expand Down
166 changes: 166 additions & 0 deletions trunk/fs/fscache/cache.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/* FS-Cache cache handling
*
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/

#define FSCACHE_DEBUG_LEVEL CACHE
#include <linux/module.h>
#include <linux/slab.h>
#include "internal.h"

LIST_HEAD(fscache_cache_list);
DECLARE_RWSEM(fscache_addremove_sem);

static LIST_HEAD(fscache_cache_tag_list);

/*
* look up a cache tag
*/
struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *name)
{
struct fscache_cache_tag *tag, *xtag;

/* firstly check for the existence of the tag under read lock */
down_read(&fscache_addremove_sem);

list_for_each_entry(tag, &fscache_cache_tag_list, link) {
if (strcmp(tag->name, name) == 0) {
atomic_inc(&tag->usage);
up_read(&fscache_addremove_sem);
return tag;
}
}

up_read(&fscache_addremove_sem);

/* the tag does not exist - create a candidate */
xtag = kzalloc(sizeof(*xtag) + strlen(name) + 1, GFP_KERNEL);
if (!xtag)
/* return a dummy tag if out of memory */
return ERR_PTR(-ENOMEM);

atomic_set(&xtag->usage, 1);
strcpy(xtag->name, name);

/* write lock, search again and add if still not present */
down_write(&fscache_addremove_sem);

list_for_each_entry(tag, &fscache_cache_tag_list, link) {
if (strcmp(tag->name, name) == 0) {
atomic_inc(&tag->usage);
up_write(&fscache_addremove_sem);
kfree(xtag);
return tag;
}
}

list_add_tail(&xtag->link, &fscache_cache_tag_list);
up_write(&fscache_addremove_sem);
return xtag;
}

/*
* release a reference to a cache tag
*/
void __fscache_release_cache_tag(struct fscache_cache_tag *tag)
{
if (tag != ERR_PTR(-ENOMEM)) {
down_write(&fscache_addremove_sem);

if (atomic_dec_and_test(&tag->usage))
list_del_init(&tag->link);
else
tag = NULL;

up_write(&fscache_addremove_sem);

kfree(tag);
}
}

/*
* select a cache in which to store an object
* - the cache addremove semaphore must be at least read-locked by the caller
* - the object will never be an index
*/
struct fscache_cache *fscache_select_cache_for_object(
struct fscache_cookie *cookie)
{
struct fscache_cache_tag *tag;
struct fscache_object *object;
struct fscache_cache *cache;

_enter("");

if (list_empty(&fscache_cache_list)) {
_leave(" = NULL [no cache]");
return NULL;
}

/* we check the parent to determine the cache to use */
spin_lock(&cookie->lock);

/* the first in the parent's backing list should be the preferred
* cache */
if (!hlist_empty(&cookie->backing_objects)) {
object = hlist_entry(cookie->backing_objects.first,
struct fscache_object, cookie_link);

cache = object->cache;
if (object->state >= FSCACHE_OBJECT_DYING ||
test_bit(FSCACHE_IOERROR, &cache->flags))
cache = NULL;

spin_unlock(&cookie->lock);
_leave(" = %p [parent]", cache);
return cache;
}

/* the parent is unbacked */
if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) {
/* cookie not an index and is unbacked */
spin_unlock(&cookie->lock);
_leave(" = NULL [cookie ub,ni]");
return NULL;
}

spin_unlock(&cookie->lock);

if (!cookie->def->select_cache)
goto no_preference;

/* ask the netfs for its preference */
tag = cookie->def->select_cache(cookie->parent->netfs_data,
cookie->netfs_data);
if (!tag)
goto no_preference;

if (tag == ERR_PTR(-ENOMEM)) {
_leave(" = NULL [nomem tag]");
return NULL;
}

if (!tag->cache) {
_leave(" = NULL [unbacked tag]");
return NULL;
}

if (test_bit(FSCACHE_IOERROR, &tag->cache->flags))
return NULL;

_leave(" = %p [specific]", tag->cache);
return tag->cache;

no_preference:
/* netfs has no preference - just select first cache */
cache = list_entry(fscache_cache_list.next,
struct fscache_cache, link);
_leave(" = %p [first]", cache);
return cache;
}
20 changes: 20 additions & 0 deletions trunk/fs/fscache/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@
#define FSCACHE_MIN_THREADS 4
#define FSCACHE_MAX_THREADS 32

/*
* fsc-cache.c
*/
extern struct list_head fscache_cache_list;
extern struct rw_semaphore fscache_addremove_sem;

extern struct fscache_cache *fscache_select_cache_for_object(
struct fscache_cookie *);

/*
* fsc-fsdef.c
*/
Expand Down Expand Up @@ -168,6 +177,17 @@ extern const struct file_operations fscache_stats_fops;
#define fscache_stat(stat) do {} while (0)
#endif

/*
* raise an event on an object
* - if the event is not masked for that object, then the object is
* queued for attention by the thread pool.
*/
static inline void fscache_raise_event(struct fscache_object *object,
unsigned event)
{
BUG(); // TODO
}

/*****************************************************************************/
/*
* debug tracing
Expand Down
9 changes: 8 additions & 1 deletion trunk/include/linux/fscache.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ struct fscache_netfs {
* - these are undefined symbols when FS-Cache is not configured and the
* optimiser takes care of not using them
*/
extern struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *);
extern void __fscache_release_cache_tag(struct fscache_cache_tag *);

/**
* fscache_register_netfs - Register a filesystem as desiring caching services
Expand Down Expand Up @@ -218,7 +220,10 @@ void fscache_unregister_netfs(struct fscache_netfs *netfs)
static inline
struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name)
{
return NULL;
if (fscache_available())
return __fscache_lookup_cache_tag(name);
else
return NULL;
}

/**
Expand All @@ -233,6 +238,8 @@ struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name)
static inline
void fscache_release_cache_tag(struct fscache_cache_tag *tag)
{
if (fscache_available())
__fscache_release_cache_tag(tag);
}

/**
Expand Down

0 comments on commit cf86d9a

Please sign in to comment.