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