/*
* Directory operations for InterMezzo filesystem
* Original version: (C) 1996 P. Braam and M. Callahan
* Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
*
* Stelias encourages users to contribute improvements to
* the InterMezzo project. Contact Peter Braam (coda@stelias.com).
*/
#define __NO_VERSION__
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/intermezzo_fs.h>
static int presto_dentry_revalidate(struct dentry *de, int );
static kmem_cache_t * presto_dentry_slab;
/* called when a cache lookup succeeds */
static int presto_dentry_revalidate(struct dentry *de, int flag)
{
struct inode *inode = de->d_inode;
ENTRY;
if (!inode) {
EXIT;
return 1;
}
if (is_bad_inode(inode)) {
EXIT;
return 0;
}
if ( S_ISDIR(inode->i_mode) ) {
EXIT;
return (presto_chk(de, PRESTO_DATA) &&
(presto_chk(de, PRESTO_ATTR)));
} else {
EXIT;
return presto_chk(de, PRESTO_ATTR);
}
}
static void presto_d_release(struct dentry *dentry)
{
if (!presto_d2d(dentry)) {
/* This should really only happen in the case of a dentry
* with no inode. */
return;
}
presto_d2d(dentry)->dd_count--;
if (! presto_d2d(dentry)->dd_count) {
kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
dentry->d_fsdata = NULL;
}
}
struct dentry_operations presto_dentry_ops =
{
d_revalidate: presto_dentry_revalidate,
d_release: presto_d_release
};
// XXX THIS DEPENDS ON THE KERNEL LOCK!
void presto_set_dd(struct dentry * dentry)
{
ENTRY;
if (dentry == NULL)
BUG();
if (dentry->d_fsdata) {
printk("VERY BAD: dentry: %p\n", dentry);
if (dentry->d_inode)
printk(" inode: %ld\n", dentry->d_inode->i_ino);
EXIT;
return;
}
if (dentry->d_inode == NULL) {
dentry->d_fsdata = kmem_cache_alloc(presto_dentry_slab,
SLAB_KERNEL);
memset(dentry->d_fsdata, 0, sizeof(struct presto_dentry_data));
presto_d2d(dentry)->dd_count = 1;
EXIT;
return;
}
/* If there's already a dentry for this inode, share the data */
if (dentry->d_alias.next != &dentry->d_inode->i_dentry ||
dentry->d_alias.prev != &dentry->d_inode->i_dentry) {
struct dentry *de;
if (dentry->d_alias.next != &dentry->d_inode->i_dentry)
de = list_entry(dentry->d_alias.next, struct dentry,
d_alias);
else
de = list_entry(dentry->d_alias.prev, struct dentry,
d_alias);
dentry->d_fsdata = de->d_fsdata;
presto_d2d(dentry)->dd_count++;
EXIT;
return;
}
dentry->d_fsdata = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
memset(dentry->d_fsdata, 0, sizeof(struct presto_dentry_data));
presto_d2d(dentry)->dd_count = 1;
EXIT;
return;
}
void presto_init_ddata_cache(void)
{
ENTRY;
presto_dentry_slab =
kmem_cache_create("presto_cache",
sizeof(struct presto_dentry_data), 0,
SLAB_HWCACHE_ALIGN, NULL,
NULL);
EXIT;
}
void presto_cleanup_ddata_cache(void)
{
kmem_cache_destroy(presto_dentry_slab);
}