Whamcloud - gitweb
- many fixes about using ENTRY, RETURN, GOTO and EXIT.
[fs/lustre-release.git] / lustre / smfs / smfs_lib.c
index 95c5fd4..9057928 100644 (file)
 #include <linux/lustre_smfs.h>
 #include "smfs_internal.h"
 
+int smfs_options(char *data, char **devstr, char **namestr, 
+                 char *ret, int *flags)  
+{
+        char * temp;
+        char * pos = NULL, *next = NULL;
+                
+        ENTRY;
+        
+        LASSERT(flags);
+        //allocate temporary buffer
+        OBD_ALLOC(temp, strlen(data) + 1);
+        if (!temp) {
+                CERROR("Can not allocate memory for options\n");
+                RETURN(-ENOMEM);
+        }
+        
+        memcpy(temp, data, strlen(data));
+        pos = temp;
+        
+        while (pos) {
+                next = strchr(pos, ',');
+                if (next) {
+                        *next = '\0';
+                        next++;
+                }
+                
+                //now pos points to one-options string
+                if (!strncmp(pos, "dev=", 4)) {
+                        if (devstr != NULL)
+                                *devstr = pos + 4;
+                } else if (!strncmp(pos, "type=", 5)) {
+                        if (namestr != NULL)
+                                *namestr = pos + 5;
+                } else if (!strcmp(pos, "kml")) {
+                        SMFS_SET(*flags, SMFS_PLG_KML);
+                } else if (!strcmp(pos, "audit")) {
+                        SMFS_SET(*flags, SMFS_PLG_AUDIT);
+                } else if (!strcmp(pos, "cache")) {
+                        SMFS_SET(*flags, SMFS_PLG_LRU);
+                } else if (!strcmp(pos, "snap")) {
+                        SMFS_SET(*flags, SMFS_PLG_COW);
+                } else {
+                        /* So it is wrong or backfs option,
+                         * let's save it
+                         */
+                        if (strlen(ret))
+                                strcat(ret, ",");
+                        
+                        strcat(ret, pos);
+                }
+                
+                pos = next;
+        }
 
-struct list_head smfs_plg_list;
+        //save dev & type for further use
+        if (*devstr)
+                *devstr = strcpy(ret + strlen(ret) + 1, *devstr);
+        if (*namestr)
+                *namestr = strcpy(*devstr + strlen(*devstr) + 1, *namestr);
+        
+        OBD_FREE(temp, strlen(data) + 1);
+        
+        RETURN(0);
+}
 
 static struct smfs_super_info *smfs_init_smb(struct super_block *sb)
 {
@@ -58,9 +120,20 @@ static struct smfs_super_info *smfs_init_smb(struct super_block *sb)
                 RETURN(NULL);        
         
         S2FSI(sb) = smb;
+        INIT_LIST_HEAD(&smb->smsi_plg_list);
+        
         RETURN(smb);        
 }
 
