1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * lustre/smfs/cache_space.c
5 * A library of functions to manage cache space based on ARC
6 * (modified LRU) replacement algorithm.
8 * Copyright (c) 2002, 2003 Cluster File Systems, Inc.
10 * This file is part of Lustre, http://www.lustre.org.
12 * Lustre is free software; you can redistribute it and/or
13 * modify it under the terms of version 2 of the GNU General Public
14 * License as published by the Free Software Foundation.
16 * Lustre is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with Lustre; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define DEBUG_SUBSYSTEM S_SM
27 #include <linux/lustre_log.h>
28 #include <linux/lustre_smfs.h>
30 #include "smfs_internal.h"
32 struct cache_purge_param {
33 int nfract; /* Percentage of cache dirty to activate cpurge */
34 int ndirty; /* Maximum number of objects to write out per
36 int interval; /* jiffies delay between cache purge */
37 int nfract_sync;/* Percentage of cache dirty to activate
38 cpurge synchronously */
39 int nfract_stop_cpurge; /* Percentage of cache dirty to stop cpurge */
40 } cf_prm = {30, 512, 600 * HZ, 60, 20};
42 static struct cache_purge_queue smfs_cpq;
43 static struct cache_purge_queue *cpq = &smfs_cpq;
45 int cache_space_hook_init(struct super_block *sb)
47 struct smfs_super_info *smfs_info = S2SMI(sb);
49 SMFS_SET_CACHE_HOOK(smfs_info);
52 int cache_space_hook_exit(struct super_block *sb)
54 struct smfs_super_info *smfs_info = S2SMI(sb);
56 SMFS_CLEAN_CACHE_HOOK(smfs_info);
59 int smfs_cache_hook(struct inode *inode)
61 struct smfs_super_info *smfs_info = I2CSB(inode);
63 if (SMFS_CACHE_HOOK(smfs_info) && SMFS_INIT_REC(smfs_info)
64 && SMFS_INODE_CACHE_HOOK(inode))
70 static int cache_leaf_node(struct dentry *dentry, __u64 *active_entry)
72 struct inode *inode = dentry->d_inode;
74 if (S_ISDIR(inode->i_mode)) {
75 if (inode->i_nlink != 2)
77 if (!strncmp(dentry->d_name.name, "lost+found", dentry->d_name.len))
79 LASSERT(active_entry != NULL);
80 get_active_entry(inode, active_entry);
81 return(*active_entry > 0 ? 0 : 1);
83 if (inode->i_nlink != 1)
85 if (!strncmp(dentry->d_name.name, KML_LOG_NAME, dentry->d_name.len) ||
86 !strncmp(dentry->d_name.name, CACHE_LRU_LOG, dentry->d_name.len))
91 static int cache_pre_leaf_node(struct dentry *dentry, __u64 *active_entry, int op)
93 if (((op == 0 && dentry->d_inode->i_nlink == 0) ||
94 (op == 1 && dentry->d_inode->i_nlink == 2)) &&
95 strncmp(dentry->d_name.name, KML_LOG_NAME, dentry->d_name.len) &&
96 strncmp(dentry->d_name.name, CACHE_LRU_LOG, dentry->d_name.len))
98 else if ((op == 2 && dentry->d_inode->i_nlink == 0) ||
99 (op == 3 && dentry->d_inode->i_nlink == 3)) {
100 LASSERT(active_entry != NULL);
101 get_active_entry(dentry->d_inode, active_entry);
102 return(*active_entry > 0 ? 0 : 1);
107 static int set_lru_logcookie(struct inode *inode, void *handle,
108 struct llog_cookie *logcookie)
110 struct fsfilt_operations *fsops = I2CSB(inode)->sm_fsfilt;
112 rc = fsops->fs_set_xattr(inode, handle, XATTR_SMFS_CACHE_LOGCOOKIE,
113 logcookie, sizeof(*logcookie));
116 static int get_lru_logcookie(struct inode *inode, struct llog_cookie *logcookie)
118 struct fsfilt_operations *fsops = I2CSB(inode)->sm_fsfilt;
120 rc = fsops->fs_get_xattr(inode, XATTR_SMFS_CACHE_LOGCOOKIE,
121 logcookie, sizeof(*logcookie));
125 static int try2purge_from_cache(struct ll_fid cfid, struct ll_fid pfid)
127 struct inode *inode, *parent;
128 struct super_block *sb = cpq->cpq_sb;
129 //struct llog_cookie logcookie;
130 __u32 hoard_priority = 0;
134 inode = iget(sb, cfid.id);
136 CERROR("not existent inode: "LPX64"/%u\n",
137 cfid.id, cfid.generation);
140 parent = iget(sb, pfid.id);
141 if (IS_ERR(parent)) {
142 CERROR("not existent inode: "LPX64"/%u\n",
143 pfid.id, pfid.generation);
148 CWARN("inode/parent %lu:%lu on the lru list\n",
149 inode->i_ino, parent->i_ino);
151 rc = get_hoard_priority(inode, &hoard_priority);
152 if (hoard_priority) {
153 CWARN("inode %lu set hoard\n", inode->i_ino);
156 if (atomic_read(&inode->i_count) > 1 || (inode->i_state & I_DIRTY)) {
157 CWARN("inode %lu is busy\n", inode->i_ino);
167 static int cache_lru_get_rec_cb(struct llog_handle *llh,
168 struct llog_rec_hdr *rec, void *data)
170 struct llog_lru_rec *llr;
171 int count = *(int *)data, rc = 0;
174 if (!(le32_to_cpu(llh->lgh_hdr->llh_flags) & LLOG_F_IS_PLAIN)) {
175 CERROR("log is not plain\n");
178 if (rec->lrh_type != CACHE_LRU_REC) {
179 CERROR("log record type error\n");
183 llr = (struct llog_lru_rec *)rec;
185 if (try2purge_from_cache(llr->llr_cfid, llr->llr_pfid)==1){
186 CDEBUG(D_INODE, "purge ino/gen "LPX64"/%u from cache\n",
187 llr->llr_cfid.id, llr->llr_cfid.generation);
190 rc = LLOG_PROC_BREAK;
191 *(int *)data = count;
197 static int cpurge_stop(void)
199 struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
200 struct obd_statfs osfs;
203 rc = fsops->fs_statfs(cpq->cpq_sb, &osfs);
206 free = osfs.os_bfree * 100;
207 if (free < cf_prm.nfract_stop_cpurge * osfs.os_blocks)
212 static int cache_balance_state(void)
214 struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
215 struct obd_statfs osfs;
218 rc = fsops->fs_statfs(cpq->cpq_sb, &osfs);
221 free = (osfs.os_blocks - osfs.os_bfree) * 100;
222 if (free > cf_prm.nfract * osfs.os_blocks) {
223 if (free < cf_prm.nfract_sync)
230 void wakeup_cpurge(void)
232 wake_up(&cpq->cpq_waitq);
235 /* walk the lru llog to purge count number of objects */
236 static int purge_some_cache(int *count)
241 rc = llog_cat_process(cpq->cpq_loghandle,
242 (llog_cb_t)cache_lru_get_rec_cb,
245 CDEBUG(D_INODE, "no enough objects available\n");
250 #define CFLUSH_NR 512
251 static void check_cache_space(void)
253 int state = cache_balance_state();
262 int count = CFLUSH_NR;
263 purge_some_cache(&count);
267 void cache_space_pre(struct inode *inode, int op)
271 /* FIXME have not used op */
275 static int cache_space_hook_lru(struct inode *inode, struct inode *parent,
276 void *handle, int op, int flags)
278 struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
279 struct llog_ctxt *ctxt = cpq->cpq_loghandle->lgh_ctxt;
280 struct llog_lru_rec *llr = NULL;
281 struct llog_cookie *logcookie = NULL;
282 int cookie_size = sizeof(struct llog_cookie);
286 LASSERT(ctxt != NULL);
288 if (op & ~(CACHE_SPACE_DELETE | CACHE_SPACE_INSERT |CACHE_SPACE_COMMIT))
291 OBD_ALLOC(logcookie, cookie_size);
293 GOTO(out, rc = -ENOMEM);
295 if (op & CACHE_SPACE_DELETE) {
296 rc = get_lru_logcookie(inode, logcookie);
300 if (logcookie->lgc_lgl.lgl_oid == 0) {
301 CWARN("inode %lu/%u is not in lru list\n",
302 inode->i_ino, inode->i_generation);
303 GOTO(insert, rc = -ENOENT);
305 if (flags && llog_cat_half_bottom(logcookie, ctxt->loc_handle))
308 rc = llog_cancel(ctxt, 1, logcookie, 0, NULL);
310 memset(logcookie, 0, cookie_size);
311 rc = set_lru_logcookie(inode, handle, logcookie);
315 CERROR("failed at llog_cancel: %d\n", rc);
321 if (op & CACHE_SPACE_INSERT) {
322 LASSERT(parent != NULL);
323 OBD_ALLOC(llr, sizeof(*llr));
325 GOTO(out, rc = -ENOMEM);
327 llr->llr_hdr.lrh_len = llr->llr_tail.lrt_len = sizeof(*llr);
328 llr->llr_hdr.lrh_type = CACHE_LRU_REC;
329 llr->llr_cfid.id = inode->i_ino;
330 llr->llr_cfid.generation = inode->i_generation;
331 llr->llr_cfid.f_type = inode->i_mode & S_IFMT;
332 llr->llr_pfid.id = parent->i_ino;
333 llr->llr_pfid.generation = parent->i_generation;
334 llr->llr_pfid.f_type = parent->i_mode & S_IFMT;
336 rc = llog_add(ctxt, &llr->llr_hdr, NULL, logcookie, 1, NULL);
338 CERROR("failed at llog_add: %d\n", rc);
341 rc = set_lru_logcookie(inode, handle, logcookie);
344 if (op & CACHE_SPACE_COMMIT) {
346 err = fsops->fs_commit(inode, handle, 0);
348 CERROR("error committing transaction: %d\n", err);
356 OBD_FREE(logcookie, cookie_size);
358 OBD_FREE(llr, sizeof(*llr));
362 static int cache_purge_thread(void *args)
365 struct l_wait_info lwi = LWI_TIMEOUT(cf_prm.interval * HZ, NULL, NULL);
369 kportal_daemonize("wb_cache_purge");
371 SIGNAL_MASK_LOCK(current, flags);
372 sigfillset(¤t->blocked);
374 SIGNAL_MASK_UNLOCK(current, flags);
377 complete(&cpq->cpq_comp);
380 int ndirty = cf_prm.ndirty;
382 purge_some_cache(&ndirty);
383 if (ndirty > 0 || cpurge_stop())
384 l_wait_event(cpq->cpq_waitq,
385 cpq->cpq_flags & SVC_STOPPING,
387 if (cpq->cpq_flags & SVC_STOPPING) {
388 cpq->cpq_flags &= ~SVC_STOPPING;
393 cpq->cpq_flags = SVC_STOPPED;
394 complete(&cpq->cpq_comp);
398 int cache_space_hook_setup(struct super_block *sb)
400 struct llog_ctxt *ctxt;
404 /* first to initialize the cache lru catalog on local fs */
405 rc = llog_catalog_setup(&ctxt, CACHE_LRU_LOG,
406 S2SMI(sb)->smsi_ctxt,
407 S2SMI(sb)->sm_fsfilt,
408 S2SMI(sb)->smsi_logs_dir,
409 S2SMI(sb)->smsi_objects_dir);
411 CERROR("failed to initialize cache lru list catalog %d\n", rc);
415 cpq->cpq_loghandle = ctxt->loc_handle;
417 /* start cache purge daemon, only one daemon now */
418 init_waitqueue_head(&cpq->cpq_waitq);
419 init_completion(&cpq->cpq_comp);
422 rc = kernel_thread(cache_purge_thread, NULL, CLONE_VM | CLONE_FILES);
424 CERROR("cannot start thread: %d\n", rc);
427 wait_for_completion(&cpq->cpq_comp);
431 llog_catalog_cleanup(ctxt);
435 int cache_space_hook_cleanup(void)
440 init_completion(&cpq->cpq_comp);
441 cpq->cpq_flags = SVC_STOPPING;
442 wake_up(&cpq->cpq_waitq);
443 wait_for_completion(&cpq->cpq_comp);
445 rc = llog_catalog_cleanup(cpq->cpq_loghandle->lgh_ctxt);
447 CERROR("failed to clean up cache lru list catalog %d\n", rc);
452 static int cache_space_hook_create(void *handle, struct inode *dir,
453 struct dentry *dentry, struct inode *new_dir,
454 struct dentry *new_dentry)
456 __u64 active_entry = 0;
459 LASSERT(cache_leaf_node(dentry, NULL));
460 rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
461 CACHE_SPACE_INSERT, 0);
464 if (cache_leaf_node(dentry->d_parent, &active_entry)) {
465 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
470 rc = get_active_entry(dir, &active_entry);
473 rc = set_active_entry(dir, &active_entry, handle);
476 static int cache_space_hook_lookup(void *handle, struct inode *dir,
477 struct dentry *dentry, struct inode *new_dir,
478 struct dentry *new_dentry)
483 if (cache_leaf_node(dentry, &active_entry))
484 rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
485 CACHE_SPACE_DELETE | CACHE_SPACE_INSERT,1);
488 static int cache_space_hook_link(void *handle, struct inode *dir,
489 struct dentry *dentry, struct inode *new_dir,
490 struct dentry *new_dentry)
492 __u64 active_entry = 0;
495 if (cache_pre_leaf_node(dentry, NULL, 1)) {
496 rc = cache_space_hook_lru(dentry->d_inode, NULL,
497 handle, CACHE_SPACE_DELETE, 0);
502 if (cache_leaf_node(dentry->d_parent, &active_entry)) {
503 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
509 rc = get_active_entry(dir, &active_entry);
512 rc = set_active_entry(dir, &active_entry, handle);
515 static int cache_space_hook_unlink(void *handle, struct inode *dir,
516 struct dentry *dentry, struct inode *new_dir,
517 struct dentry *new_dentry)
522 if (cache_pre_leaf_node(dentry, NULL, 0))
523 rc = cache_space_hook_lru(dentry->d_inode, NULL,
524 handle, CACHE_SPACE_DELETE, 0);
525 else if (cache_leaf_node(dentry, NULL))
526 rc = cache_space_hook_lru(dentry->d_inode, dir,
527 handle, CACHE_SPACE_INSERT,0);
531 rc = get_active_entry(dir, &active_entry);
534 rc = set_active_entry(dir, &active_entry, handle);
535 if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
536 rc = cache_space_hook_lru(dir,
537 dentry->d_parent->d_parent->d_inode,
538 handle, CACHE_SPACE_INSERT, 0);
541 static int cache_space_hook_mkdir(void *handle, struct inode *dir,
542 struct dentry *dentry, struct inode *new_dir,
543 struct dentry *new_dentry)
548 LASSERT(cache_leaf_node(dentry, &active_entry));
549 rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
550 CACHE_SPACE_INSERT,0);
552 if (!rc && cache_pre_leaf_node(dentry->d_parent, &active_entry, 3))
553 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
556 static int cache_space_hook_rmdir(void *handle, struct inode *dir,
557 struct dentry *dentry, struct inode *new_dir,
558 struct dentry *new_dentry)
563 LASSERT(cache_pre_leaf_node(dentry, &active_entry, 2));
564 rc = cache_space_hook_lru(dentry->d_inode, NULL, handle,
565 CACHE_SPACE_DELETE, 0);
567 if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
568 rc = cache_space_hook_lru(dir,
569 dentry->d_parent->d_parent->d_inode,
570 handle, CACHE_SPACE_INSERT, 0);
573 static int cache_space_hook_rename(void *handle, struct inode *old_dir,
574 struct dentry *old_dentry, struct inode *new_dir,
575 struct dentry *new_dentry)
580 if (new_dentry->d_inode) {
581 if (cache_pre_leaf_node(new_dentry, NULL, 0))
582 rc = cache_space_hook_lru(new_dentry->d_inode, NULL,
583 handle, CACHE_SPACE_DELETE,0);
584 else if (cache_leaf_node(new_dentry, NULL))
585 rc = cache_space_hook_lru(new_dentry->d_inode,
587 CACHE_SPACE_INSERT,0);
590 if (rc || old_dir == new_dir)
593 if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
594 if (cache_leaf_node(new_dentry->d_parent, &active_entry)) {
595 rc = cache_space_hook_lru(new_dir, NULL, handle,
596 CACHE_SPACE_DELETE, 0);
601 rc = get_active_entry(new_dir, &active_entry);
604 rc = set_active_entry(new_dir, &active_entry, handle);
607 rc = get_active_entry(old_dir, &active_entry);
610 rc = set_active_entry(old_dir, &active_entry, handle);
611 } else if (cache_pre_leaf_node(new_dentry->d_parent, &active_entry, 3))
612 rc = cache_space_hook_lru(new_dir, NULL, handle,
613 CACHE_SPACE_DELETE, 0);
615 if (!rc && cache_leaf_node(old_dentry->d_parent, &active_entry))
616 rc = cache_space_hook_lru(old_dir,
617 old_dentry->d_parent->d_parent->d_inode,
618 handle, CACHE_SPACE_INSERT, 0);
622 typedef int (*cache_hook_op)(void *handle, struct inode *old_dir,
623 struct dentry *old_dentry, struct inode *new_dir,
624 struct dentry *new_dentry);
625 static cache_hook_op cache_space_hook_ops[CACHE_HOOK_MAX + 1] = {
626 [CACHE_HOOK_CREATE] cache_space_hook_create,
627 [CACHE_HOOK_LOOKUP] cache_space_hook_lookup,
628 [CACHE_HOOK_LINK] cache_space_hook_link,
629 [CACHE_HOOK_UNLINK] cache_space_hook_unlink,
630 [CACHE_HOOK_SYMLINK] cache_space_hook_create,
631 [CACHE_HOOK_MKDIR] cache_space_hook_mkdir,
632 [CACHE_HOOK_RMDIR] cache_space_hook_rmdir,
633 [CACHE_HOOK_MKNOD] cache_space_hook_create,
634 [CACHE_HOOK_RENAME] cache_space_hook_rename,
637 int cache_space_post(int op, void *handle, struct inode *old_dir,
638 struct dentry *old_dentry, struct inode *new_dir,
639 struct dentry *new_dentry)
644 LASSERT(op <= CACHE_HOOK_MAX && cache_space_hook_ops[op] != NULL);
646 rc = cache_space_hook_ops[op](handle, old_dir, old_dentry,
647 new_dir, new_dentry);