Whamcloud - gitweb
* 5852 vibnal patch to detect __u64/void* vv_scatgat_t::v_address and
[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
49 struct list_head smfs_plg_list;
50
51 static struct smfs_super_info *smfs_init_smb(struct super_block *sb)
52 {
53         struct smfs_super_info *smb;
54         ENTRY;
55
56         OBD_ALLOC(smb, sizeof(*smb));
57         if (!smb)
58                 RETURN(NULL);        
59         
60         S2FSI(sb) = smb;
61         RETURN(smb);        
62 }
63
64 static int smfs_init_fsfilt_ops(struct smfs_super_info *smb)
65 {
66         ENTRY;
67         if (!smb->sm_cache_fsfilt) {
68                 smb->sm_cache_fsfilt =
69                         fsfilt_get_ops(smb->smsi_cache_ftype);
70                 if (!smb->sm_cache_fsfilt) {
71                         CERROR("Can not get %s fsfilt ops needed by kml\n",
72                                smb->smsi_cache_ftype);
73                         RETURN(-EINVAL);
74                 }
75         }
76         if (!smb->sm_fsfilt) {
77                 smb->sm_fsfilt =
78                         fsfilt_get_ops(smb->smsi_ftype);
79                 if (!smb->sm_fsfilt) {
80                         CERROR("Can not get %s fsfilt ops needed by kml\n",
81                                smb->smsi_ftype);
82                         RETURN(-EINVAL);
83                 }
84         }
85         RETURN(0);
86 }
87
88 void smfs_cleanup_fsfilt_ops(struct smfs_super_info *smb)
89 {
90         if (smb->sm_cache_fsfilt)
91                 fsfilt_put_ops(smb->sm_cache_fsfilt);
92         if (smb->sm_fsfilt)
93                 fsfilt_put_ops(smb->sm_fsfilt);
94 }
95
96 static int smfs_mount_cache(struct smfs_super_info *smb, char *devstr, 
97                             char *typestr, char *opts)
98 {
99         int err = 0, typelen;
100         struct vfsmount *mnt;
101         ENTRY;
102
103         typelen = strlen(typestr);
104
105         printk("smfs: mounting %s at %s\n", typestr, devstr);
106         mnt = do_kern_mount(typestr, 0, devstr, (void *)opts);
107         if (IS_ERR(mnt)) {
108                 CERROR("do_kern_mount failed: rc = %ld\n", 
109                        PTR_ERR(mnt));
110                 GOTO(err_out, err = PTR_ERR(mnt));
111         }
112
113         smb->smsi_sb = mnt->mnt_sb;
114         smb->smsi_mnt = mnt;
115
116         smfs_init_sm_ops(smb);
117
118         OBD_ALLOC(smb->smsi_cache_ftype, strlen(typestr) + 1);
119         memcpy(smb->smsi_cache_ftype, typestr, strlen(typestr));
120
121         OBD_ALLOC(smb->smsi_ftype, strlen(SMFS_TYPE) + 1);
122         memcpy(smb->smsi_ftype, SMFS_TYPE, strlen(SMFS_TYPE));
123         
124         err = smfs_init_fsfilt_ops(smb);
125 err_out:
126         RETURN(err);
127 }
128
129 static int smfs_umount_cache(struct smfs_super_info *smb)
130 {
131         mntput(smb->smsi_mnt);
132         smfs_cleanup_sm_ops(smb);
133         smfs_cleanup_fsfilt_ops(smb);
134
135         if (smb->smsi_cache_ftype)
136                 OBD_FREE(smb->smsi_cache_ftype,
137                          strlen(smb->smsi_cache_ftype) + 1);
138         if (smb->smsi_ftype)
139                 OBD_FREE(smb->smsi_ftype, strlen(smb->smsi_ftype) + 1);
140                
141         return 0;
142 }
143
144 static int smfs_init_hook_ops(struct smfs_super_info *smb)
145 {
146         ENTRY;
147         INIT_LIST_HEAD(&smb->smsi_hook_list);
148         INIT_LIST_HEAD(&smb->smsi_plg_list);
149         RETURN(0); 
150 }
151
152 static void smfs_cleanup_hook_ops(struct smfs_super_info *smb)
153 {
154         struct list_head *hlist = &smb->smsi_hook_list;
155         ENTRY;
156
157         while (!list_empty(hlist)) {
158                 struct smfs_hook_ops *smfs_hops;
159                 
160                 smfs_hops = list_entry(hlist->next, struct smfs_hook_ops, 
161                                        smh_list);
162                 CERROR("Unregister %s hook ops\n", smfs_hops->smh_name);         
163                 
164                 smfs_unregister_hook_ops(smb, smfs_hops->smh_name);
165                 smfs_free_hook_ops(smfs_hops); 
166         } 
167         EXIT;
168 }
169 static void smfs_cleanup_smb(struct super_block *sb)
170 {
171         struct smfs_super_info *smb;
172         ENTRY;
173
174         smb = S2SMI(sb);
175         if (smb) 
176                 OBD_FREE(smb, sizeof(*smb));
177         EXIT;
178 }
179
180 void smfs_cleanup_hooks(struct smfs_super_info *smb)
181 {
182         
183         if (SMFS_CACHE_HOOK(smb))
184                 cache_space_hook_exit(smb);
185         if (SMFS_DO_REC(smb))
186                 smfs_rec_cleanup(smb);
187 #if CONFIG_SNAPFS
188         if (SMFS_DO_COW(smb))
189                 smfs_cow_cleanup(smb);
190 #endif  
191         smfs_cleanup_hook_ops(smb);
192 }
193
194 void smfs_put_super(struct super_block *sb)
195 {
196         struct smfs_super_info *smfs_info = S2SMI(sb);
197
198         smfs_cleanup_hooks(smfs_info);
199         
200         if (sb)
201                 smfs_umount_cache(smfs_info);
202         smfs_cleanup_smb(sb); 
203 }
204
205 static int smfs_init_hooks(struct super_block *sb)
206
207         ENTRY;
208  
209         if (SMFS_DO_REC(S2SMI(sb))) 
210                 smfs_rec_init(sb);
211         if (SMFS_CACHE_HOOK(S2SMI(sb))) 
212                 cache_space_hook_init(sb);
213 #if CONFIG_SNAPFS
214         if (SMFS_DO_COW(S2SMI(sb))) 
215                 smfs_cow_init(sb);
216 #endif
217         RETURN(0);
218 }
219
220 extern char* smfs_options(char*, char**, char**, char*, int *);
221
222 int smfs_fill_super(struct super_block *sb, void *data, int silent)
223 {
224         struct inode *root_inode = NULL;
225         struct smfs_super_info *smb = NULL;
226         char *devstr = NULL, *typestr = NULL; 
227         char *opts = NULL, *cache_data = NULL;
228         unsigned long page;
229         int err = 0; 
230         ino_t root_ino;
231
232         ENTRY;
233
234         CDEBUG(D_SUPER, "mount opts: %s\n", data ? 
235                (char *)data : "(none)");
236
237         smb = smfs_init_smb(sb);
238         if (!smb)
239                 RETURN(-ENOMEM);
240  
241         page = __get_free_page(GFP_KERNEL);
242         if (!page)
243                 GOTO(out_err, err = -ENOMEM);
244         
245         memset((void *)page, 0, PAGE_SIZE);
246         opts = (char *)page;
247
248         cache_data = smfs_options(data, &devstr, &typestr, opts, 
249                                   &smb->smsi_flags); 
250         if (*cache_data) {
251                 CWARN("smfs_fill_super(): options parsing stoped at "
252                       "option %s\n", cache_data);
253         }
254
255         if (!typestr || !devstr) {
256                 CERROR("mount options name and dev are mandatory\n");
257                 free_page(page);
258                 GOTO(out_err, err = -EINVAL);
259         }
260         
261         err = smfs_mount_cache(smb, devstr, typestr, opts);
262         free_page(page);
263         
264         if (err) {
265                 CERROR("Can not mount %s as %s\n", devstr, typestr);
266                 GOTO(out_err, err);
267         }
268
269         duplicate_sb(sb, smb->smsi_sb);
270         sb->s_bdev = smb->smsi_sb->s_bdev;
271         sm_set_sb_ops(smb->smsi_sb, sb);
272
273         err = smfs_init_hook_ops(smb);
274         if (err) {
275                 CERROR("Can not init super hook ops err %d\n", err);
276                 smfs_umount_cache(smb);
277                 GOTO(out_err, err);
278         }
279         
280         /* init the root_inode of smfs. */ 
281         //dget(S2CSB(sb)->s_root);
282         root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
283         root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
284
285         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
286                sb->s_op->read_inode, root_ino, root_inode);
287
288         sb->s_root = d_alloc_root(root_inode);
289
290         if (!sb->s_root) {
291                 smfs_umount_cache(smb);
292                 GOTO(out_err, err = -ENOMEM);
293         }
294         
295         err = smfs_init_hooks(sb);  
296         if (err) {
297                 smfs_umount_cache(smb);
298                 GOTO(out_err, err);
299         }       
300 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
301         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
302                (ulong)sb, (ulong)&sb->u.generic_sbp);
303 #else
304         CDEBUG(D_SUPER, "sb %lx(%p), &sb->s_fs_info: %lx\n",
305                (ulong)sb, smb->smsi_sb, (ulong)&sb->s_fs_info);
306 #endif
307         
308 out_err:
309         cleanup_option();
310         if (err)
311                 smfs_cleanup_smb(sb);
312         return err;
313 }
314
315 struct smfs_hook_ops *smfs_alloc_hook_ops(char *name, smfs_hook_func pre_hook, 
316                                           smfs_hook_func post_hook)
317 {
318         struct smfs_hook_ops *smfs_hops = NULL;
319         
320         ENTRY;
321         OBD_ALLOC(smfs_hops, sizeof(struct smfs_hook_ops));
322
323         if (!smfs_hops)
324                 RETURN(NULL);
325  
326         OBD_ALLOC(smfs_hops->smh_name, strlen(name) + 1);
327         
328         if (!smfs_hops->smh_name) { 
329                 OBD_FREE(smfs_hops, sizeof(struct smfs_hook_ops));
330                 RETURN(NULL);
331         }
332         
333         memcpy(smfs_hops->smh_name, name, strlen(name));  
334        
335         smfs_hops->smh_post_op = post_hook;  
336         smfs_hops->smh_pre_op = pre_hook;  
337         
338         RETURN(smfs_hops); 
339 }
340
341 void smfs_free_hook_ops(struct smfs_hook_ops *hops)
342 {
343         if (hops) {
344                 if (hops->smh_name){
345                         OBD_FREE(hops->smh_name, strlen(hops->smh_name) + 1);
346                 }
347                 OBD_FREE(hops, sizeof(struct smfs_hook_ops));
348         }
349 }
350
351 int smfs_register_hook_ops(struct smfs_super_info *smb, 
352                            struct smfs_hook_ops *smh_ops)
353 {
354         struct list_head *hlist = &smb->smsi_hook_list;
355         struct list_head *p;
356         ENTRY;
357  
358         list_for_each(p, hlist) {
359                 struct smfs_hook_ops *found;               
360                 found = list_entry(p, struct smfs_hook_ops, smh_list);
361                 if (!strcmp(found->smh_name, smh_ops->smh_name)) {
362                         CWARN("hook ops %s list  reregister\n", smh_ops->smh_name);
363                         RETURN(0);
364                 }
365         }
366         list_add(&smh_ops->smh_list, hlist);
367         RETURN(0);
368
369
370 struct smfs_hook_ops *smfs_unregister_hook_ops(struct smfs_super_info *smb, 
371                                                char *name)
372 {
373         struct list_head *hlist = &smb->smsi_hook_list;
374         struct list_head *p;
375         ENTRY;      
376  
377         list_for_each(p, hlist) {
378                 struct smfs_hook_ops *found;
379
380                 found = list_entry(p, typeof(*found), smh_list);
381                 if (!memcmp(found->smh_name, name, strlen(name))) {
382                         list_del(p);
383                         RETURN(found);
384                 }
385         }
386
387         RETURN(NULL);
388 }
389
390 void *smfs_trans_start(struct inode *inode, int op, void *desc_private)
391 {
392         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
393
394         CDEBUG(D_INFO, "trans start %p\n", fsfilt->fs_start);
395
396         SMFS_TRANS_OP(inode, op);
397         
398         /* There are some problem here. fs_start in fsfilt is used by lustre
399          * the journal blocks of write rec are not counted in FIXME later */
400         if (fsfilt->fs_start)
401                 return fsfilt->fs_start(inode, op, desc_private, 0);
402         return NULL;
403 }
404
405 void smfs_trans_commit(struct inode *inode, void *handle, int force_sync)
406 {
407         struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
408
409         if (!handle)
410                 return;
411
412         CDEBUG(D_INFO, "trans commit %p\n", fsfilt->fs_commit);
413
414         if (fsfilt->fs_commit)
415                 fsfilt->fs_commit(inode->i_sb, inode, handle, force_sync);
416 }
417
418
419 int smfs_register_plugin(struct super_block * sb, struct smfs_plugin * new_plugin) 
420 {
421         struct smfs_plugin * plg = NULL;
422         struct list_head * plist = &S2SMI(sb)->smsi_plg_list;
423         
424         ENTRY;
425         
426         list_for_each_entry(plg, plist, plg_list) {
427                 if (plg->plg_type == new_plugin->plg_type) {
428                         CWARN("Plugin is already registered\n");
429                         RETURN(-EEXIST);
430                 }
431         }
432         
433         OBD_ALLOC(plg, sizeof(*plg));
434         if (!plg) {
435                 CWARN("Cannot allocate memory for plugin\n");
436                 RETURN(-ENOMEM);
437         }
438         
439         memcpy(plg, new_plugin, sizeof(*plg));
440         list_add_tail(&plg->plg_list, plist);
441                 
442         RETURN(0);
443 }
444
445 void * smfs_deregister_plugin(struct super_block * sb, int type)
446 {
447         struct smfs_plugin * plg = NULL;
448         struct list_head * plist = &S2SMI(sb)->smsi_plg_list;
449         void * priv = NULL;
450         
451         ENTRY;
452         list_for_each_entry(plg, plist, plg_list) {
453                 if (plg->plg_type == type) {
454                         list_del(&plg->plg_list);
455                         priv = plg->plg_private;
456                         OBD_FREE(plg, sizeof(*plg));
457                         break;
458                 }
459         }
460                 
461         RETURN(priv);
462 }
463
464