+static void smfs_cleanup_smb(struct smfs_super_info *smb)
+{
+        ENTRY;
+
+        if (smb) 
+                OBD_FREE(smb, sizeof(*smb));
+        EXIT;
+}
+
 static int smfs_init_fsfilt_ops(struct smfs_super_info *smb)
 {
         ENTRY;
@@ -68,7 +141,7 @@ static int smfs_init_fsfilt_ops(struct smfs_super_info *smb)
                 smb->sm_cache_fsfilt =
                         fsfilt_get_ops(smb->smsi_cache_ftype);
                 if (!smb->sm_cache_fsfilt) {
-                        CERROR("Can not get %s fsfilt ops needed by kml\n",
+                        CERROR("Can not get %s fsfilt ops needed by smfs\n",
                                smb->smsi_cache_ftype);
                         RETURN(-EINVAL);
                 }
@@ -77,7 +150,7 @@ static int smfs_init_fsfilt_ops(struct smfs_super_info *smb)
                 smb->sm_fsfilt =
                         fsfilt_get_ops(smb->smsi_ftype);
                 if (!smb->sm_fsfilt) {
-                        CERROR("Can not get %s fsfilt ops needed by kml\n",
+                        CERROR("Can not get %s fsfilt ops needed by smfs\n",
                                smb->smsi_ftype);
                         RETURN(-EINVAL);
                 }
@@ -93,6 +166,107 @@ void smfs_cleanup_fsfilt_ops(struct smfs_super_info *smb)
                 fsfilt_put_ops(smb->sm_fsfilt);
 }
 
+static void smfs_filter_flags(struct filter_obd * filt, struct inode * o_dir)
+{
+        struct dentry * dentry = NULL;
+        int i,j;
+        
+        CDEBUG(D_SUPER,"OST OBD post_setup\n");
+        /* enable plugins for all in O */
+        SMFS_SET(I2SMI(o_dir)->smi_flags, SMFS_PLG_ALL);
+        /* enable plugins for all already created d<n> dirs */
+        for (j = 1; j < filt->fo_group_count; j++) {
+                for (i = 0; i < filt->fo_subdir_count; i++) {
+                        dentry = (filt->fo_subdirs + j)->dentry[i];
+                        SMFS_SET(I2SMI(dentry->d_inode)->smi_flags,
+                                         SMFS_PLG_ALL);
+                }
+        }
+}
+
+static void smfs_mds_flags(struct mds_obd *mds, struct inode *root)
+{
+        struct inode *pend = mds->mds_pending_dir->d_inode;
+        
+        CDEBUG(D_SUPER,"MDS OBD post_setup\n");
+
+        /* enable plugins for all in ROOT */        
+        SMFS_SET(I2SMI(root)->smi_flags, SMFS_PLG_ALL);
+
+        /* the same for PENDING */
+        SMFS_SET(I2SMI(pend)->smi_flags, SMFS_PLG_ALL);
+}
+
+extern int (*audit_id2name_superhack) (struct obd_device *obd, char **name,
+                                       int *namelen, struct lustre_id *id);
+
+int smfs_post_setup(struct obd_device *obd, struct vfsmount *mnt,
+                    struct dentry *root_dentry)
+{
+        struct lvfs_run_ctxt saved, *current_ctxt = NULL;
+        struct smfs_super_info *smb = S2SMI(mnt->mnt_sb);
+        int rc = 0;
+        ENTRY;
+
+        /* XXX to register id2name function of mds in smfs */
+        //if (data != NULL)
+        //        audit_id2name_superhack = data;
+        OBD_ALLOC(current_ctxt, sizeof(*current_ctxt));
+        if (!current_ctxt)
+                RETURN(-ENOMEM);
+        
+        OBD_SET_CTXT_MAGIC(current_ctxt);
+        
+        current_ctxt->pwdmnt = mnt;
+        current_ctxt->pwd = mnt->mnt_root;
+        current_ctxt->fs = get_ds();
+        smb->smsi_ctxt = current_ctxt;
+        
+        push_ctxt(&saved, smb->smsi_ctxt, NULL);
+
+        rc = smfs_llog_setup(&smb->smsi_logs_dir, &smb->smsi_objects_dir);
+        if (!rc)
+                rc = SMFS_PLG_HELP(mnt->mnt_sb, PLG_START, obd);
+
+        pop_ctxt(&saved, smb->smsi_ctxt, NULL);
+
+        /* enable plugins for directories on MDS or OST */
+        if (obd && obd->obd_type && obd->obd_type->typ_name) {
+                if (!strcmp(obd->obd_type->typ_name, OBD_FILTER_DEVICENAME)) {
+                        struct filter_obd *filt = &obd->u.filter;
+                        smfs_filter_flags(filt, root_dentry->d_inode);
+                } else if (!strcmp(obd->obd_type->typ_name, OBD_MDS_DEVICENAME)) {
+                        struct mds_obd * mds = &obd->u.mds;
+                        smfs_mds_flags(mds, root_dentry->d_inode);
+                        SMFS_SET_HND_IBLOCKS(smb);
+                } else {
+                        CDEBUG(D_SUPER,"Unknown OBD (%s) post_setup\n",
+                               obd->obd_type->typ_name);
+                }
+        }
+
+        if (rc)
+                OBD_FREE(current_ctxt, sizeof(*current_ctxt));
+        
+        RETURN(rc);
+}
+
+void smfs_post_cleanup(struct super_block *sb)
+{
+        struct smfs_super_info *smb = S2SMI(sb);
+        
+        ENTRY;
+        
+        smfs_llog_cleanup(smb);
+        SMFS_PLG_HELP(sb, PLG_STOP, NULL);
+        
+        if (smb->smsi_ctxt)
+                OBD_FREE(smb->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
+        
+        EXIT;
+}
+
 static int smfs_mount_cache(struct smfs_super_info *smb, char *devstr, 
                             char *typestr, char *opts)
 {
@@ -102,12 +276,13 @@ static int smfs_mount_cache(struct smfs_super_info *smb, char *devstr,
 
         typelen = strlen(typestr);
 
-        printk("smfs: mounting %s at %s\n", typestr, devstr);
+        CDEBUG(D_INODE, "smfs: mounting %s at %s\n", typestr, devstr);
+        
         mnt = do_kern_mount(typestr, 0, devstr, (void *)opts);
         if (IS_ERR(mnt)) {
-                CERROR("do_kern_mount failed: rc = %ld\n", 
-                       PTR_ERR(mnt));
-                GOTO(err_out, err = PTR_ERR(mnt));
+                CERROR("do_kern_mount failed: rc = %d\n", 
+                       (int)PTR_ERR(mnt));
+                RETURN(PTR_ERR(mnt));
         }
 
         smb->smsi_sb = mnt->mnt_sb;
@@ -116,187 +291,181 @@ static int smfs_mount_cache(struct smfs_super_info *smb, char *devstr,
         smfs_init_sm_ops(smb);
 
         OBD_ALLOC(smb->smsi_cache_ftype, strlen(typestr) + 1);
+        if (!smb->smsi_cache_ftype)
+                GOTO(err_umount_cache, err = -ENOMEM);
+
         memcpy(smb->smsi_cache_ftype, typestr, strlen(typestr));
 
         OBD_ALLOC(smb->smsi_ftype, strlen(SMFS_TYPE) + 1);
+        if (!smb->smsi_ftype)
+                GOTO(err_free_cache_fstype, err = -ENOMEM);
+        
         memcpy(smb->smsi_ftype, SMFS_TYPE, strlen(SMFS_TYPE));
         
         err = smfs_init_fsfilt_ops(smb);
-err_out:
         RETURN(err);
+err_free_cache_fstype:
+        OBD_FREE(smb->smsi_cache_ftype, strlen(typestr) + 1);
+err_umount_cache:
+        mntput(mnt);
+err_out:
+        return err;
 }
 
 static int smfs_umount_cache(struct smfs_super_info *smb)
 {
+        ENTRY;
+        
         mntput(smb->smsi_mnt);
         smfs_cleanup_sm_ops(smb);
         smfs_cleanup_fsfilt_ops(smb);
 
-        if (smb->smsi_cache_ftype)
+        if (smb->smsi_cache_ftype) {
                 OBD_FREE(smb->smsi_cache_ftype,
                          strlen(smb->smsi_cache_ftype) + 1);
-        if (smb->smsi_ftype)
-                OBD_FREE(smb->smsi_ftype, strlen(smb->smsi_ftype) + 1);
-               
-        return 0;
+                smb->smsi_cache_ftype = NULL;
+        }
+        if (smb->smsi_ftype) {
+                OBD_FREE(smb->smsi_ftype,
+                         strlen(smb->smsi_ftype) + 1);
+                smb->smsi_ftype = NULL;
+        }
+
+        RETURN(0);
 }
 
-static int smfs_init_hook_ops(struct smfs_super_info *smb)
+/* This function initializes plugins in SMFS 
+ * @flags: are filled while options parsing 
+ * @sb: smfs super block
+ */
+static int smfs_init_plugins(struct super_block * sb, int flags)
 {
+        struct smfs_super_info * smb = S2SMI(sb);
+        
         ENTRY;
-        INIT_LIST_HEAD(&smb->smsi_hook_list);
+        
         INIT_LIST_HEAD(&smb->smsi_plg_list);
+        init_rwsem(&smb->plg_sem);
+
+        if (SMFS_IS(flags, SMFS_PLG_AUDIT))
+                smfs_init_audit(sb);
+        if (SMFS_IS(flags, SMFS_PLG_KML)) 
+                smfs_init_kml(sb);
+        if (SMFS_IS(flags, SMFS_PLG_LRU)) 
+                smfs_init_lru(sb);
+#if CONFIG_SNAPFS
+        if (SMFS_IS(flags, SMFS_PLG_COW)) 
+                smfs_init_cow(sb);
+#endif
         RETURN(0); 
 }
 
-static void smfs_cleanup_hook_ops(struct smfs_super_info *smb)
+static void smfs_remove_plugins(struct super_block *sb)
 {
-        struct list_head *hlist = &smb->smsi_hook_list;
-        ENTRY;
-
-        while (!list_empty(hlist)) {
-                struct smfs_hook_ops *smfs_hops;
+        struct smfs_plugin * plg, *tmp;
+        struct smfs_super_info *smb = S2SMI(sb);
+        struct list_head * plist = &smb->smsi_plg_list;
                 
-                smfs_hops = list_entry(hlist->next, struct smfs_hook_ops, 
-                                       smh_list);
-                CERROR("Unregister %s hook ops\n", smfs_hops->smh_name);         
-                
-                smfs_unregister_hook_ops(smb, smfs_hops->smh_name);
-                smfs_free_hook_ops(smfs_hops); 
-        } 
-        EXIT;
-}
-static void smfs_cleanup_smb(struct super_block *sb)
-{
-        struct smfs_super_info *smb;
         ENTRY;
-
-        smb = S2SMI(sb);
-        if (smb) 
-                OBD_FREE(smb, sizeof(*smb));
-        EXIT;
-}
-
-void smfs_cleanup_hooks(struct smfs_super_info *smb)
-{
         
-        if (SMFS_CACHE_HOOK(smb))
-                cache_space_hook_exit(smb);
-        if (SMFS_DO_REC(smb))
-                smfs_rec_cleanup(smb);
-#if CONFIG_SNAPFS
-        if (SMFS_DO_COW(smb))
-                smfs_cow_cleanup(smb);
-#endif  
-        smfs_cleanup_hook_ops(smb);
+        list_for_each_entry_safe(plg, tmp, plist, plg_list) {
+                plg->plg_exit(sb, plg->plg_private);
+        }
+        
+        EXIT;
 }
 
 void smfs_put_super(struct super_block *sb)
 {
-        struct smfs_super_info *smfs_info = S2SMI(sb);
-
-        smfs_cleanup_hooks(smfs_info);
-        
-        if (sb)
-                smfs_umount_cache(smfs_info);
-        smfs_cleanup_smb(sb); 
-}
-
-static int smfs_init_hooks(struct super_block *sb)
-{ 
+        struct smfs_super_info *smb = S2SMI(sb);
         ENTRY;
-        if (SMFS_DO_REC(S2SMI(sb))) 
-                smfs_rec_init(sb);
-        if (SMFS_CACHE_HOOK(S2SMI(sb))) 
-                cache_space_hook_init(sb);
-#if CONFIG_SNAPFS
-        if (SMFS_DO_COW(S2SMI(sb))) 
-                smfs_cow_init(sb);
-#endif
-        RETURN(0);
+        smfs_remove_plugins(sb);
+        
+        dput(sb->s_root);
+        
+        if (smb->smsi_mnt)
+                smfs_umount_cache(smb);
+        
+        smfs_cleanup_smb(smb);
+        EXIT;
 }
 
-extern char* smfs_options(char*, char**, char**, char*, int *);
-
 int smfs_fill_super(struct super_block *sb, void *data, int silent)
 {
         struct inode *root_inode = NULL;
+       struct inode *back_root_inode = NULL;
         struct smfs_super_info *smb = NULL;
-        char *devstr = NULL, *typestr = NULL; 
-        char *opts = NULL, *cache_data = NULL;
-        unsigned long page;
-        int err = 0; 
-        ino_t root_ino;
-
+        char *devstr = NULL, *typestr = NULL;
+        unsigned long page = 0;
+        char *opts = NULL;
+        int flags = 0;
+        int err = 0;
+        
         ENTRY;
+        
+        if (!data) {
+                CERROR("no mount options. At least name and dev are needed\n");
+                err = -EINVAL;
+                goto out_err;
+        }
 
-        CDEBUG(D_SUPER, "mount opts: %s\n", data ? 
-               (char *)data : "(none)");
+        CDEBUG(D_SUPER, "mount opts: %s\n", (char *)data);
 
         smb = smfs_init_smb(sb);
         if (!smb)
                 RETURN(-ENOMEM);
-        page = __get_free_page(GFP_KERNEL);
-        if (!page)
-                GOTO(out_err, err = -ENOMEM);
         
-        memset((void *)page, 0, PAGE_SIZE);
-        opts = (char *)page;
+        lock_kernel();
 
-        cache_data = smfs_options(data, &devstr, &typestr, opts, 
-                                  &smb->smsi_flags); 
-        if (*cache_data) {
-                CWARN("smfs_fill_super(): options parsing stoped at "
-                      "option %s\n", cache_data);
+        /* 2.6.9 selinux wants a full option page for do_kern_mount (bug6471) */
+        page = get_zeroed_page(GFP_KERNEL);
+        if (!page) {
+                err = -ENOMEM;
+                goto out_err;
         }
-
+        opts = (char *)page;
+        
+        err = smfs_options(data, &devstr, &typestr, opts, &flags);
+        if (err)
+                goto out_err;
+                
         if (!typestr || !devstr) {
                 CERROR("mount options name and dev are mandatory\n");
-                free_page(page);
-                GOTO(out_err, err = -EINVAL);
+                err = -EINVAL;
+                goto out_err;
         }
         
+        CDEBUG(D_SUPER, "backfs mount opts: %s\n", opts);
+
         err = smfs_mount_cache(smb, devstr, typestr, opts);
-        free_page(page);
-        
         if (err) {
                 CERROR("Can not mount %s as %s\n", devstr, typestr);
-                GOTO(out_err, err);
+                goto out_err;
         }
 
+        free_page(page);
+        page = 0;
+        
         duplicate_sb(sb, smb->smsi_sb);
         sb->s_bdev = smb->smsi_sb->s_bdev;
         sm_set_sb_ops(smb->smsi_sb, sb);
 
-        err = smfs_init_hook_ops(smb);
-        if (err) {
-                CERROR("Can not init super hook ops err %d\n", err);
-                smfs_umount_cache(smb);
-                GOTO(out_err, err);
-        }
-        
         /* init the root_inode of smfs. */ 
-        //dget(S2CSB(sb)->s_root);
-        root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
-        root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
+        back_root_inode = S2CSB(sb)->s_root->d_inode;
+        root_inode = smfs_get_inode(sb, back_root_inode, NULL, 0);
 
         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
-               sb->s_op->read_inode, root_ino, root_inode);
+               sb->s_op->read_inode, root_inode->i_ino, root_inode);
 
         sb->s_root = d_alloc_root(root_inode);
-
         if (!sb->s_root) {
-                smfs_umount_cache(smb);
-                GOTO(out_err, err = -ENOMEM);
+                err = -ENOMEM;
+                goto out_err;
         }
         
-        err = smfs_init_hooks(sb);  
-        if (err) {
-                smfs_umount_cache(smb);
-                GOTO(out_err, err);
-        }       
+        /* all entries created until post_setup() should not be logged */
+        SMFS_CLEAR((I2SMI(root_inode))->smi_flags, SMFS_PLG_ALL);
+   
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
                (ulong)sb, (ulong)&sb->u.generic_sbp);
@@ -305,100 +474,27 @@ int smfs_fill_super(struct super_block *sb, void *data, int silent)
                (ulong)sb, smb->smsi_sb, (ulong)&sb->s_fs_info);
 #endif
         
+        smfs_init_plugins(sb, flags);
+        unlock_kernel();
+        RETURN (0);
 out_err:
-        cleanup_option();
-        if (err)
-                smfs_cleanup_smb(sb);
-        return err;
-}
-
-struct smfs_hook_ops *smfs_alloc_hook_ops(char *name, smfs_hook_func pre_hook, 
-                                          smfs_hook_func post_hook)
-{
-        struct smfs_hook_ops *smfs_hops = NULL;
-        
-        ENTRY;
-        OBD_ALLOC(smfs_hops, sizeof(struct smfs_hook_ops));
-
-        if (!smfs_hops)
-                RETURN(NULL);
-        OBD_ALLOC(smfs_hops->smh_name, strlen(name) + 1);
-        
-        if (!smfs_hops->smh_name) { 
-                OBD_FREE(smfs_hops, sizeof(struct smfs_hook_ops));
-                RETURN(NULL);
-        }
-        
-        memcpy(smfs_hops->smh_name, name, strlen(name));  
-       
-        smfs_hops->smh_post_op = post_hook;  
-        smfs_hops->smh_pre_op = pre_hook;  
-        
-        RETURN(smfs_hops); 
-}
-
-void smfs_free_hook_ops(struct smfs_hook_ops *hops)
-{
-        if (hops) {
-                if (hops->smh_name){
-                        OBD_FREE(hops->smh_name, strlen(hops->smh_name) + 1);
-                }
-                OBD_FREE(hops, sizeof(struct smfs_hook_ops));
-        }
-}
-
-int smfs_register_hook_ops(struct smfs_super_info *smb, 
-                           struct smfs_hook_ops *smh_ops)
-{
-        struct list_head *hlist = &smb->smsi_hook_list;
-        struct list_head *p;
-        ENTRY;
-        list_for_each(p, hlist) {
-                struct smfs_hook_ops *found;               
-                found = list_entry(p, struct smfs_hook_ops, smh_list);
-                if (!strcmp(found->smh_name, smh_ops->smh_name)) {
-                        CWARN("hook ops %s list  reregister\n", smh_ops->smh_name);
-                        RETURN(0);
-                }
-        }
-       list_add(&smh_ops->smh_list, hlist);
-        RETURN(0);
-} 
-
-struct smfs_hook_ops *smfs_unregister_hook_ops(struct smfs_super_info *smb, 
-                                               char *name)
-{
-        struct list_head *hlist = &smb->smsi_hook_list;
-        struct list_head *p;
-        ENTRY;      
-        list_for_each(p, hlist) {
-               struct smfs_hook_ops *found;
+        if (smb->smsi_mnt)
+                smfs_umount_cache(smb);
 
-                found = list_entry(p, typeof(*found), smh_list);
-                if (!memcmp(found->smh_name, name, strlen(name))) {
-                        list_del(p);
-                        RETURN(found);
-                }
-        }
+        if (page)
+                free_page(page);
 
-        RETURN(NULL);
+        smfs_cleanup_smb(smb);
+        unlock_kernel();
+        RETURN(err);
 }
 
 void *smfs_trans_start(struct inode *inode, int op, void *desc_private)
 {
         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
 
-        CDEBUG(D_INFO, "trans start %p\n", fsfilt->fs_start);
-
-        SMFS_TRANS_OP(inode, op);
-        
-        /* There are some problem here. fs_start in fsfilt is used by lustre
-         * the journal blocks of write rec are not counted in FIXME later */
         if (fsfilt->fs_start)
-                return fsfilt->fs_start(inode, op, desc_private, 0);
+                return fsfilt->fs_start(inode, op, NULL, 0);
         return NULL;
 }
 
@@ -406,59 +502,142 @@ void smfs_trans_commit(struct inode *inode, void *handle, int force_sync)
 {
         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
 
-        if (!handle)
-                return;
-
-        CDEBUG(D_INFO, "trans commit %p\n", fsfilt->fs_commit);
-
-        if (fsfilt->fs_commit)
+        if (handle && fsfilt->fs_commit)
                 fsfilt->fs_commit(inode->i_sb, inode, handle, force_sync);
 }
-
-
-int smfs_register_plugin(struct super_block * sb, struct smfs_plugin * new_plugin
+/* Plugin API */
+int smfs_register_plugin(struct super_block * sb,
+                         struct smfs_plugin * plg
 {
-        struct smfs_plugin * plg = NULL;
-        struct list_head * plist = &S2SMI(sb)->smsi_plg_list;
+        struct smfs_plugin * tmp = NULL;
+        struct smfs_super_info * smb = S2SMI(sb);
+        struct list_head * plist = &smb->smsi_plg_list;
+        int rc = 0;
         
         ENTRY;
         
-        list_for_each_entry(plg, plist, plg_list) {
-                if (plg->plg_type == new_plugin->plg_type) {
+        down_write(&smb->plg_sem);
+        list_for_each_entry(tmp, plist, plg_list) {
+                if (tmp->plg_type == plg->plg_type) {
                         CWARN("Plugin is already registered\n");
-                        RETURN(-EEXIST);
+                        rc = -EEXIST;
+                        goto exit;
                 }
         }
-        
-        OBD_ALLOC(plg, sizeof(*plg));
-        if (!plg) {
-                CWARN("Cannot allocate memory for plugin\n");
-                RETURN(-ENOMEM);
-        }
-        
-        memcpy(plg, new_plugin, sizeof(*plg));
+
         list_add_tail(&plg->plg_list, plist);
-                
+exit:
+        up_write(&smb->plg_sem);
         RETURN(0);
 }
 
-void * smfs_deregister_plugin(struct super_block * sb, int type)
+struct smfs_plugin * smfs_deregister_plugin(struct super_block *sb, int type)
 {
         struct smfs_plugin * plg = NULL;
-        struct list_head * plist = &S2SMI(sb)->smsi_plg_list;
-        void * priv = NULL;
-        
+        struct smfs_super_info *smb = S2SMI(sb);
+        struct list_head * plist = &smb->smsi_plg_list;
+                
         ENTRY;
+        down_write(&smb->plg_sem);
         list_for_each_entry(plg, plist, plg_list) {
                 if (plg->plg_type == type) {
                         list_del(&plg->plg_list);
-                        priv = plg->plg_private;
-                        OBD_FREE(plg, sizeof(*plg));
                         break;
                 }
         }
+        up_write(&smb->plg_sem);
+        RETURN(plg);
+}
+
+void smfs_pre_hook (struct inode * inode, hook_op op, void * msg) 
+{
+        struct smfs_super_info *smb = S2SMI(inode->i_sb);    
+        struct smfs_inode_info *smi = I2SMI(inode);
+        struct list_head *hlist = &smb->smsi_plg_list;
+        struct smfs_plugin *plg;
                 
-        RETURN(priv);
+        //ENTRY;
+        LASSERT(op < HOOK_MAX);
+        //call hook operations
+        down_read(&smb->plg_sem);
+        list_for_each_entry(plg, hlist, plg_list) {
+                //check that plugin is active
+                if(!SMFS_IS(smb->plg_flags, plg->plg_type))
+                        continue;
+                //check that inode is allowed
+                if (!SMFS_IS(smi->smi_flags, plg->plg_type))
+                        continue;
+                
+                if (plg->plg_pre_op)
+                        plg->plg_pre_op(op, inode, msg, 0, plg->plg_private);
+        }
+        up_read(&smb->plg_sem);
+        //EXIT;
+}
+
+void smfs_post_hook (struct inode * inode, hook_op op, void * msg, int ret)
+{
+        struct smfs_super_info *smb = S2SMI(inode->i_sb);
+        //struct smfs_inode_info *smi = I2SMI(inode);
+        struct list_head *hlist = &smb->smsi_plg_list;
+        struct smfs_plugin *plg;
+        
+        //ENTRY;
+        down_read(&smb->plg_sem);
+        list_for_each_entry(plg, hlist, plg_list) {
+                //check that plugin is active
+                if(!SMFS_IS(smb->plg_flags, plg->plg_type))
+                        continue;
+                /* this will be checked inside plg_post_op()
+                if (!SMFS_IS(smi->smi_flags, plg->plg_type))
+                        continue;
+                */
+                if (plg->plg_post_op)
+                        plg->plg_post_op(op, inode, msg, ret, plg->plg_private);
+        }
+        up_read(&smb->plg_sem);
+        //EXIT;
+}
+
+int smfs_helper (struct super_block * sb, int op, void * msg) 
+{
+        struct smfs_super_info *smb = S2SMI(sb);    
+        struct list_head *hlist = &smb->smsi_plg_list;
+        struct smfs_plugin *plg, *tmp;
+        int rc = 0;
+        
+        //ENTRY;
+        LASSERT(op < PLG_HELPER_MAX);
+        //call hook operations
+        down_read(&smb->plg_sem);
+        list_for_each_entry_safe(plg, tmp, hlist, plg_list) {
+                //check that plugin is active
+                if(!SMFS_IS(smb->plg_flags, plg->plg_type) && 
+                   !(op == PLG_START || op == PLG_EXIT))
+                        continue;
+               
+                if (plg->plg_helper)
+                       rc += plg->plg_helper(op, sb, msg, plg->plg_private);
+        }
+        up_read(&smb->plg_sem);
+        //EXIT;
+        
+        return rc;
 }
 
+void * smfs_get_plg_priv(struct smfs_super_info * smb, int type) 
+{
+        struct list_head *hlist = &smb->smsi_plg_list;
+        struct smfs_plugin *plg, *tmp;
+        
+        list_for_each_entry_safe(plg, tmp, hlist, plg_list) {
+                if (plg->plg_type == type) {
+                        return (plg->plg_private);
+                }
+        }
+        
+        EXIT;
+        
+        return NULL;
+}