* vim:expandtab:shiftwidth=8:tabstop=8:
*
* lustre/smfs/cache_space.c
- * A library of functions to manage cache space based on ARC
+ * A library of functions to manage cache space based on ARC
* (modified LRU) replacement algorithm.
- *
- * Copyright (c) 2002, 2003 Cluster File Systems, Inc.
+ *
+ * Copyright (c) 2004 Cluster File Systems, Inc.
*
* This file is part of Lustre, http://www.lustre.org.
*
#define DEBUG_SUBSYSTEM S_SM
#include <linux/lustre_log.h>
+#include <linux/lustre_fsfilt.h>
#include <linux/lustre_smfs.h>
#include "smfs_internal.h"
int ndirty; /* Maximum number of objects to write out per
wake-cycle */
int interval; /* jiffies delay between cache purge */
- int nfract_sync;/* Percentage of cache dirty to activate
+ int nfract_sync;/* Percentage of cache dirty to activate
cpurge synchronously */
int nfract_stop_cpurge; /* Percentage of cache dirty to stop cpurge */
} cf_prm = {30, 512, 600 * HZ, 60, 20};
static struct cache_purge_queue smfs_cpq;
static struct cache_purge_queue *cpq = &smfs_cpq;
+#define CACHE_HOOK "cache_hook"
+int cache_space_pre_hook(struct inode *inode, void *dentry,
+ void *data1, void *data2, int op, void *handle)
+{
+ int rc = 0;
+ ENTRY;
+
+ if (smfs_cache_hook(inode)) {
+ if (!handle) {
+ handle = smfs_trans_start(inode, KML_CACHE_NOOP, NULL);
+ if (IS_ERR(handle)) {
+ RETURN(PTR_ERR(handle));
+ }
+ }
+ cache_space_pre(inode, op);
+ }
+ RETURN(rc);
+}
+
+int cache_space_post_hook(struct inode *inode, void *de, void *data1,
+ void *data2, int op, void *handle)
+{
+ int rc = 0;
+ ENTRY;
+ if (smfs_cache_hook(inode)) {
+ struct inode *new_inode = (struct inode*)data1;
+ struct dentry *new_dentry = (struct dentry*)data2;
+ struct dentry *dentry = (struct dentry *)de;
+
+ LASSERT(handle != NULL);
+ rc = cache_space_post(op, handle, inode, dentry, new_inode,
+ new_dentry);
+ }
+ RETURN(rc);
+}
+
int cache_space_hook_init(struct super_block *sb)
{
- struct smfs_super_info *smfs_info = S2SMI(sb);
+ struct smfs_super_info *smfs_info = S2SMI(sb);
+ struct smfs_hook_ops *cache_hops;
+ int rc = 0;
+ ENTRY;
+ cache_hops = smfs_alloc_hook_ops(CACHE_HOOK, cache_space_pre_hook,
+ cache_space_post_hook);
+ if (!cache_hops) {
+ RETURN(-ENOMEM);
+ }
+ rc = smfs_register_hook_ops(smfs_info, cache_hops);
+ if (rc) {
+ smfs_free_hook_ops(cache_hops);
+ RETURN(rc);
+ }
SMFS_SET_CACHE_HOOK(smfs_info);
- return 0;
+
+ RETURN(0);
}
-int cache_space_hook_exit(struct super_block *sb)
+
+int cache_space_hook_exit(struct smfs_super_info *smfs_info)
{
- struct smfs_super_info *smfs_info = S2SMI(sb);
+ struct smfs_hook_ops *cache_hops;
+
+ cache_hops = smfs_unregister_hook_ops(smfs_info, CACHE_HOOK);
+ smfs_free_hook_ops(cache_hops);
SMFS_CLEAN_CACHE_HOOK(smfs_info);
return 0;
}
-int smfs_cache_hook(struct inode *inode)
-{
- struct smfs_super_info *smfs_info = I2CSB(inode);
-
- if (SMFS_CACHE_HOOK(smfs_info) && SMFS_INIT_REC(smfs_info)
- && SMFS_INODE_CACHE_HOOK(inode))
- return 1;
- else
- return 0;
-}
static int cache_leaf_node(struct dentry *dentry, __u64 *active_entry)
{
struct inode *inode = dentry->d_inode;
+ if (!dentry->d_inode)
+ return 0;
if (S_ISDIR(inode->i_mode)) {
if (inode->i_nlink != 2)
return 0;
inode = iget(sb, cfid.id);
if (IS_ERR(inode)) {
- CERROR("not existent inode: "LPX64"/%u\n",
+ CERROR("not existent inode: "LPX64"/%u\n",
cfid.id, cfid.generation);
RETURN(-ENOENT);
}
parent = iget(sb, pfid.id);
if (IS_ERR(parent)) {
- CERROR("not existent inode: "LPX64"/%u\n",
+ CERROR("not existent inode: "LPX64"/%u\n",
pfid.id, pfid.generation);
iput(inode);
RETURN(-ENOENT);
rc = fsops->fs_statfs(cpq->cpq_sb, &osfs);
LASSERT(rc == 0);
- free = (osfs.os_blocks - osfs.os_bfree) * 100;
+ free = (osfs.os_blocks - osfs.os_bfree) * 100;
if (free > cf_prm.nfract * osfs.os_blocks) {
if (free < cf_prm.nfract_sync)
return 1;
return 0;
}
- return -1;
+ return -1;
}
void wakeup_cpurge(void)
check_cache_space();
}
-static int cache_space_hook_lru(struct inode *inode, struct inode *parent,
+static int cache_space_hook_lru(struct inode *inode, struct inode *parent,
void *handle, int op, int flags)
{
struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
struct llog_ctxt *ctxt = cpq->cpq_loghandle->lgh_ctxt;
- struct llog_lru_rec *llr = NULL;
+ struct llog_lru_rec *llr = NULL;
struct llog_cookie *logcookie = NULL;
int cookie_size = sizeof(struct llog_cookie);
int rc = 0, err;
if (op & CACHE_SPACE_DELETE) {
rc = get_lru_logcookie(inode, logcookie);
- if (rc < 0)
+ if (rc < 0)
GOTO(out, rc);
if (logcookie->lgc_lgl.lgl_oid == 0) {
CWARN("inode %lu/%u is not in lru list\n",
inode->i_ino, inode->i_generation);
- GOTO(insert, rc = -ENOENT);
+ GOTO(insert, rc = -ENOENT);
}
if (flags && llog_cat_half_bottom(logcookie, ctxt->loc_handle))
GOTO(out, rc = 0);
LASSERT(parent != NULL);
OBD_ALLOC(llr, sizeof(*llr));
if (llr == NULL)
- GOTO(out, rc = -ENOMEM);
+ GOTO(out, rc = -ENOMEM);
llr->llr_hdr.lrh_len = llr->llr_tail.lrt_len = sizeof(*llr);
llr->llr_hdr.lrh_type = CACHE_LRU_REC;
llr->llr_pfid.generation = parent->i_generation;
llr->llr_pfid.f_type = parent->i_mode & S_IFMT;
- rc = llog_add(ctxt, &llr->llr_hdr, NULL, logcookie, 1, NULL);
+ rc = llog_add(ctxt, &llr->llr_hdr, NULL, logcookie, 1,
+ NULL, NULL, NULL);
if (rc != 1) {
CERROR("failed at llog_add: %d\n", rc);
GOTO(out, rc);
if (op & CACHE_SPACE_COMMIT) {
if (handle) {
- err = fsops->fs_commit(inode, handle, 0);
+ err = fsops->fs_commit(inode->i_sb, inode, handle, 0);
if (err) {
CERROR("error committing transaction: %d\n", err);
if (!rc)
}
}
}
-out:
+out:
if (logcookie)
OBD_FREE(logcookie, cookie_size);
if (llr)
purge_some_cache(&ndirty);
if (ndirty > 0 || cpurge_stop())
- l_wait_event(cpq->cpq_waitq,
+ l_wait_event(cpq->cpq_waitq,
cpq->cpq_flags & SVC_STOPPING,
&lwi);
if (cpq->cpq_flags & SVC_STOPPING) {
- cpq->cpq_flags &= ~SVC_STOPPING;
+ cpq->cpq_flags &= ~SVC_STOPPING;
EXIT;
break;
}
/* first to initialize the cache lru catalog on local fs */
rc = llog_catalog_setup(&ctxt, CACHE_LRU_LOG,
+ S2SMI(sb)->smsi_exp,
S2SMI(sb)->smsi_ctxt,
S2SMI(sb)->sm_fsfilt,
S2SMI(sb)->smsi_logs_dir,
RETURN(rc);
}
cpq->cpq_sb = sb;
- cpq->cpq_loghandle = ctxt->loc_handle;
+ cpq->cpq_loghandle = ctxt->loc_handle;
/* start cache purge daemon, only one daemon now */
init_waitqueue_head(&cpq->cpq_waitq);
RETURN(0);
err_out:
llog_catalog_cleanup(ctxt);
+ OBD_FREE(ctxt, sizeof(*ctxt));
RETURN(rc);
}
int cache_space_hook_cleanup(void)
{
+ struct llog_ctxt *ctxt;
int rc;
ENTRY;
cpq->cpq_flags = SVC_STOPPING;
wake_up(&cpq->cpq_waitq);
wait_for_completion(&cpq->cpq_comp);
-
- rc = llog_catalog_cleanup(cpq->cpq_loghandle->lgh_ctxt);
- if (rc)
+
+ ctxt = cpq->cpq_loghandle->lgh_ctxt;
+ rc = llog_catalog_cleanup(ctxt);
+ OBD_FREE(ctxt, sizeof(*ctxt));
+ if (rc)
CERROR("failed to clean up cache lru list catalog %d\n", rc);
RETURN(rc);
rc = get_active_entry(dir, &active_entry);
active_entry ++;
if (!rc)
- rc = set_active_entry(dir, &active_entry, handle);
+ rc = set_active_entry(dir, &active_entry, handle);
RETURN(rc);
}
static int cache_space_hook_lookup(void *handle, struct inode *dir,
__u64 active_entry;
int rc = 0;
- if (cache_leaf_node(dentry, &active_entry))
+ if (cache_leaf_node(dentry, &active_entry))
rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
CACHE_SPACE_DELETE | CACHE_SPACE_INSERT,1);
RETURN(rc);
if (cache_pre_leaf_node(dentry, NULL, 1)) {
rc = cache_space_hook_lru(dentry->d_inode, NULL,
- handle, CACHE_SPACE_DELETE, 0);
+ handle, CACHE_SPACE_DELETE, 0);
if (rc)
RETURN(rc);
}
rc = get_active_entry(dir, &active_entry);
active_entry ++;
if (!rc)
- rc = set_active_entry(dir, &active_entry, handle);
+ rc = set_active_entry(dir, &active_entry, handle);
RETURN(rc);
}
static int cache_space_hook_unlink(void *handle, struct inode *dir,
int rc = 0;
if (cache_pre_leaf_node(dentry, NULL, 0))
- rc = cache_space_hook_lru(dentry->d_inode, NULL,
+ rc = cache_space_hook_lru(dentry->d_inode, NULL,
handle, CACHE_SPACE_DELETE, 0);
else if (cache_leaf_node(dentry, NULL))
rc = cache_space_hook_lru(dentry->d_inode, dir,
active_entry --;
if (!rc)
rc = set_active_entry(dir, &active_entry, handle);
- if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
+ if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
rc = cache_space_hook_lru(dir,
dentry->d_parent->d_parent->d_inode,
handle, CACHE_SPACE_INSERT, 0);
RETURN(rc);
}
-static int cache_space_hook_mkdir(void *handle, struct inode *dir,
+static int cache_space_hook_mkdir(void *handle, struct inode *dir,
struct dentry *dentry, struct inode *new_dir,
struct dentry *new_dentry)
{
rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
RETURN(rc);
}
-static int cache_space_hook_rmdir(void *handle, struct inode *dir,
+static int cache_space_hook_rmdir(void *handle, struct inode *dir,
struct dentry *dentry, struct inode *new_dir,
struct dentry *new_dentry)
{
handle, CACHE_SPACE_INSERT, 0);
RETURN(rc);
}
-static int cache_space_hook_rename(void *handle, struct inode *old_dir,
+static int cache_space_hook_rename(void *handle, struct inode *old_dir,
struct dentry *old_dentry, struct inode *new_dir,
struct dentry *new_dentry)
{
typedef int (*cache_hook_op)(void *handle, struct inode *old_dir,
struct dentry *old_dentry, struct inode *new_dir,
struct dentry *new_dentry);
-static cache_hook_op cache_space_hook_ops[CACHE_HOOK_MAX + 1] = {
- [CACHE_HOOK_CREATE] cache_space_hook_create,
- [CACHE_HOOK_LOOKUP] cache_space_hook_lookup,
- [CACHE_HOOK_LINK] cache_space_hook_link,
- [CACHE_HOOK_UNLINK] cache_space_hook_unlink,
- [CACHE_HOOK_SYMLINK] cache_space_hook_create,
- [CACHE_HOOK_MKDIR] cache_space_hook_mkdir,
- [CACHE_HOOK_RMDIR] cache_space_hook_rmdir,
- [CACHE_HOOK_MKNOD] cache_space_hook_create,
- [CACHE_HOOK_RENAME] cache_space_hook_rename,
+
+static cache_hook_op cache_space_hook_ops[HOOK_MAX + 1] = {
+ [HOOK_CREATE] cache_space_hook_create,
+ [HOOK_LOOKUP] cache_space_hook_lookup,
+ [HOOK_LINK] cache_space_hook_link,
+ [HOOK_UNLINK] cache_space_hook_unlink,
+ [HOOK_SYMLINK] cache_space_hook_create,
+ [HOOK_MKDIR] cache_space_hook_mkdir,
+ [HOOK_RMDIR] cache_space_hook_rmdir,
+ [HOOK_MKNOD] cache_space_hook_create,
+ [HOOK_RENAME] cache_space_hook_rename,
+ [HOOK_SETATTR] NULL,
+ [HOOK_WRITE] NULL,
+ [HOOK_READDIR] NULL,
};
int cache_space_post(int op, void *handle, struct inode *old_dir,
struct dentry *old_dentry, struct inode *new_dir,
struct dentry *new_dentry)
{
- int rc;
+ int rc = 0;
ENTRY;
- LASSERT(op <= CACHE_HOOK_MAX && cache_space_hook_ops[op] != NULL);
+ LASSERT(op <= HOOK_MAX + 1);
- rc = cache_space_hook_ops[op](handle, old_dir, old_dentry,
- new_dir, new_dentry);
+ if (cache_space_hook_ops[op])
+ rc = cache_space_hook_ops[op](handle, old_dir, old_dentry,
+ new_dir, new_dentry);
RETURN(rc);
}