X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fsmfs%2Fdir.c;h=4130858f6bfa89a20f66444defbe015151b1208e;hb=da2e78ae73129188f1324615c6c78ee0dddb36ed;hp=6996a0cbfdb47893d74e93cb1cf143bf52143303;hpb=29a9b5d7e11386493d356e8b2436894b7b6c9f91;p=fs%2Flustre-release.git diff --git a/lustre/smfs/dir.c b/lustre/smfs/dir.c index 6996a0c..4130858 100644 --- a/lustre/smfs/dir.c +++ b/lustre/smfs/dir.c @@ -1,7 +1,26 @@ -/* - * dir.c +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (C) 2004 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * Lustre is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * */ -#define DEBUG_SUBSYSTEM S_SNAP + +#define DEBUG_SUBSYSTEM S_SM #include #include @@ -9,410 +28,752 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smfs_internal.h" + +//#define NAME_ALLOC_LEN(len) ((len+16) & ~15) + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static int smfs_create(struct inode *dir, struct dentry *dentry, + int mode) +#else +static int smfs_create(struct inode *dir, struct dentry *dentry, + int mode, struct nameidata *nd) +#endif +{ + struct inode *inode = NULL; + struct inode *parent = I2CI(dentry->d_parent->d_inode); + struct inode *cache_dir = I2CI(dir); + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + struct hook_msg msg = { + .dentry = dentry, + }; + int rc = 0; + + ENTRY; + + LASSERT(cache_dir); + LASSERT(cache_dir->i_op->create); + + cache_parent = pre_smfs_dentry(NULL, parent, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + if (!cache_dentry || !cache_parent) { + rc = -ENOMEM; + goto exit; + } + + handle = smfs_trans_start(dir, FSFILT_OP_CREATE, NULL); + if (IS_ERR(handle)) { + rc = -ENOSPC; + goto exit; + } + + SMFS_PRE_HOOK(dir, HOOK_CREATE, &msg); + + pre_smfs_inode(dir, cache_dir); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + rc = cache_dir->i_op->create(cache_dir, cache_dentry, mode); +#else + rc = cache_dir->i_op->create(cache_dir, cache_dentry, mode, nd); +#endif + if (!rc) { + inode = smfs_get_inode(dir->i_sb, cache_dentry->d_inode->i_ino, + dir, 0); + if (inode) { + d_instantiate(dentry, inode); + } + else + rc = -ENOENT; + } + + SMFS_POST_HOOK(dir, HOOK_CREATE, &msg, rc); + + post_smfs_inode(dir, cache_dir); + smfs_trans_commit(dir, handle, 0); + +exit: + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + RETURN(rc); +} -#include "smfs_internal.h" +static struct dentry * iopen_connect_dentry(struct dentry * dentry, + struct inode *inode, int rehash) +{ + struct dentry *tmp, *goal = NULL; + struct list_head *lp; -#define NAME_ALLOC_LEN(len) ((len+16) & ~15) + /* verify this dentry is really new */ + LASSERT(dentry->d_inode == NULL); + LASSERT(list_empty(&dentry->d_alias)); /* d_instantiate */ + if (rehash) + LASSERT(d_unhashed(dentry)); /* d_rehash */ + LASSERT(list_empty(&dentry->d_subdirs)); -void smfs_clear_dentry(struct dentry *dentry) -{ - struct qstr *name = NULL; - - if (dentry) { - if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) - return; - list_del(&dentry->d_hash); - INIT_LIST_HEAD(&dentry->d_hash); - list_del(&dentry->d_child); - if (dentry->d_inode) { - dentry->d_inode = NULL; - list_del_init(&dentry->d_alias); - } - - name = &(dentry->d_name); - if (name->len > DNAME_INLINE_LEN-1) { - SM_FREE((char *)name->name, NAME_ALLOC_LEN(name->len)); + spin_lock(&dcache_lock); + if (!inode) + goto do_rehash; + + /* preferrably return a connected dentry */ + list_for_each(lp, &inode->i_dentry) { + tmp = list_entry(lp, struct dentry, d_alias); + if (tmp->d_flags & DCACHE_DISCONNECTED) { + LASSERT(tmp->d_alias.next == &inode->i_dentry); + LASSERT(tmp->d_alias.prev == &inode->i_dentry); + goal = tmp; + dget_locked(goal); + break; } } -} -int smfs_prepare_dentry(struct dentry *dentry, - struct dentry *parent, - struct qstr *name) -{ - char *str = NULL; - - if (name->len > DNAME_INLINE_LEN-1) { - SM_ALLOC(str, NAME_ALLOC_LEN(name->len)); - if (!str) - return (-ENOMEM); - } else - str = dentry->d_iname; - - memcpy(str, name->name, name->len); - str[name->len] = 0; - - atomic_set(&dentry->d_count, 1); - dentry->d_vfs_flags = 0; - dentry->d_flags = 0; - dentry->d_inode = NULL; - dentry->d_parent = NULL; - dentry->d_sb = NULL; - dentry->d_name.name = str; - dentry->d_name.len = name->len; - dentry->d_name.hash = name->hash; - dentry->d_op = NULL; - dentry->d_fsdata = NULL; - dentry->d_mounted = 0; - INIT_LIST_HEAD(&dentry->d_hash); - INIT_LIST_HEAD(&dentry->d_lru); - INIT_LIST_HEAD(&dentry->d_subdirs); - INIT_LIST_HEAD(&dentry->d_alias); - - if (parent) { - dentry->d_parent = dget(parent); - dentry->d_sb = parent->d_sb; - list_add(&dentry->d_child, &parent->d_subdirs); - } else - INIT_LIST_HEAD(&dentry->d_child); - - return 0; -} -static void prepare_parent_dentry(struct dentry *dentry, struct inode *inode) -{ - atomic_set(&dentry->d_count, 1); - dentry->d_vfs_flags = 0; - dentry->d_flags = 0; - dentry->d_inode = inode; - dentry->d_op = NULL; - dentry->d_fsdata = NULL; - dentry->d_mounted = 0; - INIT_LIST_HEAD(&dentry->d_hash); - INIT_LIST_HEAD(&dentry->d_lru); - INIT_LIST_HEAD(&dentry->d_subdirs); - INIT_LIST_HEAD(&dentry->d_alias); + if (!goal) + goto do_instantiate; + + /* Move the goal to the de hash queue */ + goal->d_flags &= ~ DCACHE_DISCONNECTED; + security_d_instantiate(goal, inode); + __d_rehash(dentry); + __d_move(goal, dentry); + spin_unlock(&dcache_lock); + iput(inode); + + RETURN(goal); + + /* d_add(), but don't drop dcache_lock before adding dentry to inode */ +do_instantiate: + list_add(&dentry->d_alias, &inode->i_dentry); /* d_instantiate */ + dentry->d_inode = inode; +do_rehash: + if (rehash) + __d_rehash(dentry); + spin_unlock(&dcache_lock); + + RETURN(NULL); + } -static int smfs_create(struct inode *dir, - struct dentry *dentry, - int mode) +static int smfs_do_lookup (struct inode * dir, + struct dentry * dentry, + struct nameidata *nd, + struct inode **inode) { - struct inode *cache_dir; - struct inode *cache_inode = NULL, *inode; - struct dentry parent; - struct dentry cache_dentry; - int rc; - - ENTRY; - - cache_dir = I2CI(dir); + struct inode *cache_dir = I2CI(dir); + struct inode *parent = I2CI(dentry->d_parent->d_inode); + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + struct dentry *rdentry = NULL, *tmp = NULL; + int rc = 0; + struct hook_msg msg = { + .dentry = dentry, + }; + + ENTRY; + if (!cache_dir) RETURN(-ENOENT); - - prepare_parent_dentry(&parent, cache_dir); - smfs_prepare_dentry(&cache_dentry, &parent, &dentry->d_name); - - if (cache_dir && cache_dir->i_op->create) - rc = cache_dir->i_op->create(cache_dir, &cache_dentry, mode); - if (rc) - GOTO(exit, rc); - - cache_inode = cache_dentry.d_inode; - - inode = iget(dir->i_sb, cache_inode->i_ino); - - if (!inode) - GOTO(exit, rc = -ENOMEM); - - d_instantiate(dentry, inode); - - sm_set_inode_ops(cache_inode, inode); + + LASSERT(cache_dir->i_op->lookup); + + /* preparing artificial backing fs dentries. */ + cache_parent = pre_smfs_dentry(NULL, parent, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + if (!cache_dentry || !cache_parent) { + rc = -ENOMEM; + goto exit; + } + + SMFS_PRE_HOOK(dir, HOOK_LOOKUP, &msg); + + /* perform lookup in backing fs. */ + rdentry = cache_dir->i_op->lookup(cache_dir, cache_dentry, nd); + if (rdentry) { + if (IS_ERR(rdentry)) { + rc = PTR_ERR(rdentry); + rdentry = NULL; + } else { + tmp = rdentry; + } + } else { + tmp = cache_dentry; + } + + SMFS_POST_HOOK(dir, HOOK_LOOKUP, &msg, rc); + + if (tmp) { + //copy fields if DCACHE_CROSS_REF + smfs_update_dentry(dentry, tmp); + + if (tmp->d_inode) { + if (!tmp->d_inode->i_nlink) + CWARN("inode #%lu (%p) nlink is 0\n", + tmp->d_inode->i_ino, tmp->d_inode); + + *inode = smfs_get_inode(dir->i_sb, tmp->d_inode->i_ino, + dir, 0); + if (!(*inode)) + rc = -ENOENT; + } + } + + if (rdentry) { + dput(rdentry); + } + exit: - smfs_clear_dentry(&cache_dentry); - RETURN(rc); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + + RETURN(rc); } -static struct dentry *smfs_lookup(struct inode *dir, - struct dentry *dentry) +static struct dentry * smfs_iopen_lookup(struct inode * dir, + struct dentry *dentry, + struct nameidata *nd) { - struct inode *cache_dir; - struct inode *cache_inode = NULL, *inode; - struct dentry tmp; - struct dentry cache_dentry; - struct dentry *rc = NULL; - - ENTRY; - - cache_dir = I2CI(dir); - if (!cache_dir) - RETURN(ERR_PTR(-ENOENT)); - prepare_parent_dentry(&tmp, cache_dir); - smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name); - - if(cache_dir && cache_dir->i_op->lookup) - rc = cache_dir->i_op->lookup(cache_dir, &cache_dentry); - - if (rc || !cache_dentry.d_inode || - is_bad_inode(cache_dentry.d_inode) || - IS_ERR(cache_dentry.d_inode)) { - GOTO(exit, rc); + struct dentry * alternate = NULL; + struct inode *inode = NULL; + int rc = 0; + ENTRY; + + rc = smfs_do_lookup(dir, dentry, nd, &inode); + if (rc) + RETURN(ERR_PTR(rc)); + + LASSERT(inode); + /* preferrably return a connected dentry */ + spin_lock(&dcache_lock); + list_for_each_entry(alternate, &inode->i_dentry, d_alias) { + LASSERT(!(alternate->d_flags & DCACHE_DISCONNECTED)); } - cache_inode = cache_dentry.d_inode; - - inode = iget(dir->i_sb, cache_inode->i_ino); - - d_add(dentry, inode); -exit: - smfs_clear_dentry(&cache_dentry); - RETURN(rc); -} + list_for_each_entry(alternate, &inode->i_dentry, d_alias) { + dget_locked(alternate); + spin_lock(&alternate->d_lock); + alternate->d_flags |= DCACHE_REFERENCED; + spin_unlock(&alternate->d_lock); + iput(inode); + spin_unlock(&dcache_lock); + RETURN(alternate); + } + + dentry->d_flags |= DCACHE_DISCONNECTED; + + /* d_add(), but don't drop dcache_lock before adding dentry to inode */ + list_add(&dentry->d_alias, &inode->i_dentry); /* d_instantiate */ + dentry->d_inode = inode; + + __d_rehash(dentry); /* d_rehash */ + spin_unlock(&dcache_lock); + + return NULL; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static struct dentry *smfs_lookup(struct inode *dir, struct dentry *dentry) +#else +static struct dentry *smfs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +#endif +{ + struct dentry * rdentry = NULL; + struct inode * inode = NULL; + int rc; + + ENTRY; + + rc = smfs_do_lookup(dir, dentry, nd, &inode); + if (rc) + RETURN(ERR_PTR(rc)); + + //lmv stuff. Special dentry that has no inode. + if (dentry->d_flags & DCACHE_CROSS_REF) { + d_add(dentry, NULL); + RETURN(NULL); + } + //TODO: should flags be checked and copied before? + rdentry = iopen_connect_dentry(dentry, inode, 1); + + RETURN(rdentry); +} +#if HAVE_LOOKUP_RAW static int smfs_lookup_raw(struct inode *dir, const char *name, int len, ino_t *data) { - struct inode *cache_dir; - int rc = 0; + struct inode *cache_dir = I2CI(dir); + int rc = 0; - cache_dir = I2CI(dir); - - if (!cache_dir) + if (!cache_dir) RETURN(-ENOENT); - - if (cache_dir->i_op->lookup_raw) - rc = cache_dir->i_op->lookup_raw(cache_dir, name, len, data); - - RETURN(rc); + + if (cache_dir->i_op->lookup_raw) { + rc = cache_dir->i_op->lookup_raw(cache_dir, name, len, data); + } else { + CWARN("do not have raw lookup ops in bottom fs\n"); + } + + RETURN(rc); } +#endif -static int smfs_link(struct dentry * old_dentry, - struct inode * dir, struct dentry *dentry) +static int smfs_link(struct dentry *old_dentry, + struct inode *dir, struct dentry *dentry) { - struct inode *cache_old_inode = NULL; - struct inode *cache_dir = I2CI(dir); - struct inode *inode = NULL; - struct dentry cache_dentry; - struct dentry cache_old_dentry; - struct dentry tmp; - struct dentry tmp_old; - int rc = 0; - - inode = old_dentry->d_inode; - - cache_old_inode = I2CI(inode); - - if (!cache_old_inode || !cache_dir) + struct inode *parent = I2CI(dentry->d_parent->d_inode); + struct inode *cache_dir = I2CI(dir); + struct inode *old_inode = old_dentry->d_inode; + struct inode *cache_old_inode = I2CI(old_inode); + struct dentry *cache_old_dentry = NULL; + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; + struct hook_link_msg msg = { + .dentry = old_dentry, + .new_dentry = dentry + }; + + ENTRY; + + if (!cache_dir) + RETURN(-ENOENT); + + if (!cache_old_inode) RETURN(-ENOENT); - - prepare_parent_dentry(&tmp, cache_dir); - smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name); - - prepare_parent_dentry(&tmp_old, cache_dir); - smfs_prepare_dentry(&cache_old_dentry, &tmp_old, &dentry->d_name); - d_add(&cache_old_dentry, cache_old_inode); - - if (cache_dir->i_op->link) - rc = cache_dir->i_op->link(&cache_old_dentry, cache_dir, &cache_dentry); - - if (rc == 0) { - atomic_inc(&inode->i_count); - duplicate_inode(cache_old_dentry.d_inode, inode); - d_instantiate(dentry, inode); - } - - smfs_clear_dentry(&cache_dentry); - smfs_clear_dentry(&cache_old_dentry); - RETURN(rc); + + cache_parent = pre_smfs_dentry(NULL, parent, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + cache_old_dentry = pre_smfs_dentry(NULL, cache_old_inode, old_dentry); + if (!cache_old_dentry || !cache_dentry || !cache_parent) { + rc = -ENOMEM; + goto exit; + } + + handle = smfs_trans_start(dir, FSFILT_OP_LINK, NULL); + if (IS_ERR(handle)) { + rc = -ENOSPC; + goto exit; + } + + pre_smfs_inode(dir, cache_dir); + pre_smfs_inode(old_inode, cache_old_inode); + + //lock_kernel(); + SMFS_PRE_HOOK(dir, HOOK_LINK, &msg); + + rc = cache_dir->i_op->link(cache_old_dentry, cache_dir, cache_dentry); + if (!rc) { + atomic_inc(&old_inode->i_count); + dput(iopen_connect_dentry(dentry, old_inode, 0)); + } + + SMFS_POST_HOOK(dir, HOOK_LINK, &msg, rc); + + post_smfs_inode(old_inode, cache_old_inode); + post_smfs_inode(dir, cache_dir); + + smfs_trans_commit(dir, handle, 0); + +exit: + //unlock_kernel(); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + post_smfs_dentry(cache_old_dentry); + + RETURN(rc); } -static int smfs_unlink(struct inode * dir, - struct dentry *dentry) +static int smfs_unlink(struct inode * dir, struct dentry *dentry) { - struct inode *cache_dir = I2CI(dir); - struct inode *cache_inode = I2CI(dentry->d_inode); - struct dentry cache_dentry; - struct dentry tmp; - int rc = 0; - - if (!cache_dir || !cache_inode) - RETURN(-ENOENT); - - prepare_parent_dentry(&tmp, cache_dir); - smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name); - d_add(&cache_dentry, cache_inode); - - if (cache_dir->i_op->unlink) - rc = cache_dir->i_op->unlink(cache_dir, &cache_dentry); - - duplicate_inode(cache_dentry.d_inode, dentry->d_inode); - duplicate_inode(cache_dir, dir); - - smfs_clear_dentry(&cache_dentry); - RETURN(rc); + struct inode *cache_dir = I2CI(dir); + struct inode *cache_inode = I2CI(dentry->d_inode); + struct inode *parent = I2CI(dentry->d_parent->d_inode); + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; + //int mode = 0; + struct hook_unlink_msg msg = { + .dentry = dentry, + .mode = dentry->d_inode->i_mode + }; + + ENTRY; + + LASSERT(cache_dir); + LASSERT(cache_inode); + LASSERT(cache_dir->i_op->unlink); + LASSERT(parent); + + cache_parent = pre_smfs_dentry(NULL, parent, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, cache_inode, dentry); + if (!cache_dentry || !cache_parent) { + rc = -ENOMEM; + goto exit; + } + + handle = smfs_trans_start(dir, FSFILT_OP_UNLINK, NULL); + if (IS_ERR(handle)) { + rc = -ENOSPC; + goto exit; + } + + pre_smfs_inode(dir, cache_dir); + pre_smfs_inode(dentry->d_inode, cache_inode); + + SMFS_PRE_HOOK(dir, HOOK_UNLINK, &msg); + + rc = cache_dir->i_op->unlink(cache_dir, cache_dentry); + + SMFS_POST_HOOK(dir, HOOK_UNLINK, &msg, rc); + + post_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + post_smfs_inode(dir, cache_dir); + + smfs_trans_commit(dir, handle, 0); +exit: + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + RETURN(rc); } -static int smfs_symlink (struct inode * dir, - struct dentry *dentry, - const char * symname) +static int smfs_symlink(struct inode *dir, struct dentry *dentry, + const char *symname) { - struct inode *cache_dir = I2CI(dir); - struct inode *cache_inode = NULL; - struct inode *inode = NULL; - struct dentry cache_dentry; - struct dentry tmp; - int rc = 0; - - if (!cache_dir) - RETURN(-ENOENT); - - prepare_parent_dentry(&tmp, cache_dir); - smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name); - - if (cache_dir->i_op->symlink) - rc = cache_dir->i_op->symlink(cache_dir, &cache_dentry, symname); - - cache_inode = cache_dentry.d_inode; - - inode = iget(dir->i_sb, cache_inode->i_ino); - - if (inode) - d_instantiate(dentry, inode); - else - rc = -ENOENT; - - smfs_clear_dentry(&cache_dentry); - RETURN(rc); + struct inode *cache_dir = I2CI(dir); + struct inode *inode = NULL; + struct inode *parent = I2CI(dentry->d_parent->d_inode); + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; + struct hook_symlink_msg msg = { + .dentry = dentry, + .tgt_len = strlen(symname) + 1, + .symname = (char*)symname + }; + + ENTRY; + + LASSERT(cache_dir); + LASSERT(cache_dir->i_op->symlink); + LASSERT(parent); + + cache_parent = pre_smfs_dentry(NULL, parent, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + if (!cache_parent || !cache_dentry) { + rc = -ENOMEM; + goto exit; + } + + handle = smfs_trans_start(dir, FSFILT_OP_SYMLINK, NULL); + if (IS_ERR(handle)) { + rc = -ENOSPC; + goto exit; + } + + pre_smfs_inode(dir, cache_dir); + + SMFS_PRE_HOOK(dir, HOOK_SYMLINK, &msg); + + rc = cache_dir->i_op->symlink(cache_dir, cache_dentry, symname); + if (!rc) { + inode = smfs_get_inode(dir->i_sb, cache_dentry->d_inode->i_ino, + dir, 0); + if (inode) { + d_instantiate(dentry, inode); + } + else + rc = -ENOENT; + } + + SMFS_POST_HOOK(dir, HOOK_SYMLINK, &msg, rc); + + post_smfs_inode(dir, cache_dir); + smfs_trans_commit(dir, handle, 0); + +exit: + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + RETURN(rc); } -static int smfs_mkdir(struct inode * dir, - struct dentry * dentry, - int mode) +static int smfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { - struct inode *cache_dir = I2CI(dir); - struct inode *cache_inode = NULL; - struct inode *inode = NULL; - struct dentry cache_dentry; - struct dentry tmp; - int rc = 0; - - if (!cache_dir) - RETURN(-ENOENT); - - prepare_parent_dentry(&tmp, cache_dir); - smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name); - - if (cache_dir->i_op->mkdir) - rc = cache_dir->i_op->mkdir(cache_dir, &cache_dentry, mode); + struct inode *cache_dir = I2CI(dir); + struct inode *parent = I2CI(dentry->d_parent->d_inode); + struct inode *inode = NULL; + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; + struct hook_msg msg = { + .dentry = dentry, + }; + + ENTRY; + + LASSERT(cache_dir); + LASSERT(parent); + + cache_parent = pre_smfs_dentry(NULL, parent, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + if (!cache_parent || !cache_dentry) { + rc = -ENOMEM; + goto exit; + } + + handle = smfs_trans_start(dir, FSFILT_OP_MKDIR, NULL); + if (IS_ERR(handle)) { + rc = -ENOSPC; + goto exit; + } + + pre_smfs_inode(dir, cache_dir); + SMFS_PRE_HOOK(dir, HOOK_MKDIR, &msg); + + rc = cache_dir->i_op->mkdir(cache_dir, cache_dentry, mode); + if (!rc) { + inode = smfs_get_inode(dir->i_sb, cache_dentry->d_inode->i_ino, + dir, 0); + if (inode) { + //smsf_update_dentry(dentry, cache_dentry); + d_instantiate(dentry, inode); + } + else + rc = -ENOENT; + } + + SMFS_POST_HOOK(dir, HOOK_MKDIR, &msg, rc); + post_smfs_inode(dir, cache_dir); + smfs_trans_commit(dir, handle, 0); - cache_inode = cache_dentry.d_inode; - - inode = iget(dir->i_sb, cache_inode->i_ino); - - if (!inode) - GOTO(exit, rc = -ENOENT); - - d_instantiate(dentry, inode); - duplicate_inode(cache_dir, dir); exit: - smfs_clear_dentry(&cache_dentry); - RETURN(rc); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + RETURN(rc); } -static int smfs_rmdir(struct inode * dir, - struct dentry *dentry) +static int smfs_rmdir(struct inode *dir, struct dentry *dentry) { - struct inode *cache_dir = I2CI(dir); - struct inode *cache_inode = I2CI(dentry->d_inode); - struct dentry cache_dentry; - struct dentry tmp; - int rc = 0; - - if (!cache_dir) - RETURN(-ENOENT); - - prepare_parent_dentry(&tmp, cache_dir); - smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name); - d_add(&cache_dentry, cache_inode); - - if (cache_dir->i_op->rmdir) - rc = cache_dir->i_op->rmdir(cache_dir, &cache_dentry); - - duplicate_inode(cache_dir, dir); - duplicate_inode(cache_dentry.d_inode, dentry->d_inode); - - smfs_clear_dentry(&cache_dentry); - RETURN(rc); + struct inode *cache_dir = I2CI(dir); + struct inode *cache_inode = I2CI(dentry->d_inode); + struct inode *parent = I2CI(dentry->d_parent->d_inode); + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; + struct hook_unlink_msg msg = { + .dentry = dentry, + .mode = S_IFDIR + }; + + ENTRY; + + LASSERT(cache_dir); + LASSERT(cache_dir->i_op->rmdir); + LASSERT(parent); + + cache_parent = pre_smfs_dentry(NULL, parent, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, cache_inode, dentry); + if (!cache_parent || !cache_dentry) { + rc = -ENOMEM; + goto exit; + } + + handle = smfs_trans_start(dir, FSFILT_OP_RMDIR, NULL); + if (IS_ERR(handle) ) { + rc = -ENOSPC; + goto exit; + } + + pre_smfs_inode(dir, cache_dir); + pre_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + + SMFS_PRE_HOOK(dir, HOOK_RMDIR, &msg); + + rc = cache_dir->i_op->rmdir(cache_dir, cache_dentry); + + SMFS_POST_HOOK(dir, HOOK_RMDIR, &msg, rc); + + post_smfs_inode(dir, cache_dir); + post_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + //like vfs_rmdir is doing with inode + if (!rc) + cache_dentry->d_inode->i_flags |= S_DEAD; + + smfs_trans_commit(dir, handle, 0); + +exit: + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + RETURN(rc); } -static int smfs_mknod(struct inode * dir, struct dentry *dentry, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +static int smfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) +#else +static int smfs_mknod(struct inode *dir, struct dentry *dentry, + int mode, dev_t rdev) +#endif { - struct inode *cache_dir = I2CI(dir); - struct inode *inode = NULL; - struct inode *cache_inode = NULL; - struct dentry cache_dentry; - struct dentry tmp; - int rc = 0; - - if (!cache_dir) - RETURN(-ENOENT); - - prepare_parent_dentry(&tmp, cache_dir); - smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name); - - if (cache_dir->i_op->mknod) - rc = cache_dir->i_op->mknod(cache_dir, &cache_dentry, mode, rdev); - - if (!rc) { - cache_inode = cache_dentry.d_inode; - inode = iget(dir->i_sb, cache_inode->i_ino); - d_instantiate(dentry, inode); - duplicate_inode(cache_dir, dir); - duplicate_inode(cache_dentry.d_inode, dentry->d_inode); - } - smfs_clear_dentry(&cache_dentry); - RETURN(rc); + struct inode *cache_dir = I2CI(dir); + struct inode *inode = NULL; + struct inode *parent = I2CI(dentry->d_parent->d_inode); + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; + struct hook_msg msg = { + .dentry = dentry, + }; + + ENTRY; + + LASSERT(parent); + LASSERT(cache_dir); + LASSERT(cache_dir->i_op->mknod); + + cache_parent = pre_smfs_dentry(NULL, parent, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + if (!cache_parent || !cache_dentry) { + rc = -ENOMEM; + goto exit; + } + + handle = smfs_trans_start(dir, FSFILT_OP_MKNOD, NULL); + if (IS_ERR(handle)) { + rc = -ENOSPC; + goto exit; + } + + pre_smfs_inode(dir, cache_dir); + + SMFS_PRE_HOOK(dir, HOOK_MKNOD, &msg); + + rc = cache_dir->i_op->mknod(cache_dir, cache_dentry, mode, rdev); + if (!rc) { + inode = smfs_get_inode(dir->i_sb, cache_dentry->d_inode->i_ino, + dir, 0); + if (inode) { + //smsf_update_dentry(dentry, cache_dentry); + d_instantiate(dentry, inode); + } + else + rc = -ENOENT; + } + + SMFS_POST_HOOK(dir, HOOK_MKNOD, &msg, rc); + + post_smfs_inode(dir, cache_dir); + + smfs_trans_commit(dir, handle, 0); + +exit: + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + RETURN(rc); } -static int smfs_rename(struct inode * old_dir, struct dentry *old_dentry, - struct inode * new_dir,struct dentry *new_dentry) + +static int smfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir,struct dentry *new_dentry) { - struct inode *cache_old_dir = I2CI(old_dir); - struct inode *cache_new_dir = I2CI(new_dir); - struct inode *cache_old_inode = I2CI(old_dentry->d_inode); - struct inode *cache_new_inode = NULL; - struct inode *new_inode = NULL; - struct dentry cache_old_dentry; - struct dentry cache_new_dentry; - struct dentry tmp_new; - struct dentry tmp_old; - int rc = 0; - - if (!cache_old_dir || !cache_new_dir || !cache_old_inode) - RETURN(-ENOENT); - - prepare_parent_dentry(&tmp_old, cache_old_dir); - smfs_prepare_dentry(&cache_old_dentry, &tmp_old, &old_dentry->d_name); - d_add(&cache_old_dentry, cache_old_inode); - - prepare_parent_dentry(&tmp_new, cache_new_dir); - smfs_prepare_dentry(&cache_new_dentry, &tmp_new, &new_dentry->d_name); - - if (cache_old_dir->i_op->rename) - rc = cache_old_dir->i_op->rename(cache_old_dir, &cache_old_dentry, - cache_new_dir, &cache_new_dentry); - - duplicate_inode(cache_old_dir, old_dir); - duplicate_inode(cache_new_dir, new_dir); - smfs_clear_dentry(&cache_old_dentry); - smfs_clear_dentry(&cache_new_dentry); - - RETURN(rc); + struct inode *cache_old_dir = I2CI(old_dir); + struct inode *cache_new_dir = I2CI(new_dir); + struct inode *cache_old_inode = I2CI(old_dentry->d_inode); + struct inode *old_parent = I2CI(old_dentry->d_parent->d_inode); + struct inode *new_parent = I2CI(new_dentry->d_parent->d_inode); + struct inode *cache_new_inode = NULL; + struct dentry *cache_old_dentry = NULL; + struct dentry *cache_new_dentry = NULL; + struct dentry *cache_new_parent = NULL; + struct dentry *cache_old_parent = NULL; + void *handle = NULL; + int rc = 0; + struct hook_rename_msg msg = { + .dentry = old_dentry, + .new_dir = new_dir, + .new_dentry = new_dentry + }; + + ENTRY; + + if (!cache_old_dir || !cache_new_dir || !cache_old_inode) + RETURN(-ENOENT); + + if (new_dentry->d_inode) { + cache_new_inode = I2CI(new_dentry->d_inode); + if (!cache_new_inode) + RETURN(-ENOENT); + } + + cache_old_parent = pre_smfs_dentry(NULL, old_parent, old_dentry->d_parent); + cache_old_dentry = pre_smfs_dentry(cache_old_parent, cache_old_inode, + old_dentry); + if (!cache_old_parent || !cache_old_dentry) { + rc = -ENOMEM; + goto exit; + } + + cache_new_parent = pre_smfs_dentry(NULL, new_parent, new_dentry->d_parent); + cache_new_dentry = pre_smfs_dentry(cache_new_parent, cache_new_inode, + new_dentry); + if (!cache_new_parent || !cache_new_dentry) { + rc = -ENOMEM; + goto exit; + } + + handle = smfs_trans_start(old_dir, FSFILT_OP_RENAME, NULL); + if (IS_ERR(handle)) { + rc = -ENOSPC; + goto exit; + } + + pre_smfs_inode(old_dir, cache_old_dir); + pre_smfs_inode(new_dir, cache_new_dir); + if (new_dentry->d_inode) + pre_smfs_inode(new_dentry->d_inode, cache_new_dentry->d_inode); + + SMFS_PRE_HOOK(old_dir, HOOK_RENAME, &msg); + + rc = cache_old_dir->i_op->rename(cache_old_dir, cache_old_dentry, + cache_new_dir, cache_new_dentry); + + SMFS_POST_HOOK(old_dir, HOOK_RENAME, &msg, rc); + + post_smfs_inode(old_dir, cache_old_dir); + post_smfs_inode(new_dir, cache_new_dir); + if (new_dentry->d_inode) + post_smfs_inode(new_dentry->d_inode, cache_new_dentry->d_inode); + + smfs_trans_commit(old_dir, handle, 0); + +exit: + post_smfs_dentry(cache_old_dentry); + post_smfs_dentry(cache_old_parent); + post_smfs_dentry(cache_new_dentry); + post_smfs_dentry(cache_new_parent); + RETURN(rc); } struct inode_operations smfs_dir_iops = { - create: smfs_create, - lookup: smfs_lookup, - lookup_raw: smfs_lookup_raw, /* BKL held */ + create: smfs_create, + lookup: smfs_lookup, +#if HAVE_LOOKUP_RAW + lookup_raw: smfs_lookup_raw, +#endif link: smfs_link, /* BKL held */ unlink: smfs_unlink, /* BKL held */ symlink: smfs_symlink, /* BKL held */ @@ -426,58 +787,91 @@ struct inode_operations smfs_dir_iops = { removexattr: smfs_removexattr, /* BKL held */ }; -static ssize_t smfs_read_dir(struct file *filp, char *buf, - size_t size, loff_t *ppos) +struct inode_operations smfs_iopen_iops = { + lookup: smfs_iopen_lookup, +}; + +static ssize_t smfs_read_dir(struct file *filp, char *buf, + size_t size, loff_t *ppos) { - struct dentry *dentry = filp->f_dentry; - struct inode *cache_inode = NULL; - struct file open_file; - struct dentry open_dentry; - int rc = 0; - - cache_inode = I2CI(dentry->d_inode); - - if (!cache_inode) - RETURN(-EINVAL); - - smfs_prepare_cachefile(dentry->d_inode, filp, cache_inode, - &open_file, &open_dentry); - - if (cache_inode->i_fop->read) - rc = cache_inode->i_fop->read(&open_file, buf, size, ppos); - - smfs_update_file(filp, &open_file); - RETURN(rc); + struct dentry *dentry = filp->f_dentry; + struct inode *cache_inode = NULL; + struct smfs_file_info *sfi = NULL; + loff_t tmp_ppos; + loff_t *cache_ppos = NULL; + int rc = 0; + + ENTRY; + + cache_inode = I2CI(dentry->d_inode); + + if (!cache_inode || !cache_inode->i_fop->read) + RETURN(-EINVAL); + + sfi = F2SMFI(filp); + if (sfi->magic != SMFS_FILE_MAGIC) + BUG(); + + if (ppos != &(filp->f_pos)) + cache_ppos = &tmp_ppos; + else + cache_ppos = &sfi->c_file->f_pos; + + *cache_ppos = *ppos; + + rc = cache_inode->i_fop->read(sfi->c_file, buf, size, cache_ppos); + if (rc) + RETURN(rc); + + *ppos = *cache_ppos; + + duplicate_file(filp, sfi->c_file); + + RETURN(rc); } -static int smfs_readdir(struct file * filp, - void * dirent, - filldir_t filldir) +static int smfs_readdir(struct file *filp, void *dirent, filldir_t filldir) { - struct dentry *dentry = filp->f_dentry; - struct inode *cache_inode = NULL; - struct file open_file; - struct dentry open_dentry; - int rc = 0; - - cache_inode = I2CI(dentry->d_inode); - - if (!cache_inode) - RETURN(-EINVAL); - - smfs_prepare_cachefile(dentry->d_inode, filp, cache_inode, - &open_file, &open_dentry); - - if (cache_inode->i_fop->readdir) - rc = cache_inode->i_fop->readdir(&open_file, dirent, filldir); - - smfs_update_file(filp, &open_file); - RETURN(rc); + struct dentry *dentry = filp->f_dentry; + struct inode *cache_inode = NULL; + struct smfs_file_info *sfi = NULL; + int rc = 0; + struct hook_readdir_msg msg = { + .dentry = dentry, + .filp = filp, + .dirent = dirent, + .filldir = filldir + }; + + ENTRY; + + cache_inode = I2CI(dentry->d_inode); + if (!cache_inode || !cache_inode->i_fop->readdir) + RETURN(-EINVAL); + + sfi = F2SMFI(filp); + if (sfi->magic != SMFS_FILE_MAGIC) BUG(); + + SMFS_PRE_HOOK(dentry->d_inode, HOOK_READDIR, &msg); + + rc = cache_inode->i_fop->readdir(sfi->c_file, dirent, filldir); + + SMFS_POST_HOOK(dentry->d_inode, HOOK_READDIR, &msg, rc); + duplicate_file(filp, sfi->c_file); + + RETURN(rc); } struct file_operations smfs_dir_fops = { - read: smfs_read_dir, - readdir: smfs_readdir, /* BKL held */ - ioctl: smfs_ioctl, /* BKL held */ - fsync: smfs_fsync, /* BKL held */ + .read = smfs_read_dir, + .readdir = smfs_readdir, /* BKL held */ + .ioctl = smfs_ioctl, /* BKL held */ + .fsync = smfs_fsync, /* BKL held */ + .open = smfs_open, + .release = smfs_release, +}; + +struct file_operations smfs_iopen_fops = { + .read = smfs_read_dir, }; +