-/* -*- 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.
* GPL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2012, Whamcloud, Inc.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#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"
/*
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;
}
struct inode *ll_iget(struct super_block *sb, ino_t hash,
struct lustre_md *md)
{
- struct ll_inode_info *lli;
struct inode *inode;
ENTRY;
inode = iget5_locked(sb, hash, ll_test_inode, ll_set_inode, md);
if (inode) {
- lli = ll_i2info(inode);
if (inode->i_state & I_NEW) {
+ 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, "got inode: %lu/%u(%p) for "DFID"\n",
- inode->i_ino, inode->i_generation, inode,
- PFID(&lli->lli_fid));
+ 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);
}
-static void ll_drop_negative_dentry(struct inode *dir)
-{
- struct dentry *dentry, *tmp_alias, *tmp_subdir;
-
- spin_lock(&ll_lookup_lock);
- 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);
- spin_unlock(&ll_lookup_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;
}
__u32 ll_i2suppgid(struct inode *i)
{
- if (in_group_p(i->i_gid))
+ if (cfs_curproc_is_in_groups(i->i_gid))
return (__u32)i->i_gid;
else
return (__u32)(-1);
#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_cond(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.
*/
-static 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(&ll_lookup_lock);
- 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 DCACHE_LUSTRE_INVALID
- dentry->d_flags &= ~DCACHE_LUSTRE_INVALID;
-#endif
- unlock_dentry(dentry);
- ll_dops_init(dentry, 0);
- d_rehash_cond(dentry, 0); /* avoid taking dcache_lock inside */
- spin_unlock(&dcache_lock);
- spin_unlock(&ll_lookup_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));
- dget_locked(last_discon);
- spin_unlock(&dcache_lock);
- spin_unlock(&ll_lookup_lock);
- ll_dops_init(last_discon, 1);
- d_rehash(de);
- d_move(last_discon, de);
- iput(inode);
- return last_discon;
- }
-
- ll_d_add(de, inode);
-
- spin_unlock(&dcache_lock);
- spin_unlock(&ll_lookup_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;
}
int ll_lookup_it_finish(struct ptlrpc_request *request,
- struct lookup_intent *it, void *data)
+ 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;
- ENTRY;
-
- /* NB 1 request reference will be taken away by ll_intent_lock()
- * when I return */
- if (!it_disposition(it, DISP_LOOKUP_NEG)) {
- struct dentry *save = *de;
+ __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. */
-
- ll_dops_init(*de, 1);
- *de = ll_find_alias(inode, *de);
- if (*de != save) {
- struct ll_dentry_data *lld = ll_d2d(*de);
-
- /* just make sure the ll_dentry_data is ready */
- if (unlikely(lld == NULL)) {
- ll_set_dd(*de);
- lld = ll_d2d(*de);
- if (likely(lld != NULL))
- lld->lld_sa_generation = 0;
- }
- }
- } else {
- ll_dops_init(*de, 1);
- /* 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);
+ }
}
RETURN(0);
struct md_op_data *op_data;
struct it_cb_data icbd;
__u32 opc;
- int rc, first = 0;
+ int rc;
ENTRY;
if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
* 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) {
- first = ll_statahead_enter(parent, &dentry, 1);
- if (first >= 0) {
- ll_statahead_exit(dentry, first);
- if (first == 1)
- RETURN(retval = dentry);
+ rc = ll_statahead_enter(parent, &dentry, 0);
+ if (rc == 1) {
+ if (dentry == save)
+ GOTO(out, retval = NULL);
+ GOTO(out, retval = dentry);
}
}
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);
GOTO(out, retval = ERR_PTR(rc));
}
- if (first == -EEXIST)
- ll_statahead_mark(dentry);
-
if ((it->it_op & IT_OPEN) && dentry->d_inode &&
!S_ISREG(dentry->d_inode->i_mode) &&
!S_ISDIR(dentry->d_inode->i_mode)) {
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 HAVE_VFS_INTENT_PATCHES
-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,
* 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_cond(dentry, 0);
- spin_unlock(&dcache_lock);
RETURN(0);
}
&RMF_MDT_BODY);
LASSERT(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. */
+ 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,
+ cfs_curproc_fsuid(), cfs_curproc_fsgid(),
cfs_curproc_cap_pack(), rdev, &request);
ll_finish_md_op_data(op_data);
if (err)
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 HAVE_VFS_INTENT_PATCHES
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, 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)
+ 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;
}
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 =
+ oti.oti_logcookies =
req_capsule_server_sized_get(&request->rq_pill,
&RMF_LOGCOOKIES,
sizeof(struct llog_cookie) *
}
}
- 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)
{
GOTO(out, rc);
ll_update_times(request, dir);
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_UNLINK, 1);
rc = ll_objects_destroy(request, dir);
out:
if (!err) {
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 HAVE_VFS_INTENT_PATCHES
-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)
{
}
struct inode_operations ll_dir_inode_operations = {
-#ifdef HAVE_VFS_INTENT_PATCHES
- .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 HAVE_VFS_INTENT_PATCHES
- .setattr_raw = ll_setattr_raw,
-#endif
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,