Whamcloud - gitweb
b=3550
[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,
328                               NULL, NULL, NULL);
329                 if (rc != 1) {
330                         CERROR("failed at llog_add: %d\n", rc);
331                         GOTO(out, rc);
332                 }
333                 rc = set_lru_logcookie(inode, handle, logcookie);
334         }
335
336         if (op & CACHE_SPACE_COMMIT) {
337                 if (handle) {
338                         err = fsops->fs_commit(inode->i_sb, inode, handle, 0);
339                         if (err) {
340                                 CERROR("error committing transaction: %d\n", err);
341                                 if (!rc)
342                                         rc = err;
343                         }
344                 }
345         }
346 out:
347         if (logcookie)
348                 OBD_FREE(logcookie, cookie_size);
349         if (llr)
350                 OBD_FREE(llr, sizeof(*llr));
351         RETURN(rc);
352 }
353
354 static int cache_purge_thread(void *args)
355 {
356         unsigned long flags;
357         struct l_wait_info lwi = LWI_TIMEOUT(cf_prm.interval * HZ, NULL, NULL);
358         ENTRY;
359
360         lock_kernel();
361         kportal_daemonize("wb_cache_purge");
362
363         SIGNAL_MASK_LOCK(current, flags);
364         sigfillset(&current->blocked);
365         RECALC_SIGPENDING;
366         SIGNAL_MASK_UNLOCK(current, flags);
367
368         unlock_kernel();
369         complete(&cpq->cpq_comp);
370
371         while (1) {
372                 int ndirty = cf_prm.ndirty;
373
374                 purge_some_cache(&ndirty);
375                 if (ndirty > 0 || cpurge_stop())
376                         l_wait_event(cpq->cpq_waitq,
377                                      cpq->cpq_flags & SVC_STOPPING,
378                                      &lwi);
379                 if (cpq->cpq_flags & SVC_STOPPING) {
380                         cpq->cpq_flags &= ~SVC_STOPPING;
381                         EXIT;
382                         break;
383                 }
384         }
385         cpq->cpq_flags = SVC_STOPPED;
386         complete(&cpq->cpq_comp);
387         return 0;
388 }
389
390 int cache_space_hook_setup(struct super_block *sb)
391 {
392         struct llog_ctxt *ctxt;
393         int rc;
394         ENTRY;
395
396         /* first to initialize the cache lru catalog on local fs */
397         rc = llog_catalog_setup(&ctxt, CACHE_LRU_LOG,
398                                 S2SMI(sb)->smsi_exp,
399                                 S2SMI(sb)->smsi_ctxt,
400                                 S2SMI(sb)->sm_fsfilt,
401                                 S2SMI(sb)->smsi_logs_dir,
402                                 S2SMI(sb)->smsi_objects_dir);
403         if (rc) {
404                 CERROR("failed to initialize cache lru list catalog %d\n", rc);
405                 RETURN(rc);
406         }
407         cpq->cpq_sb = sb;
408         cpq->cpq_loghandle = ctxt->loc_handle;
409
410         /* start cache purge daemon, only one daemon now */
411         init_waitqueue_head(&cpq->cpq_waitq);
412         init_completion(&cpq->cpq_comp);
413         cpq->cpq_flags = 0;
414
415         rc = kernel_thread(cache_purge_thread, NULL, CLONE_VM | CLONE_FILES);
416         if (rc < 0) {
417                 CERROR("cannot start thread: %d\n", rc);
418                 GOTO(err_out, rc);
419         }
420         wait_for_completion(&cpq->cpq_comp);
421
422         RETURN(0);
423 err_out:
424         llog_catalog_cleanup(ctxt);
425         OBD_FREE(ctxt, sizeof(*ctxt));
426         RETURN(rc);
427 }
428
429 int cache_space_hook_cleanup(void)
430 {
431         struct llog_ctxt *ctxt;
432         int rc;
433         ENTRY;
434
435         init_completion(&cpq->cpq_comp);
436         cpq->cpq_flags = SVC_STOPPING;
437         wake_up(&cpq->cpq_waitq);
438         wait_for_completion(&cpq->cpq_comp);
439         
440         ctxt = cpq->cpq_loghandle->lgh_ctxt;
441         rc = llog_catalog_cleanup(ctxt);
442         OBD_FREE(ctxt, sizeof(*ctxt));
443         if (rc)
444                 CERROR("failed to clean up cache lru list catalog %d\n", rc);
445
446         RETURN(rc);
447 }
448
449 static int cache_space_hook_create(void *handle, struct inode *dir,
450                                    struct dentry *dentry, struct inode *new_dir,
451                                    struct dentry *new_dentry)
452 {
453         __u64 active_entry = 0;
454         int rc;
455
456         LASSERT(cache_leaf_node(dentry, NULL));
457         rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
458                                   CACHE_SPACE_INSERT, 0);
459         if (rc)
460                 RETURN(rc);
461         if (cache_leaf_node(dentry->d_parent, &active_entry)) {
462                 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
463                 if (rc)
464                         RETURN(rc);
465         }
466         if (!active_entry)
467                 rc = get_active_entry(dir, &active_entry);
468         active_entry ++;
469         if (!rc)
470                 rc = set_active_entry(dir, &active_entry, handle);
471         RETURN(rc);
472 }
473 static int cache_space_hook_lookup(void *handle, struct inode *dir,
474                                    struct dentry *dentry, struct inode *new_dir,
475                                    struct dentry *new_dentry)
476 {
477         __u64 active_entry;
478         int rc = 0;
479
480         if (cache_leaf_node(dentry, &active_entry))
481                 rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
482                                 CACHE_SPACE_DELETE | CACHE_SPACE_INSERT,1);
483         RETURN(rc);
484 }
485 static int cache_space_hook_link(void *handle, struct inode *dir,
486                                  struct dentry *dentry, struct inode *new_dir,
487                                  struct dentry *new_dentry)
488 {
489         __u64 active_entry = 0;
490         int rc = 0;
491
492         if (cache_pre_leaf_node(dentry, NULL, 1)) {
493                 rc = cache_space_hook_lru(dentry->d_inode, NULL,
494                                           handle, CACHE_SPACE_DELETE, 0);
495                 if (rc)
496                         RETURN(rc);
497         }
498
499         if (cache_leaf_node(dentry->d_parent, &active_entry)) {
500                 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
501                 if (rc)
502                         RETURN(rc);
503         }
504
505         if (!active_entry)
506                 rc = get_active_entry(dir, &active_entry);
507         active_entry ++;
508         if (!rc)
509                 rc = set_active_entry(dir, &active_entry, handle);
510         RETURN(rc);
511 }
512 static int cache_space_hook_unlink(void *handle, struct inode *dir,
513                                    struct dentry *dentry, struct inode *new_dir,
514                                    struct dentry *new_dentry)
515 {
516         __u64 active_entry;
517         int rc = 0;
518
519         if (cache_pre_leaf_node(dentry, NULL, 0))
520                 rc = cache_space_hook_lru(dentry->d_inode, NULL,
521                                           handle, CACHE_SPACE_DELETE, 0);
522         else if (cache_leaf_node(dentry, NULL))
523                         rc = cache_space_hook_lru(dentry->d_inode, dir,
524                                                   handle, CACHE_SPACE_INSERT,0);
525         if (rc)
526                 RETURN(rc);
527
528         rc = get_active_entry(dir, &active_entry);
529         active_entry --;
530         if (!rc)
531                 rc = set_active_entry(dir, &active_entry, handle);
532         if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
533                 rc = cache_space_hook_lru(dir,
534                                           dentry->d_parent->d_parent->d_inode,
535                                           handle, CACHE_SPACE_INSERT, 0);
536         RETURN(rc);
537 }
538 static int cache_space_hook_mkdir(void *handle, struct inode *dir,
539                                   struct dentry *dentry, struct inode *new_dir,
540                                   struct dentry *new_dentry)
541 {
542         __u64 active_entry;
543         int rc;
544
545         LASSERT(cache_leaf_node(dentry, &active_entry));
546         rc = cache_space_hook_lru(dentry->d_inode, dir, handle,
547                                   CACHE_SPACE_INSERT,0);
548
549         if (!rc && cache_pre_leaf_node(dentry->d_parent, &active_entry, 3))
550                 rc = cache_space_hook_lru(dir,NULL,handle,CACHE_SPACE_DELETE,0);
551         RETURN(rc);
552 }
553 static int cache_space_hook_rmdir(void *handle, struct inode *dir,
554                                   struct dentry *dentry, struct inode *new_dir,
555                                   struct dentry *new_dentry)
556 {
557         __u64 active_entry;
558         int rc;
559
560         LASSERT(cache_pre_leaf_node(dentry, &active_entry, 2));
561         rc = cache_space_hook_lru(dentry->d_inode, NULL, handle,
562                                   CACHE_SPACE_DELETE, 0);
563
564         if (!rc && cache_leaf_node(dentry->d_parent, &active_entry))
565                 rc = cache_space_hook_lru(dir,
566                                           dentry->d_parent->d_parent->d_inode,
567                                           handle, CACHE_SPACE_INSERT, 0);
568         RETURN(rc);
569 }
570 static int cache_space_hook_rename(void *handle, struct inode *old_dir,
571                         struct dentry *old_dentry, struct inode *new_dir,
572                         struct dentry *new_dentry)
573 {
574         __u64 active_entry;
575         int rc = 0;
576
577         if (new_dentry->d_inode) {
578                 if (cache_pre_leaf_node(new_dentry, NULL, 0))
579                         rc = cache_space_hook_lru(new_dentry->d_inode, NULL,
580                                                   handle, CACHE_SPACE_DELETE,0);
581                 else if (cache_leaf_node(new_dentry, NULL))
582                         rc = cache_space_hook_lru(new_dentry->d_inode,
583                                                   new_dir, handle,
584                                                   CACHE_SPACE_INSERT,0);
585         }
586
587         if (rc || old_dir == new_dir)
588                 RETURN(rc);
589
590         if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
591                 if (cache_leaf_node(new_dentry->d_parent, &active_entry)) {
592                         rc = cache_space_hook_lru(new_dir, NULL, handle,
593                                                   CACHE_SPACE_DELETE, 0);
594                         if (rc)
595                                 RETURN(rc);
596                 }
597                 if (!active_entry)
598                         rc = get_active_entry(new_dir, &active_entry);
599                 active_entry ++;
600                 if (!rc)
601                         rc = set_active_entry(new_dir, &active_entry, handle);
602                 if (rc)
603                         RETURN(rc);
604                 rc = get_active_entry(old_dir, &active_entry);
605                 active_entry --;
606                 if (!rc)
607                         rc = set_active_entry(old_dir, &active_entry, handle);
608         } else if (cache_pre_leaf_node(new_dentry->d_parent, &active_entry, 3))
609                 rc = cache_space_hook_lru(new_dir, NULL, handle,
610                                           CACHE_SPACE_DELETE, 0);
611
612         if (!rc && cache_leaf_node(old_dentry->d_parent, &active_entry))
613                 rc = cache_space_hook_lru(old_dir,
614                                         old_dentry->d_parent->d_parent->d_inode,
615                                         handle, CACHE_SPACE_INSERT, 0);
616         RETURN(rc);
617 }
618
619 typedef int (*cache_hook_op)(void *handle, struct inode *old_dir,
620                              struct dentry *old_dentry, struct inode *new_dir,
621                              struct dentry *new_dentry);
622 static  cache_hook_op cache_space_hook_ops[CACHE_HOOK_MAX + 1] = {
623         [CACHE_HOOK_CREATE]     cache_space_hook_create,
624         [CACHE_HOOK_LOOKUP]     cache_space_hook_lookup,
625         [CACHE_HOOK_LINK]       cache_space_hook_link,
626         [CACHE_HOOK_UNLINK]     cache_space_hook_unlink,
627         [CACHE_HOOK_SYMLINK]    cache_space_hook_create,
628         [CACHE_HOOK_MKDIR]      cache_space_hook_mkdir,
629         [CACHE_HOOK_RMDIR]      cache_space_hook_rmdir,
630         [CACHE_HOOK_MKNOD]      cache_space_hook_create,
631         [CACHE_HOOK_RENAME]     cache_space_hook_rename,
632 };
633
634 int cache_space_post(int op, void *handle, struct inode *old_dir,
635                struct dentry *old_dentry, struct inode *new_dir,
636                struct dentry *new_dentry)
637 {
638         int rc;
639         ENTRY;
640
641         LASSERT(op <= CACHE_HOOK_MAX && cache_space_hook_ops[op] != NULL);
642
643         rc = cache_space_hook_ops[op](handle, old_dir, old_dentry,
644                                       new_dir, new_dentry);
645         RETURN(rc);
646 }