Whamcloud - gitweb
- recursive chmod u+s for test 2g
[fs/lustre-release.git] / lustre / smfs / smfs_lib.c
index 55662ae..6194a17 100644 (file)
 #include <linux/lustre_smfs.h>
 #include "smfs_internal.h"
 
-static char *smfs_options(char *data, char **devstr, 
-                          char **namestr, char *opts, 
-                          int *flags)  
+int smfs_options(char *data, char **devstr, char **namestr, 
+                 char *ret, int *flags)  
 {
-        struct option *opt_value = NULL;
-        char   *pos;
+        char * temp;
+        char * pos = NULL, *next = NULL;
+                
+        ENTRY;
         
-        LASSERT(opts && flags);
-
-        while (!(get_opt(&opt_value, &pos))) {
-                if (!strcmp(opt_value->opt, "dev")) {
+        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 = opt_value->value;
-                } else if (!strcmp(opt_value->opt, "type")) {
+                                *devstr = pos + 4;
+                } else if (!strncmp(pos, "type=", 5)) {
                         if (namestr != NULL)
-                                *namestr = opt_value->value;
-                } else if (!strcmp(opt_value->opt, "kml")) {
-                        *flags |= SM_DO_REC;
-                } else if (!strcmp(opt_value->opt, "cache")) {
-                        *flags |= SM_CACHE_HOOK;
-                } else if (!strcmp(opt_value->opt, "snap")) {
-                        *flags |= SM_DO_COW;
-                } else if (!strcmp(opt_value->opt, "options")) {
-                        if (strlen(opts) == 0)
-                                sprintf((char *)opts + strlen(opts), "%s",
-                                        opt_value->value);
-                        else  
-                                sprintf((char *)opts + strlen(opts), ",%s",
-                                        opt_value->value);
+                                *namestr = pos + 5;
+                } else if (!strcmp(pos, "kml")) {
+                        SMFS_SET(*flags, SMFS_PLG_KML);
+                } else if (!strcmp(pos, "cache")) {
+                        SMFS_SET(*flags, SMFS_PLG_LRU);
+                } else if (!strcmp(pos, "snap")) {
+                        SMFS_SET(*flags, SMFS_PLG_COW);
                 } else {
-                        /* FIXME-WANGDI: how about the opt_value->value */
-                        if (strlen(opts) == 0)
-                                sprintf((char *)opts + strlen(opts), "%s",
-                                        opt_value->opt);
-                        else  
-                                sprintf((char *)opts + strlen(opts), ",%s",
-                                        opt_value->opt);
-                }
-        }
-        return pos;
-}
-
-struct super_block *smfs_get_sb_by_path(char *path, int len)
-{
-        struct super_block *sb;
-        struct nameidata nd;
-        int error = 0;
-
-        ENTRY;
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-        if (path_init(path, LOOKUP_FOLLOW, &nd)) {
-#else
-        if (path_lookup(path, LOOKUP_FOLLOW, &nd)) {
-#endif
-                error = path_walk(path, &nd);
-                if (error) {
-                        path_release(&nd);
-                        RETURN(NULL);
+                        /* So it is wrong or backfs option,
+                         * let's save it
+                         */
+                        if (strlen(ret))
+                                strcat(ret, ",");
+                        
+                        strcat(ret, pos);
                 }
-        } else {
-                RETURN(NULL);
+                
+                pos = next;
         }
 
-        /* FIXME-WANGDI: add some check code here. */
-        sb = nd.dentry->d_sb;
-        path_release(&nd);
-        RETURN(sb);
+        //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)
@@ -128,6 +121,15 @@ static struct smfs_super_info *smfs_init_smb(struct super_block *sb)
         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;
@@ -135,7 +137,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);
                 }
@@ -144,7 +146,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);
                 }
@@ -160,6 +162,55 @@ void smfs_cleanup_fsfilt_ops(struct smfs_super_info *smb)
                 fsfilt_put_ops(smb->sm_fsfilt);
 }
 
