patch-2.4.15 linux/fs/intermezzo/cache.c
Next file: linux/fs/intermezzo/dcache.c
Previous file: linux/fs/intermezzo/Makefile
Back to the patch index
Back to the overall index
- Lines: 257
- Date:
Sun Nov 11 10:20:21 2001
- Orig file:
v2.4.14/linux/fs/intermezzo/cache.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.4.14/linux/fs/intermezzo/cache.c linux/fs/intermezzo/cache.c
@@ -0,0 +1,256 @@
+/*
+ *
+ *
+ * Copyright (C) 2000 Stelias Computing, Inc.
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <stdarg.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+
+#include <linux/intermezzo_fs.h>
+#include <linux/intermezzo_upcall.h>
+#include <linux/intermezzo_psdev.h>
+
+/*
+ This file contains the routines associated with managing a
+ cache of files for InterMezzo. These caches have two reqs:
+ - need to be found fast so they are hashed by the device,
+ with an attempt to have collision chains of length 1.
+ The methods for the cache are set up in methods.
+*/
+
+/* the intent of this hash is to have collision chains of length 1 */
+#define CACHES_BITS 8
+#define CACHES_SIZE (1 << CACHES_BITS)
+#define CACHES_MASK CACHES_SIZE - 1
+static struct list_head presto_caches[CACHES_SIZE];
+
+static inline int presto_cache_hash(kdev_t dev)
+{
+ return (CACHES_MASK) & ((0x000F & (dev)) + ((0x0F00 & (dev)) >>8));
+}
+
+inline void presto_cache_add(struct presto_cache *cache, kdev_t dev)
+{
+ list_add(&cache->cache_chain,
+ &presto_caches[presto_cache_hash(dev)]);
+ cache->cache_dev = dev;
+}
+
+inline void presto_init_cache_hash(void)
+{
+ int i;
+ for ( i = 0; i < CACHES_SIZE; i++ ) {
+ INIT_LIST_HEAD(&presto_caches[i]);
+ }
+}
+
+/* map a device to a cache */
+struct presto_cache *presto_find_cache(kdev_t dev)
+{
+ struct presto_cache *cache;
+ struct list_head *lh, *tmp;
+
+ lh = tmp = &(presto_caches[presto_cache_hash(dev)]);
+ while ( (tmp = lh->next) != lh ) {
+ cache = list_entry(tmp, struct presto_cache, cache_chain);
+ if ( cache->cache_dev == dev ) {
+ return cache;
+ }
+ }
+ return NULL;
+}
+
+
+/* map an inode to a cache */
+struct presto_cache *presto_get_cache(struct inode *inode)
+{
+ struct presto_cache *cache;
+
+ /* find the correct presto_cache here, based on the device */
+ cache = presto_find_cache(inode->i_dev);
+ if ( !cache ) {
+ printk("WARNING: no presto cache for dev %x, ino %ld\n",
+ inode->i_dev, inode->i_ino);
+ EXIT;
+ return NULL;
+ }
+ return cache;
+}
+
+
+/* list cache mount points for ioctl's or /proc/fs/intermezzo/mounts */
+int presto_sprint_mounts(char *buf, int buflen, int minor)
+{
+ int len = 0;
+ int i;
+ struct list_head *head, *tmp;
+ struct presto_cache *cache;
+
+ buf[0] = '\0';
+ for (i=0 ; i<CACHES_SIZE ; i++) {
+ head = tmp = &presto_caches[i];
+ while ( (tmp = tmp->next) != head ) {
+ cache = list_entry(tmp, struct presto_cache,
+ cache_chain);
+ if ( !cache->cache_root_fileset || !cache->cache_mtpt)
+ continue;
+ if ((minor != -1) &&
+ (cache->cache_psdev->uc_minor != minor))
+ continue;
+ if ( strlen(cache->cache_root_fileset) +
+ strlen(cache->cache_mtpt) +
+ strlen(cache->cache_psdev->uc_devname) +
+ 4 > buflen - len)
+ break;
+ len += sprintf(buf + len, "%s %s %s\n",
+ cache->cache_root_fileset,
+ cache->cache_mtpt,
+ cache->cache_psdev->uc_devname);
+ }
+ }
+
+ buf[buflen-1] = '\0';
+ CDEBUG(D_SUPER, "%s\n", buf);
+ return len;
+}
+
+#ifdef CONFIG_KREINT
+/* get mount point by volname
+ Arthur Ma, 2000.12.25
+ */
+int presto_get_mount (char *buf, int buflen, char *volname)
+{
+ int i;
+ struct list_head *head, *tmp;
+ struct presto_cache *cache = NULL;
+ char *path = "";
+
+ buf[0] = '\0';
+ for (i=0 ; i<CACHES_SIZE ; i++) {
+ head = tmp = &presto_caches[i];
+ while ( (tmp = tmp->next) != head ) {
+ cache = list_entry(tmp, struct presto_cache,
+ cache_chain);
+ if ( !cache->cache_root_fileset || !cache->cache_mtpt)
+ continue;
+ if ( strcmp(cache->cache_root_fileset, volname) == 0)
+ break;
+ }
+ }
+ if (cache != NULL)
+ path = cache->cache_mtpt;
+ strncpy (buf, path, buflen);
+ return strlen (buf);
+}
+#endif
+
+/* another debugging routine: check fs is InterMezzo fs */
+int presto_ispresto(struct inode *inode)
+{
+ struct presto_cache *cache;
+
+ if ( !inode )
+ return 0;
+ cache = presto_get_cache(inode);
+ if ( !cache )
+ return 0;
+ return (inode->i_dev == cache->cache_dev);
+}
+
+/* setup a cache structure when we need one */
+struct presto_cache *presto_init_cache(void)
+{
+ struct presto_cache *cache;
+
+ /* make a presto_cache structure for the hash */
+ PRESTO_ALLOC(cache, struct presto_cache *, sizeof(struct presto_cache));
+ if ( cache ) {
+ memset(cache, 0, sizeof(struct presto_cache));
+ INIT_LIST_HEAD(&cache->cache_chain);
+ INIT_LIST_HEAD(&cache->cache_fset_list);
+ }
+ cache->cache_lock = SPIN_LOCK_UNLOCKED;
+ cache->cache_reserved = 0;
+ return cache;
+}
+
+
+/* free a cache structure and all of the memory it is pointing to */
+inline void presto_free_cache(struct presto_cache *cache)
+{
+ if (!cache)
+ return;
+
+ list_del(&cache->cache_chain);
+ if (cache->cache_mtpt)
+ PRESTO_FREE(cache->cache_mtpt, strlen(cache->cache_mtpt) + 1);
+ if (cache->cache_type)
+ PRESTO_FREE(cache->cache_type, strlen(cache->cache_type) + 1);
+ if (cache->cache_root_fileset)
+ PRESTO_FREE(cache->cache_root_fileset, strlen(cache->cache_root_fileset) + 1);
+
+ PRESTO_FREE(cache, sizeof(struct presto_cache));
+}
+
+int presto_reserve_space(struct presto_cache *cache, loff_t req)
+{
+ struct filter_fs *filter;
+ loff_t avail;
+ struct super_block *sb = cache->cache_sb;
+ filter = cache->cache_filter;
+ if (!filter ) {
+ EXIT;
+ return 0;
+ }
+ if (!filter->o_trops ) {
+ EXIT;
+ return 0;
+ }
+ if (!filter->o_trops->tr_avail ) {
+ EXIT;
+ return 0;
+ }
+ avail = filter->o_trops->tr_avail(cache, sb);
+ CDEBUG(D_SUPER, "ESC::%ld +++> %ld \n", (long) cache->cache_reserved,
+ (long) (cache->cache_reserved + req));
+ CDEBUG(D_SUPER, "ESC::Avail::%ld \n", (long) avail);
+ spin_lock(&cache->cache_lock);
+ if (req + cache->cache_reserved > avail) {
+ spin_unlock(&cache->cache_lock);
+ EXIT;
+ return -ENOSPC;
+ }
+ cache->cache_reserved += req;
+ spin_unlock(&cache->cache_lock);
+
+ return 0;
+}
+
+void presto_release_space(struct presto_cache *cache, loff_t req)
+{
+ CDEBUG(D_SUPER, "ESC::%ld ---> %ld \n", (long) cache->cache_reserved,
+ (long) (cache->cache_reserved - req));
+ spin_lock(&cache->cache_lock);
+ cache->cache_reserved -= req;
+ spin_unlock(&cache->cache_lock);
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)