Whamcloud - gitweb
03147a482f10f31d2046f4fc286e4d993dcebbf6
[fs/lustre-release.git] / lustre / smfs / smfs_lib.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/smfs/super.c
5  *  Lustre filesystem abstraction routines
6  *
7  *  Copyright (C) 2004 Cluster File Systems, Inc.
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #define DEBUG_SUBSYSTEM S_SM
26
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/kmod.h>
30 #include <linux/init.h>
31 #include <linux/fs.h>
32 #include <linux/string.h>
33 #include <linux/mm.h>
34 #include <linux/utime.h>
35 #include <linux/file.h>
36 #include <linux/slab.h>
37 #include <linux/dcache.h>
38 #include <linux/loop.h>
39 #include <linux/errno.h>
40 #include <linux/obd_class.h>
41 #include <linux/obd_support.h>
42 #include <linux/lustre_lib.h>
43 #include <linux/lustre_idl.h>
44 #include <linux/lustre_fsfilt.h>
45 #include <linux/lustre_smfs.h>
46 #include "smfs_internal.h"
47
48 int smfs_options(char *data, char **devstr, char **namestr, 
49                  char *ret, int *flags)  
50 {
51         char * temp;
52         char * pos = NULL, *next = NULL;
53                 
54         ENTRY;
55         
56         LASSERT(flags);
57         //allocate temporary buffer
58         OBD_ALLOC(temp, strlen(data) + 1);
59         if (!temp) {
60                 CERROR("Can not allocate memory for options\n");
61                 RETURN(-ENOMEM);
62         }
63         
64         memcpy(temp, data, strlen(data));
65         pos = temp;
66         
67         while (pos) {
68                 next = strchr(pos, ',');
69                 if (next) {
70                         *next = '\0';
71                         next++;
72                 }
73                 
74                 //now pos points to one-options string
75                 if (!strncmp(pos, "dev=", 4)) {
76                         if (devstr != NULL)
77                                 *devstr = pos + 4;
78                 } else if (!strncmp(pos, "type=", 5)) {
79                         if (namestr != NULL)
80                                 *namestr = pos + 5;
81                 } else if (!strcmp(pos, "kml")) {
82                         SMFS_SET(*flags, SMFS_PLG_KML);
83                 } else if (!strcmp(pos, "cache")) {
84                         SMFS_SET(*flags, SMFS_PLG_LRU);
85                 } else if (!strcmp(pos, "snap")) {
86                         SMFS_SET(*flags, SMFS_PLG_COW);
87                 } else {
88                         /* So it is wrong or backfs option,
89                          * let's save it
90                          */
91                         if (strlen(ret))
92                                 strcat(ret, ",");
93                         
94                         strcat(ret, pos);
95                 }
96                 
97                 pos = next;
98         }
99
100         //save dev & type for further use
101         if (*devstr)
102                 *devstr = strcpy(ret + strlen(ret) + 1, *devstr);
103         if (*namestr)
104                 *namestr = strcpy(*devstr + strlen(*devstr) + 1, *namestr);
105         
106         OBD_FREE(temp, strlen(data) + 1);
107         
108         RETURN(0);
109 }
110
111 static struct smfs_super_info *smfs_init_smb(struct super_block *sb)
112 {
113         struct smfs_super_info *smb;
114         ENTRY;
115
116         OBD_ALLOC(smb, sizeof(*smb));
117         if (!smb)
118                 RETURN(NULL);        
119         
120         S2FSI(sb) = smb;
121         INIT_LIST_HEAD(&smb->smsi_plg_list);
122         
123         RETURN(smb);        
124 }
125
126 static void smfs_cleanup_smb(struct smfs_super_info *smb)
127 {
128         ENTRY;
129
130         if (smb) 
131                 OBD_FREE(smb, sizeof(*smb));
132         EXIT;
133 }
134
135 static int smfs_init_fsfilt_ops(struct smfs_super_info *smb)
136 {
137         ENTRY;
138         if (!smb->sm_cache_fsfilt) {
139                 smb->sm_cache_fsfilt =
140                         fsfilt_get_ops(smb->smsi_cache_ftype);
141                 if (!smb->sm_cache_fsfilt) {
142                         CERROR("Can not get %s fsfilt ops needed by smfs\n",
143                                smb->smsi_cache_ftype);
144                         RETURN(-EINVAL);
145                 }
146         }
147         if (!smb->sm_fsfilt) {
148                 smb->sm_fsfilt =
149                         fsfilt_get_ops(smb->smsi_ftype);
150                 if (!smb->sm_fsfilt) {
151                         CERROR("Can not get %s fsfilt ops needed by smfs\n",
152                                smb->smsi_ftype);
153                         RETURN(-EINVAL);
154                 }
155         }
156         RETURN(0);
157 }
158
159 void smfs_cleanup_fsfilt_ops(struct smfs_super_info *smb)
160 {
161         if (smb->sm_cache_fsfilt)
162                 fsfilt_put_ops(smb->sm_cache_fsfilt);
163         if (smb->sm_fsfilt)
164                 fsfilt_put_ops(smb->sm_fsfilt);
165 }
166
167 static void smfs_filter_flags(struct filter_obd * filt, struct inode * o_dir)
168 {
169         struct dentry * dentry = NULL;
170         int i,j;
171         
172         CDEBUG(D_SUPER,"OST OBD post_setup\n");
173         /* enable plugins for all in O */
174         SMFS_SET(I2SMI(o_dir)->smi_flags, SMFS_PLG_ALL);
175         /* enable plugins for all already created d<n> dirs */
176         for (j = 1; j < filt->fo_group_count; j++) {
177                 for (i = 0; i < filt->fo_subdir_count; i++) {
178                         dentry = (filt->fo_subdirs + j)->dentry[i];
179                         SMFS_SET(I2SMI(dentry->d_inode)->smi_flags,
180                                          SMFS_PLG_ALL);
181                 }
182         }
183 }
184
185 static void smfs_mds_flags(struct mds_obd * mds, struct inode * root)
186 {
187         struct inode * pend = mds->mds_pending_dir->d_inode;
188         
189         CDEBUG(D_SUPER,"MDS OBD post_setup\n");
190         /* enable plugins for all in ROOT */        
191         SMFS_SET(I2SMI(root)->smi_flags, SMFS_PLG_ALL);
192         /* the same for PENDING */
193         SMFS_SET(I2SMI(pend)->smi_flags, SMFS_PLG_ALL);
194 }
195                         
196
197 int smfs_post_setup(struct obd_device *obd, struct vfsmount *mnt,
198                     struct dentry * root_dentry)
199 {
200         struct lvfs_run_ctxt saved, *current_ctxt = NULL;
201         struct smfs_super_info *smb = S2SMI(mnt->mnt_sb);
202         int rc = 0;
203         
204         ENTRY;
205  
206         OBD_ALLOC(current_ctxt, sizeof(*current_ctxt));
207         if (!current_ctxt)
208                 RETURN(-ENOMEM);
209         
210         OBD_SET_CTXT_MAGIC(current_ctxt);
211         
212         current_ctxt->pwdmnt = mnt;
213         current_ctxt->pwd = mnt->mnt_root;
214         current_ctxt->fs = get_ds();
215         smb->smsi_ctxt = current_ctxt;
216         
217         push_ctxt(&saved, smb->smsi_ctxt, NULL);
218
219         rc = smfs_llog_setup(smb);
220         if (!rc) {
221                 rc = SMFS_PLG_HELP(mnt->mnt_sb, PLG_START, NULL);
222         }
223
224         pop_ctxt(&saved, smb->smsi_ctxt, NULL);
225
226         /* connect KML ctxt to obd */
227         if (obd && smb->smsi_kml_log) {
228                 smb->smsi_kml_log->loc_idx = LLOG_REINT_ORIG_CTXT;
229                 smb->smsi_kml_log->loc_obd = obd;
230                 obd->obd_llog_ctxt[LLOG_REINT_ORIG_CTXT] = smb->smsi_kml_log;
231         }
232         
233         /* enable plugins for directories on MDS or OST */
234         if (obd && obd->obd_type && obd->obd_type->typ_name) {
235                 if (!strcmp(obd->obd_type->typ_name, "obdfilter")) {
236                         struct filter_obd *filt = &obd->u.filter;
237  
238                         smfs_filter_flags(filt, root_dentry->d_inode);
239                 }
240                 else if (!strcmp(obd->obd_type->typ_name, "mds")) {
241                         struct mds_obd * mds = &obd->u.mds;
242                         
243                         smfs_mds_flags(mds, root_dentry->d_inode);
244                         SMFS_SET_HND_IBLOCKS(smb);
245                 }
246                 else
247                         CDEBUG(D_SUPER,"Unknown OBD (%s) post_setup\n",
248                                obd->obd_type->typ_name);
249         }
250
251         if (rc)
252                 OBD_FREE(current_ctxt, sizeof(*current_ctxt));
253   
254         RETURN(rc);
255 }
256
257 void smfs_post_cleanup(struct super_block *sb)
258 {
259         struct smfs_super_info *smb = S2SMI(sb);
260         
261         ENTRY;
262         
263         smfs_llog_cleanup(smb);
264         SMFS_PLG_HELP(sb, PLG_STOP, NULL);
265         
266         if (smb->smsi_ctxt)
267                 OBD_FREE(smb->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
268         
269         EXIT;
270 }
271
272 static int smfs_mount_cache(struct smfs_super_info *smb, char *devstr, 
273                             char *typestr, char *opts)
274 {
275         int err = 0, typelen;
276         struct vfsmount *mnt;
277         ENTRY;
278
279         typelen = strlen(typestr);
280
281         CDEBUG(D_INODE, "smfs: mounting %s at %s\n", typestr, devstr);
282         
283         mnt = do_kern_mount(typestr, 0, devstr, (void *)opts);
284         if (IS_ERR(mnt)) {
285                 CERROR("do_kern_mount failed: rc = %ld\n", 
286                        PTR_ERR(mnt));
287                 GOTO(err_out, err = PTR_ERR(mnt));
288         }
289
290         smb->smsi_sb = mnt->mnt_sb;
291         smb->smsi_mnt = mnt;
292
293         smfs_init_sm_ops(smb);
294
295         OBD_ALLOC(smb->smsi_cache_ftype, strlen(typestr) + 1);
296         memcpy(smb->smsi_cache_ftype, typestr, strlen(typestr));
297
298         OBD_ALLOC(smb->smsi_ftype, strlen(SMFS_TYPE) + 1);
299         memcpy(smb->smsi_ftype, SMFS_TYPE, strlen(SMFS_TYPE));
300         
301         err = smfs_init_fsfilt_ops(smb);
302 err_out:
303         RETURN(err);
304 }
305
306 static int smfs_umount_cache(struct smfs_super_info *smb)
307 {
308         mntput(smb->smsi_mnt);
309         smfs_cleanup_sm_ops(smb);
310         smfs_cleanup_fsfilt_ops(smb);
311
312         if (smb->smsi_cache_ftype)
313                 OBD_FREE(smb->smsi_cache_ftype,
314                          strlen(smb->smsi_cache_ftype) + 1);
315         if (smb->smsi_ftype)
316                 OBD_FREE(smb->smsi_ftype, strlen(smb->smsi_ftype) + 1);
317                
318         return 0;
319 }
320
321 /* This function initializes plugins in SMFS 
322  * @flags: are filled while options parsing 
323  * @sb: smfs super block
324  */
325
326 static int smfs_init_plugins(struct super_block * sb, int flags)
327 {
328         struct smfs_super_info * smb = S2SMI(sb);
329         
330         ENTRY;
331         
332         INIT_LIST_HEAD(&smb->smsi_plg_list);
333         init_rwsem(&smb->plg_sem);
334
335         if (SMFS_IS(flags, SMFS_PLG_KML)) 
336                 smfs_init_kml(sb);
337         if (SMFS_IS(flags, SMFS_PLG_LRU)) 
338                 smfs_init_lru(sb);
339 #if CONFIG_SNAPFS
340         if (SMFS_IS(flags, SMFS_PLG_COW)) 
341                 smfs_init_cow(sb);
342 #endif
343         RETURN(0); 
344 }
345
346 static void smfs_remove_plugins(struct super_block *sb)
347 {
348         ENTRY;
349
350         SMFS_PLG_HELP(sb, PLG_EXIT, (void*)sb);
351         
352         EXIT;
353 }
354
355 void smfs_put_super(struct super_block *sb)
356 {
357         struct smfs_super_info *smb = S2SMI(sb);
358         ENTRY;
359         smfs_remove_plugins(sb);
360         
361         dput(sb->s_root);
362         
363         if (smb->smsi_mnt)
364                 smfs_umount_cache(smb);
365         
366         smfs_cleanup_smb(smb);
367         EXIT;
368 }
369
370 int smfs_fill_super(struct super_block *sb, void *data, int silent)
371 {
372         struct inode *root_inode = NULL;
373         struct inode *back_root_inode = NULL;
374         struct smfs_super_info *smb = NULL;
375         char *devstr = NULL, *typestr = NULL;
376         unsigned long page = 0;
377         char *opts = NULL;
378         int flags = 0;
379         int err = 0;
380         
381         ENTRY;
382         
383         if (!data) {
384                 CERROR("no mount options. At least name and dev are needed\n");
385                 err = -EINVAL;
386                 goto out_err;
387         }
388
389         CDEBUG(D_SUPER, "mount opts: %s\n", (char *)data);
390
391         smb = smfs_init_smb(sb);
392         if (!smb)
393                 RETURN(-ENOMEM);
394         
395         lock_kernel();
396
397         /* 2.6.9 selinux wants a full option page for do_kern_mount (bug6471) */
398         page = get_zeroed_page(GFP_KERNEL);
399         if (!page) {
400                 err = -ENOMEM;
401                 goto out_err;
402         }
403         opts = (char *)page;
404         
405         err = smfs_options(data, &devstr, &typestr, opts, &flags);
406         if (err)
407                 goto out_err;
408                 
409         if (!typestr || !devstr) {
410                 CERROR("mount options name and dev are mandatory\n");
411                 err = -EINVAL;
412                 goto out_err;
413         }
414         
415         CDEBUG(D_SUPER, "backfs mount opts: %s\n", opts);
416
417         err = smfs_mount_cache(smb, devstr, typestr, opts);
418         if (err) {
419                 CERROR("Can not mount %s as %s\n", devstr, typestr);
420                 goto out_err;
421         }
422
423         free_page(page);
424         page = 0;
425         
426         duplicate_sb(sb, smb->smsi_sb);
427         sb->s_bdev = smb->smsi_sb->s_bdev;
428         sm_set_sb_ops(smb->smsi_sb, sb);
429
430         /* init the root_inode of smfs. */ 
431         back_root_inode = S2CSB(sb)->s_root->d_inode;
432         root_inode = smfs_get_inode(sb, back_root_inode, NULL, 0);
433
434         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
435                sb->s_op->read_inode, root_inode->i_ino, root_inode);
436
437         sb->s_root = d_alloc_root(root_inode);
438         if (!sb->s_root) {
439                 err = -ENOMEM;
440                 goto out_err;
441         }
442         
443         /* all entries created until post_setup() should not be logged */
444         SMFS_CLEAR((I2SMI(root_inode))->smi_flags, SMFS_PLG_ALL);
445    
446 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
447         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
448                (ulong)sb, (ulong)&sb->u.generic_sbp);
449 #else
450         CDEBUG(D_SUPER, "sb %lx(%p), &sb->s_fs_info: %lx\n",
451                (ulong)sb, smb->smsi_sb, (ulong)&sb->s_fs_info);
452 #endif
453         
454         smfs_init_plugins(sb, flags);
455         unlock_kernel();
456         RETURN (0);
457 out_err:
458         if (smb->smsi_mnt)
459                 smfs_umount_cache(smb);
460
461         if (page)
462                 free_page(page);
463
464         smfs_cleanup_smb(smb);
465         unlock_kernel();
466         RETURN(err);
467 }
468
469 void *smfs_trans_start(struct inode *inode, int op, void *desc_private)
470 {
471         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
472
473         if (fsfilt->fs_start)
474                 return fsfilt->fs_start(inode, op, NULL, 0);
475         return NULL;
476 }
477
478 void smfs_trans_commit(struct inode *inode, void *handle, int force_sync)
479 {
480         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
481
482         if (handle && fsfilt->fs_commit)
483                 fsfilt->fs_commit(inode->i_sb, inode, handle, force_sync);
484 }
485 /* Plugin API */
486 int smfs_register_plugin(struct super_block * sb,
487                          struct smfs_plugin * plg) 
488 {
489         struct smfs_plugin * tmp = NULL;
490         struct smfs_super_info * smb = S2SMI(sb);
491         struct list_head * plist = &smb->smsi_plg_list;
492         int rc = 0;
493         
494         ENTRY;
495         
496         down_write(&smb->plg_sem);
497         list_for_each_entry(tmp, plist, plg_list) {
498                 if (tmp->plg_type == plg->plg_type) {
499                         CWARN("Plugin is already registered\n");
500                         rc = -EEXIST;
501                         goto exit;
502                 }
503         }
504
505         list_add_tail(&plg->plg_list, plist);
506 exit:
507         up_write(&smb->plg_sem);
508         RETURN(0);
509 }
510
511 struct smfs_plugin * smfs_deregister_plugin(struct super_block *sb, int type)
512 {
513         struct smfs_plugin * plg = NULL;
514         struct smfs_super_info *smb = S2SMI(sb);
515         struct list_head * plist = &smb->smsi_plg_list;
516                 
517         ENTRY;
518         down_write(&smb->plg_sem);
519         list_for_each_entry(plg, plist, plg_list) {
520                 if (plg->plg_type == type) {
521                         list_del(&plg->plg_list);
522                         break;
523                 }
524         }
525         up_write(&smb->plg_sem);
526         RETURN(plg);
527 }
528
529 void smfs_pre_hook (struct inode * inode, int op, void * msg) 
530 {
531         struct smfs_super_info *smb = S2SMI(inode->i_sb);    
532         struct smfs_inode_info *smi = I2SMI(inode);
533         struct list_head *hlist = &smb->smsi_plg_list;
534         struct smfs_plugin *plg;
535                 
536         //ENTRY;
537         LASSERT(op < HOOK_MAX);
538         //call hook operations
539         down_read(&smb->plg_sem);
540         list_for_each_entry(plg, hlist, plg_list) {
541                 //check that plugin is active
542                 if(!SMFS_IS(smb->plg_flags, plg->plg_type))
543                         continue;
544                 //check that inode is allowed
545                 if (!SMFS_IS(smi->smi_flags, plg->plg_type))
546                         continue;
547                 
548                 if (plg->plg_pre_op)
549                         plg->plg_pre_op(op, inode, msg, 0, plg->plg_private);
550         }
551         up_read(&smb->plg_sem);
552         //EXIT;
553 }
554
555 void smfs_post_hook (struct inode * inode, int op, void * msg, int ret)
556 {
557         struct smfs_super_info *smb = S2SMI(inode->i_sb);
558         struct smfs_inode_info *smi = I2SMI(inode);
559         struct list_head *hlist = &smb->smsi_plg_list;
560         struct smfs_plugin *plg;
561         
562         //ENTRY;
563         down_read(&smb->plg_sem);
564         list_for_each_entry(plg, hlist, plg_list) {
565                 //check that plugin is active
566                 if(!SMFS_IS(smb->plg_flags, plg->plg_type))
567                         continue;
568                 //check that inode is allowed
569                 if (!SMFS_IS(smi->smi_flags, plg->plg_type))
570                         continue;
571                 
572                 if (plg->plg_post_op)
573                         plg->plg_post_op(op, inode, msg, ret, plg->plg_private);
574         }
575         up_read(&smb->plg_sem);
576         //EXIT;
577 }
578
579 int smfs_helper (struct super_block * sb, int op, void * msg) 
580 {
581         struct smfs_super_info *smb = S2SMI(sb);    
582         struct list_head *hlist = &smb->smsi_plg_list;
583         struct smfs_plugin *plg, *tmp;
584         int rc = 0;
585         
586         //ENTRY;
587         LASSERT(op < PLG_HELPER_MAX);
588         //call hook operations
589         down_read(&smb->plg_sem);
590         list_for_each_entry_safe(plg, tmp, hlist, plg_list) {
591                 //check that plugin is active
592                 if(!SMFS_IS(smb->plg_flags, plg->plg_type) && 
593                    !(op == PLG_START || op == PLG_EXIT))
594                         continue;
595                
596                 if (plg->plg_helper)
597                        rc += plg->plg_helper(op, sb, msg, plg->plg_private);
598         }
599         up_read(&smb->plg_sem);
600         //EXIT;
601         
602         return rc;
603 }
604
605