Whamcloud - gitweb
- many fixes about using ENTRY, RETURN, GOTO and EXIT.
[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, "audit")) {
84                         SMFS_SET(*flags, SMFS_PLG_AUDIT);
85                 } else if (!strcmp(pos, "cache")) {
86                         SMFS_SET(*flags, SMFS_PLG_LRU);
87                 } else if (!strcmp(pos, "snap")) {
88                         SMFS_SET(*flags, SMFS_PLG_COW);
89                 } else {
90                         /* So it is wrong or backfs option,
91                          * let's save it
92                          */
93                         if (strlen(ret))
94                                 strcat(ret, ",");
95                         
96                         strcat(ret, pos);
97                 }
98                 
99                 pos = next;
100         }
101
102         //save dev & type for further use
103         if (*devstr)
104                 *devstr = strcpy(ret + strlen(ret) + 1, *devstr);
105         if (*namestr)
106                 *namestr = strcpy(*devstr + strlen(*devstr) + 1, *namestr);
107         
108         OBD_FREE(temp, strlen(data) + 1);
109         
110         RETURN(0);
111 }
112
113 static struct smfs_super_info *smfs_init_smb(struct super_block *sb)
114 {
115         struct smfs_super_info *smb;
116         ENTRY;
117
118         OBD_ALLOC(smb, sizeof(*smb));
119         if (!smb)
120                 RETURN(NULL);        
121         
122         S2FSI(sb) = smb;
123         INIT_LIST_HEAD(&smb->smsi_plg_list);
124         
125         RETURN(smb);        
126 }
127
128 static void smfs_cleanup_smb(struct smfs_super_info *smb)
129 {
130         ENTRY;
131
132         if (smb) 
133                 OBD_FREE(smb, sizeof(*smb));
134         EXIT;
135 }
136
137 static int smfs_init_fsfilt_ops(struct smfs_super_info *smb)
138 {
139         ENTRY;
140         if (!smb->sm_cache_fsfilt) {
141                 smb->sm_cache_fsfilt =
142                         fsfilt_get_ops(smb->smsi_cache_ftype);
143                 if (!smb->sm_cache_fsfilt) {
144                         CERROR("Can not get %s fsfilt ops needed by smfs\n",
145                                smb->smsi_cache_ftype);
146                         RETURN(-EINVAL);
147                 }
148         }
149         if (!smb->sm_fsfilt) {
150                 smb->sm_fsfilt =
151                         fsfilt_get_ops(smb->smsi_ftype);
152                 if (!smb->sm_fsfilt) {
153                         CERROR("Can not get %s fsfilt ops needed by smfs\n",
154                                smb->smsi_ftype);
155                         RETURN(-EINVAL);
156                 }
157         }
158         RETURN(0);
159 }
160
161 void smfs_cleanup_fsfilt_ops(struct smfs_super_info *smb)
162 {
163         if (smb->sm_cache_fsfilt)
164                 fsfilt_put_ops(smb->sm_cache_fsfilt);
165         if (smb->sm_fsfilt)
166                 fsfilt_put_ops(smb->sm_fsfilt);
167 }
168
169 static void smfs_filter_flags(struct filter_obd * filt, struct inode * o_dir)
170 {
171         struct dentry * dentry = NULL;
172         int i,j;
173         
174         CDEBUG(D_SUPER,"OST OBD post_setup\n");
175         /* enable plugins for all in O */
176         SMFS_SET(I2SMI(o_dir)->smi_flags, SMFS_PLG_ALL);
177         /* enable plugins for all already created d<n> dirs */
178         for (j = 1; j < filt->fo_group_count; j++) {
179                 for (i = 0; i < filt->fo_subdir_count; i++) {
180                         dentry = (filt->fo_subdirs + j)->dentry[i];
181                         SMFS_SET(I2SMI(dentry->d_inode)->smi_flags,
182                                          SMFS_PLG_ALL);
183                 }
184         }
185 }
186
187 static void smfs_mds_flags(struct mds_obd *mds, struct inode *root)
188 {
189         struct inode *pend = mds->mds_pending_dir->d_inode;
190         
191         CDEBUG(D_SUPER,"MDS OBD post_setup\n");
192
193         /* enable plugins for all in ROOT */        
194         SMFS_SET(I2SMI(root)->smi_flags, SMFS_PLG_ALL);
195
196         /* the same for PENDING */
197         SMFS_SET(I2SMI(pend)->smi_flags, SMFS_PLG_ALL);
198 }
199
200 extern int (*audit_id2name_superhack) (struct obd_device *obd, char **name,
201                                        int *namelen, struct lustre_id *id);
202
203 int smfs_post_setup(struct obd_device *obd, struct vfsmount *mnt,
204                     struct dentry *root_dentry)
205 {
206         struct lvfs_run_ctxt saved, *current_ctxt = NULL;
207         struct smfs_super_info *smb = S2SMI(mnt->mnt_sb);
208         int rc = 0;
209         ENTRY;
210
211         /* XXX to register id2name function of mds in smfs */
212         //if (data != NULL)
213         //        audit_id2name_superhack = data;
214  
215         OBD_ALLOC(current_ctxt, sizeof(*current_ctxt));
216         if (!current_ctxt)
217                 RETURN(-ENOMEM);
218         
219         OBD_SET_CTXT_MAGIC(current_ctxt);
220         
221         current_ctxt->pwdmnt = mnt;
222         current_ctxt->pwd = mnt->mnt_root;
223         current_ctxt->fs = get_ds();
224         smb->smsi_ctxt = current_ctxt;
225         
226         push_ctxt(&saved, smb->smsi_ctxt, NULL);
227
228         rc = smfs_llog_setup(&smb->smsi_logs_dir, &smb->smsi_objects_dir);
229         if (!rc)
230                 rc = SMFS_PLG_HELP(mnt->mnt_sb, PLG_START, obd);
231
232         pop_ctxt(&saved, smb->smsi_ctxt, NULL);
233
234         /* enable plugins for directories on MDS or OST */
235         if (obd && obd->obd_type && obd->obd_type->typ_name) {
236                 if (!strcmp(obd->obd_type->typ_name, OBD_FILTER_DEVICENAME)) {
237                         struct filter_obd *filt = &obd->u.filter;
238                         smfs_filter_flags(filt, root_dentry->d_inode);
239                 } else if (!strcmp(obd->obd_type->typ_name, OBD_MDS_DEVICENAME)) {
240                         struct mds_obd * mds = &obd->u.mds;
241                         smfs_mds_flags(mds, root_dentry->d_inode);
242                         SMFS_SET_HND_IBLOCKS(smb);
243                 } else {
244                         CDEBUG(D_SUPER,"Unknown OBD (%s) post_setup\n",
245                                obd->obd_type->typ_name);
246                 }
247         }
248
249         if (rc)
250                 OBD_FREE(current_ctxt, sizeof(*current_ctxt));
251         
252         RETURN(rc);
253 }
254
255 void smfs_post_cleanup(struct super_block *sb)
256 {
257         struct smfs_super_info *smb = S2SMI(sb);
258         
259         ENTRY;
260         
261         smfs_llog_cleanup(smb);
262         SMFS_PLG_HELP(sb, PLG_STOP, NULL);
263         
264         if (smb->smsi_ctxt)
265                 OBD_FREE(smb->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
266         
267         EXIT;
268 }
269
270 static int smfs_mount_cache(struct smfs_super_info *smb, char *devstr, 
271                             char *typestr, char *opts)
272 {
273         int err = 0, typelen;
274         struct vfsmount *mnt;
275         ENTRY;
276
277         typelen = strlen(typestr);
278
279         CDEBUG(D_INODE, "smfs: mounting %s at %s\n", typestr, devstr);
280         
281         mnt = do_kern_mount(typestr, 0, devstr, (void *)opts);
282         if (IS_ERR(mnt)) {
283                 CERROR("do_kern_mount failed: rc = %d\n", 
284                        (int)PTR_ERR(mnt));
285                 RETURN(PTR_ERR(mnt));
286         }
287
288         smb->smsi_sb = mnt->mnt_sb;
289         smb->smsi_mnt = mnt;
290
291         smfs_init_sm_ops(smb);
292
293         OBD_ALLOC(smb->smsi_cache_ftype, strlen(typestr) + 1);
294         if (!smb->smsi_cache_ftype)
295                 GOTO(err_umount_cache, err = -ENOMEM);
296
297         memcpy(smb->smsi_cache_ftype, typestr, strlen(typestr));
298
299         OBD_ALLOC(smb->smsi_ftype, strlen(SMFS_TYPE) + 1);
300         if (!smb->smsi_ftype)
301                 GOTO(err_free_cache_fstype, err = -ENOMEM);
302         
303         memcpy(smb->smsi_ftype, SMFS_TYPE, strlen(SMFS_TYPE));
304         
305         err = smfs_init_fsfilt_ops(smb);
306         RETURN(err);
307 err_free_cache_fstype:
308         OBD_FREE(smb->smsi_cache_ftype, strlen(typestr) + 1);
309 err_umount_cache:
310         mntput(mnt);
311 err_out:
312         return err;
313 }
314
315 static int smfs_umount_cache(struct smfs_super_info *smb)
316 {
317         ENTRY;
318         
319         mntput(smb->smsi_mnt);
320         smfs_cleanup_sm_ops(smb);
321         smfs_cleanup_fsfilt_ops(smb);
322
323         if (smb->smsi_cache_ftype) {
324                 OBD_FREE(smb->smsi_cache_ftype,
325                          strlen(smb->smsi_cache_ftype) + 1);
326                 smb->smsi_cache_ftype = NULL;
327         }
328         if (smb->smsi_ftype) {
329                 OBD_FREE(smb->smsi_ftype,
330                          strlen(smb->smsi_ftype) + 1);
331                 smb->smsi_ftype = NULL;
332         }
333
334         RETURN(0);
335 }
336
337 /* This function initializes plugins in SMFS 
338  * @flags: are filled while options parsing 
339  * @sb: smfs super block
340  */
341 static int smfs_init_plugins(struct super_block * sb, int flags)
342 {
343         struct smfs_super_info * smb = S2SMI(sb);
344         
345         ENTRY;
346         
347         INIT_LIST_HEAD(&smb->smsi_plg_list);
348         init_rwsem(&smb->plg_sem);
349
350         if (SMFS_IS(flags, SMFS_PLG_AUDIT))
351                 smfs_init_audit(sb);
352         if (SMFS_IS(flags, SMFS_PLG_KML)) 
353                 smfs_init_kml(sb);
354         if (SMFS_IS(flags, SMFS_PLG_LRU)) 
355                 smfs_init_lru(sb);
356 #if CONFIG_SNAPFS
357         if (SMFS_IS(flags, SMFS_PLG_COW)) 
358                 smfs_init_cow(sb);
359 #endif
360         RETURN(0); 
361 }
362
363 static void smfs_remove_plugins(struct super_block *sb)
364 {
365         struct smfs_plugin * plg, *tmp;
366         struct smfs_super_info *smb = S2SMI(sb);
367         struct list_head * plist = &smb->smsi_plg_list;
368                 
369         ENTRY;
370         
371         list_for_each_entry_safe(plg, tmp, plist, plg_list) {
372                 plg->plg_exit(sb, plg->plg_private);
373         }
374         
375         EXIT;
376 }
377
378 void smfs_put_super(struct super_block *sb)
379 {
380         struct smfs_super_info *smb = S2SMI(sb);
381         ENTRY;
382         smfs_remove_plugins(sb);
383         
384         dput(sb->s_root);
385         
386         if (smb->smsi_mnt)
387                 smfs_umount_cache(smb);
388         
389         smfs_cleanup_smb(smb);
390         EXIT;
391 }
392
393 int smfs_fill_super(struct super_block *sb, void *data, int silent)
394 {
395         struct inode *root_inode = NULL;
396         struct inode *back_root_inode = NULL;
397         struct smfs_super_info *smb = NULL;
398         char *devstr = NULL, *typestr = NULL;
399         unsigned long page = 0;
400         char *opts = NULL;
401         int flags = 0;
402         int err = 0;
403         
404         ENTRY;
405         
406         if (!data) {
407                 CERROR("no mount options. At least name and dev are needed\n");
408                 err = -EINVAL;
409                 goto out_err;
410         }
411
412         CDEBUG(D_SUPER, "mount opts: %s\n", (char *)data);
413
414         smb = smfs_init_smb(sb);
415         if (!smb)
416                 RETURN(-ENOMEM);
417         
418         lock_kernel();
419
420         /* 2.6.9 selinux wants a full option page for do_kern_mount (bug6471) */
421         page = get_zeroed_page(GFP_KERNEL);
422         if (!page) {
423                 err = -ENOMEM;
424                 goto out_err;
425         }
426         opts = (char *)page;
427         
428         err = smfs_options(data, &devstr, &typestr, opts, &flags);
429         if (err)
430                 goto out_err;
431                 
432         if (!typestr || !devstr) {
433                 CERROR("mount options name and dev are mandatory\n");
434                 err = -EINVAL;
435                 goto out_err;
436         }
437         
438         CDEBUG(D_SUPER, "backfs mount opts: %s\n", opts);
439
440         err = smfs_mount_cache(smb, devstr, typestr, opts);
441         if (err) {
442                 CERROR("Can not mount %s as %s\n", devstr, typestr);
443                 goto out_err;
444         }
445
446         free_page(page);
447         page = 0;
448         
449         duplicate_sb(sb, smb->smsi_sb);
450         sb->s_bdev = smb->smsi_sb->s_bdev;
451         sm_set_sb_ops(smb->smsi_sb, sb);
452
453         /* init the root_inode of smfs. */ 
454         back_root_inode = S2CSB(sb)->s_root->d_inode;
455         root_inode = smfs_get_inode(sb, back_root_inode, NULL, 0);
456
457         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
458                sb->s_op->read_inode, root_inode->i_ino, root_inode);
459
460         sb->s_root = d_alloc_root(root_inode);
461         if (!sb->s_root) {
462                 err = -ENOMEM;
463                 goto out_err;
464         }
465         
466         /* all entries created until post_setup() should not be logged */
467         SMFS_CLEAR((I2SMI(root_inode))->smi_flags, SMFS_PLG_ALL);
468    
469 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
470         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
471                (ulong)sb, (ulong)&sb->u.generic_sbp);
472 #else
473         CDEBUG(D_SUPER, "sb %lx(%p), &sb->s_fs_info: %lx\n",
474                (ulong)sb, smb->smsi_sb, (ulong)&sb->s_fs_info);
475 #endif
476         
477         smfs_init_plugins(sb, flags);
478         unlock_kernel();
479         RETURN (0);
480 out_err:
481         if (smb->smsi_mnt)
482                 smfs_umount_cache(smb);
483
484         if (page)
485                 free_page(page);
486
487         smfs_cleanup_smb(smb);
488         unlock_kernel();
489         RETURN(err);
490 }
491
492 void *smfs_trans_start(struct inode *inode, int op, void *desc_private)
493 {
494         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
495
496         if (fsfilt->fs_start)
497                 return fsfilt->fs_start(inode, op, NULL, 0);
498         return NULL;
499 }
500
501 void smfs_trans_commit(struct inode *inode, void *handle, int force_sync)
502 {
503         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
504
505         if (handle && fsfilt->fs_commit)
506                 fsfilt->fs_commit(inode->i_sb, inode, handle, force_sync);
507 }
508 /* Plugin API */
509 int smfs_register_plugin(struct super_block * sb,
510                          struct smfs_plugin * plg) 
511 {
512         struct smfs_plugin * tmp = NULL;
513         struct smfs_super_info * smb = S2SMI(sb);
514         struct list_head * plist = &smb->smsi_plg_list;
515         int rc = 0;
516         
517         ENTRY;
518         
519         down_write(&smb->plg_sem);
520         list_for_each_entry(tmp, plist, plg_list) {
521                 if (tmp->plg_type == plg->plg_type) {
522                         CWARN("Plugin is already registered\n");
523                         rc = -EEXIST;
524                         goto exit;
525                 }
526         }
527
528         list_add_tail(&plg->plg_list, plist);
529 exit:
530         up_write(&smb->plg_sem);
531         RETURN(0);
532 }
533
534 struct smfs_plugin * smfs_deregister_plugin(struct super_block *sb, int type)
535 {
536         struct smfs_plugin * plg = NULL;
537         struct smfs_super_info *smb = S2SMI(sb);
538         struct list_head * plist = &smb->smsi_plg_list;
539                 
540         ENTRY;
541         down_write(&smb->plg_sem);
542         list_for_each_entry(plg, plist, plg_list) {
543                 if (plg->plg_type == type) {
544                         list_del(&plg->plg_list);
545                         break;
546                 }
547         }
548         up_write(&smb->plg_sem);
549         RETURN(plg);
550 }
551
552 void smfs_pre_hook (struct inode * inode, hook_op op, void * msg) 
553 {
554         struct smfs_super_info *smb = S2SMI(inode->i_sb);    
555         struct smfs_inode_info *smi = I2SMI(inode);
556         struct list_head *hlist = &smb->smsi_plg_list;
557         struct smfs_plugin *plg;
558                 
559         //ENTRY;
560         LASSERT(op < HOOK_MAX);
561         //call hook operations
562         down_read(&smb->plg_sem);
563         list_for_each_entry(plg, hlist, plg_list) {
564                 //check that plugin is active
565                 if(!SMFS_IS(smb->plg_flags, plg->plg_type))
566                         continue;
567                 //check that inode is allowed
568                 if (!SMFS_IS(smi->smi_flags, plg->plg_type))
569                         continue;
570                 
571                 if (plg->plg_pre_op)
572                         plg->plg_pre_op(op, inode, msg, 0, plg->plg_private);
573         }
574         up_read(&smb->plg_sem);
575         //EXIT;
576 }
577
578 void smfs_post_hook (struct inode * inode, hook_op op, void * msg, int ret)
579 {
580         struct smfs_super_info *smb = S2SMI(inode->i_sb);
581         //struct smfs_inode_info *smi = I2SMI(inode);
582         struct list_head *hlist = &smb->smsi_plg_list;
583         struct smfs_plugin *plg;
584         
585         //ENTRY;
586         down_read(&smb->plg_sem);
587         list_for_each_entry(plg, hlist, plg_list) {
588                 //check that plugin is active
589                 if(!SMFS_IS(smb->plg_flags, plg->plg_type))
590                         continue;
591                 /* this will be checked inside plg_post_op()
592                 if (!SMFS_IS(smi->smi_flags, plg->plg_type))
593                         continue;
594                 */
595                 if (plg->plg_post_op)
596                         plg->plg_post_op(op, inode, msg, ret, plg->plg_private);
597         }
598         up_read(&smb->plg_sem);
599         //EXIT;
600 }
601
602 int smfs_helper (struct super_block * sb, int op, void * msg) 
603 {
604         struct smfs_super_info *smb = S2SMI(sb);    
605         struct list_head *hlist = &smb->smsi_plg_list;
606         struct smfs_plugin *plg, *tmp;
607         int rc = 0;
608         
609         //ENTRY;
610         LASSERT(op < PLG_HELPER_MAX);
611         //call hook operations
612         down_read(&smb->plg_sem);
613         list_for_each_entry_safe(plg, tmp, hlist, plg_list) {
614                 //check that plugin is active
615                 if(!SMFS_IS(smb->plg_flags, plg->plg_type) && 
616                    !(op == PLG_START || op == PLG_EXIT))
617                         continue;
618                
619                 if (plg->plg_helper)
620                        rc += plg->plg_helper(op, sb, msg, plg->plg_private);
621         }
622         up_read(&smb->plg_sem);
623         //EXIT;
624         
625         return rc;
626 }
627
628 void * smfs_get_plg_priv(struct smfs_super_info * smb, int type) 
629 {
630         struct list_head *hlist = &smb->smsi_plg_list;
631         struct smfs_plugin *plg, *tmp;
632         
633         list_for_each_entry_safe(plg, tmp, hlist, plg_list) {
634                 if (plg->plg_type == type) {
635                         return (plg->plg_private);
636                 }
637         }
638         
639         EXIT;
640         
641         return NULL;
642 }
643