Whamcloud - gitweb
landing b_cmobd_merge on HEAD
[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 {
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 {
74                         break;
75                 }
76         }
77         return pos;
78 }
79
80 struct vfsmount *get_vfsmount(struct super_block *sb)
81 {
82         struct vfsmount *rootmnt, *mnt, *ret = NULL;
83         struct list_head *end, *list;
84
85         rootmnt = mntget(current->fs->rootmnt);
86         end = list = &rootmnt->mnt_list;
87         do {
88                 mnt = list_entry(list, struct vfsmount, mnt_list);
89                 if (mnt->mnt_sb == sb) {
90                         ret = mnt;
91                         break;
92                 }
93                 list = list->next;
94         } while (end != list);
95
96         mntput(current->fs->rootmnt);
97         return ret;
98 }
99
100 struct super_block *smfs_get_sb_by_path(char *path, int len)
101 {
102         struct super_block *sb;
103         struct nameidata nd;
104         int error = 0;
105
106         ENTRY;
107
108 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
109         if (path_init(path, LOOKUP_FOLLOW, &nd)) {
110 #else
111         if (path_lookup(path, LOOKUP_FOLLOW, &nd)) {
112 #endif
113                 error = path_walk(path, &nd);
114                 if (error) {
115                         path_release(&nd);
116                         RETURN(NULL);
117                 }
118         } else {
119                 RETURN(NULL);
120         }
121
122         /* FIXME-WANGDI: add some check code here. */
123         sb = nd.dentry->d_sb;
124         path_release(&nd);
125         RETURN(sb);
126 }
127
128 static int smfs_init_fsfilt_ops(struct super_block *sb)
129 {
130         ENTRY;
131         if (!S2SMI(sb)->sm_cache_fsfilt) {
132                 S2SMI(sb)->sm_cache_fsfilt =
133                         fsfilt_get_ops(S2SMI(sb)->smsi_cache_ftype);
134                 if (!S2SMI(sb)->sm_cache_fsfilt) {
135                         CERROR("Can not get %s fsfilt ops needed by kml\n",
136                                S2SMI(sb)->smsi_cache_ftype);
137                         RETURN(-EINVAL);
138                 }
139         }
140         if (!S2SMI(sb)->sm_fsfilt) {
141                 S2SMI(sb)->sm_fsfilt =
142                         fsfilt_get_ops(S2SMI(sb)->smsi_ftype);
143                 if (!S2SMI(sb)->sm_fsfilt) {
144                         CERROR("Can not get %s fsfilt ops needed by kml\n",
145                                S2SMI(sb)->smsi_ftype);
146                         RETURN(-EINVAL);
147                 }
148         }
149         RETURN(0);
150 }
151
152 void smfs_cleanup_fsfilt_ops(struct super_block *sb)
153 {
154         if (S2SMI(sb)->sm_cache_fsfilt)
155                 fsfilt_put_ops(S2SMI(sb)->sm_cache_fsfilt);
156         if (S2SMI(sb)->sm_fsfilt)
157                 fsfilt_put_ops(S2SMI(sb)->sm_fsfilt);
158 }
159
160 static int sm_mount_cache(struct super_block *sb, char *devstr,
161                           char *typestr, char *opts, int iopen_nopriv)
162 {
163         struct smfs_super_info *smb;
164         int err = 0, typelen;
165         struct vfsmount *mnt;
166         unsigned long page;
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->smsi_cache_ftype, strlen(typestr) + 1);
201         memcpy(smb->smsi_cache_ftype, typestr, strlen(typestr));
202
203         OBD_ALLOC(smb->smsi_ftype, strlen(SMFS_TYPE) + 1);
204         memcpy(smb->smsi_ftype, 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         iput(S2CSB(sb)->s_root->d_inode);
218         dput(S2CSB(sb)->s_root);
219         mntput(smb->smsi_mnt);
220         smfs_cleanup_sm_ops(smb);
221         smfs_cleanup_fsfilt_ops(sb);
222
223         if (smb->smsi_cache_ftype)
224                 OBD_FREE(smb->smsi_cache_ftype,
225                          strlen(smb->smsi_cache_ftype) + 1);
226
227         if (smb->smsi_ftype)
228                 OBD_FREE(smb->smsi_ftype, strlen(smb->smsi_ftype) + 1);
229
230         return 0;
231 }
232
233 void smfs_put_super(struct super_block *sb)
234 {
235         if (SMFS_CACHE_HOOK(S2SMI(sb)))
236                 cache_space_hook_exit(sb);
237         if (SMFS_DO_REC(S2SMI(sb)))
238                 smfs_rec_cleanup(sb);
239         if (sb)
240                 sm_umount_cache(sb);
241         return;
242 }
243
244 static int smfs_fill_super(struct super_block *sb,
245                            void *data, int silent)
246 {
247         ino_t root_ino;
248         char *cache_data;
249
250         int iopen_nopriv = 0;
251         struct inode *root_inode = NULL;
252         int err = 0, do_rec = 0, cache_hook = 0;
253         char *devstr = NULL, *typestr = NULL, *opts = NULL;
254
255         ENTRY;
256
257         CDEBUG(D_SUPER, "mount opts: %s\n", data ?
258                (char *)data : "(none)");
259
260         init_option(data);
261
262         /* read and validate passed options. */
263         cache_data = smfs_options(data, &devstr, &typestr,
264                                   &do_rec, &cache_hook, &opts,
265                                   &iopen_nopriv);
266
267         if (*cache_data)
268                 CWARN("smfs_fill_super(): options parsing stoped at "
269                       "option %s\n", cache_data);
270
271         if (!typestr || !devstr) {
272                 CERROR("mount options name and dev mandatory\n");
273                 GOTO(out_err, err = -EINVAL);
274         }
275         err = sm_mount_cache(sb, devstr, typestr, opts, iopen_nopriv);
276         if (err) {
277                 CERROR("Can not mount %s as %s\n", devstr, typestr);
278                 GOTO(out_err, 0);
279         }
280
281         if (do_rec) smfs_rec_init(sb);
282         if (cache_hook) cache_space_hook_init(sb);
283
284         dget(S2CSB(sb)->s_root);
285         root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
286         root_inode = iget(sb, root_ino);
287
288         CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
289                sb->s_op->read_inode, root_ino, root_inode);
290
291         sb->s_root = d_alloc_root(root_inode);
292
293         if (!sb->s_root) {
294                 sm_umount_cache(sb);
295                 GOTO(out_err, err=-EINVAL);
296         }
297
298         sb->s_root = d_alloc_root(root_inode);
299
300         if (!sb->s_root) {
301                 sm_umount_cache(sb);
302                 GOTO(out_err, err = -EINVAL);
303         }
304
305 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
306         CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
307                (ulong)sb, (ulong)&sb->u.generic_sbp);
308 #else
309         CDEBUG(D_SUPER, "sb %lx, &sb->s_fs_info: %lx\n",
310                (ulong)sb, (ulong)&sb->s_fs_info);
311 #endif
312
313 out_err:
314         cleanup_option();
315         return err;
316 }
317
318 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
319 static struct super_block *smfs_read_super(struct super_block *sb,
320                                            void *data, int silent)
321 {
322         int err;
323
324         err = smfs_fill_super(sb, data, silent);
325         if (err)
326                 return NULL;
327
328         return sb;
329 }
330 #else
331 struct super_block *smfs_get_sb(struct file_system_type *fs_type,
332                                 int flags, const char *dev_name, 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, rc = %d\n", err);
356         return err;
357 }
358
359 int cleanup_smfs(void)
360 {
361         int err = 0;
362
363         err = unregister_filesystem(&smfs_type);
364         if (err)
365                 CERROR("unregister_filesystem() failed, rc = %d\n", err);
366         return 0;
367 }