X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fsmfs%2Fdir.c;h=85fb5b4d762fe7de7448cb3684f17fa00a3e8a10;hb=c39489126f88bb5b30643ebb11c72fbe9f9d2241;hp=2a995524cb434d4f3ab932ea776897c8b9262ecf;hpb=82946c53e02e67a00553401eba17a89098d09d67;p=fs%2Flustre-release.git diff --git a/lustre/smfs/dir.c b/lustre/smfs/dir.c index 2a99552..85fb5b4 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,405 +28,530 @@ #include #include #include -#include #include +#include +#include +#include +#include +#include +#include +#include -#include "smfs_internal.h" -#include "kml_idl.h" +#include "smfs_internal.h" #define NAME_ALLOC_LEN(len) ((len+16) & ~15) - -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); -} -void d_unalloc(struct dentry *dentry) +#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 *cache_dir = NULL; + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; - list_del(&dentry->d_hash); - INIT_LIST_HEAD(&dentry->d_hash); - dput(dentry); /* this will free the dentry memory */ -} + ENTRY; -static int smfs_create(struct inode *dir, - struct dentry *dentry, - int mode) -{ - struct inode *cache_dir; - struct inode *cache_inode = NULL, *inode; - struct dentry parent; - struct dentry *cache_dentry = NULL; - int rc; - - ENTRY; - - cache_dir = I2CI(dir); + cache_dir = I2CI(dir); if (!cache_dir) RETURN(-ENOENT); + + handle = smfs_trans_start(dir, FSFILT_OP_CREATE, NULL); + if (IS_ERR(handle)) + RETURN(-ENOSPC); + + lock_kernel(); + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_CREATE, handle, PRE_HOOK, rc, + exit); + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + + if (!cache_dentry || !cache_parent) + GOTO(exit, rc = -ENOMEM); - prepare_parent_dentry(&parent, cache_dir); - cache_dentry = d_alloc(&parent, &dentry->d_name); - - if (!cache_dentry) { - RETURN(-ENOMEM); - } - - 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 = igrab(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); + pre_smfs_inode(dir, cache_dir); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + if (cache_dir && cache_dir->i_op->create) + rc = cache_dir->i_op->create(cache_dir, cache_dentry, + mode); +#else + if (cache_dir && cache_dir->i_op->create) + rc = cache_dir->i_op->create(cache_dir, cache_dentry, + mode, nd); +#endif + if (rc) + GOTO(exit, rc); + + SMFS_GET_INODE(dir->i_sb, cache_dentry->d_inode, dir, inode, rc, exit); + + d_instantiate(dentry, inode); + post_smfs_inode(dir, cache_dir); + + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_CREATE, handle, POST_HOOK, rc, + exit); exit: - d_unalloc(cache_dentry); - RETURN(rc); + unlock_kernel(); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + smfs_trans_commit(dir, handle, 0); + RETURN(rc); } -static struct dentry *smfs_lookup(struct inode *dir, - struct dentry *dentry) +#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 inode *cache_dir; - struct inode *cache_inode = NULL, *inode; - struct dentry parent; - struct dentry *cache_dentry = NULL; - struct dentry *rc = NULL; - - ENTRY; - - cache_dir = I2CI(dir); - if (!cache_dir) + struct inode *cache_dir; + struct inode *cache_inode; + struct inode *inode = NULL; + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + struct dentry *rc = NULL; + void *handle = NULL; + int rc2 = 0; + + ENTRY; + + if (!(cache_dir = I2CI(dir))) RETURN(ERR_PTR(-ENOENT)); - prepare_parent_dentry(&parent, cache_dir); - cache_dentry = d_alloc(&parent, &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); - } - - cache_inode = igrab(cache_dentry->d_inode); - - inode = iget(dir->i_sb, cache_inode->i_ino); - - d_add(dentry, inode); -exit: - d_unalloc(cache_dentry); - RETURN(rc); -} - -static int smfs_lookup_raw(struct inode *dir, const char *name, - int len, ino_t *data) -{ - struct inode *cache_dir; - int rc = 0; - - cache_dir = I2CI(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); + /* preparing artificial backing fs dentries. */ + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + + if (!cache_dentry || !cache_parent) + GOTO(exit, rc = ERR_PTR(-ENOMEM)); + + if (!cache_dir && cache_dir->i_op->lookup) + GOTO(exit, rc = ERR_PTR(-ENOENT)); + + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_LOOKUP, handle, + PRE_HOOK, rc2, exit); + + /* perform lookup in backing fs. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + rc = cache_dir->i_op->lookup(cache_dir, cache_dentry); +#else + rc = cache_dir->i_op->lookup(cache_dir, cache_dentry, nd); +#endif + if (rc && IS_ERR(rc)) + GOTO(exit, rc); + + if ((cache_inode = rc ? rc->d_inode : cache_dentry->d_inode)) { + if (IS_ERR(cache_inode)) { + dentry->d_inode = cache_inode; + GOTO(exit, rc = NULL); + } + SMFS_GET_INODE(dir->i_sb, cache_inode, dir, inode, rc2, exit); + } + + d_add(dentry, inode); + rc = NULL; + + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_LOOKUP, handle, POST_HOOK, rc2, + exit); +exit: + if (rc2 < 0) + rc = ERR_PTR(rc2); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + smfs_trans_commit(dir, handle, 0); + RETURN(rc); } 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 parent; - struct dentry parent_old; - int rc = 0; - - inode = old_dentry->d_inode; - - cache_old_inode = I2CI(inode); - - if (!cache_old_inode || !cache_dir) - RETURN(-ENOENT); - - prepare_parent_dentry(&parent, cache_dir); - cache_dentry = d_alloc(&parent, &dentry->d_name); - - prepare_parent_dentry(&parent_old, cache_dir); - cache_old_dentry = d_alloc(&parent_old, &dentry->d_name); - d_add(cache_old_dentry, cache_old_inode); - pre_smfs_inode(inode, cache_old_dentry->d_inode); - - if (cache_dir->i_op->link) - rc = cache_dir->i_op->link(cache_old_dentry, cache_dir, cache_dentry); - - if (rc) - GOTO(exit, rc); - - atomic_inc(&inode->i_count); - post_smfs_inode(inode, cache_old_dentry->d_inode); - d_instantiate(dentry, inode); - + struct inode *cache_old_inode = NULL; + struct inode *cache_dir = I2CI(dir); + struct inode *inode = NULL; + struct dentry *cache_dentry = NULL; + struct dentry *cache_old_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; + + inode = old_dentry->d_inode; + + cache_old_inode = I2CI(inode); + + handle = smfs_trans_start(dir, FSFILT_OP_LINK, NULL); + if (IS_ERR(handle)) + RETURN(-ENOSPC); + + lock_kernel(); + SMFS_HOOK(dir, old_dentry, NULL, NULL, HOOK_LINK, handle, PRE_HOOK, rc, + exit); + + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + + if (!cache_parent || !cache_dentry) + GOTO(exit, rc = -ENOMEM); + + cache_old_dentry = pre_smfs_dentry(NULL, cache_old_inode, old_dentry); + if (!cache_old_dentry) + GOTO(exit, rc = -ENOMEM); + + pre_smfs_inode(dir, cache_dir); + pre_smfs_inode(inode, cache_old_dentry->d_inode); + + if (cache_dir->i_op->link) + rc = cache_dir->i_op->link(cache_old_dentry, cache_dir, + cache_dentry); + if (rc) + GOTO(exit, rc); + + atomic_inc(&inode->i_count); + post_smfs_inode(inode, cache_old_dentry->d_inode); + d_instantiate(dentry, inode); + post_smfs_inode(dir, cache_dir); + + SMFS_HOOK(dir, old_dentry, dentry, NULL, HOOK_LINK, handle, POST_HOOK, + rc, exit); exit: - if (cache_dentry->d_inode) - igrab(cache_dentry->d_inode); - if (cache_old_dentry->d_inode) - igrab(cache_old_dentry->d_inode); - - d_unalloc(cache_dentry); - d_unalloc(cache_old_dentry); - - RETURN(rc); + unlock_kernel(); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + post_smfs_dentry(cache_old_dentry); + smfs_trans_commit(dir, handle, 0); + 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 parent; - int rc = 0; - - if (!cache_dir || !cache_inode) - RETURN(-ENOENT); - - prepare_parent_dentry(&parent, cache_dir); - cache_dentry = d_alloc(&parent, &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); - - - post_smfs_inode(dentry->d_inode, cache_dentry->d_inode); - post_smfs_inode(dir, cache_dir); - - igrab(cache_dentry->d_inode); - - d_unalloc(cache_dentry); - RETURN(rc); + struct inode *cache_dir = I2CI(dir); + struct inode *cache_inode = I2CI(dentry->d_inode); + struct dentry *cache_dentry; + struct dentry *cache_parent; + void *handle = NULL; + int rc = 0; + int mode = 0; + + if (!cache_dir || !cache_inode) + RETURN(-ENOENT); + + handle = smfs_trans_start(dir, FSFILT_OP_UNLINK, NULL); + if (IS_ERR(handle)) + RETURN(-ENOSPC); + + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_UNLINK, handle, PRE_HOOK, rc, + exit); + + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); + cache_dentry = pre_smfs_dentry(cache_parent, cache_inode, dentry); + + if (!cache_parent || !cache_dentry) + GOTO(exit, rc = -ENOMEM); + + lock_kernel(); + pre_smfs_inode(dir, cache_dir); + pre_smfs_inode(dentry->d_inode, cache_inode); + if (cache_dir->i_op->unlink) + rc = cache_dir->i_op->unlink(cache_dir, cache_dentry); + post_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + post_smfs_inode(dir, cache_dir); + unlock_kernel(); + + SMFS_HOOK(dir, dentry, &mode, NULL, HOOK_UNLINK, handle, POST_HOOK, + rc, exit); +exit: + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + smfs_trans_commit(dir, handle, 0); + 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 parent; - int rc = 0; - - if (!cache_dir) - RETURN(-ENOENT); - - prepare_parent_dentry(&parent, cache_dir); - cache_dentry = d_alloc(&parent, &dentry->d_name); - - if (cache_dir->i_op->symlink) - rc = cache_dir->i_op->symlink(cache_dir, cache_dentry, symname); - - cache_inode = igrab(cache_dentry->d_inode); - - inode = iget(dir->i_sb, cache_inode->i_ino); - - if (inode) - d_instantiate(dentry, inode); - else - rc = -ENOENT; - - d_unalloc(cache_dentry); - - RETURN(rc); + struct inode *cache_dir = I2CI(dir); + struct inode *inode = NULL; + struct dentry *cache_dentry; + struct dentry *cache_parent; + void *handle = NULL; + int rc = 0, tgt_len; + + if (!cache_dir) + RETURN(-ENOENT); + + handle = smfs_trans_start(dir, FSFILT_OP_SYMLINK, NULL); + if (IS_ERR(handle)) + RETURN(-ENOSPC); + + lock_kernel(); + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_SYMLINK, handle, PRE_HOOK, rc, + exit); + + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + + if (!cache_parent || !cache_dentry) + GOTO(exit, rc = -ENOMEM); + + pre_smfs_inode(dir, cache_dir); + if (cache_dir->i_op->symlink) + rc = cache_dir->i_op->symlink(cache_dir, cache_dentry, symname); + + post_smfs_inode(dir, cache_dir); + + SMFS_GET_INODE(dir->i_sb, cache_dentry->d_inode, dir, inode, rc, exit); + if (inode) + d_instantiate(dentry, inode); + else + rc = -ENOENT; + + tgt_len = strlen(symname) + 1; + + SMFS_HOOK(dir, dentry, (char *)symname, &tgt_len, HOOK_SYMLINK, handle, + POST_HOOK, rc, exit); +exit: + unlock_kernel(); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + smfs_trans_commit(dir, handle, 0); + 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 parent; - void *handle; - int rc = 0; - - if (!cache_dir) - RETURN(-ENOENT); - - handle = smfs_trans_start(cache_dir, KML_OPCODE_MKDIR); - if (IS_ERR(handle) ) { - CERROR("smfs_do_mkdir: no space for transaction\n"); - RETURN(-ENOSPC); - } - - prepare_parent_dentry(&parent, cache_dir); - cache_dentry = d_alloc(&parent, &dentry->d_name); - - pre_smfs_inode(dir, cache_dir); - lock_kernel(); - if (cache_dir->i_op->mkdir) - rc = cache_dir->i_op->mkdir(cache_dir, cache_dentry, mode); - - cache_inode = igrab(cache_dentry->d_inode); - - inode = iget(dir->i_sb, cache_inode->i_ino); - - if (!inode) - GOTO(exit, rc = -ENOENT); - - d_instantiate(dentry, inode); - /*Do KML post hook*/ - if (smfs_do_kml(dir)) { - rc = post_kml_mkdir(dir, dentry); - GOTO(exit, rc); - } - post_smfs_inode(dir, cache_dir); + struct inode *cache_dir = I2CI(dir); + struct inode *inode = NULL; + struct dentry *cache_dentry; + struct dentry *cache_parent; + void *handle = NULL; + int rc = 0; + + if (!cache_dir) + RETURN(-ENOENT); + + handle = smfs_trans_start(dir, FSFILT_OP_MKDIR, NULL); + if (IS_ERR(handle)) + RETURN(-ENOSPC); + + lock_kernel(); + + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_MKDIR, handle, PRE_HOOK, rc, + exit); + + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + + if (!cache_parent || !cache_dentry) + GOTO(exit, rc = -ENOMEM); + + pre_smfs_inode(dir, cache_dir); + + if (cache_dir->i_op->mkdir) + rc = cache_dir->i_op->mkdir(cache_dir, cache_dentry, mode); + + if (rc) + GOTO(exit, rc); + + SMFS_GET_INODE(dir->i_sb, cache_dentry->d_inode, dir, inode, rc, exit); + d_instantiate(dentry, inode); + post_smfs_inode(dir, cache_dir); + + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_MKDIR, handle, POST_HOOK, rc, + exit); exit: - unlock_kernel(); - smfs_trans_commit(handle); - d_unalloc(cache_dentry); - RETURN(rc); + unlock_kernel(); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + smfs_trans_commit(dir, handle, 0); + 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 parent; - int rc = 0; - - if (!cache_dir) - RETURN(-ENOENT); - - prepare_parent_dentry(&parent, cache_dir); - cache_dentry = d_alloc(&parent, &dentry->d_name); - d_add(cache_dentry, cache_inode); - igrab(cache_inode); - - pre_smfs_inode(dir, cache_dir); - pre_smfs_inode(dentry->d_inode, cache_dentry->d_inode); - - - if (cache_dir->i_op->rmdir) - rc = cache_dir->i_op->rmdir(cache_dir, cache_dentry); - - post_smfs_inode(dir, cache_dir); - post_smfs_inode(dentry->d_inode, cache_dentry->d_inode); - d_unalloc(cache_dentry); - RETURN(rc); + struct inode *cache_dir = I2CI(dir); + struct inode *cache_inode = I2CI(dentry->d_inode); + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0, mode = S_IFDIR; + + if (!cache_dir) + RETURN(-ENOENT); + + handle = smfs_trans_start(dir, FSFILT_OP_RMDIR, NULL); + if (IS_ERR(handle) ) { + CERROR("smfs_do_mkdir: no space for transaction\n"); + RETURN(-ENOSPC); + } + + lock_kernel(); + + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_RMDIR, handle, PRE_HOOK, rc, + exit); + + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); + cache_dentry = pre_smfs_dentry(cache_parent, cache_inode, dentry); + + if (!cache_parent || !cache_dentry) + GOTO(exit, rc = -ENOMEM); + + pre_smfs_inode(dir, cache_dir); + pre_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + if (cache_dir->i_op->rmdir) + rc = cache_dir->i_op->rmdir(cache_dir, cache_dentry); + + post_smfs_inode(dir, cache_dir); + post_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + unlock_kernel(); + + SMFS_HOOK(dir, dentry, &mode, NULL, HOOK_RMDIR, handle, POST_HOOK, + rc, exit); +exit: + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + smfs_trans_commit(dir, handle, 0); + 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 parent; - int rc = 0; - - if (!cache_dir) - RETURN(-ENOENT); - - prepare_parent_dentry(&parent, cache_dir); - cache_dentry = d_alloc(&parent, &dentry->d_name); - - pre_smfs_inode(dir, cache_dir); - pre_smfs_inode(dentry->d_inode, cache_dentry->d_inode); - - if (cache_dir->i_op->mknod) - rc = cache_dir->i_op->mknod(cache_dir, cache_dentry, mode, rdev); - - if (cache_dentry->d_inode) - cache_inode = igrab(cache_dentry->d_inode); - if (rc) - GOTO(exit, rc); - - inode = iget(dir->i_sb, cache_inode->i_ino); - d_instantiate(dentry, inode); - post_smfs_inode(dir, cache_dir); - post_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + struct inode *cache_dir = I2CI(dir); + struct inode *inode = NULL; + struct dentry *cache_dentry = NULL; + struct dentry *cache_parent = NULL; + void *handle = NULL; + int rc = 0; + + if (!cache_dir) + RETURN(-ENOENT); + + handle = smfs_trans_start(dir, FSFILT_OP_MKNOD, NULL); + if (IS_ERR(handle)) { + CERROR("smfs_do_mkdir: no space for transaction\n"); + RETURN(-ENOSPC); + } + + lock_kernel(); + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_MKNOD, handle, PRE_HOOK, rc, + exit); + + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry->d_parent); + cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); + if (!cache_parent || !cache_dentry) + GOTO(exit, rc = -ENOMEM); + + pre_smfs_inode(dir, cache_dir); + pre_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + + if (!cache_dir->i_op->mknod) + RETURN(-ENOENT); + + if ((rc = cache_dir->i_op->mknod(cache_dir, cache_dentry, + mode, rdev))) + GOTO(exit, rc); + + SMFS_GET_INODE(dir->i_sb, cache_dentry->d_inode, dir, inode, rc, exit); + + d_instantiate(dentry, inode); + + pre_smfs_inode(dir, cache_dir); + pre_smfs_inode(dentry->d_inode, cache_dentry->d_inode); + + SMFS_HOOK(dir, dentry, NULL, NULL, HOOK_MKNOD, handle, POST_HOOK, rc, + exit); + exit: - d_unalloc(cache_dentry); - RETURN(rc); + unlock_kernel(); + post_smfs_dentry(cache_dentry); + post_smfs_dentry(cache_parent); + smfs_trans_commit(dir, handle, 0); + RETURN(rc); } + 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 dentry *cache_old_dentry; - struct dentry *cache_new_dentry; - struct dentry parent_new; - struct dentry parent_old; - int rc = 0; - - if (!cache_old_dir || !cache_new_dir || !cache_old_inode) - RETURN(-ENOENT); - - prepare_parent_dentry(&parent_old, cache_old_dir); - cache_old_dentry = d_alloc(&parent_old, &old_dentry->d_name); - d_add(cache_old_dentry, cache_old_inode); - igrab(cache_old_inode); - - prepare_parent_dentry(&parent_new, cache_new_dir); - cache_new_dentry = d_alloc(&parent_new, &new_dentry->d_name); - - pre_smfs_inode(old_dir, cache_old_dir) ; - pre_smfs_inode(new_dir, cache_new_dir); - - 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); - - post_smfs_inode(old_dir, cache_old_dir) ; - post_smfs_inode(new_dir, cache_new_dir); - if (cache_new_dentry->d_inode) { - igrab(cache_new_dentry->d_inode); - } - d_unalloc(cache_old_dentry); - d_unalloc(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 *cache_new_inode = new_dentry->d_inode ? + I2CI(new_dentry->d_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; + + if (!cache_old_dir || !cache_new_dir || !cache_old_inode) + RETURN(-ENOENT); + + handle = smfs_trans_start(old_dir, FSFILT_OP_RENAME, NULL); + if (IS_ERR(handle)) { + CERROR("smfs_do_mkdir: no space for transaction\n"); + RETURN(-ENOSPC); + } + lock_kernel(); + + + SMFS_HOOK(old_dir, old_dentry, new_dir, new_dentry, HOOK_RENAME, handle, + PRE_HOOK, rc, exit); + + cache_old_parent = pre_smfs_dentry(NULL, cache_old_dir, old_dentry); + cache_old_dentry = pre_smfs_dentry(cache_old_parent, cache_old_inode, + old_dentry); + if (!cache_old_parent || !cache_old_dentry) + GOTO(exit, rc = -ENOMEM); + + cache_new_parent = pre_smfs_dentry(NULL, cache_new_dir, new_dentry); + cache_new_dentry = pre_smfs_dentry(cache_new_parent, cache_new_inode, + new_dentry); + if (!cache_new_parent || !cache_new_dentry) + GOTO(exit, rc = -ENOMEM); + + pre_smfs_inode(old_dir, cache_old_dir); + pre_smfs_inode(new_dir, cache_new_dir); + + 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); + + post_smfs_inode(old_dir, cache_old_dir); + post_smfs_inode(new_dir, cache_new_dir); + + SMFS_HOOK(old_dir, old_dentry, new_dir, new_dentry, HOOK_RENAME, handle, + POST_HOOK, rc, exit); + + if (new_dentry->d_inode) + post_smfs_inode(new_dentry->d_inode, cache_new_dentry->d_inode); +exit: + unlock_kernel(); + post_smfs_dentry(cache_old_dentry); + post_smfs_dentry(cache_old_parent); + post_smfs_dentry(cache_new_dentry); + post_smfs_dentry(cache_new_parent); + smfs_trans_commit(old_dir, handle, 0); + 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, link: smfs_link, /* BKL held */ unlink: smfs_unlink, /* BKL held */ symlink: smfs_symlink, /* BKL held */ @@ -421,58 +565,73 @@ 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) +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; + int rc = 0; + + cache_inode = I2CI(dentry->d_inode); + + if (!cache_inode) + 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; + + if (cache_inode->i_fop->read) + rc = cache_inode->i_fop->read(sfi->c_file, buf, size, + cache_ppos); + *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; + + cache_inode = I2CI(dentry->d_inode); + if (!cache_inode) + RETURN(-EINVAL); + + sfi = F2SMFI(filp); + if (sfi->magic != SMFS_FILE_MAGIC) BUG(); + + SMFS_HOOK(dentry->d_inode, filp, dirent, filldir, HOOK_READDIR, NULL, + PRE_HOOK, rc, exit); + + if (cache_inode->i_fop->readdir) + rc = cache_inode->i_fop->readdir(sfi->c_file, dirent, filldir); + + SMFS_HOOK(dentry->d_inode, filp, dirent, filldir, HOOK_READDIR, NULL, + POST_HOOK, rc, exit); + + duplicate_file(filp, sfi->c_file); +exit: + if (rc > 0) + rc = 0; + RETURN(rc); } struct file_operations smfs_dir_fops = { - read: smfs_read_dir, + 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, };