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