Whamcloud - gitweb
b=3031
[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         RETURN(smb);        
122 }
123
124 static void smfs_cleanup_smb(struct smfs_super_info *smb)
125 {
126         ENTRY;
127
128         if (smb) 
129                 OBD_FREE(smb, sizeof(*smb));
130         EXIT;
131 }
132
133 static int smfs_init_fsfilt_ops(struct smfs_super_info *smb)
134 {
135         ENTRY;
136         if (!smb->sm_cache_fsfilt) {
137                 smb->sm_cache_fsfilt =
138                         fsfilt_get_ops(smb->smsi_cache_ftype);
139                 if (!smb->sm_cache_fsfilt) {
140                         CERROR("Can not get %s fsfilt ops needed by smfs\n",
141                                smb->smsi_cache_ftype);
142                         RETURN(-EINVAL);
143                 }
144         }
145         if (!smb->sm_fsfilt) {
146                 smb->sm_fsfilt =
147                         fsfilt_get_ops(smb->smsi_ftype);
148                 if (!smb->sm_fsfilt) {
149                         CERROR("Can not get %s fsfilt ops needed by smfs\n",
150                                smb->smsi_ftype);
151                         RETURN(-EINVAL);
152                 }
153         }
154         RETURN(0);
155 }
156
157 void smfs_cleanup_fsfilt_ops(struct smfs_super_info *smb)
158 {
159         if (smb->sm_cache_fsfilt)
160                 fsfilt_put_ops(smb->sm_cache_fsfilt);
161         if (smb->sm_fsfilt)
162                 fsfilt_put_ops(smb->sm_fsfilt);
163 }
164
165 int smfs_post_setup(struct super_block *sb, struct vfsmount *mnt)
166 {
167         struct lvfs_run_ctxt saved, *current_ctxt = NULL;
168         struct smfs_super_info *smb = S2SMI(sb);
169         int rc = 0;
170         
171         ENTRY;
172  
173         OBD_ALLOC(current_ctxt, sizeof(*current_ctxt));
174         if (!current_ctxt)
175                 RETURN(-ENOMEM);
176         
177         OBD_SET_CTXT_MAGIC(current_ctxt);
178         
179         current_ctxt->pwdmnt = mnt;
180         current_ctxt->pwd = mnt->mnt_root;
181         current_ctxt->fs = get_ds();
182         smb->smsi_ctxt = current_ctxt;
183         
184         push_ctxt(&saved, smb->smsi_ctxt, NULL);
185
186         rc = smfs_llog_setup(sb, mnt);
187         if (!rc) {
188                 rc = SMFS_PLG_HELP(sb, PLG_START, NULL);
189         }
190
191         pop_ctxt(&saved, smb->smsi_ctxt, NULL);
192
193         if (rc)
194                 OBD_FREE(current_ctxt, sizeof(*current_ctxt));
195   
196         RETURN(rc);
197 }
198
199 void smfs_post_cleanup(struct super_block *sb)
200 {
201         struct smfs_super_info *smb = S2SMI(sb);
202         
203         ENTRY;
204         
205         smfs_llog_cleanup(sb);
206         SMFS_PLG_HELP(sb, PLG_STOP, NULL);
207         
208         if (smb->smsi_ctxt)
209                 OBD_FREE(smb->smsi_ctxt, sizeof(struct lvfs_run_ctxt));
210         
211         EXIT;
212 }
213
214 static int smfs_mount_cache(struct smfs_super_info *smb, char *devstr, 
215                             char *typestr, char *opts)
216 {
217         int err = 0, typelen;
218         struct vfsmount *mnt;
219         ENTRY;
220
221         typelen = strlen(typestr);
222
223         CDEBUG(D_INODE, "smfs: mounting %s at %s\n", typestr, devstr);
224         mnt = do_kern_mount(typestr, 0, devstr, (void *)opts);
225         if (IS_ERR(mnt)) {
226                 CERROR("do_kern_mount failed: rc = %ld\n", 
227                        PTR_ERR(mnt));
228                 GOTO(err_out, err = PTR_ERR(mnt));
229         }
230
231         smb->smsi_sb = mnt->mnt_sb;
232         smb->smsi_mnt = mnt;
233
234         smfs_init_sm_ops(smb);
235
236         OBD_ALLOC(smb->smsi_cache_ftype, strlen(typestr) + 1);
237         memcpy(smb->smsi_cache_ftype, typestr, strlen(typestr));
238
239         OBD_ALLOC(smb->smsi_ftype, strlen(SMFS_TYPE) + 1);
240         memcpy(smb->smsi_ftype, SMFS_TYPE, strlen(SMFS_TYPE));
241         
242         err = smfs_init_fsfilt_ops(smb);
243 err_out:
244         RETURN(err);
245 }
246
247 static int smfs_umount_cache(struct smfs_super_info *smb)
248 {
249         mntput(smb->smsi_mnt);
250         smfs_cleanup_sm_ops(smb);
251         smfs_cleanup_fsfilt_ops(smb);
252
253         if (smb->smsi_cache_ftype)
254                 OBD_FREE(smb->smsi_cache_ftype,
255                          strlen(smb->smsi_cache_ftype) + 1);
256         if (smb->smsi_ftype)
257                 OBD_FREE(smb->smsi_ftype, strlen(smb->smsi_ftype) + 1);
258                
259         return 0;
260 }
261
262 /* This function initializes plugins in SMFS 
263  * @flags: are filled while options parsing 
264  * @sb: smfs super block
265  */
266
267 static int smfs_init_plugins(struct super_block * sb, int flags)
268 {
269         struct smfs_super_info * smb = S2SMI(sb);
270         
271         ENTRY;
272         
273         INIT_LIST_HEAD(&smb->smsi_plg_list);
274
275         if (SMFS_IS(flags, SMFS_PLG_KML)) 
276                 smfs_init_kml(sb);
277         if (SMFS_IS(flags, SMFS_PLG_LRU)) 
278                 smfs_init_lru(sb);
279 #if CONFIG_SNAPFS
280         if (SMFS_IS(flags, SMFS_PLG_COW)) 
281                 smfs_init_cow(sb);
282 #endif
283         RETURN(0); 
284 }
285
286 static void smfs_remove_plugins(struct super_block *sb)
287 {
288         ENTRY;
289
290         SMFS_PLG_HELP(sb, PLG_EXIT, (void*)sb);
291         
292         EXIT;
293 }
294
295 void smfs_put_super(struct super_block *sb)
296 {
297         struct smfs_super_info *smb = S2SMI(sb);
298         ENTRY;
299         smfs_remove_plugins(sb);
300         
301         dput(sb->s_root);
302         
303         if (smb->smsi_mnt)
304                 smfs_umount_cache(smb);
305         
306         smfs_cleanup_smb(smb);
307         EXIT;
308 }
309
310 int smfs_fill_super(struct super_block *sb, void *data, int silent)
311 {
312         struct inode *root_inode = NULL;
313         struct smfs_super_info *smb = NULL;
314         char *devstr = NULL, *typestr = NULL; 
315         char *opts = NULL;
316         int err = 0;
317         int flags = 0;
318         ino_t root_ino;
319
320         ENTRY;
321         
322         if (!data) {
323                 CERROR("no mount options. At least name and dev are needed\n");
324                 err = -EINVAL;
325                 goto out_err;
326         }
327
328         CDEBUG(D_SUPER, "mount opts: %s\n", (char *)data);
329
330         smb = smfs_init_smb(sb);
331         if (!smb)
332                 RETURN(-ENOMEM);
333         lock_kernel();
334         OBD_ALLOC(opts, strlen(data) + 1);
335         if (!opts) {
336                 err = -ENOMEM;
337                 goto out_err;
338         }
339         
340         err = smfs_options(data, &devstr, &typestr, opts, &flags);
341         if (err)
342                 goto out_err;
343                 
344         if (!typestr || !devstr) {
345                 CERROR("mount options name and dev are mandatory\n");
346                 err = -EINVAL;
347                 goto out_err;
348         }
349         
350         CDEBUG(D_SUPER, "backfs mount opts: %s\n", opts);
351
352         err = smfs_mount_cache(smb, devstr, typestr, opts);
353         if (err) {
354                 CERROR("Can not mount %s as %s\n", devstr, typestr);
355                 goto out_err;
356         }
357
358         OBD_FREE(opts, strlen(data) + 1);
359         opts = NULL;
360         
361         duplicate_sb(sb, smb->smsi_sb);
362         sb->s_bdev = smb->smsi_sb->s_bdev;
363         sm_set_sb_ops(smb->smsi_sb, sb);
364
365         /* init the root_inode of smfs. */ 
366         root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
367         root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
368
369         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
370                sb->s_op->read_inode, root_ino, root_inode);
371
372         sb->s_root = d_alloc_root(root_inode);
373         if (!sb->s_root) {
374                 err = -ENOMEM;
375                 goto out_err;
376         }
377         
378 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
379         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
380                (ulong)sb, (ulong)&sb->u.generic_sbp);
381 #else
382         CDEBUG(D_SUPER, "sb %lx(%p), &sb->s_fs_info: %lx\n",
383                (ulong)sb, smb->smsi_sb, (ulong)&sb->s_fs_info);
384 #endif
385         
386         smfs_init_plugins(sb, flags);
387         unlock_kernel();
388         RETURN (0);
389 out_err:
390         if (smb->smsi_mnt)
391                 smfs_umount_cache(smb);
392
393         if (opts)
394                 OBD_FREE(opts, strlen(data) + 1);
395
396         smfs_cleanup_smb(smb);
397         unlock_kernel();
398         RETURN(err);
399 }
400
401 void *smfs_trans_start(struct inode *inode, int op, void *desc_private)
402 {
403         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
404
405         CDEBUG(D_INFO, "trans start %p\n", fsfilt->fs_start);
406
407         SMFS_TRANS_OP(inode, op);
408         
409         /* There are some problem here. fs_start in fsfilt is used by lustre
410          * the journal blocks of write rec are not counted in FIXME later */
411         if (fsfilt->fs_start)
412                 return fsfilt->fs_start(inode, op, desc_private, 0);
413         return NULL;
414 }
415
416 void smfs_trans_commit(struct inode *inode, void *handle, int force_sync)
417 {
418         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
419
420         if (!handle)
421                 return;
422
423         CDEBUG(D_INFO, "trans commit %p\n", fsfilt->fs_commit);
424
425         if (fsfilt->fs_commit)
426                 fsfilt->fs_commit(inode->i_sb, inode, handle, force_sync);
427 }
428 /* Plugin API */
429 int smfs_register_plugin(struct super_block * sb,
430                          struct smfs_plugin * new_plugin) 
431 {
432         struct smfs_super_info * smb = S2SMI(sb);
433         struct smfs_plugin * plg = NULL;
434         struct list_head * plist = &S2SMI(sb)->smsi_plg_list;
435         
436         ENTRY;
437         
438         list_for_each_entry(plg, plist, plg_list) {
439                 if (plg->plg_type == new_plugin->plg_type) {
440                         CWARN("Plugin is already registered\n");
441                         RETURN(-EEXIST);
442                 }
443         }
444         
445         
446         if (SMFS_IS(smb->smsi_flags, new_plugin->plg_type)) {
447                 CWARN("Plugin is already registered\n");
448                 RETURN(-EEXIST);  
449         }
450                 
451         OBD_ALLOC(plg, sizeof(*plg));
452         if (!plg) {
453                 CWARN("Cannot allocate memory for plugin\n");
454                 RETURN(-ENOMEM);
455         }
456         
457         memcpy(plg, new_plugin, sizeof(*plg));
458         list_add_tail(&plg->plg_list, plist);
459         
460         RETURN(0);
461 }
462
463 void * smfs_deregister_plugin(struct super_block *sb, int type)
464 {
465         struct smfs_plugin * plg = NULL;
466         struct list_head * plist = &S2SMI(sb)->smsi_plg_list;
467         void * priv = NULL;
468         
469         ENTRY;
470
471         list_for_each_entry(plg, plist, plg_list) {
472                 if (plg->plg_type == type) {
473                         list_del(&plg->plg_list);
474                         priv = plg->plg_private;
475                         OBD_FREE(plg, sizeof(*plg));
476                         break;
477                 }
478         }
479                 
480         RETURN(priv);
481 }
482
483 void smfs_pre_hook (struct inode * inode, int op, void * msg) 
484 {
485         struct smfs_super_info *smb = S2SMI(inode->i_sb);    
486         struct smfs_inode_info *smi = I2SMI(inode);
487         struct list_head *hlist = &smb->smsi_plg_list;
488         struct smfs_plugin *plg;
489                 
490         //ENTRY;
491         LASSERT(op < HOOK_MAX);
492         //call hook operations
493         list_for_each_entry(plg, hlist, plg_list) {
494                 //check that plugin is active
495                 if(!SMFS_IS(smb->plg_flags, plg->plg_type))
496                         continue;
497                 //check that inode is not exclusion
498                 if (!SMFS_IS(smi->smi_flags, plg->plg_type))
499                         continue;
500                 
501                 if (plg->plg_pre_op)
502                         plg->plg_pre_op(op, inode, msg, 0, plg->plg_private);
503         }
504
505         //EXIT;
506 }
507
508 void smfs_post_hook (struct inode * inode, int op, void * msg, int ret)
509 {
510         struct smfs_super_info *smb = S2SMI(inode->i_sb);
511         struct smfs_inode_info *smi = I2SMI(inode);
512         struct list_head *hlist = &smb->smsi_plg_list;
513         struct smfs_plugin *plg;
514         
515         //ENTRY;
516         
517         list_for_each_entry(plg, hlist, plg_list) {
518                 //check that plugin is active
519                 if(!SMFS_IS(smb->plg_flags, plg->plg_type))
520                         continue;
521                 //check that inode is not exclusion
522                 if (!SMFS_IS(smi->smi_flags, plg->plg_type))
523                         continue;
524                 
525                 if (plg->plg_post_op)
526                         plg->plg_post_op(op, inode, msg, ret, plg->plg_private);
527         }
528
529         //EXIT;
530 }
531
532 int smfs_helper (struct super_block * sb, int op, void * msg) 
533 {
534         struct smfs_super_info *smb = S2SMI(sb);    
535         struct list_head *hlist = &smb->smsi_plg_list;
536         struct smfs_plugin *plg;
537         int rc = 0;
538         
539         ENTRY;
540         LASSERT(op < PLG_HELPER_MAX);
541         //call hook operations
542         list_for_each_entry(plg, hlist, plg_list) {
543                if (plg->plg_helper)
544                        rc += plg->plg_helper(op, sb, msg, plg->plg_private);
545         }
546
547         EXIT;
548         
549         return rc;
550 }
551
552