-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
*
- * Copyright (c) 2002, 2003 Cluster File Systems, Inc.
+ * This program 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
*
- * This file is part of Lustre, http://www.lustre.org.
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
*
- * 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.
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
*
- * 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.
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
*
- * 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.
+ * Copyright (c) 2011, 2012, Whamcloud, Inc.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
*/
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/quotaops.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
+#include <linux/security.h>
#define DEBUG_SUBSYSTEM S_LLITE
#include <lustre_lite.h>
#include <lustre_dlm.h>
#include <lustre_ver.h>
-#include <lustre_mdc.h>
#include "llite_internal.h"
-/* methods */
-extern struct dentry_operations ll_d_ops;
-
/*
* Check if we have something mounted at the named dchild.
* In such a case there would always be dentry present.
RETURN(0);
}
+
+/* called from iget5_locked->find_inode() under inode_lock spinlock */
+static int ll_test_inode(struct inode *inode, void *opaque)
+{
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct lustre_md *md = opaque;
+
+ if (unlikely(!(md->body->valid & OBD_MD_FLID))) {
+ CERROR("MDS body missing FID\n");
+ return 0;
+ }
+
+ if (!lu_fid_eq(&lli->lli_fid, &md->body->fid1))
+ return 0;
+
+ return 1;
+}
+
+static int ll_set_inode(struct inode *inode, void *opaque)
+{
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct mdt_body *body = ((struct lustre_md *)opaque)->body;
+
+ if (unlikely(!(body->valid & OBD_MD_FLID))) {
+ CERROR("MDS body missing FID\n");
+ return -EINVAL;
+ }
+
+ lli->lli_fid = body->fid1;
+ if (unlikely(!(body->valid & OBD_MD_FLTYPE))) {
+ CERROR("Can not initialize inode "DFID" without object type: "
+ "valid = "LPX64"\n", PFID(&lli->lli_fid), body->valid);
+ return -EINVAL;
+ }
+
+ inode->i_mode = (inode->i_mode & ~S_IFMT) | (body->mode & S_IFMT);
+ if (unlikely(inode->i_mode == 0)) {
+ CERROR("Invalid inode "DFID" type\n", PFID(&lli->lli_fid));
+ return -EINVAL;
+ }
+
+ ll_lli_init(lli);
+
+ return 0;
+}
+
+
/*
* Get an inode by inode number (already instantiated by the intent lookup).
* Returns inode or NULL
struct inode *ll_iget(struct super_block *sb, ino_t hash,
struct lustre_md *md)
{
- struct ll_inode_info *lli;
- struct inode *inode;
+ struct inode *inode;
+ ENTRY;
+
LASSERT(hash != 0);
+ inode = iget5_locked(sb, hash, ll_test_inode, ll_set_inode, md);
- inode = iget_locked(sb, hash);
if (inode) {
if (inode->i_state & I_NEW) {
- lli = ll_i2info(inode);
+ int rc = 0;
+
ll_read_inode2(inode, md);
- unlock_new_inode(inode);
- } else {
- if (!(inode->i_state & (I_FREEING | I_CLEAR)))
- ll_update_inode(inode, md);
- }
- CDEBUG(D_VFSTRACE, "inode: %lu/%u(%p)\n",
- inode->i_ino, inode->i_generation, inode);
+ if (S_ISREG(inode->i_mode) &&
+ ll_i2info(inode)->lli_clob == NULL)
+ rc = cl_file_inode_init(inode, md);
+ if (rc != 0) {
+ md->lsm = NULL;
+ make_bad_inode(inode);
+ unlock_new_inode(inode);
+ iput(inode);
+ inode = ERR_PTR(rc);
+ } else
+ unlock_new_inode(inode);
+ } else if (!(inode->i_state & (I_FREEING | I_CLEAR)))
+ ll_update_inode(inode, md);
+ CDEBUG(D_VFSTRACE, "got inode: %p for "DFID"\n",
+ inode, PFID(&md->body->fid1));
}
-
- return inode;
+ RETURN(inode);
}
-static void ll_drop_negative_dentry(struct inode *dir)
-{
- struct dentry *dentry, *tmp_alias, *tmp_subdir;
-
- spin_lock(&dcache_lock);
-restart:
- list_for_each_entry_safe(dentry, tmp_alias,
- &dir->i_dentry,d_alias) {
- if (!list_empty(&dentry->d_subdirs)) {
- struct dentry *child;
- list_for_each_entry_safe(child, tmp_subdir,
- &dentry->d_subdirs,
- d_child) {
- /* XXX Print some debug here? */
- if (!child->d_inode)
- /* Negative dentry. If we were
- dropping dcache lock, go
- throught the list again */
- if (ll_drop_dentry(child))
- goto restart;
- }
- }
- }
- spin_unlock(&dcache_lock);
+static void ll_invalidate_negative_children(struct inode *dir)
+{
+ struct dentry *dentry, *tmp_subdir;
+
+ ll_lock_dcache(dir);
+ list_for_each_entry(dentry, &dir->i_dentry, d_alias) {
+ spin_lock(&dentry->d_lock);
+ if (!list_empty(&dentry->d_subdirs)) {
+ struct dentry *child;
+
+ list_for_each_entry_safe(child, tmp_subdir,
+ &dentry->d_subdirs,
+ d_child) {
+ if (child->d_inode == NULL)
+ d_lustre_invalidate(child);
+ }
+ }
+ spin_unlock(&dentry->d_lock);
+ }
+ ll_unlock_dcache(dir);
}
-
int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
void *data, int flag)
{
break;
case LDLM_CB_CANCELING: {
struct inode *inode = ll_inode_from_lock(lock);
+ struct ll_inode_info *lli;
__u64 bits = lock->l_policy_data.l_inodebits.bits;
struct lu_fid *fid;
+ ldlm_mode_t mode = lock->l_req_mode;
/* Invalidate all dentries associated with this inode */
if (inode == NULL)
break;
LASSERT(lock->l_flags & LDLM_FL_CANCELING);
- if ((bits & MDS_INODELOCK_LOOKUP) &&
- ll_have_md_lock(inode, MDS_INODELOCK_LOOKUP))
- bits &= ~MDS_INODELOCK_LOOKUP;
- if ((bits & MDS_INODELOCK_UPDATE) &&
- ll_have_md_lock(inode, MDS_INODELOCK_UPDATE))
- bits &= ~MDS_INODELOCK_UPDATE;
- if ((bits & MDS_INODELOCK_OPEN) &&
- ll_have_md_lock(inode, MDS_INODELOCK_OPEN))
- bits &= ~MDS_INODELOCK_OPEN;
+ /* For OPEN locks we differentiate between lock modes
+ * LCK_CR, LCK_CW, LCK_PR - bug 22891 */
+ if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE |
+ MDS_INODELOCK_LAYOUT))
+ ll_have_md_lock(inode, &bits, LCK_MINMODE);
+
+ if (bits & MDS_INODELOCK_OPEN)
+ ll_have_md_lock(inode, &bits, mode);
fid = ll_inode2fid(inode);
if (lock->l_resource->lr_name.name[0] != fid_seq(fid) ||
ll_md_real_close(inode, flags);
}
+ lli = ll_i2info(inode);
+ if (bits & MDS_INODELOCK_LAYOUT) {
+ struct cl_object_conf conf = { .coc_inode = inode,
+ .coc_invalidate = true };
+ rc = ll_layout_conf(inode, &conf);
+ if (rc)
+ CDEBUG(D_INODE, "invaliding layout %d.\n", rc);
+ }
+
if (bits & MDS_INODELOCK_UPDATE)
- ll_i2info(inode)->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
+ lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
if (S_ISDIR(inode->i_mode) &&
(bits & MDS_INODELOCK_UPDATE)) {
CDEBUG(D_INODE, "invalidating inode %lu\n",
inode->i_ino);
truncate_inode_pages(inode->i_mapping, 0);
- ll_drop_negative_dentry(inode);
- }
+ ll_invalidate_negative_children(inode);
+ }
- if (inode->i_sb->s_root &&
- inode != inode->i_sb->s_root->d_inode &&
- (bits & MDS_INODELOCK_LOOKUP))
- ll_unhash_aliases(inode);
+ if (inode->i_sb->s_root &&
+ inode != inode->i_sb->s_root->d_inode &&
+ (bits & MDS_INODELOCK_LOOKUP))
+ ll_invalidate_aliases(inode);
iput(inode);
break;
}
RETURN(0);
}
+__u32 ll_i2suppgid(struct inode *i)
+{
+ if (cfs_curproc_is_in_groups(i->i_gid))
+ return (__u32)i->i_gid;
+ else
+ return (__u32)(-1);
+}
+
/* Pack the required supplementary groups into the supplied groups array.
* If we don't need to use the groups from the target inode(s) then we
* instead pack one or more groups from the user's supplementary group
* array in case it might be useful. Not needed if doing an MDS-side upcall. */
void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2)
{
+#if 0
int i;
+#endif
LASSERT(i1 != NULL);
LASSERT(suppgids != NULL);
- if (in_group_p(i1->i_gid))
- suppgids[0] = i1->i_gid;
- else
- suppgids[0] = -1;
+ suppgids[0] = ll_i2suppgid(i1);
- if (i2) {
- if (in_group_p(i2->i_gid))
- suppgids[1] = i2->i_gid;
+ if (i2)
+ suppgids[1] = ll_i2suppgid(i2);
else
suppgids[1] = -1;
- } else {
- suppgids[1] = -1;
- }
+#if 0
for (i = 0; i < current_ngroups; i++) {
if (suppgids[0] == -1) {
if (current_groups[i] != suppgids[1])
}
break;
}
+#endif
}
-static void ll_d_add(struct dentry *de, struct inode *inode)
+/*
+ * try to reuse three types of dentry:
+ * 1. unhashed alias, this one is unhashed by d_invalidate (but it may be valid
+ * by concurrent .revalidate).
+ * 2. INVALID alias (common case for no valid ldlm lock held, but this flag may
+ * be cleared by others calling d_lustre_revalidate).
+ * 3. DISCONNECTED alias.
+ */
+static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
{
- CDEBUG(D_DENTRY, "adding inode %p to dentry %p\n", inode, de);
- /* d_instantiate */
- if (!list_empty(&de->d_alias)) {
- spin_unlock(&dcache_lock);
- CERROR("dentry %.*s %p alias next %p, prev %p\n",
- de->d_name.len, de->d_name.name, de,
- de->d_alias.next, de->d_alias.prev);
- LBUG();
- }
- if (inode)
- list_add(&de->d_alias, &inode->i_dentry);
- de->d_inode = inode;
-
- /* d_rehash */
- if (!d_unhashed(de)) {
- spin_unlock(&dcache_lock);
- CERROR("dentry %.*s %p hash next %p\n",
- de->d_name.len, de->d_name.name, de, de->d_hash.next);
- LBUG();
- }
- __d_rehash(de, 0);
+ struct dentry *alias, *discon_alias, *invalid_alias;
+
+ if (list_empty(&inode->i_dentry))
+ return NULL;
+
+ discon_alias = invalid_alias = NULL;
+
+ ll_lock_dcache(inode);
+ list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ LASSERT(alias != dentry);
+
+ spin_lock(&alias->d_lock);
+ if (alias->d_flags & DCACHE_DISCONNECTED)
+ /* LASSERT(last_discon == NULL); LU-405, bz 20055 */
+ discon_alias = alias;
+ else if (alias->d_parent == dentry->d_parent &&
+ alias->d_name.hash == dentry->d_name.hash &&
+ alias->d_name.len == dentry->d_name.len &&
+ memcmp(alias->d_name.name, dentry->d_name.name,
+ dentry->d_name.len) == 0)
+ invalid_alias = alias;
+ spin_unlock(&alias->d_lock);
+
+ if (invalid_alias)
+ break;
+ }
+ alias = invalid_alias ?: discon_alias ?: NULL;
+ if (alias) {
+ spin_lock(&alias->d_lock);
+ dget_dlock(alias);
+ spin_unlock(&alias->d_lock);
+ }
+ ll_unlock_dcache(inode);
+
+ return alias;
}
-/* Search "inode"'s alias list for a dentry that has the same name and parent
- * as de. If found, return it. If not found, return de.
- * Lustre can't use d_add_unique because don't unhash aliases for directory
- * in ll_revalidate_it. After revaliadate inode will be have hashed aliases
- * and it triggers BUG_ON in d_instantiate_unique (bug #10954).
+/*
+ * Similar to d_splice_alias(), but lustre treats DCACHE_LUSTRE_INVALID alias
+ * similar to DCACHE_DISCONNECTED, and tries to use it anyway.
*/
-struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
+struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
{
- struct list_head *tmp;
- struct dentry *dentry;
- struct dentry *last_discon = NULL;
-
- spin_lock(&dcache_lock);
- list_for_each(tmp, &inode->i_dentry) {
- dentry = list_entry(tmp, struct dentry, d_alias);
-
- /* We are called here with 'de' already on the aliases list. */
- if (unlikely(dentry == de)) {
- CERROR("whoops\n");
- continue;
- }
-
- if (dentry->d_flags & DCACHE_DISCONNECTED) {
- LASSERT(last_discon == NULL);
- last_discon = dentry;
- continue;
- }
-
- if (dentry->d_parent != de->d_parent)
- continue;
-
- if (dentry->d_name.hash != de->d_name.hash)
- continue;
-
- if (dentry->d_name.len != de->d_name.len)
- continue;
-
- if (memcmp(dentry->d_name.name, de->d_name.name,
- de->d_name.len) != 0)
- continue;
-
- dget_locked(dentry);
- lock_dentry(dentry);
- __d_drop(dentry);
-#ifdef LUSTRE_KERNEL_VERSION
- dentry->d_flags &= ~DCACHE_LUSTRE_INVALID;
-#endif
- unlock_dentry(dentry);
- __d_rehash(dentry, 0); /* avoid taking dcache_lock inside */
- spin_unlock(&dcache_lock);
- iput(inode);
- CDEBUG(D_DENTRY, "alias dentry %.*s (%p) parent %p inode %p "
- "refc %d\n", de->d_name.len, de->d_name.name, de,
- de->d_parent, de->d_inode, atomic_read(&de->d_count));
- return dentry;
- }
-
- if (last_discon) {
- CDEBUG(D_DENTRY, "Reuse disconnected dentry %p inode %p "
- "refc %d\n", last_discon, last_discon->d_inode,
- atomic_read(&last_discon->d_count));
- __d_rehash(de, 0);
- dget_locked(last_discon);
- __d_move(last_discon, de);
- spin_unlock(&dcache_lock);
- d_rehash(de);
- iput(inode);
- return last_discon;
- }
-
- ll_d_add(de, inode);
-
- spin_unlock(&dcache_lock);
-
+ struct dentry *new;
+
+ if (inode) {
+ new = ll_find_alias(inode, de);
+ if (new) {
+ ll_dops_init(new, 1, 1);
+ d_move(new, de);
+ iput(inode);
+ CDEBUG(D_DENTRY,
+ "Reuse dentry %p inode %p refc %d flags %#x\n",
+ new, new->d_inode, d_refcount(new), new->d_flags);
+ return new;
+ }
+ }
+ __d_lustre_invalidate(de);
+ ll_dops_init(de, 1, 1);
+ d_add(de, inode);
+ CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
+ de, de->d_inode, d_refcount(de), de->d_flags);
return de;
}
-static int lookup_it_finish(struct ptlrpc_request *request, int offset,
- struct lookup_intent *it, void *data)
+int ll_lookup_it_finish(struct ptlrpc_request *request,
+ struct lookup_intent *it, void *data)
{
struct it_cb_data *icbd = data;
struct dentry **de = icbd->icbd_childp;
struct inode *parent = icbd->icbd_parent;
- struct ll_sb_info *sbi = ll_i2sbi(parent);
struct inode *inode = NULL;
- int rc;
-
- /* NB 1 request reference will be taken away by ll_intent_lock()
- * when I return */
- if (!it_disposition(it, DISP_LOOKUP_NEG)) {
- ENTRY;
-
- rc = ll_prep_inode(&inode, request, offset,
- (*de)->d_sb);
+ __u64 bits = 0;
+ int rc;
+ ENTRY;
+
+ /* NB 1 request reference will be taken away by ll_intent_lock()
+ * when I return */
+ if (!it_disposition(it, DISP_LOOKUP_NEG)) {
+ rc = ll_prep_inode(&inode, request, (*de)->d_sb);
if (rc)
RETURN(rc);
- CDEBUG(D_DLMTRACE, "setting l_data to inode %p (%lu/%u)\n",
- inode, inode->i_ino, inode->i_generation);
- md_set_lock_data(sbi->ll_md_exp,
- &it->d.lustre.it_lock_handle, inode);
+ ll_set_lock_data(ll_i2sbi(parent)->ll_md_exp, inode, it, &bits);
/* We used to query real size from OSTs here, but actually
this is not needed. For stat() calls size would be updated
Everybody else who needs correct file size would call
ll_glimpse_size or some equivalent themselves anyway.
Also see bug 7198. */
-
- *de = ll_find_alias(inode, *de);
- } else {
- ENTRY;
- /* Check that parent has UPDATE lock. If there is none, we
- cannot afford to hash this dentry (done by ll_d_add) as it
- might get picked up later when UPDATE lock will appear */
- if (ll_have_md_lock(parent, MDS_INODELOCK_UPDATE)) {
- spin_lock(&dcache_lock);
- ll_d_add(*de, inode);
- spin_unlock(&dcache_lock);
- } else {
- (*de)->d_inode = NULL;
- /* We do not want to hash the dentry if don`t have a
- * lock, but if this dentry is later used in d_move,
- * we'd hit uninitialised list head d_hash, so we just
- * do this to init d_hash field but leave dentry
- * unhashed. (bug 10796). */
- d_rehash(*de);
- d_drop(*de);
- }
+ }
+
+ *de = ll_splice_alias(inode, *de);
+
+ if (!it_disposition(it, DISP_LOOKUP_NEG)) {
+ /* we have lookup look - unhide dentry */
+ if (bits & MDS_INODELOCK_LOOKUP)
+ d_lustre_revalidate(*de);
+ } else {
+ /* Check that parent has UPDATE lock. */
+ struct lookup_intent parent_it = {
+ .it_op = IT_GETATTR,
+ .d.lustre.it_lock_handle = 0 };
+
+ if (md_revalidate_lock(ll_i2mdexp(parent), &parent_it,
+ &ll_i2info(parent)->lli_fid, NULL)) {
+ d_lustre_revalidate(*de);
+ ll_intent_release(&parent_it);
+ }
}
- ll_set_dd(*de);
- (*de)->d_op = &ll_d_ops;
-
RETURN(0);
}
* not valid, revalidate it here. */
if (parent->i_sb->s_root && (parent->i_sb->s_root->d_inode == parent) &&
(it->it_op & (IT_OPEN | IT_CREAT))) {
- rc = ll_inode_revalidate_it(parent->i_sb->s_root, it);
+ rc = ll_inode_revalidate_it(parent->i_sb->s_root, it,
+ MDS_INODELOCK_LOOKUP);
if (rc)
RETURN(ERR_PTR(rc));
}
+ if (it->it_op == IT_GETATTR) {
+ rc = ll_statahead_enter(parent, &dentry, 0);
+ if (rc == 1) {
+ if (dentry == save)
+ GOTO(out, retval = NULL);
+ GOTO(out, retval = dentry);
+ }
+ }
+
icbd.icbd_childp = &dentry;
icbd.icbd_parent = parent;
if (IS_ERR(op_data))
RETURN((void *)op_data);
- it->it_create_mode &= ~current->fs->umask;
+ it->it_create_mode &= ~cfs_curproc_umask();
rc = md_intent_lock(ll_i2mdexp(parent), op_data, NULL, 0, it,
lookup_flags, &req, ll_md_blocking_ast, 0);
if (rc < 0)
GOTO(out, retval = ERR_PTR(rc));
- rc = lookup_it_finish(req, DLM_REPLY_REC_OFF, it, &icbd);
+ rc = ll_lookup_it_finish(req, it, &icbd);
if (rc != 0) {
ll_intent_release(it);
GOTO(out, retval = ERR_PTR(rc));
out:
if (req)
ptlrpc_req_finished(req);
+ if (it->it_op == IT_GETATTR && (retval == NULL || retval == dentry))
+ ll_statahead_mark(parent, dentry);
return retval;
}
-#ifdef LUSTRE_KERNEL_VERSION
-static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
- struct nameidata *nd)
-{
- struct dentry *de;
- ENTRY;
-
- if (nd && nd->flags & LOOKUP_LAST && !(nd->flags & LOOKUP_LINK_NOTLAST))
- de = ll_lookup_it(parent, dentry, &nd->intent, nd->flags);
- else
- de = ll_lookup_it(parent, dentry, NULL, 0);
-
- RETURN(de);
-}
-#else
struct lookup_intent *ll_convert_intent(struct open_intent *oit,
int lookup_flags)
{
it->it_op = IT_OPEN;
if (lookup_flags & LOOKUP_CREATE)
it->it_op |= IT_CREAT;
- it->it_create_mode = oit->create_mode;
+ it->it_create_mode = (oit->create_mode & S_IALLUGO) | S_IFREG;
it->it_flags = oit->flags;
} else {
it->it_op = IT_GETATTR;
}
-#ifndef HAVE_FILE_IN_STRUCT_INTENT
- /* Since there is no way to pass our intent to ll_file_open,
- * just check the file is there. Actual open will be done
- * in ll_file_open */
- if (it->it_op & IT_OPEN)
- it->it_op = IT_LOOKUP;
-#endif
-
return it;
}
if (nd && !(nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))) {
struct lookup_intent *it;
-#if defined(HAVE_FILE_IN_STRUCT_INTENT) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
/* Did we came here from failed revalidate just to propagate
* its error? */
if (nd->flags & LOOKUP_OPEN)
if (IS_ERR(nd->intent.open.file))
RETURN((struct dentry *)nd->intent.open.file);
#endif
-
if (ll_d2d(dentry) && ll_d2d(dentry)->lld_it) {
it = ll_d2d(dentry)->lld_it;
ll_d2d(dentry)->lld_it = NULL;
} else {
+ if ((nd->flags & LOOKUP_CREATE ) && !(nd->flags & LOOKUP_OPEN)) {
+ /* We are sure this is new dentry, so we need to create
+ our private data and set the dentry ops */
+ ll_dops_init(dentry, 1, 1);
+ __d_lustre_invalidate(dentry);
+ d_add(dentry, NULL);
+ RETURN(NULL);
+ }
it = ll_convert_intent(&nd->intent.open, nd->flags);
if (IS_ERR(it))
RETURN((struct dentry *)it);
if ((nd->flags & LOOKUP_OPEN) && !IS_ERR(dentry)) { /* Open */
if (dentry->d_inode &&
it_disposition(it, DISP_OPEN_OPEN)) { /* nocreate */
-#ifdef HAVE_FILE_IN_STRUCT_INTENT
if (S_ISFIFO(dentry->d_inode->i_mode)) {
// We cannot call open here as it would
// deadlock.
(struct ptlrpc_request *)
it->d.lustre.it_data);
} else {
- struct file *filp;
- nd->intent.open.file->private_data = it;
- filp =lookup_instantiate_filp(nd,dentry,
- NULL);
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
-/* 2.6.1[456] have a bug in open_namei() that forgets to check
- * nd->intent.open.file for error, so we need to return it as lookup's result
- * instead */
- if (IS_ERR(filp)) {
- if (de)
- dput(de);
- de = (struct dentry *) filp;
- }
-#endif
-
+ struct file *filp;
+
+ nd->intent.open.file->private_data = it;
+ filp = lookup_instantiate_filp(nd,
+ dentry,
+ NULL);
+ if (IS_ERR(filp)) {
+ if (de)
+ dput(de);
+ de = (struct dentry *)filp;
+ }
}
-#else /* HAVE_FILE_IN_STRUCT_INTENT */
- /* Release open handle as we have no way to
- * pass it to ll_file_open */
- ll_release_openhandle(dentry, it);
-#endif /* HAVE_FILE_IN_STRUCT_INTENT */
} else if (it_disposition(it, DISP_OPEN_CREATE)) {
// XXX This can only reliably work on assumption
// that there are NO hashed negative dentries.
RETURN(de);
}
-#endif
/* We depend on "mode" being set with the proper file type/umask by now */
static struct inode *ll_create_node(struct inode *dir, const char *name,
LASSERT(it_disposition(it, DISP_ENQ_CREATE_REF));
request = it->d.lustre.it_data;
it_clear_disposition(it, DISP_ENQ_CREATE_REF);
- rc = ll_prep_inode(&inode, request, DLM_REPLY_REC_OFF, dir->i_sb);
+ rc = ll_prep_inode(&inode, request, dir->i_sb);
if (rc)
GOTO(out, inode = ERR_PTR(rc));
* stuff it in the lock. */
CDEBUG(D_DLMTRACE, "setting l_ast_data to inode %p (%lu/%u)\n",
inode, inode->i_ino, inode->i_generation);
- md_set_lock_data(sbi->ll_md_exp,
- &it->d.lustre.it_lock_handle, inode);
+ ll_set_lock_data(sbi->ll_md_exp, inode, it, NULL);
EXIT;
out:
ptlrpc_req_finished(request);
inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
NULL, 0, mode, 0, it);
- if (IS_ERR(inode)) {
+ if (IS_ERR(inode))
RETURN(PTR_ERR(inode));
- }
d_instantiate(dentry, inode);
- /* Negative dentry may be unhashed if parent does not have UPDATE lock,
- * but some callers, e.g. do_coredump, expect dentry to be hashed after
- * successful create. Hash it here. */
- spin_lock(&dcache_lock);
- if (d_unhashed(dentry))
- __d_rehash(dentry, 0);
- spin_unlock(&dcache_lock);
RETURN(0);
}
-static void ll_update_times(struct ptlrpc_request *request, int offset,
+static void ll_update_times(struct ptlrpc_request *request,
struct inode *inode)
{
- struct mdt_body *body = lustre_msg_buf(request->rq_repmsg, offset,
- sizeof(*body));
- LASSERT(body);
+ struct mdt_body *body = req_capsule_server_get(&request->rq_pill,
+ &RMF_MDT_BODY);
- /* mtime is always updated with ctime, but can be set in past.
- As write and utime(2) may happen within 1 second, and utime's
- mtime has a priority over write's one, so take mtime from mds
- for the same ctimes. */
+ LASSERT(body);
+ if (body->valid & OBD_MD_FLMTIME &&
+ body->mtime > LTIME_S(inode->i_mtime)) {
+ CDEBUG(D_INODE, "setting ino %lu mtime from %lu to "LPU64"\n",
+ inode->i_ino, LTIME_S(inode->i_mtime), body->mtime);
+ LTIME_S(inode->i_mtime) = body->mtime;
+ }
if (body->valid & OBD_MD_FLCTIME &&
- body->ctime >= LTIME_S(inode->i_ctime)) {
+ body->ctime > LTIME_S(inode->i_ctime))
LTIME_S(inode->i_ctime) = body->ctime;
-
- if (body->valid & OBD_MD_FLMTIME) {
- CDEBUG(D_INODE, "setting ino %lu mtime from %lu "
- "to "LPU64"\n", inode->i_ino,
- LTIME_S(inode->i_mtime), body->mtime);
- LTIME_S(inode->i_mtime) = body->mtime;
- }
- }
}
static int ll_new_node(struct inode *dir, struct qstr *name,
GOTO(err_exit, err = PTR_ERR(op_data));
err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
- current->fsuid, current->fsgid,
- current->cap_effective, rdev, &request);
+ cfs_curproc_fsuid(), cfs_curproc_fsgid(),
+ cfs_curproc_cap_pack(), rdev, &request);
ll_finish_md_op_data(op_data);
if (err)
GOTO(err_exit, err);
- ll_update_times(request, REPLY_REC_OFF, dir);
+ ll_update_times(request, dir);
if (dchild) {
- err = ll_prep_inode(&inode, request, REPLY_REC_OFF,
- dchild->d_sb);
+ err = ll_prep_inode(&inode, request, dchild->d_sb);
if (err)
GOTO(err_exit, err);
- d_drop(dchild);
d_instantiate(dchild, inode);
- EXIT;
}
+ EXIT;
err_exit:
ptlrpc_req_finished(request);
name->len, name->name, dir->i_ino, dir->i_generation, dir,
mode, rdev);
- mode &= ~current->fs->umask;
+ mode &= ~cfs_curproc_umask();
switch (mode & S_IFMT) {
case 0:
default:
err = -EINVAL;
}
+
+ if (!err)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKNOD, 1);
+
RETURN(err);
}
-#ifndef LUSTRE_KERNEL_VERSION
static int ll_create_nd(struct inode *dir, struct dentry *dentry,
int mode, struct nameidata *nd)
{
}
rc = ll_create_it(dir, dentry, mode, it);
-#ifdef HAVE_FILE_IN_STRUCT_INTENT
if (nd && (nd->flags & LOOKUP_OPEN) && dentry->d_inode) { /* Open */
- nd->intent.open.file->private_data = it;
- lookup_instantiate_filp(nd, dentry, NULL);
+ struct file *filp;
+
+ nd->intent.open.file->private_data = it;
+ filp = lookup_instantiate_filp(nd, dentry, NULL);
+ if (IS_ERR(filp))
+ rc = PTR_ERR(filp);
}
-#else
- ll_release_openhandle(dentry,it);
-#endif
out:
ll_intent_release(it);
OBD_FREE(it, sizeof(*it));
- return rc;
-}
-#else
-static int ll_create_nd(struct inode *dir, struct dentry *dentry,
- int mode, struct nameidata *nd)
-{
- if (!nd || !nd->intent.d.lustre.it_disposition)
- /* No saved request? Just mknod the file */
- return ll_mknod_generic(dir, &dentry->d_name, mode, 0, dentry);
+ if (!rc)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_CREATE, 1);
- return ll_create_it(dir, dentry, mode, &nd->intent);
+ return rc;
}
-#endif
static int ll_symlink_generic(struct inode *dir, struct qstr *name,
const char *tgt, struct dentry *dchild)
err = ll_new_node(dir, name, (char *)tgt, S_IFLNK | S_IRWXUGO,
0, dchild, LUSTRE_OPC_SYMLINK);
+
+ if (!err)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_SYMLINK, 1);
+
RETURN(err);
}
ll_finish_md_op_data(op_data);
if (err)
GOTO(out, err);
- if (dchild)
- d_drop(dchild);
- ll_update_times(request, REPLY_REC_OFF, dir);
+ ll_update_times(request, dir);
+ ll_stats_ops_tally(sbi, LPROC_LL_LINK, 1);
EXIT;
out:
ptlrpc_req_finished(request);
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
name->len, name->name, dir->i_ino, dir->i_generation, dir);
- mode = (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask) | S_IFDIR;
+ mode = (mode & (S_IRWXUGO|S_ISVTX) & ~cfs_curproc_umask()) | S_IFDIR;
err = ll_new_node(dir, name, NULL, mode, 0, dchild, LUSTRE_OPC_MKDIR);
+ if (!err)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKDIR, 1);
+
RETURN(err);
}
struct lu_fid *fid)
{
struct dentry *parent, *child;
-
+
parent = list_entry(dir->i_dentry.next, struct dentry, d_alias);
child = d_lookup(parent, name);
if (child) {
struct md_op_data *op_data;
int rc;
ENTRY;
-
+
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
name->len, name->name, dir->i_ino, dir->i_generation, dir);
ll_get_child_fid(dir, name, &op_data->op_fid3);
rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
- if (rc == 0)
- ll_update_times(request, REPLY_REC_OFF, dir);
+ if (rc == 0) {
+ ll_update_times(request, dir);
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_RMDIR, 1);
+ }
+
ptlrpc_req_finished(request);
RETURN(rc);
}
struct lov_stripe_md *lsm = NULL;
struct obd_trans_info oti = { 0 };
struct obdo *oa;
+ struct obd_capa *oc = NULL;
int rc;
ENTRY;
/* req is swabbed so this is safe */
- body = lustre_msg_buf(request->rq_repmsg, REPLY_REC_OFF, sizeof(*body));
-
+ body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
if (!(body->valid & OBD_MD_FLEASIZE))
RETURN(0);
* to this file. Use this EA to unlink the objects on the OST.
* It's opaque so we don't swab here; we leave it to obd_unpackmd() to
* check it is complete and sensible. */
- eadata = lustre_swab_repbuf(request, REPLY_REC_OFF + 1,
- body->eadatasize, NULL);
+ eadata = req_capsule_server_sized_get(&request->rq_pill, &RMF_MDT_MD,
+ body->eadatasize);
LASSERT(eadata != NULL);
- if (eadata == NULL) {
- CERROR("Can't unpack MDS EA data\n");
- GOTO(out, rc = -EPROTO);
- }
rc = obd_unpackmd(ll_i2dtexp(dir), &lsm, eadata, body->eadatasize);
if (rc < 0) {
}
LASSERT(rc >= sizeof(*lsm));
- rc = obd_checkmd(ll_i2dtexp(dir), ll_i2mdexp(dir), lsm);
- if (rc)
- GOTO(out_free_memmd, rc);
-
OBDO_ALLOC(oa);
if (oa == NULL)
GOTO(out_free_memmd, rc = -ENOMEM);
oa->o_id = lsm->lsm_object_id;
- oa->o_gr = lsm->lsm_object_gr;
+ oa->o_seq = lsm->lsm_object_seq;
oa->o_mode = body->mode & S_IFMT;
oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLGROUP;
if (body->valid & OBD_MD_FLCOOKIE) {
oa->o_valid |= OBD_MD_FLCOOKIE;
oti.oti_logcookies =
- lustre_msg_buf(request->rq_repmsg, REPLY_REC_OFF + 2,
- sizeof(struct llog_cookie) *
- lsm->lsm_stripe_count);
+ req_capsule_server_sized_get(&request->rq_pill,
+ &RMF_LOGCOOKIES,
+ sizeof(struct llog_cookie) *
+ lsm->lsm_stripe_count);
if (oti.oti_logcookies == NULL) {
oa->o_valid &= ~OBD_MD_FLCOOKIE;
body->valid &= ~OBD_MD_FLCOOKIE;
}
}
- rc = obd_destroy(ll_i2dtexp(dir), oa, lsm, &oti, ll_i2mdexp(dir));
+ if (body->valid & OBD_MD_FLOSSCAPA) {
+ rc = md_unpack_capa(ll_i2mdexp(dir), request, &RMF_CAPA2, &oc);
+ if (rc)
+ GOTO(out_free_memmd, rc);
+ }
+
+ rc = obd_destroy(NULL, ll_i2dtexp(dir), oa, lsm, &oti,
+ ll_i2mdexp(dir), oc);
+ capa_put(oc);
OBDO_FREE(oa);
if (rc)
CERROR("obd destroy objid "LPX64" error %d\n",
return rc;
}
+/* ll_unlink_generic() doesn't update the inode with the new link count.
+ * Instead, ll_ddelete() and ll_d_iput() will update it based upon if there
+ * is any lock existing. They will recycle dentries and inodes based upon locks
+ * too. b=20433 */
static int ll_unlink_generic(struct inode *dir, struct dentry *dparent,
struct dentry *dchild, struct qstr *name)
{
ll_get_child_fid(dir, name, &op_data->op_fid3);
rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
-
if (rc)
GOTO(out, rc);
- ll_update_times(request, REPLY_REC_OFF, dir);
+ ll_update_times(request, dir);
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_UNLINK, 1);
rc = ll_objects_destroy(request, dir);
out:
tgt_name->name, tgt_name->len, &request);
ll_finish_md_op_data(op_data);
if (!err) {
- ll_update_times(request, REPLY_REC_OFF, src);
- ll_update_times(request, REPLY_REC_OFF, tgt);
+ ll_update_times(request, src);
+ ll_update_times(request, tgt);
+ ll_stats_ops_tally(sbi, LPROC_LL_RENAME, 1);
err = ll_objects_destroy(request, src);
}
RETURN(err);
}
-#ifdef LUSTRE_KERNEL_VERSION
-static int ll_mknod_raw(struct nameidata *nd, int mode, dev_t rdev)
-{
- return ll_mknod_generic(nd->dentry->d_inode, &nd->last, mode,rdev,NULL);
-}
-static int ll_rename_raw(struct nameidata *srcnd, struct nameidata *tgtnd)
-{
- return ll_rename_generic(srcnd->dentry->d_inode, srcnd->dentry,
- NULL, &srcnd->last,
- tgtnd->dentry->d_inode, tgtnd->dentry,
- NULL, &tgtnd->last);
-}
-static int ll_link_raw(struct nameidata *srcnd, struct nameidata *tgtnd)
-{
- return ll_link_generic(srcnd->dentry->d_inode, tgtnd->dentry->d_inode,
- &tgtnd->last, NULL);
-}
-static int ll_symlink_raw(struct nameidata *nd, const char *tgt)
-{
- return ll_symlink_generic(nd->dentry->d_inode, &nd->last, tgt, NULL);
-}
-static int ll_rmdir_raw(struct nameidata *nd)
-{
- return ll_rmdir_generic(nd->dentry->d_inode, nd->dentry, NULL,
- &nd->last);
-}
-static int ll_mkdir_raw(struct nameidata *nd, int mode)
-{
- return ll_mkdir_generic(nd->dentry->d_inode, &nd->last, mode, NULL);
-}
-static int ll_unlink_raw(struct nameidata *nd)
-{
- return ll_unlink_generic(nd->dentry->d_inode, nd->dentry, NULL,
- &nd->last);
-}
-#endif
-
static int ll_mknod(struct inode *dir, struct dentry *dchild, int mode,
ll_dev_t rdev)
{
static int ll_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- return ll_rename_generic(old_dir, NULL,
+ int err;
+ err = ll_rename_generic(old_dir, NULL,
old_dentry, &old_dentry->d_name,
new_dir, NULL, new_dentry,
&new_dentry->d_name);
+ if (!err) {
+#ifndef HAVE_FS_RENAME_DOES_D_MOVE
+ if (!S_ISDIR(old_dentry->d_inode->i_mode))
+#endif
+ d_move(old_dentry, new_dentry);
+ }
+ return err;
}
struct inode_operations ll_dir_inode_operations = {
-#ifdef LUSTRE_KERNEL_VERSION
- .link_raw = ll_link_raw,
- .unlink_raw = ll_unlink_raw,
- .symlink_raw = ll_symlink_raw,
- .mkdir_raw = ll_mkdir_raw,
- .rmdir_raw = ll_rmdir_raw,
- .mknod_raw = ll_mknod_raw,
- .rename_raw = ll_rename_raw,
- .setattr = ll_setattr,
- .setattr_raw = ll_setattr_raw,
-#endif
.mknod = ll_mknod,
.lookup = ll_lookup_nd,
.create = ll_create_nd,
};
struct inode_operations ll_special_inode_operations = {
-#ifdef LUSTRE_KERNEL_VERSION
- .setattr_raw = ll_setattr_raw,
-#endif
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,