+int smfs_post_setup(struct super_block *sb, struct vfsmount *mnt)
+{
+        struct lvfs_run_ctxt saved, *current_ctxt = NULL;
+        struct smfs_super_info *smb = S2SMI(sb);
+        int rc = 0;
+        
+        ENTRY;
+        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(sb, mnt);
+        if (!rc) {
+                rc = SMFS_PLG_HELP(sb, PLG_START, NULL);
+        }
+
+        pop_ctxt(&saved, smb->smsi_ctxt, NULL);
+
+        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(sb);
+        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)
 {
@@ -169,7 +220,7 @@ 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", 
@@ -195,12 +246,6 @@ err_out:
 
 static int smfs_umount_cache(struct smfs_super_info *smb)
 {
-        struct dentry *root = smb->smsi_sb->s_root;
-        
-        dput(root);
-        if (atomic_read(&root->d_inode->i_count) == 0)
-                igrab(root->d_inode); 
-        
         mntput(smb->smsi_mnt);
         smfs_cleanup_sm_ops(smb);
         smfs_cleanup_fsfilt_ops(smb);
@@ -214,80 +259,52 @@ static int smfs_umount_cache(struct smfs_super_info *smb)
         return 0;
 }
 
-static int smfs_init_hook_ops(struct smfs_super_info *smb)
-{
-        ENTRY;
-        INIT_LIST_HEAD(&smb->smsi_hook_list);
-        RETURN(0); 
-}
+/* This function initializes plugins in SMFS 
+ * @flags: are filled while options parsing 
+ * @sb: smfs super block
+ */
 
-static void smfs_cleanup_hook_ops(struct smfs_super_info *smb)
+static int smfs_init_plugins(struct super_block * sb, int flags)
 {
-        struct list_head *hlist = &smb->smsi_hook_list;
+        struct smfs_super_info * smb = S2SMI(sb);
+        
         ENTRY;
+        
+        INIT_LIST_HEAD(&smb->smsi_plg_list);
 
-        while (!list_empty(hlist)) {
-                struct smfs_hook_ops *smfs_hops;
-                
-                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;
+        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_smb(struct super_block *sb)
+static void smfs_remove_plugins(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)
-{
+        SMFS_PLG_HELP(sb, PLG_EXIT, (void*)sb);
         
-        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);
+        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;
 }
 
 int smfs_fill_super(struct super_block *sb, void *data, int silent)
@@ -295,61 +312,57 @@ int smfs_fill_super(struct super_block *sb, void *data, int silent)
         struct inode *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; 
+        char *opts = NULL;
+        int err = 0;
+        int flags = 0;
         ino_t root_ino;
 
         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;
-
-        init_option(data);
-        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);
+        lock_kernel();
+        OBD_ALLOC(opts, strlen(data) + 1);
+        if (!opts) {
+                err = -ENOMEM;
+                goto out_err;
         }
-
+        
+        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;
         }
 
+        OBD_FREE(opts, strlen(data) + 1);
+        opts = NULL;
+        
         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);
 
@@ -357,103 +370,32 @@ int smfs_fill_super(struct super_block *sb, void *data, int silent)
                sb->s_op->read_inode, root_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);
-        }       
 #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);
 #else
-        CDEBUG(D_SUPER, "sb %lx, &sb->s_fs_info: %lx\n",
-               (ulong)sb, (ulong)&sb->s_fs_info);
+        CDEBUG(D_SUPER, "sb %lx(%p), &sb->s_fs_info: %lx\n",
+               (ulong)sb, smb->smsi_sb, (ulong)&sb->s_fs_info);
 #endif
-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);
-} 
+        smfs_init_plugins(sb, flags);
+        unlock_kernel();
+        RETURN (0);
+out_err:
+        if (smb->smsi_mnt)
+                smfs_umount_cache(smb);
 
-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 (opts)
+                OBD_FREE(opts, strlen(data) + 1);
 
-                found = list_entry(p, typeof(*found), smh_list);
-                if (!memcmp(found->smh_name, name, strlen(name))) {
-                        list_del(p);
-                        RETURN(found);
-                }
-        } 
-        RETURN(NULL);
+        smfs_cleanup_smb(smb);
+        unlock_kernel();
+        RETURN(err);
 }
 
 void *smfs_trans_start(struct inode *inode, int op, void *desc_private)
@@ -483,4 +425,128 @@ void smfs_trans_commit(struct inode *inode, void *handle, int force_sync)
         if (fsfilt->fs_commit)
                 fsfilt->fs_commit(inode->i_sb, inode, handle, force_sync);
 }
+/* Plugin API */
+int smfs_register_plugin(struct super_block * sb,
+                         struct smfs_plugin * new_plugin) 
+{
+        struct smfs_super_info * smb = S2SMI(sb);
+        struct smfs_plugin * plg = NULL;
+        struct list_head * plist = &S2SMI(sb)->smsi_plg_list;
+        
+        ENTRY;
+        
+        list_for_each_entry(plg, plist, plg_list) {
+                if (plg->plg_type == new_plugin->plg_type) {
+                        CWARN("Plugin is already registered\n");
+                        RETURN(-EEXIST);
+                }
+        }
+        
+        
+        if (SMFS_IS(smb->smsi_flags, new_plugin->plg_type)) {
+                CWARN("Plugin is already registered\n");
+                RETURN(-EEXIST);  
+        }
+                
+        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);
+        
+        RETURN(0);
+}
+
+void * 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;
+        
+        ENTRY;
+
+        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;
+                }
+        }
+                
+        RETURN(priv);
+}
+
+void smfs_pre_hook (struct inode * inode, int 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;
+                
+        //ENTRY;
+        LASSERT(op < HOOK_MAX);
+        //call hook operations
+        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 not exclusion
+                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);
+        }
+
+        //EXIT;
+}
+
+void smfs_post_hook (struct inode * inode, int 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;
+        
+        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 not exclusion
+                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);
+        }
+
+        //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;
+        int rc = 0;
+        
+        ENTRY;
+        LASSERT(op < PLG_HELPER_MAX);
+        //call hook operations
+        list_for_each_entry(plg, hlist, plg_list) {
+               if (plg->plg_helper)
+                       rc += plg->plg_helper(op, sb, msg, plg->plg_private);
+        }
+
+        EXIT;
+        
+        return rc;
+}
+