Whamcloud - gitweb
6b33b2924f797ffa5cbba4b61aea19816a175329
[fs/lustre-release.git] / lustre / smfs / cache_space.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/smfs/cache_space.c
5  *  A library of functions to manage cache space based on ARC
6  *  (modified LRU) replacement algorithm.
7  *
8  *  Copyright (c) 2004 Cluster File Systems, Inc.
9  *
10  *   This file is part of Lustre, http://www.lustre.org.
11  *
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.
15  *
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.
20  *
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.
24  */
25 #define DEBUG_SUBSYSTEM S_SM
26
27 #include <linux/lustre_log.h>
28 #include <linux/lustre_fsfilt.h>
29 #include <linux/lustre_smfs.h>
30
31 #include "smfs_internal.h"
32
33 struct cache_purge_param {
34         int nfract;             /* percentage of cache dirty to activate
35                                  * cpurge */
36         int ndirty;             /* maximum number of objects to write out per
37                                    wake-cycle */
38         int interval;           /* jiffies delay between cache purge */
39         int nfract_sync;        /* percentage of cache dirty to activate cpurge
40                                    synchronously */
41         int nfract_stop_cpurge; /* percentage of cache dirty to stop cpurge */
42 } cf_prm = {30, 512, 600 * HZ, 60, 20};
43
44 static struct cache_purge_queue smfs_cpq;
45 static struct cache_purge_queue *cpq = &smfs_cpq;
46
47 static int cache_leaf_node(struct dentry *dentry, __u64 *active_entry)
48 {
49         struct inode *inode = dentry->d_inode;
50
51         if (!inode)
52                 return 0;
53         
54         if (S_ISDIR(inode->i_mode)) {
55                 if (inode->i_nlink != 2)
56                         return 0;
57                 if (!strncmp((char *)dentry->d_name.name,
58                              "lost+found", dentry->d_name.len))
59                         return 0;
60                 LASSERT(active_entry != NULL);
61                 get_active_entry(inode, active_entry);
62                 return(*active_entry > 0 ? 0 : 1);
63         } else {
64                 if (inode->i_nlink != 1)
65                         return 0;
66                 if (!strncmp((char *)dentry->d_name.name, KML_LOG_NAME, dentry->d_name.len) ||
67                     !strncmp((char *)dentry->d_name.name, CACHE_LRU_LOG, dentry->d_name.len))
68                         return 0;
69                 return 1;
70         }
71 }
72
73 static int cache_pre_leaf_node(struct dentry *dentry, __u64 *active_entry, int op)
74 {
75         if (((op == 0 && dentry->d_inode->i_nlink == 0) ||
76             (op == 1 && dentry->d_inode->i_nlink == 2)) &&
77             strncmp((char *)dentry->d_name.name, KML_LOG_NAME, dentry->d_name.len) &&
78             strncmp((char *)dentry->d_name.name, CACHE_LRU_LOG, dentry->d_name.len))
79                 return 1;
80         else if ((op == 2 && dentry->d_inode->i_nlink == 0) ||
81                  (op == 3 && dentry->d_inode->i_nlink == 3)) {
82                 LASSERT(active_entry != NULL);
83                 get_active_entry(dentry->d_inode, active_entry);
84                 return(*active_entry > 0 ? 0 : 1);
85         }
86         return 0;
87 }
88
89 static int set_lru_logcookie(struct inode *inode, void *handle,
90                              struct llog_cookie *logcookie)
91 {
92         struct fsfilt_operations *fsops = I2CSB(inode)->sm_fsfilt;
93         int rc;
94         ENTRY;
95
96         rc = fsops->fs_set_xattr(inode, handle, XATTR_SMFS_CACHE_LOGCOOKIE,
97                                  logcookie, sizeof(*logcookie));
98         RETURN(rc);
99 }
100
101 static int get_lru_logcookie(struct inode *inode, struct llog_cookie *logcookie)
102 {
103         struct fsfilt_operations *fsops = I2CSB(inode)->sm_fsfilt;
104         int rc;
105         
106         ENTRY;
107         rc = fsops->fs_get_xattr(inode, XATTR_SMFS_CACHE_LOGCOOKIE,
108                                  logcookie, sizeof(*logcookie));
109         RETURN(rc);
110 }
111
112 static int try2purge_from_cache(struct lustre_id cid,
113                                 struct lustre_id pid)
114 {
115         struct inode *inode, *parent;
116         struct super_block *sb = cpq->cpq_sb;
117         __u32 hoard_priority = 0;
118         int rc = 0;
119         ENTRY;
120
121         inode = iget(sb, cid.li_stc.u.e3s.l3s_ino);
122         if (IS_ERR(inode)) {
123                 CERROR("not existent inode: "LPX64"/%u\n",
124                        cid.li_stc.u.e3s.l3s_ino,
125                        cid.li_stc.u.e3s.l3s_gen);
126                 RETURN(-ENOENT);
127         }
128         parent = iget(sb, pid.li_stc.u.e3s.l3s_ino);
129         if (IS_ERR(parent)) {
130                 CERROR("not existent inode: "LPX64"/%u\n",
131                        pid.li_stc.u.e3s.l3s_ino,
132                        pid.li_stc.u.e3s.l3s_gen);
133                 iput(inode);
134                 RETURN(-ENOENT);
135         }
136
137         CWARN("inode/parent %lu:%lu on the lru list\n",
138               inode->i_ino, parent->i_ino);
139
140         rc = get_hoard_priority(inode, &hoard_priority);
141         if (hoard_priority) {
142                 CWARN("inode %lu set hoard\n", inode->i_ino);
143                 GOTO(out, rc);
144         }
145         if (atomic_read(&inode->i_count) > 1 || (inode->i_state & I_DIRTY)) {
146                 CWARN("inode %lu is busy\n", inode->i_ino);
147                 GOTO(out, rc = 0);
148         }
149
150 out:
151         iput(inode);
152         iput(parent);
153         RETURN(rc);
154 }
155
156 static int cache_lru_get_rec_cb(struct llog_handle *llh,
157                                 struct llog_rec_hdr *rec, void *data)
158 {
159         struct llog_lru_rec *llr;
160         int count = *(int *)data, rc = 0;
161         ENTRY;
162
163         if (!(le32_to_cpu(llh->lgh_hdr->llh_flags) & LLOG_F_IS_PLAIN)) {
164                 CERROR("log is not plain\n");
165                 RETURN(-EINVAL);
166         }
167         if (rec->lrh_type != CACHE_LRU_REC) {
168                 CERROR("log record type error\n");
169                 RETURN(-EINVAL);
170         }
171
172         llr = (struct llog_lru_rec *)rec;
173
174         if (try2purge_from_cache(llr->llr_cid, llr->llr_pid)==1){
175                 CDEBUG(D_INODE, "purge ino/gen "LPX64"/%u from cache\n",
176                        llr->llr_cid.li_stc.u.e3s.l3s_ino,
177                        llr->llr_cid.li_stc.u.e3s.l3s_gen);
178                 count --;
179                 if (count == 0)
180                         rc = LLOG_PROC_BREAK;
181                 *(int *)data = count;
182         }
183
184         RETURN(rc);
185 }
186
187 static int cpurge_stop(void)
188 {
189         struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
190         struct obd_statfs osfs;
191         int rc, free;
192
193         rc = fsops->fs_statfs(cpq->cpq_sb, &osfs);
194         LASSERT(rc == 0);
195
196         free = osfs.os_bfree * 100;
197         if (free < cf_prm.nfract_stop_cpurge * osfs.os_blocks)
198                 return 1;
199         return 0;
200 }
201
202 static int cache_balance_state(void)
203 {
204         struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
205         struct obd_statfs osfs;
206         int rc, free;
207
208         rc = fsops->fs_statfs(cpq->cpq_sb, &osfs);
209         LASSERT(rc == 0);
210
211         free = (osfs.os_blocks - osfs.os_bfree) * 100;
212         if (free > cf_prm.nfract * osfs.os_blocks) {
213                 if (free < cf_prm.nfract_sync)
214                         return 1;
215                 return 0;
216         }
217         return -1;
218 }
219
220 void wakeup_cpurge(void)
221 {
222         wake_up(&cpq->cpq_waitq);
223 }
224
225 /* walk the lru llog to purge count number of objects */
226 static int purge_some_cache(int *count)
227 {
228         int rc;
229         ENTRY;
230
231         rc = llog_cat_process(cpq->cpq_loghandle,
232                               (llog_cb_t)cache_lru_get_rec_cb,
233                               count);
234         if (!rc)
235                 CDEBUG(D_INODE, "no enough objects available\n");
236
237         RETURN(rc);
238 }
239
240 #define CFLUSH_NR 512
241
242 static void check_cache_space(void)
243 {
244         int state = cache_balance_state();
245         ENTRY;
246
247         if (state < 0) {
248                 EXIT;
249                 return;
250         }
251
252         wakeup_cpurge();
253
254         if (state > 0) {
255                 int count = CFLUSH_NR;
256                 purge_some_cache(&count);
257         }
258         EXIT;
259 }
260
261 static int cache_space_hook_lru(struct inode *inode, struct inode *parent,
262                                 int op, int flags)
263 {
264         struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
265         struct llog_ctxt *ctxt = cpq->cpq_loghandle->lgh_ctxt;
266         struct llog_lru_rec *llr = NULL;
267         struct llog_cookie *logcookie = NULL;
268         void * handle = NULL;
269         int cookie_size = sizeof(struct llog_cookie);
270         int rc = 0, err;
271         ENTRY;
272
273         LASSERT(ctxt != NULL);
274
275         if (op & ~(CACHE_SPACE_DELETE | CACHE_SPACE_INSERT |CACHE_SPACE_COMMIT))
276                 RETURN(-EINVAL);
277
278         OBD_ALLOC(logcookie, cookie_size);
279         if (!logcookie)
280                 GOTO(out, rc = -ENOMEM);
281
282          if (op & CACHE_SPACE_DELETE) {
283                 rc = get_lru_logcookie(inode, logcookie);
284                 if (rc < 0)
285                         goto out;
286
287                 if (logcookie->lgc_lgl.lgl_oid == 0) {
288                         CWARN("inode %lu/%u is not in lru list\n",
289                               inode->i_ino, inode->i_generation);
290                         rc = -ENOENT;
291                 }
292                 else {
293                         rc = 0;
294                         if (flags && llog_cat_half_bottom(logcookie, ctxt->loc_handle))
295                                goto out;
296
297                         rc = llog_cancel(ctxt, 1, logcookie, 0, NULL);
298                         if (!rc) {
299                                 memset(logcookie, 0, cookie_size);
300                                 rc = set_lru_logcookie(inode, handle, logcookie);
301                         }
302                         if (rc)
303                                         goto out;
304                 }
305         }
306
307          if (op & CACHE_SPACE_INSERT) {
308                 LASSERT(parent != NULL);
309                 OBD_ALLOC(llr, sizeof(*llr));
310                 if (llr == NULL)
311                         GOTO(out, rc = -ENOMEM);
312
313                 llr->llr_hdr.lrh_len = llr->llr_tail.lrt_len = sizeof(*llr);
314                 llr->llr_hdr.lrh_type = CACHE_LRU_REC;
315
316                 /* FIXME-UMKA: should we setup fid components here? */
317                 id_ino(&llr->llr_cid) = inode->i_ino;
318                 id_gen(&llr->llr_cid) = inode->i_generation;
319                 id_type(&llr->llr_cid) = inode->i_mode & S_IFMT;
320
321                 id_ino(&llr->llr_pid) = parent->i_ino;
322                 id_gen(&llr->llr_pid) = parent->i_generation;
323                 id_type(&llr->llr_pid) = parent->i_mode & S_IFMT;
324
325                 rc = llog_add(ctxt, &llr->llr_hdr, NULL, logcookie, 1,
326                               NULL, NULL, NULL);
327                 if (rc != 1) {
328                         CERROR("failed at llog_add: %d\n", rc);
329                         GOTO(out, rc);
330                 }
331                 rc = set_lru_logcookie(inode, handle, logcookie);
332         }
333
334         if (op & CACHE_SPACE_COMMIT) {
335                 if (handle) {
336                         err = fsops->fs_commit(inode->i_sb, inode, handle, 0);
337                         if (err) {
338                                 CERROR("error committing transaction: %d\n", err);
339                                 if (!rc)
340                                         rc = err;
341                         }
342                 }
343         }
344 out:
345         if (logcookie)
346                 OBD_FREE(logcookie, cookie_size);
347         if (llr)
348                 OBD_FREE(llr, sizeof(*llr));
349         RETURN(rc);
350 }
351
352 static int cache_purge_thread(void *args)
353 {
354         unsigned long flags;
355         struct l_wait_info lwi = LWI_TIMEOUT(cf_prm.interval * HZ, NULL, NULL);
356         ENTRY;
357
358         lock_kernel();
359         kportal_daemonize("wb_cache_purge");
360
361         SIGNAL_MASK_LOCK(current, flags);
362         sigfillset(&current->blocked);
363         RECALC_SIGPENDING;
364         SIGNAL_MASK_UNLOCK(current, flags);
365
366         unlock_kernel();
367         complete(&cpq->cpq_comp);
368
369         while (1) {
370                 int ndirty = cf_prm.ndirty;
371
372                 purge_some_cache(&ndirty);
373                 if (ndirty > 0 || cpurge_stop())
374                         l_wait_event(cpq->cpq_waitq,
375                                      cpq->cpq_flags & SVC_STOPPING,
376                                      &lwi);
377                 if (cpq->cpq_flags & SVC_STOPPING) {
378                         cpq->cpq_flags &= ~SVC_STOPPING;
379                         EXIT;
380                         break;
381                 }
382         }
383         cpq->cpq_flags = SVC_STOPPED;
384         complete(&cpq->cpq_comp);
385         RETURN(0);
386 }
387
388 /* Hooks */
389 static int cache_space_hook_create (struct inode *dir, struct dentry * dentry)
390 {
391         __u64 active_entry = 0;
392         int rc;
393         ENTRY;
394
395         LASSERT(cache_leaf_node(dentry, NULL));
396         rc = cache_space_hook_lru(dentry->d_inode, dir, CACHE_SPACE_INSERT, 0);
397         if (rc)
398                 RETURN(rc);
399         if (cache_leaf_node(dentry->d_parent, &active_entry)) {
400                 rc = cache_space_hook_lru(dir, NULL, CACHE_SPACE_DELETE, 0);
401                 if (rc)
402                         RETURN(rc);
403         }
404         if (!active_entry)
405                 rc = get_active_entry(dir, &active_entry);
406         active_entry ++;
407         if (!rc)
408                 rc = set_active_entry(dir, &active_entry, NULL);
409         RETURN(rc);
410 }
411
412 static int cache_space_hook_lookup(struct inode *dir, struct dentry *dentry)
413 {
414         __u64 active_entry;
415         int rc = 0;
416         ENTRY;
417
418         if (cache_leaf_node(dentry, &active_entry))
419                 rc = cache_space_hook_lru(dentry->d_inode, dir, 
420                                           CACHE_SPACE_DELETE | CACHE_SPACE_INSERT, 1);
421         RETURN(rc);
422 }
423
424 static int cache_space_hook_link(struct inode *dir, struct dentry *dentry)
425 {
426         __u64 active_entry = 0;
427         int rc = 0;
428         ENTRY;
429
430         if (cache_pre_leaf_node(dentry, NULL, 1)) {
431                 rc = cache_space_hook_lru(dentry->d_inode, NULL, 
432                                           CACHE_SPACE_DELETE, 0);
433                 if (rc)
434                         RETURN(rc);
435         }
436
437         if (cache_leaf_node(dentry->d_parent, &active_entry)) {
438                 rc = cache_space_hook_lru(dir, NULL, CACHE_SPACE_DELETE, 0);
439                 if (rc)
440                         RETURN(rc);
441         }
442
443         if (!active_entry)
444                 rc = get_active_entry(dir, &active_entry);
445         active_entry ++;
446         if (!rc)
447                 rc = set_active_entry(dir, &active_entry, NULL);
448         RETURN(rc);
449 }
450
451 static int cache_space_hook_unlink(struct inode *dir, struct dentry *dentry)
452 {
453         __u64 active_entry;
454         int rc = 0;
455         ENTRY;
456
457         if (cache_pre_leaf_node(dentry, NULL, 0))
458                 rc = cache_space_hook_lru(dentry->d_inode, NULL,
459                                           CACHE_SPACE_DELETE, 0);
460         else if (cache_leaf_node(dentry, NULL))
461                         rc = cache_space_hook_lru(dentry->d_inode, dir,
462                                                   CACHE_SPACE_INSERT,0);
463         if (rc)
464                 RETURN(rc);
465
466         rc = get_active_entry(dir, &active_entry);
467         active_entry --;
468         if (!rc)
469                 rc = set_active_entry(dir, &active_entry, NULL);
470         if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
471                 rc = cache_space_hook_lru(dir,
472                                           dentry->d_parent->d_parent->d_inode,
473                                           CACHE_SPACE_INSERT, 0);
474         RETURN(rc);
475 }
476
477 static int cache_space_hook_mkdir(struct inode *dir, struct dentry *dentry)
478 {
479         __u64 active_entry;
480         int rc;
481         ENTRY;
482
483         LASSERT(cache_leaf_node(dentry, &active_entry));
484         rc = cache_space_hook_lru(dentry->d_inode, dir, CACHE_SPACE_INSERT, 0);
485
486         if (!rc && cache_pre_leaf_node(dentry->d_parent, &active_entry, 3))
487                 rc = cache_space_hook_lru(dir, NULL, CACHE_SPACE_DELETE, 0);
488         RETURN(rc);
489 }
490
491 static int cache_space_hook_rmdir(struct inode *dir, struct dentry *dentry)
492 {
493         __u64 active_entry;
494         int rc;
495         ENTRY;
496
497         LASSERT(cache_pre_leaf_node(dentry, &active_entry, 2));
498         rc = cache_space_hook_lru(dentry->d_inode, NULL, 
499                                   CACHE_SPACE_DELETE, 0);
500
501         if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
502                 rc = cache_space_hook_lru(dir,
503                                           dentry->d_parent->d_parent->d_inode,
504                                           CACHE_SPACE_INSERT, 0);
505         RETURN(rc);
506 }
507
508 static int cache_space_hook_rename(struct inode *old_dir, struct dentry *old_dentry,
509                                    struct inode *new_dir, struct dentry *new_dentry)
510 {
511         __u64 active_entry;
512         int rc = 0;
513         ENTRY;
514
515         if (new_dentry->d_inode) {
516                 if (cache_pre_leaf_node(new_dentry, NULL, 0))
517                         rc = cache_space_hook_lru(new_dentry->d_inode, NULL,
518                                                   CACHE_SPACE_DELETE,0);
519                 else if (cache_leaf_node(new_dentry, NULL))
520                         rc = cache_space_hook_lru(new_dentry->d_inode,
521                                                   new_dir,
522                                                   CACHE_SPACE_INSERT,0);
523         }
524
525         if (rc || old_dir == new_dir)
526                 RETURN(rc);
527
528         if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
529                 if (cache_leaf_node(new_dentry->d_parent, &active_entry)) {
530                         rc = cache_space_hook_lru(new_dir, NULL,
531                                                   CACHE_SPACE_DELETE, 0);
532                         if (rc)
533                                 RETURN(rc);
534                 }
535                 if (!active_entry)
536                         rc = get_active_entry(new_dir, &active_entry);
537                 active_entry ++;
538                 if (!rc)
539                         rc = set_active_entry(new_dir, &active_entry, NULL);
540                 if (rc)
541                         RETURN(rc);
542                 rc = get_active_entry(old_dir, &active_entry);
543                 active_entry --;
544                 if (!rc)
545                         rc = set_active_entry(old_dir, &active_entry, NULL);
546         } else if (cache_pre_leaf_node(new_dentry->d_parent, &active_entry, 3)) {
547                 rc = cache_space_hook_lru(new_dir, NULL,
548                                           CACHE_SPACE_DELETE, 0);
549         }
550
551         if (!rc && cache_leaf_node(old_dentry->d_parent, &active_entry)) {
552                 rc = cache_space_hook_lru(old_dir,
553                                           old_dentry->d_parent->d_parent->d_inode,
554                                           CACHE_SPACE_INSERT, 0);
555         }
556         
557         RETURN(rc);
558 }
559
560 static int lru_create (struct inode * inode, void * arg)
561 {
562         struct hook_msg * msg = arg;
563         return cache_space_hook_create(inode, msg->dentry);
564 }
565 static int lru_lookup (struct inode * inode, void * arg)
566 {
567         struct hook_msg * msg = arg;
568         return cache_space_hook_lookup(inode, msg->dentry);
569 }
570 static int lru_link (struct inode * inode, void * arg)
571 {
572         struct hook_link_msg * msg = arg;
573         return cache_space_hook_link(inode, msg->dentry);
574 }
575 static int lru_unlink (struct inode * inode, void * arg)
576 {
577         struct hook_unlink_msg * msg = arg;
578         return cache_space_hook_unlink(inode, msg->dentry);
579 }
580 static int lru_symlink (struct inode * inode, void * arg)
581 {
582         struct hook_symlink_msg * msg = arg;
583         return cache_space_hook_create(inode, msg->dentry);
584 }
585 static int lru_mkdir (struct inode * inode, void * arg)
586 {
587         struct hook_msg * msg = arg;
588         return cache_space_hook_mkdir(inode, msg->dentry);
589 }
590 static int lru_rmdir (struct inode * inode, void * arg)
591 {
592         struct hook_unlink_msg * msg = arg;
593         return cache_space_hook_rmdir(inode, msg->dentry);
594 }
595 static int lru_rename (struct inode * inode, void * arg)
596 {
597         struct hook_rename_msg * msg = arg;
598         return cache_space_hook_rename(inode, msg->dentry,
599                                        msg->new_dir, msg->new_dentry);
600 }
601
602
603 typedef int (*post_lru_op)(struct inode *inode, void * msg);
604 static  post_lru_op smfs_lru_post[HOOK_MAX] = {
605         [HOOK_CREATE]     lru_create,
606         [HOOK_LOOKUP]     lru_lookup,
607         [HOOK_LINK]       lru_link,
608         [HOOK_UNLINK]     lru_unlink,
609         [HOOK_SYMLINK]    lru_symlink,
610         [HOOK_MKDIR]      lru_mkdir,
611         [HOOK_RMDIR]      lru_rmdir,
612         [HOOK_MKNOD]      lru_create,
613         [HOOK_RENAME]     lru_rename,
614         [HOOK_SETATTR]    NULL,
615         [HOOK_WRITE]      NULL,
616         [HOOK_READDIR]    NULL,
617 };
618
619 static int smfs_lru_pre_op(int op, struct inode *inode, void * msg, int ret, 
620                            void *priv)
621 {
622         int rc = 0;
623         ENTRY;
624         
625         /* FIXME have not used op */
626         check_cache_space();                                       
627                                                                                
628         RETURN(rc); 
629 }
630
631 static int smfs_lru_post_op(int op, struct inode *inode, void *msg, int ret,
632                             void *priv)
633 {
634         int rc = 0;
635         
636         ENTRY;
637         if (ret)
638                 RETURN(0);
639         
640         if (smfs_lru_post[op])
641                 rc = smfs_lru_post[op](inode, msg);
642         
643         RETURN(rc);                                                             
644 }
645
646 /* Helpers */
647 static int smfs_exit_lru(struct super_block *sb, void * arg, void * priv)
648 {
649         ENTRY;
650
651         smfs_deregister_plugin(sb, SMFS_PLG_LRU);
652                 
653         EXIT;
654         return 0;
655 }
656
657 static int smfs_trans_lru (struct super_block *sb, void *arg, void * priv)
658 {
659         int size;
660         
661         ENTRY;
662         
663         size = 20;//LDISKFS_INDEX_EXTRA_TRANS_BLOCKS+LDISKFS_DATA_TRANS_BLOCKS;
664         
665         RETURN(size);
666 }
667
668 static int smfs_start_lru(struct super_block *sb, void *arg, void * priv)
669 {
670         int rc = 0;
671         struct smfs_super_info * smb = S2SMI(sb);
672         struct llog_ctxt *ctxt;
673         
674         ENTRY;
675         
676         if (SMFS_IS(smb->plg_flags, SMFS_PLG_LRU))
677                 RETURN(0);
678
679         /* first to initialize the cache lru catalog on local fs */
680         rc = llog_catalog_setup(&ctxt, CACHE_LRU_LOG, smb->smsi_exp,
681                                 smb->smsi_ctxt, smb->sm_fsfilt,
682                                 smb->smsi_logs_dir,
683                                 smb->smsi_objects_dir);
684         if (rc) {
685                 CERROR("failed to initialize cache lru list catalog %d\n", rc);
686                 RETURN(rc);
687         }
688         cpq->cpq_sb = sb;
689         cpq->cpq_loghandle = ctxt->loc_handle;
690
691         /* start cache purge daemon, only one daemon now */
692         init_waitqueue_head(&cpq->cpq_waitq);
693         init_completion(&cpq->cpq_comp);
694         cpq->cpq_flags = 0;
695
696         rc = kernel_thread(cache_purge_thread, NULL, CLONE_VM | CLONE_FILES);
697         if (rc < 0) {
698                 CERROR("cannot start thread: %d\n", rc);
699                 goto err_out;
700         }
701         wait_for_completion(&cpq->cpq_comp);
702
703         SMFS_SET(smb->plg_flags, SMFS_PLG_LRU);
704
705         RETURN(0);
706 err_out:
707         llog_catalog_cleanup(ctxt);
708         OBD_FREE(ctxt, sizeof(*ctxt));
709         RETURN(rc);
710 }
711
712 static int smfs_stop_lru(struct super_block *sb, void *arg, void * priv)
713 {
714         struct smfs_super_info * smb = S2SMI(sb);
715         struct llog_ctxt *ctxt;
716         int rc;
717         ENTRY;
718         
719         if (!SMFS_IS(smb->plg_flags, SMFS_PLG_LRU))
720                 RETURN(0);
721
722         SMFS_CLEAR(smb->plg_flags, SMFS_PLG_LRU);
723
724         init_completion(&cpq->cpq_comp);
725         cpq->cpq_flags = SVC_STOPPING;
726         wake_up(&cpq->cpq_waitq);
727         wait_for_completion(&cpq->cpq_comp);
728         
729         ctxt = cpq->cpq_loghandle->lgh_ctxt;
730         rc = llog_catalog_cleanup(ctxt);
731         OBD_FREE(ctxt, sizeof(*ctxt));
732         RETURN(0);        
733 }
734
735 typedef int (*lru_helper)(struct super_block * sb, void *msg, void *);
736 static lru_helper smfs_lru_helpers[PLG_HELPER_MAX] = {
737         [PLG_EXIT]       smfs_exit_lru,
738         [PLG_START]      smfs_start_lru,
739         [PLG_STOP]       smfs_stop_lru,
740         [PLG_TRANS_SIZE] smfs_trans_lru,
741         [PLG_TEST_INODE] NULL,
742         [PLG_SET_INODE]  NULL,
743 };
744
745 static int smfs_lru_help_op(int code, struct super_block * sb,
746                             void * arg, void * priv)
747 {
748         ENTRY;
749         if (smfs_lru_helpers[code])
750                 smfs_lru_helpers[code](sb, arg, priv);
751         RETURN(0);
752 }
753
754 int smfs_init_lru(struct super_block *sb)
755 {
756         struct smfs_plugin plg = {
757                 .plg_type = SMFS_PLG_LRU,
758                 .plg_pre_op = &smfs_lru_pre_op,
759                 .plg_post_op = &smfs_lru_post_op,
760                 .plg_helper = &smfs_lru_help_op,
761                 .plg_private = NULL
762         };
763         int rc = 0;
764         
765         ENTRY;
766
767         rc = smfs_register_plugin(sb, &plg); 
768         
769         RETURN(rc);
770 }
771
772