1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
5 * Lustre filesystem abstraction routines
7 * Copyright (C) 2004 Cluster File Systems, Inc.
9 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
25 #define DEBUG_SUBSYSTEM S_SM
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/kmod.h>
30 #include <linux/init.h>
32 #include <linux/string.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,
52 struct option *opt_value = NULL;
54 while (!(get_opt(&opt_value, &pos))) {
55 if (!strcmp(opt_value->opt, "dev")) {
57 *devstr = opt_value->value;
58 } else if (!strcmp(opt_value->opt, "type")) {
60 *namestr = opt_value->value;
61 } else if (!strcmp(opt_value->opt, "kml")) {
64 } else if (!strcmp(opt_value->opt, "cache")) {
67 } else if (!strcmp(opt_value->opt, "options")) {
69 *opts = opt_value->value;
70 } else if (!strcmp(opt_value->opt, "iopen_nopriv")) {
71 if (iopen_nopriv != NULL)
73 } else if (!strcmp(opt_value->opt, "snap")) {
82 struct super_block *smfs_get_sb_by_path(char *path, int len)
84 struct super_block *sb;
90 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
91 if (path_init(path, LOOKUP_FOLLOW, &nd)) {
93 if (path_lookup(path, LOOKUP_FOLLOW, &nd)) {
95 error = path_walk(path, &nd);
104 /* FIXME-WANGDI: add some check code here. */
105 sb = nd.dentry->d_sb;
110 static int smfs_init_fsfilt_ops(struct super_block *sb)
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);
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);
134 void smfs_cleanup_fsfilt_ops(struct super_block *sb)
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);
142 static int sm_mount_cache(struct super_block *sb, char *devstr,
143 char *typestr, char *opts, int iopen_nopriv)
145 struct smfs_super_info *smb = S2SMI(sb);
146 int err = 0, typelen;
147 struct vfsmount *mnt;
151 typelen = strlen(typestr);
153 page = __get_free_page(GFP_KERNEL);
155 GOTO(err_out, err = -ENOMEM);
157 memset((void *)page, 0, PAGE_SIZE);
160 sprintf((char *)page, "iopen_nopriv");
162 if (opts && strlen(opts)) {
163 int n = strlen((char *)page);
164 sprintf((char *)page + n, ",%s", opts);
167 printk("smfs: mounting %s at %s\n", typestr, devstr);
169 mnt = do_kern_mount(typestr, 0, devstr, (void *)page);
173 CERROR("do_kern_mount failed: rc = %ld\n", PTR_ERR(mnt));
174 GOTO(err_out, err = PTR_ERR(mnt));
177 smb->smsi_sb = mnt->mnt_sb;
180 smfs_init_sm_ops(smb);
182 OBD_ALLOC(smb->smsi_cache_ftype, strlen(typestr) + 1);
183 memcpy(smb->smsi_cache_ftype, typestr, strlen(typestr));
185 OBD_ALLOC(smb->smsi_ftype, strlen(SMFS_TYPE) + 1);
186 memcpy(smb->smsi_ftype, SMFS_TYPE, strlen(SMFS_TYPE));
188 duplicate_sb(sb, mnt->mnt_sb);
189 sm_set_sb_ops(mnt->mnt_sb, sb);
191 err = smfs_init_fsfilt_ops(sb);
196 static int sm_umount_cache(struct super_block *sb)
198 struct smfs_super_info *smb = S2SMI(sb);
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);
206 if (smb->smsi_cache_ftype)
207 OBD_FREE(smb->smsi_cache_ftype,
208 strlen(smb->smsi_cache_ftype) + 1);
210 OBD_FREE(smb->smsi_ftype, strlen(smb->smsi_ftype) + 1);
215 static int smfs_init_hook_ops(struct super_block *sb)
217 struct smfs_super_info *smb = S2SMI(sb);
220 INIT_LIST_HEAD(&smb->smsi_hook_list);
224 static void smfs_cleanup_hook_ops(struct super_block *sb)
226 struct smfs_super_info *smb = S2SMI(sb);
227 struct list_head *hlist = &smb->smsi_hook_list;
230 while (!list_empty(hlist)) {
231 struct smfs_hook_ops *smfs_hops;
233 smfs_hops = list_entry(hlist->next, struct smfs_hook_ops,
235 CERROR("Unregister %s hook ops\n", smfs_hops->smh_name);
237 smfs_unregister_hook_ops(sb, smfs_hops->smh_name);
238 smfs_free_hook_ops(smfs_hops);
244 void smfs_put_super(struct super_block *sb)
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);
251 if (SMFS_DO_COW(S2SMI(sb)))
252 smfs_cow_cleanup(sb);
254 smfs_cleanup_hook_ops(sb);
260 int smfs_fill_super(struct super_block *sb, void *data, int silent)
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;
272 CDEBUG(D_SUPER, "mount opts: %s\n", data ?
273 (char *)data : "(none)");
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);
283 CWARN("smfs_fill_super(): options parsing stoped at "
284 "option %s\n", cache_data);
286 if (!typestr || !devstr) {
287 CERROR("mount options name and dev mandatory\n");
288 GOTO(out_err, err = -EINVAL);
290 err = sm_mount_cache(sb, devstr, typestr, opts, iopen_nopriv);
292 CERROR("Can not mount %s as %s\n", devstr, typestr);
296 err = smfs_init_hook_ops(sb);
298 CERROR("Can not init super hook ops err %d\n", err);
302 if (do_rec) smfs_rec_init(sb);
303 if (cache_hook) cache_space_hook_init(sb);
305 dget(S2CSB(sb)->s_root);
306 root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
307 root_inode = iget(sb, root_ino);
309 CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
310 sb->s_op->read_inode, root_ino, root_inode);
312 sb->s_root = d_alloc_root(root_inode);
316 GOTO(out_err, err=-EINVAL);
319 if (do_cow) smfs_cow_init(sb);
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);
326 CDEBUG(D_SUPER, "sb %lx, &sb->s_fs_info: %lx\n",
327 (ulong)sb, (ulong)&sb->s_fs_info);
334 struct smfs_hook_ops *smfs_alloc_hook_ops(char *name, smfs_hook_func pre_hook,
335 smfs_hook_func post_hook)
337 struct smfs_hook_ops *smfs_hops = NULL;
340 OBD_ALLOC(smfs_hops, sizeof(struct smfs_hook_ops));
345 OBD_ALLOC(smfs_hops->smh_name, strlen(name) + 1);
347 if (!smfs_hops->smh_name) {
348 OBD_FREE(smfs_hops, sizeof(struct smfs_hook_ops));
352 memcpy(smfs_hops->smh_name, name, strlen(name));
354 smfs_hops->smh_post_op = post_hook;
355 smfs_hops->smh_pre_op = pre_hook;
360 void smfs_free_hook_ops(struct smfs_hook_ops *hops)
364 OBD_FREE(hops->smh_name, strlen(hops->smh_name) + 1);
366 OBD_FREE(hops, sizeof(struct smfs_hook_ops));
370 int smfs_register_hook_ops(struct super_block *sb,
371 struct smfs_hook_ops *smh_ops)
373 struct smfs_super_info *smb = S2SMI(sb);
374 struct list_head *hlist = &smb->smsi_hook_list;
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);
386 list_add(&smh_ops->smh_list, hlist);
389 struct smfs_hook_ops *smfs_unregister_hook_ops(struct super_block *sb,
392 struct smfs_super_info *smb = S2SMI(sb);
393 struct list_head *hlist = &smb->smsi_hook_list;
397 list_for_each(p, hlist) {
398 struct smfs_hook_ops *found;
400 found = list_entry(p, typeof(*found), smh_list);
401 if (!memcmp(found->smh_name, name, strlen(name))) {