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