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