Whamcloud - gitweb
landing b_cmobd_merge on HEAD
[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 cpurge */
35         int ndirty;     /* Maximum number of objects to write out per
36                            wake-cycle */
37         int interval;   /* jiffies delay between cache purge */
38         int nfract_sync;/* Percentage of cache dirty to activate
39                            cpurge synchronously */
40         int nfract_stop_cpurge; /* Percentage of cache dirty to stop cpurge */
41 } cf_prm = {30, 512, 600 * HZ, 60, 20};
42
43 static struct cache_purge_queue smfs_cpq;
44 static struct cache_purge_queue *cpq = &smfs_cpq;
45
46 int cache_space_hook_init(struct super_block *sb)
47 {
48         struct smfs_super_info  *smfs_info = S2SMI(sb);
49
50         SMFS_SET_CACHE_HOOK(smfs_info);
51         return 0;
52 }
53 int cache_space_hook_exit(struct super_block *sb)
54 {
55         struct smfs_super_info  *smfs_info = S2SMI(sb);
56
57         SMFS_CLEAN_CACHE_HOOK(smfs_info);
58         return 0;
59 }
60
61 static int cache_leaf_node(struct dentry *dentry, __u64 *active_entry)
62 {
63         struct inode *inode = dentry->d_inode;
64
65         if (S_ISDIR(inode->i_mode)) {
66                 if (inode->i_nlink != 2)
67                         return 0;
68                 if (!strncmp(dentry->d_name.name, "lost+found", dentry->d_name.len))
69                         return 0;
70                 LASSERT(active_entry != NULL);
71                 get_active_entry(inode, active_entry);
72                 return(*active_entry > 0 ? 0 : 1);
73         } else {
74                 if (inode->i_nlink != 1)
75                         return 0;
76                 if (!strncmp(dentry->d_name.name, KML_LOG_NAME, dentry->d_name.len) ||
77                     !strncmp(dentry->d_name.name, CACHE_LRU_LOG, dentry->d_name.len))
78                         return 0;
79                 return 1;
80         }
81 }
82 static int cache_pre_leaf_node(struct dentry *dentry, __u64 *active_entry, int op)
83 {
84         if (((op == 0 && dentry->d_inode->i_nlink == 0) ||
85             (op == 1 && dentry->d_inode->i_nlink == 2)) &&
86             strncmp(dentry->d_name.name, KML_LOG_NAME, dentry->d_name.len) &&
87             strncmp(dentry->d_name.name, CACHE_LRU_LOG, dentry->d_name.len))
88                 return 1;
89         else if ((op == 2 && dentry->d_inode->i_nlink == 0) ||
90                  (op == 3 && dentry->d_inode->i_nlink == 3)) {
91                 LASSERT(active_entry != NULL);
92                 get_active_entry(dentry->d_inode, active_entry);
93                 return(*active_entry > 0 ? 0 : 1);
94         }
95         return 0;
96 }
97
98 static int set_lru_logcookie(struct inode *inode, void *handle,
99                              struct llog_cookie *logcookie)
100 {
101         struct fsfilt_operations *fsops = I2CSB(inode)->sm_fsfilt;
102         int rc;
103         rc = fsops->fs_set_xattr(inode, handle, XATTR_SMFS_CACHE_LOGCOOKIE,
104                                  logcookie, sizeof(*logcookie));
105         RETURN(rc);
106 }
107 static int get_lru_logcookie(struct inode *inode, struct llog_cookie *logcookie)
108 {
109         struct fsfilt_operations *fsops = I2CSB(inode)->sm_fsfilt;
110         int rc;
111         rc = fsops->fs_get_xattr(inode, XATTR_SMFS_CACHE_LOGCOOKIE,
112                                  logcookie, sizeof(*logcookie));
113         RETURN(rc);
114 }
115
116 static int try2purge_from_cache(struct ll_fid cfid, struct ll_fid pfid)
117 {
118         struct inode *inode, *parent;
119         struct super_block *sb = cpq->cpq_sb;
120         //struct llog_cookie logcookie;
121         __u32 hoard_priority = 0;
122         int rc = 0;
123         ENTRY;
124
125         inode = iget(sb, cfid.id);
126         if (IS_ERR(inode)) {
127                 CERROR("not existent inode: "LPX64"/%u\n",
128                        cfid.id, cfid.generation);
129                 RETURN(-ENOENT);
130         }
131         parent = iget(sb, pfid.id);
132         if (IS_ERR(parent)) {
133                 CERROR("not existent inode: "LPX64"/%u\n",
134                        pfid.id, pfid.generation);
135                 iput(inode);
136                 RETURN(-ENOENT);
137         }
138
139         CWARN("inode/parent %lu:%lu on the lru list\n",
140               inode->i_ino, parent->i_ino);
141
142         rc = get_hoard_priority(inode, &hoard_priority);
143         if (hoard_priority) {
144                 CWARN("inode %lu set hoard\n", inode->i_ino);
145                 GOTO(out, rc);
146         }
147         if (atomic_read(&inode->i_count) > 1 || (inode->i_state & I_DIRTY)) {
148                 CWARN("inode %lu is busy\n", inode->i_ino);
149                 GOTO(out, rc = 0);
150         }
151
152 out:
153         iput(inode);
154         iput(parent);
155         RETURN(rc);
156 }
157
158 static int cache_lru_get_rec_cb(struct llog_handle *llh,
159                                 struct llog_rec_hdr *rec, void *data)
160 {
161         struct llog_lru_rec *llr;
162         int count = *(int *)data, rc = 0;
163         ENTRY;
164
165         if (!(le32_to_cpu(llh->lgh_hdr->llh_flags) & LLOG_F_IS_PLAIN)) {
166                 CERROR("log is not plain\n");
167                 RETURN(-EINVAL);
168         }
169         if (rec->lrh_type != CACHE_LRU_REC) {
170                 CERROR("log record type error\n");
171                 RETURN(-EINVAL);
172         }
173
174         llr = (struct llog_lru_rec *)rec;
175
176         if (try2purge_from_cache(llr->llr_cfid, llr->llr_pfid)==1){
177                 CDEBUG(D_INODE, "purge ino/gen "LPX64"/%u from cache\n",
178                        llr->llr_cfid.id, llr->llr_cfid.generation);
179                 count --;
180                 if (count == 0)
181                         rc = LLOG_PROC_BREAK;
182                 *(int *)data = count;
183         }
184
185         RETURN(rc);
186 }
187
188 static int cpurge_stop(void)
189 {
190         struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
191         struct obd_statfs osfs;
192         int rc, free;
193
194         rc = fsops->fs_statfs(cpq->cpq_sb, &osfs);
195         LASSERT(rc == 0);
196
197         free = osfs.os_bfree * 100;
198         if (free < cf_prm.nfract_stop_cpurge * osfs.os_blocks)
199                 return 1;
200         return 0;
201 }
202
203 static int cache_balance_state(void)
204 {
205         struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
206         struct obd_statfs osfs;
207         int rc, free;
208
209         rc = fsops->fs_statfs(cpq->cpq_sb, &osfs);
210         LASSERT(rc == 0);
211
212         free = (osfs.os_blocks - osfs.os_bfree) * 100;
213         if (free > cf_prm.nfract * osfs.os_blocks) {
214                 if (free < cf_prm.nfract_sync)
215                         return 1;
216                 return 0;
217         }
218         return -1;
219 }
220
221 void wakeup_cpurge(void)
222 {
223         wake_up(&cpq->cpq_waitq);
224 }
225
226 /* walk the lru llog to purge count number of objects */
227 static int purge_some_cache(int *count)
228 {
229         int rc;
230         ENTRY;
231
232         rc = llog_cat_process(cpq->cpq_loghandle,
233                               (llog_cb_t)cache_lru_get_rec_cb,
234                               count);
235         if (!rc)
236                 CDEBUG(D_INODE, "no enough objects available\n");
237
238         RETURN(rc);
239 }
240
241 #define CFLUSH_NR 512
242 static void check_cache_space(void)
243 {
244         int state = cache_balance_state();
245         ENTRY;
246
247         if (state < 0)
248                 return;
249
250         wakeup_cpurge();
251
252         if (state > 0) {
253                 int count = CFLUSH_NR;
254                 purge_some_cache(&count);
255         }
256 }
257
258 void cache_space_pre(struct inode *inode, int op)
259 {
260         ENTRY;
261
262         /* FIXME have not used op */
263         check_cache_space();
264 }
265
266 static int cache_space_hook_lru(struct inode *inode, struct inode *parent,
267                      void *handle, int op, int flags)
268 {
269         struct fsfilt_operations *fsops = S2SMI(cpq->cpq_sb)->sm_fsfilt;
270         struct llog_ctxt *ctxt = cpq->cpq_loghandle->lgh_ctxt;
271         struct llog_lru_rec *llr = NULL;
272         struct llog_cookie *logcookie = NULL;
273         int cookie_size = sizeof(struct llog_cookie);
274         int rc = 0, err;
275         ENTRY;
276
277         LASSERT(ctxt != NULL);
278
279         if (op & ~(CACHE_SPACE_DELETE | CACHE_SPACE_INSERT |CACHE_SPACE_COMMIT))
280                 RETURN(-EINVAL);
281
282         OBD_ALLOC(logcookie, cookie_size);
283         if (!logcookie)
284                 GOTO(out, rc = -ENOMEM);
285
286         if (op & CACHE_SPACE_DELETE) {
287                 rc = get_lru_logcookie(inode, logcookie);
288                 if (rc < 0)
289                         GOTO(out, rc);
290
291                 if (logcookie->lgc_lgl.lgl_oid == 0) {
292                         CWARN("inode %lu/%u is not in lru list\n",
293                               inode->i_ino, inode->i_generation);
294                         GOTO(insert, rc = -ENOENT);
295                 }
296                 if (flags && llog_cat_half_bottom(logcookie, ctxt->loc_handle))
297                         GOTO(out, rc = 0);
298
299                 rc = llog_cancel(ctxt, 1, logcookie, 0, NULL);
300                 if (!rc) {
301                         memset(logcookie, 0, cookie_size);
302                         rc = set_lru_logcookie(inode, handle, logcookie);
303                         if (rc)
304                                 GOTO(out, rc);
305                 } else {
306                         CERROR("failed at llog_cancel: %d\n", rc);
307                         GOTO(out, rc);
308                 }
309         }
310
311 insert:
312         if (op & CACHE_SPACE_INSERT) {
313                 LASSERT(parent != NULL);
314                 OBD_ALLOC(llr, sizeof(*llr));
315                 if (llr == NULL)
316                         GOTO(out, rc = -ENOMEM);
317
318                 llr->llr_hdr.lrh_len = llr->llr_tail.lrt_len = sizeof(*llr);
319                 llr->llr_hdr.lrh_type = CACHE_LRU_REC;
320                 llr->llr_cfid.id = inode->i_ino;
321                 llr->llr_cfid.generation = inode->i_generation;
322                 llr->llr_cfid.f_type = inode->i_mode & S_IFMT;
323                 llr->llr_pfid.id = parent->i_ino;
324                 llr->llr_pfid.generation = parent->i_generation;
325                 llr->llr_pfid.f_type = parent->i_mode & S_IFMT;
326
327                 rc = llog_add(ctxt, &llr->llr_hdr, NULL, logcookie, 1, NULL);
328                 if (rc != 1) {
329                         CERROR("failed at llog_add: %d\n", rc);
330                         GOTO(out, rc);
331                 }
332                 rc = set_lru_logcookie(inode, handle, logcookie);
333         }
334
335         if (op & CACHE_SPACE_COMMIT) {
336                 if (handle) {
337                         err = fsops->fs_commit(inode, handle, 0);
338                         if (err) {
339                                 CERROR("error committing transaction: %d\n", err);
340                                 if (!rc)
341                                         rc = err;
342                         }
343                 }
344         }
345 out:
346         if (logcookie)
347                 OBD_FREE(logcookie, cookie_size);
348         if (llr)
349                 OBD_FREE(llr, sizeof(*llr));
350         RETURN(rc);
351 }
352
353 static int cache_purge_thread(void *args)
354 {
355         unsigned long flags;
356         struct l_wait_info lwi = LWI_TIMEOUT(cf_prm.interval * HZ, NULL, NULL);
357         ENTRY;
358
359         lock_kernel();
360         kportal_daemonize("wb_cache_purge");
361
362         SIGNAL_MASK_LOCK(current, flags);
363         sigfillset(&current->blocked);
364         RECALC_SIGPENDING;
365         SIGNAL_MASK_UNLOCK(current, flags);
366
367         unlock_kernel();
368         complete(&cpq->cpq_comp);
369
370         while (1) {
371                 int ndirty = cf_prm.ndirty;
372
373                 purge_some_cache(&ndirty);
374                 if (ndirty > 0 || cpurge_stop())
375                         l_wait_event(cpq->cpq_waitq,
376                                      cpq->cpq_flags & SVC_STOPPING,
377                                      &lwi);
378                 if (cpq->cpq_flags & SVC_STOPPING) {
379                         cpq->cpq_flags &= ~SVC_STOPPING;
380                         EXIT;
381                         break;
382                 }
383         }
384         cpq->cpq_flags = SVC_STOPPED;
385         complete(&cpq->cpq_comp);
386         return 0;
387 }
388
389 int cache_space_hook_setup(struct super_block *sb)
390 {
391         struct llog_ctxt *ctxt;
392         int rc;
393         ENTRY;
394
395         /* first to initialize the cache lru catalog on local fs */
396         rc = llog_catalog_setup(&ctxt, CACHE_LRU_LOG,
397                                 S2SMI(sb)->smsi_exp,
398                                 S2SMI(sb)->smsi_ctxt,
399                                 S2SMI(sb)->sm_fsfilt,
400                                 S2SMI(sb)->smsi_logs_dir,
401                                 S2SMI(sb)->smsi_objects_dir);
402         if (rc) {
403                 CERROR("failed to initialize cache lru list catalog %d\n", rc);
404                 RETURN(rc);
405         }
406         cpq->cpq_sb = sb;
407         cpq->cpq_loghandle = ctxt->loc_handle;
408
409         /* start cache purge daemon, only one daemon now */
410         init_waitqueue_head(&cpq->cpq_waitq);
411         init_completion(&cpq->cpq_comp);
412         cpq->cpq_flags = 0;
413
414         rc = kernel_thread(cache_purge_thread, NULL, CLONE_VM | CLONE_FILES);
415         if (rc < 0) {
416                 CERROR("cannot start thread: %d\n", rc);
417                 GOTO(err_out, rc);
418         }
419         wait_for_completion(&cpq->cpq_comp);
420
421         RETURN(0);
422 err_out:
423         llog_catalog_cleanup(ctxt);
424         OBD_FREE(ctxt, sizeof(*ctxt));
425         RETURN(rc);
426 }
427
428 int cache_space_hook_cleanup(void)
429 {
430         struct llog_ctxt *ctxt;
431         int rc;
432         ENTRY;
433
434         init_completion(&cpq->cpq_comp);
435         cpq->cpq_flags = SVC_STOPPING;
436         wake_up(&cpq->cpq_waitq);
437         wait_for_completion(&cpq->cpq_comp);
438         
439         ctxt = cpq->cpq_loghandle->lgh_ctxt;
440         rc = llog_catalog_cleanup(ctxt);
441         OBD_FREE(ctxt, sizeof(*ctxt));
442         if (rc)
443                 CERROR("failed to clean up cache lru list catalog %d\n", rc);
444
445         RETURN(rc);
446 }
447
448 static int cache_space_hook_create(void *handle, struct inode *dir,
449                                    struct dentry *dentry, struct inode *new_dir,
450                                    struct dentry *new_dentry)
451 {
452         __u64 active_entry = 0;
453         int rc;
454
455         LASSERT(cache_leaf_node(dentry, NULL));
456         rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
457                                   CACHE_SPACE_INSERT, 0);
458         if (rc)
459                 RETURN(rc);
460         if (cache_leaf_node(dentry->d_parent, &active_entry)) {
461                 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
462                 if (rc)
463                         RETURN(rc);
464         }
465         if (!active_entry)
466                 rc = get_active_entry(dir, &active_entry);
467         active_entry ++;
468         if (!rc)
469                 rc = set_active_entry(dir, &active_entry, handle);
470         RETURN(rc);
471 }
472 static int cache_space_hook_lookup(void *handle, struct inode *dir,
473                                    struct dentry *dentry, struct inode *new_dir,
474                                    struct dentry *new_dentry)
475 {
476         __u64 active_entry;
477         int rc = 0;
478
479         if (cache_leaf_node(dentry, &active_entry))
480                 rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
481                                 CACHE_SPACE_DELETE | CACHE_SPACE_INSERT,1);
482         RETURN(rc);
483 }
484 static int cache_space_hook_link(void *handle, struct inode *dir,
485                                  struct dentry *dentry, struct inode *new_dir,
486                                  struct dentry *new_dentry)
487 {
488         __u64 active_entry = 0;
489         int rc = 0;
490
491         if (cache_pre_leaf_node(dentry, NULL, 1)) {
492                 rc = cache_space_hook_lru(dentry->d_inode, NULL,
493                                           handle, CACHE_SPACE_DELETE, 0);
494                 if (rc)
495                         RETURN(rc);
496         }
497
498         if (cache_leaf_node(dentry->d_parent, &active_entry)) {
499                 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
500                 if (rc)
501                         RETURN(rc);
502         }
503
504         if (!active_entry)
505                 rc = get_active_entry(dir, &active_entry);
506         active_entry ++;
507         if (!rc)
508                 rc = set_active_entry(dir, &active_entry, handle);
509         RETURN(rc);
510 }
511 static int cache_space_hook_unlink(void *handle, struct inode *dir,
512                                    struct dentry *dentry, struct inode *new_dir,
513                                    struct dentry *new_dentry)
514 {
515         __u64 active_entry;
516         int rc = 0;
517
518         if (cache_pre_leaf_node(dentry, NULL, 0))
519                 rc = cache_space_hook_lru(dentry->d_inode, NULL,
520                                           handle, CACHE_SPACE_DELETE, 0);
521         else if (cache_leaf_node(dentry, NULL))
522                         rc = cache_space_hook_lru(dentry->d_inode, dir,
523                                                   handle, CACHE_SPACE_INSERT,0);
524         if (rc)
525                 RETURN(rc);
526
527         rc = get_active_entry(dir, &active_entry);
528         active_entry --;
529         if (!rc)
530                 rc = set_active_entry(dir, &active_entry, handle);
531         if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
532                 rc = cache_space_hook_lru(dir,
533                                           dentry->d_parent->d_parent->d_inode,
534                                           handle, CACHE_SPACE_INSERT, 0);
535         RETURN(rc);
536 }
537 static int cache_space_hook_mkdir(void *handle, struct inode *dir,
538                                   struct dentry *dentry, struct inode *new_dir,
539                                   struct dentry *new_dentry)
540 {
541         __u64 active_entry;
542         int rc;
543
544         LASSERT(cache_leaf_node(dentry, &active_entry));
545         rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
546                                   CACHE_SPACE_INSERT,0);
547
548         if (!rc && cache_pre_leaf_node(dentry->d_parent, &active_entry, 3))
549                 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
550         RETURN(rc);
551 }
552 static int cache_space_hook_rmdir(void *handle, struct inode *dir,
553                                   struct dentry *dentry, struct inode *new_dir,
554                                   struct dentry *new_dentry)
555 {
556         __u64 active_entry;
557         int rc;
558
559         LASSERT(cache_pre_leaf_node(dentry, &active_entry, 2));
560         rc = cache_space_hook_lru(dentry->d_inode, NULL, handle,
561                                   CACHE_SPACE_DELETE, 0);
562
563         if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
564                 rc = cache_space_hook_lru(dir,
565                                           dentry->d_parent->d_parent->d_inode,
566                                           handle, CACHE_SPACE_INSERT, 0);
567         RETURN(rc);
568 }
569 static int cache_space_hook_rename(void *handle, struct inode *old_dir,
570                         struct dentry *old_dentry, struct inode *new_dir,
571                         struct dentry *new_dentry)
572 {
573         __u64 active_entry;
574         int rc = 0;
575
576         if (new_dentry->d_inode) {
577                 if (cache_pre_leaf_node(new_dentry, NULL, 0))
578                         rc = cache_space_hook_lru(new_dentry->d_inode, NULL,
579                                                   handle, CACHE_SPACE_DELETE,0);
580                 else if (cache_leaf_node(new_dentry, NULL))
581                         rc = cache_space_hook_lru(new_dentry->d_inode,
582                                                   new_dir, handle,
583                                                   CACHE_SPACE_INSERT,0);
584         }
585
586         if (rc || old_dir == new_dir)
587                 RETURN(rc);
588
589         if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
590                 if (cache_leaf_node(new_dentry->d_parent, &active_entry)) {
591                         rc = cache_space_hook_lru(new_dir, NULL, handle,
592                                                   CACHE_SPACE_DELETE, 0);
593                         if (rc)
594                                 RETURN(rc);
595                 }
596                 if (!active_entry)
597                         rc = get_active_entry(new_dir, &active_entry);
598                 active_entry ++;
599                 if (!rc)
600                         rc = set_active_entry(new_dir, &active_entry, handle);
601                 if (rc)
602                         RETURN(rc);
603                 rc = get_active_entry(old_dir, &active_entry);
604                 active_entry --;
605                 if (!rc)
606                         rc = set_active_entry(old_dir, &active_entry, handle);
607         } else if (cache_pre_leaf_node(new_dentry->d_parent, &active_entry, 3))
608                 rc = cache_space_hook_lru(new_dir, NULL, handle,
609                                           CACHE_SPACE_DELETE, 0);
610
611         if (!rc && cache_leaf_node(old_dentry->d_parent, &active_entry))
612                 rc = cache_space_hook_lru(old_dir,
613                                         old_dentry->d_parent->d_parent->d_inode,
614                                         handle, CACHE_SPACE_INSERT, 0);
615         RETURN(rc);
616 }
617
618 typedef int (*cache_hook_op)(void *handle, struct inode *old_dir,
619                              struct dentry *old_dentry, struct inode *new_dir,
620                              struct dentry *new_dentry);
621 static  cache_hook_op cache_space_hook_ops[CACHE_HOOK_MAX + 1] = {
622         [CACHE_HOOK_CREATE]     cache_space_hook_create,
623         [CACHE_HOOK_LOOKUP]     cache_space_hook_lookup,
624         [CACHE_HOOK_LINK]       cache_space_hook_link,
625         [CACHE_HOOK_UNLINK]     cache_space_hook_unlink,
626         [CACHE_HOOK_SYMLINK]    cache_space_hook_create,
627         [CACHE_HOOK_MKDIR]      cache_space_hook_mkdir,
628         [CACHE_HOOK_RMDIR]      cache_space_hook_rmdir,
629         [CACHE_HOOK_MKNOD]      cache_space_hook_create,
630         [CACHE_HOOK_RENAME]     cache_space_hook_rename,
631 };
632
633 int cache_space_post(int op, void *handle, struct inode *old_dir,
634                struct dentry *old_dentry, struct inode *new_dir,
635                struct dentry *new_dentry)
636 {
637         int rc;
638         ENTRY;
639
640         LASSERT(op <= CACHE_HOOK_MAX && cache_space_hook_ops[op] != NULL);
641
642         rc = cache_space_hook_ops[op](handle, old_dir, old_dentry,
643                                       new_dir, new_dentry);
644         RETURN(rc);
645 }