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"
48 static char *smfs_options(char *data, char **devstr,
49 char **namestr, char *opts,
52 struct option *opt_value = NULL;
55 LASSERT(opts && flags);
57 while (!(get_opt(&opt_value, &pos))) {
58 if (!strcmp(opt_value->opt, "dev")) {
60 *devstr = opt_value->value;
61 } else if (!strcmp(opt_value->opt, "type")) {
63 *namestr = opt_value->value;
64 } else if (!strcmp(opt_value->opt, "kml")) {
66 } else if (!strcmp(opt_value->opt, "cache")) {
67 *flags |= SM_CACHE_HOOK;
68 } else if (!strcmp(opt_value->opt, "snap")) {
70 } else if (!strcmp(opt_value->opt, "options")) {
71 if (strlen(opts) == 0)
72 sprintf((char *)opts + strlen(opts), "%s",
75 sprintf((char *)opts + strlen(opts), ",%s",
78 /* FIXME-WANGDI: how about the opt_value->value */
79 if (strlen(opts) == 0)
80 sprintf((char *)opts + strlen(opts), "%s",
83 sprintf((char *)opts + strlen(opts), ",%s",
90 struct super_block *smfs_get_sb_by_path(char *path, int len)
92 struct super_block *sb;
98 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
99 if (path_init(path, LOOKUP_FOLLOW, &nd)) {
101 if (path_lookup(path, LOOKUP_FOLLOW, &nd)) {
103 error = path_walk(path, &nd);
112 /* FIXME-WANGDI: add some check code here. */
113 sb = nd.dentry->d_sb;
118 static struct smfs_super_info *smfs_init_smb(struct super_block *sb)
120 struct smfs_super_info *smb;
123 OBD_ALLOC(smb, sizeof(*smb));
131 static int smfs_init_fsfilt_ops(struct smfs_super_info *smb)
134 if (!smb->sm_cache_fsfilt) {
135 smb->sm_cache_fsfilt =
136 fsfilt_get_ops(smb->smsi_cache_ftype);
137 if (!smb->sm_cache_fsfilt) {
138 CERROR("Can not get %s fsfilt ops needed by kml\n",
139 smb->smsi_cache_ftype);
143 if (!smb->sm_fsfilt) {
145 fsfilt_get_ops(smb->smsi_ftype);
146 if (!smb->sm_fsfilt) {
147 CERROR("Can not get %s fsfilt ops needed by kml\n",
155 void smfs_cleanup_fsfilt_ops(struct smfs_super_info *smb)
157 if (smb->sm_cache_fsfilt)
158 fsfilt_put_ops(smb->sm_cache_fsfilt);
160 fsfilt_put_ops(smb->sm_fsfilt);
163 static int smfs_mount_cache(struct smfs_super_info *smb, char *devstr,
164 char *typestr, char *opts)
166 int err = 0, typelen;
167 struct vfsmount *mnt;
170 typelen = strlen(typestr);
172 printk("smfs: mounting %s at %s\n", typestr, devstr);
173 mnt = do_kern_mount(typestr, 0, devstr, (void *)opts);
175 CERROR("do_kern_mount failed: rc = %ld\n",
177 GOTO(err_out, err = PTR_ERR(mnt));
180 smb->smsi_sb = mnt->mnt_sb;
183 smfs_init_sm_ops(smb);
185 OBD_ALLOC(smb->smsi_cache_ftype, strlen(typestr) + 1);
186 memcpy(smb->smsi_cache_ftype, typestr, strlen(typestr));
188 OBD_ALLOC(smb->smsi_ftype, strlen(SMFS_TYPE) + 1);
189 memcpy(smb->smsi_ftype, SMFS_TYPE, strlen(SMFS_TYPE));
191 err = smfs_init_fsfilt_ops(smb);
196 static int smfs_umount_cache(struct smfs_super_info *smb)
198 struct dentry *root = smb->smsi_sb->s_root;
201 if (atomic_read(&root->d_inode->i_count) == 0)
202 igrab(root->d_inode);
204 mntput(smb->smsi_mnt);
205 smfs_cleanup_sm_ops(smb);
206 smfs_cleanup_fsfilt_ops(smb);
208 if (smb->smsi_cache_ftype)
209 OBD_FREE(smb->smsi_cache_ftype,
210 strlen(smb->smsi_cache_ftype) + 1);
212 OBD_FREE(smb->smsi_ftype, strlen(smb->smsi_ftype) + 1);
217 static int smfs_init_hook_ops(struct smfs_super_info *smb)
220 INIT_LIST_HEAD(&smb->smsi_hook_list);
224 static void smfs_cleanup_hook_ops(struct smfs_super_info *smb)
226 struct list_head *hlist = &smb->smsi_hook_list;
229 while (!list_empty(hlist)) {
230 struct smfs_hook_ops *smfs_hops;
232 smfs_hops = list_entry(hlist->next, struct smfs_hook_ops,
234 CERROR("Unregister %s hook ops\n", smfs_hops->smh_name);
236 smfs_unregister_hook_ops(smb, smfs_hops->smh_name);
237 smfs_free_hook_ops(smfs_hops);
242 static void smfs_cleanup_smb(struct super_block *sb)
244 struct smfs_super_info *smb;
249 OBD_FREE(smb, sizeof(*smb));
253 void smfs_cleanup_hooks(struct smfs_super_info *smb)
256 if (SMFS_CACHE_HOOK(smb))
257 cache_space_hook_exit(smb);
258 if (SMFS_DO_REC(smb))
259 smfs_rec_cleanup(smb);
261 if (SMFS_DO_COW(smb))
262 smfs_cow_cleanup(smb);
264 smfs_cleanup_hook_ops(smb);
267 void smfs_put_super(struct super_block *sb)
269 struct smfs_super_info *smfs_info = S2SMI(sb);
271 smfs_cleanup_hooks(smfs_info);
274 smfs_umount_cache(smfs_info);
275 smfs_cleanup_smb(sb);
278 static int smfs_init_hooks(struct super_block *sb)
282 if (SMFS_DO_REC(S2SMI(sb)))
284 if (SMFS_CACHE_HOOK(S2SMI(sb)))
285 cache_space_hook_init(sb);
287 if (SMFS_DO_COW(S2SMI(sb)))
293 int smfs_fill_super(struct super_block *sb, void *data, int silent)
295 struct inode *root_inode = NULL;
296 struct smfs_super_info *smb = NULL;
297 char *devstr = NULL, *typestr = NULL;
298 char *opts = NULL, *cache_data = NULL;
305 CDEBUG(D_SUPER, "mount opts: %s\n", data ?
306 (char *)data : "(none)");
308 smb = smfs_init_smb(sb);
312 page = __get_free_page(GFP_KERNEL);
314 GOTO(out_err, err = -ENOMEM);
316 memset((void *)page, 0, PAGE_SIZE);
320 cache_data = smfs_options(data, &devstr, &typestr, opts,
323 CWARN("smfs_fill_super(): options parsing stoped at "
324 "option %s\n", cache_data);
327 if (!typestr || !devstr) {
328 CERROR("mount options name and dev are mandatory\n");
330 GOTO(out_err, err = -EINVAL);
333 err = smfs_mount_cache(smb, devstr, typestr, opts);
337 CERROR("Can not mount %s as %s\n", devstr, typestr);
341 duplicate_sb(sb, smb->smsi_sb);
342 sm_set_sb_ops(smb->smsi_sb, sb);
344 err = smfs_init_hook_ops(smb);
346 CERROR("Can not init super hook ops err %d\n", err);
347 smfs_umount_cache(smb);
351 /* init the root_inode of smfs. */
352 dget(S2CSB(sb)->s_root);
353 root_ino = S2CSB(sb)->s_root->d_inode->i_ino;
354 root_inode = smfs_get_inode(sb, root_ino, NULL, 0);
356 CDEBUG(D_SUPER, "readinode %p, root ino %ld, root inode at %p\n",
357 sb->s_op->read_inode, root_ino, root_inode);
359 sb->s_root = d_alloc_root(root_inode);
362 smfs_umount_cache(smb);
363 GOTO(out_err, err = -ENOMEM);
366 err = smfs_init_hooks(sb);
368 smfs_umount_cache(smb);
371 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
372 CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n",
373 (ulong)sb, (ulong)&sb->u.generic_sbp);
375 CDEBUG(D_SUPER, "sb %lx, &sb->s_fs_info: %lx\n",
376 (ulong)sb, (ulong)&sb->s_fs_info);
381 smfs_cleanup_smb(sb);
385 struct smfs_hook_ops *smfs_alloc_hook_ops(char *name, smfs_hook_func pre_hook,
386 smfs_hook_func post_hook)
388 struct smfs_hook_ops *smfs_hops = NULL;
391 OBD_ALLOC(smfs_hops, sizeof(struct smfs_hook_ops));
396 OBD_ALLOC(smfs_hops->smh_name, strlen(name) + 1);
398 if (!smfs_hops->smh_name) {
399 OBD_FREE(smfs_hops, sizeof(struct smfs_hook_ops));
403 memcpy(smfs_hops->smh_name, name, strlen(name));
405 smfs_hops->smh_post_op = post_hook;
406 smfs_hops->smh_pre_op = pre_hook;
411 void smfs_free_hook_ops(struct smfs_hook_ops *hops)
415 OBD_FREE(hops->smh_name, strlen(hops->smh_name) + 1);
417 OBD_FREE(hops, sizeof(struct smfs_hook_ops));
421 int smfs_register_hook_ops(struct smfs_super_info *smb,
422 struct smfs_hook_ops *smh_ops)
424 struct list_head *hlist = &smb->smsi_hook_list;
428 list_for_each(p, hlist) {
429 struct smfs_hook_ops *found;
430 found = list_entry(p, struct smfs_hook_ops, smh_list);
431 if (!strcmp(found->smh_name, smh_ops->smh_name)) {
432 CWARN("hook ops %s list reregister\n", smh_ops->smh_name);
436 list_add(&smh_ops->smh_list, hlist);
440 struct smfs_hook_ops *smfs_unregister_hook_ops(struct smfs_super_info *smb,
443 struct list_head *hlist = &smb->smsi_hook_list;
447 list_for_each(p, hlist) {
448 struct smfs_hook_ops *found;
450 found = list_entry(p, typeof(*found), smh_list);
451 if (!memcmp(found->smh_name, name, strlen(name))) {
459 void *smfs_trans_start(struct inode *inode, int op, void *desc_private)
461 struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
463 CDEBUG(D_INFO, "trans start %p\n", fsfilt->fs_start);
465 SMFS_TRANS_OP(inode, op);
467 /* There are some problem here. fs_start in fsfilt is used by lustre
468 * the journal blocks of write rec are not counted in FIXME later */
469 if (fsfilt->fs_start)
470 return fsfilt->fs_start(inode, op, desc_private, 0);
474 void smfs_trans_commit(struct inode *inode, void *handle, int force_sync)
476 struct fsfilt_operations *fsfilt = S2SMI(inode->i_sb)->sm_fsfilt;
481 CDEBUG(D_INFO, "trans commit %p\n", fsfilt->fs_commit);
483 if (fsfilt->fs_commit)
484 fsfilt->fs_commit(inode->i_sb, inode, handle, force_sync);