Whamcloud - gitweb
Small fix on the description of some lctl commands.
[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  *  Copyright (C) 2004 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #define DEBUG_SUBSYSTEM S_SM
24
25 #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/kmod.h>
28 #include <linux/init.h>
29 #include <linux/fs.h>
30 #include <linux/string.h>
31 #include <linux/mm.h>
32 #include <linux/utime.h>
33 #include <linux/file.h>
34 #include <linux/slab.h>
35 #include <linux/dcache.h>
36 #include <linux/loop.h>
37 #include <linux/errno.h>
38 #include <linux/obd_class.h>
39 #include <linux/obd_support.h>
40 #include <linux/lustre_lib.h>
41 #include <linux/lustre_idl.h>
42 #include <linux/lustre_fsfilt.h>
43 #include <linux/lustre_smfs.h>
44 #include "smfs_internal.h"
45
46 static char *smfs_options(char *data, char **devstr, char **namestr,
47                           int *kml, int *cache, char **opts, 
48                           int *iopen_nopriv)
49 {
50         char *pos;
51         struct option *opt_value = NULL;
52
53         while (!(get_opt(&opt_value, &pos))) {
54                 if (!strcmp(opt_value->opt, "dev")) {
55                         if (devstr != NULL)
56                                 *devstr = opt_value->value;
57                 } else if (!strcmp(opt_value->opt, "type")) {
58                         if (namestr != NULL)
59                                 *namestr = opt_value->value;
60                 } else if (!strcmp(opt_value->opt, "kml")) {
61                         if (kml)
62                                 *kml = 1;
63                 } else if (!strcmp(opt_value->opt, "cache")) {
64                         if (cache)
65                                 *cache = 1;
66                 } else if (!strcmp(opt_value->opt, "options")) {
67                         if (opts != NULL)
68                                 *opts = opt_value->value;
69                 } else if (!strcmp(opt_value->opt, "iopen_nopriv")) {
70                         if (iopen_nopriv != NULL)
71                                 *iopen_nopriv = 1;
72                 } else {
73                         break;
74                 }
75         }
76         return pos;
77 }
78
79 struct vfsmount *get_vfsmount(struct super_block *sb)
80 {
81         struct vfsmount *rootmnt, *mnt, *ret = NULL;
82         struct list_head *end, *list;
83
84         rootmnt = mntget(current->fs->rootmnt);
85         end = list = &rootmnt->mnt_list;
86         do {
87                 mnt = list_entry(list, struct vfsmount, mnt_list);
88                 if (mnt->mnt_sb == sb) {
89                         ret = mnt;
90                         break;
91                 }
92                 list = list->next;
93         } while (end != list);
94         
95         mntput(current->fs->rootmnt);
96         return ret;
97 }
98
99 struct super_block *smfs_get_sb_by_path(char *path, int len)
100 {
101         struct super_block *sb;
102         struct nameidata nd;
103         int error = 0;
104
105         ENTRY;
106
107 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
108         if (path_init(path, LOOKUP_FOLLOW, &nd)) {
109 #else
110         if (path_lookup(path, LOOKUP_FOLLOW, &nd)) {
111 #endif
112                 error = path_walk(path, &nd);
113                 if (error) {
114                         path_release(&nd);
115                         RETURN(NULL);
116                 }
117         } else {
118                 RETURN(NULL);
119         }
120
121         /* FIXME-WANGDI: add some check code here. */
122         sb = nd.dentry->d_sb;
123         path_release(&nd);
124         RETURN(sb);
125 }
126
127 static int smfs_init_fsfilt_ops(struct super_block *sb)
128 {
129         ENTRY;
130         if (!S2SMI(sb)->sm_cache_fsfilt) {
131                 S2SMI(sb)->sm_cache_fsfilt =
132                         fsfilt_get_ops(S2SMI(sb)->cache_fs_type);
133                 if (!S2SMI(sb)->sm_cache_fsfilt) {
134                         CERROR("Can not get %s fsfilt ops needed by kml\n",
135                                S2SMI(sb)->cache_fs_type);
136                         RETURN(-EINVAL);
137                 }
138         }
139         if (!S2SMI(sb)->sm_fsfilt) {
140                 S2SMI(sb)->sm_fsfilt =
141                         fsfilt_get_ops(S2SMI(sb)->fs_type);
142                 if (!S2SMI(sb)->sm_fsfilt) {
143                         CERROR("Can not get %s fsfilt ops needed by kml\n",
144                                S2SMI(sb)->fs_type);
145                         RETURN(-EINVAL);
146                 }
147         }
148         RETURN(0);
149 }
150
151 void smfs_cleanup_fsfilt_ops(struct super_block *sb)
152 {
153         if (S2SMI(sb)->sm_cache_fsfilt)
154                 fsfilt_put_ops(S2SMI(sb)->sm_cache_fsfilt);
155         if (S2SMI(sb)->sm_fsfilt)
156                 fsfilt_put_ops(S2SMI(sb)->sm_fsfilt);
157 }
158
159 static int sm_mount_cache(struct super_block *sb, char *devstr, 
160                           char *typestr, char *opts, int iopen_nopriv)
161 {
162         struct smfs_super_info *smb;
163         int err = 0, typelen;
164         struct vfsmount *mnt;
165         unsigned long page;
166
167         ENTRY;
168
169         typelen = strlen(typestr);
170        
171         page = __get_free_page(GFP_KERNEL);
172         if (!page)
173                 GOTO(err_out, err = -ENOMEM);
174
175         memset((void *)page, 0, PAGE_SIZE);
176         
177         if (iopen_nopriv)
178                 sprintf((char *)page, "iopen_nopriv");
179
180         if (opts && strlen(opts)) {
181                 int n = strlen((char *)page);
182                 sprintf((char *)page + n, ",%s", opts);
183         }
184         
185         printk("smfs: mounting %s at %s\n", typestr, devstr);
186
187         mnt = do_kern_mount(typestr, 0, devstr, (void *)page);
188         free_page(page);
189
190         if (IS_ERR(mnt)) {
191                 CERROR("do_kern_mount failed: rc = %ld\n", PTR_ERR(mnt));
192                 GOTO(err_out, err = PTR_ERR(mnt));
193         }
194         smb = S2SMI(sb);
195         smb->smsi_sb = mnt->mnt_sb;
196         smb->smsi_mnt = mnt;
197
198         smfs_init_sm_ops(smb);
199
200         OBD_ALLOC(smb->cache_fs_type, strlen(typestr) + 1);
201         memcpy(smb->cache_fs_type, typestr, strlen(typestr));
202
203         OBD_ALLOC(smb->fs_type, strlen(SMFS_TYPE) + 1);
204         memcpy(smb->fs_type, SMFS_TYPE, strlen(SMFS_TYPE));
205
206         duplicate_sb(sb, mnt->mnt_sb);
207         sm_set_sb_ops(mnt->mnt_sb, sb);
208         err = smfs_init_fsfilt_ops(sb);
209 err_out:
210         return err;
211 }
212
213 static int sm_umount_cache(struct super_block *sb)
214 {
215         struct smfs_super_info *smb = S2SMI(sb);
216
217         mntput(smb->smsi_mnt);
218         smfs_cleanup_sm_ops(smb);
219         smfs_cleanup_fsfilt_ops(sb);
220
221         if (smb->cache_fs_type)
222                 OBD_FREE(smb->cache_fs_type, strlen(smb->cache_fs_type) + 1);
223         
224         if (smb->fs_type)
225                 OBD_FREE(smb->fs_type, strlen(smb->fs_type) + 1);
226         
227         return 0;
228 }
229
230 void smfs_put_super(struct super_block *sb)
231 {
232         if (SMFS_CACHE_HOOK(S2SMI(sb)))
233                 cache_space_hook_exit(sb);
234         
235         if (SMFS_DO_REC(S2SMI(sb)))
236                 smfs_rec_cleanup(sb);
237         
238         if (sb)
239                 sm_umount_cache(sb);
240         return;
241 }
242
243 static int smfs_fill_super(struct super_block *sb,
244                            void *data, int silent)
245 {
246         ino_t root_ino;
247         char *cache_data;
248
249         int iopen_nopriv = 0;
250         struct inode *root_inode = NULL;
251         int err = 0, do_rec = 0, cache_hook = 0;
252         char *devstr = NULL, *typestr = NULL, *opts = NULL;
253
254         ENTRY;
255
256         CDEBUG(D_SUPER, "mount opts: %s\n", data ?
257                (char *)data : "(none)");
258
259         init_option(data);
260         
261         /* read and validate passed options. */
262         cache_data = smfs_options(data, &devstr, &typestr,
263                                   &do_rec, &cache_hook, &opts,
264                                   &iopen_nopriv);
265         
266         if (*cache_data)
267                 CWARN("smfs_fill_super(): options parsing stoped at "
268                       "option %s\n", cache_data);
269         
270         if (!typestr || !devstr) {
271                 CERROR("mount options name and dev mandatory\n");
272                 GOTO(out_err, err = -EINVAL);
273         }
274
275         err = sm_mount_cache(sb, devstr, typestr, opts, 
276                              iopen_nopriv);
277                              
278         if (err) {
279                 CERROR("Can not mount %s as %s, rc = %d\n", devstr, 
280                         typestr, err);
281                 GOTO(out_err, err);
282         }
283
284         if (do_rec)
285                 smfs_rec_init(sb);
286
287         if (cache_hook)
288                 cache_space_hook_init(sb);
289
290         dget(S2CSB(sb)->s_root);
291         root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
292         root_inode = iget(sb, root_ino);
293
294         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
295                sb->s_op->read_inode, root_ino, root_inode);
296
297         sb->s_root = d_alloc_root(root_inode);
298
299         if (!sb->s_root) {
300                 sm_umount_cache(sb);
301                 GOTO(out_err, err = -EINVAL);
302         }
303
304 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
305         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
306                (ulong)sb, (ulong)&sb->u.generic_sbp);
307 #else
308         CDEBUG(D_SUPER, "sb %lx, &sb->s_fs_info: %lx\n",
309                (ulong)sb, (ulong)&sb->s_fs_info);
310 #endif
311
312 out_err:
313         cleanup_option();
314         return err;
315 }
316
317 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
318 static struct super_block *smfs_read_super(struct super_block *sb,
319                                            void *data, int silent)
320 {
321         int err;
322
323         err = smfs_fill_super(sb, data, silent);
324         if (err)
325                 return NULL;
326         
327         return sb;
328 }
329 #else
330 struct super_block *smfs_get_sb(struct file_system_type *fs_type,
331                                 int flags, const char *dev_name,
332                                 void *data)
333 {
334         return get_sb_nodev(fs_type, flags, data, smfs_fill_super);
335 }
336 #endif
337
338 static struct file_system_type smfs_type = {
339         .owner       = THIS_MODULE,
340         .name        = "smfs",
341 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
342         .read_super  = smfs_read_super,
343 #else
344         .get_sb      = smfs_get_sb,
345         .kill_sb     = kill_anon_super,
346 #endif
347 };
348
349 int init_smfs(void)
350 {
351         int err;
352
353         err = register_filesystem(&smfs_type);
354         if (err) {
355                 CERROR("register_filesystem() failed, "
356                        "rc = %d\n", err);
357         }
358         return err;
359 }
360
361 int cleanup_smfs(void)
362 {
363         int err = 0;
364
365         err = unregister_filesystem(&smfs_type);
366         if (err) {
367                 CERROR("unregister_filesystem() failed, "
368                        "rc = %d\n", err);
369         }
370         return 0;
371 }