-/* -*- 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, 2013, Intel Corporation.
*/
/*
* 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_create_it(struct inode *, struct dentry *,
+ int, struct lookup_intent *);
+
/*
* Check if we have something mounted at the named dchild.
* In such a case there would always be dentry present.
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) {
+ CDEBUG(D_INODE,
+ "%s: apply lsm %p to inode "DFID".\n",
+ ll_get_fsname(sb, NULL, 0), md->lsm,
+ PFID(ll_inode2fid(inode)));
+ rc = cl_file_inode_init(inode, md);
+ }
+ if (rc != 0) {
+ 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: "DFID"(%p)\n",
+ PFID(&md->body->fid1), 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;
+ DECLARE_LL_D_HLIST_NODE_PTR(p);
+
+ ll_lock_dcache(dir);
+ ll_d_hlist_for_each_entry(dentry, p, &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_u.d_child) {
+ if (child->d_inode == NULL)
+ d_lustre_invalidate(child, 1);
+ }
+ }
+ 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)
+ void *data, int flag)
{
- int rc;
- struct lustre_handle lockh;
- ENTRY;
-
- switch (flag) {
- case LDLM_CB_BLOCKING:
- ldlm_lock2handle(lock, &lockh);
- rc = ldlm_cli_cancel(&lockh);
- if (rc < 0) {
- CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc);
- RETURN(rc);
- }
- break;
- case LDLM_CB_CANCELING: {
- struct inode *inode = ll_inode_from_lock(lock);
- __u64 bits = lock->l_policy_data.l_inodebits.bits;
- struct lu_fid *fid;
-
- /* 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;
-
- fid = ll_inode2fid(inode);
- if (lock->l_resource->lr_name.name[0] != fid_seq(fid) ||
- lock->l_resource->lr_name.name[1] != fid_oid(fid) ||
- lock->l_resource->lr_name.name[2] != fid_ver(fid)) {
- LDLM_ERROR(lock, "data mismatch with object "
- DFID" (%p)", PFID(fid), inode);
- }
-
- if (bits & MDS_INODELOCK_OPEN) {
- int flags = 0;
- switch (lock->l_req_mode) {
- case LCK_CW:
- flags = FMODE_WRITE;
- break;
- case LCK_PR:
- flags = FMODE_EXEC;
- break;
- case LCK_CR:
- flags = FMODE_READ;
- break;
- default:
- CERROR("Unexpected lock mode for OPEN lock "
- "%d, inode %ld\n", lock->l_req_mode,
- inode->i_ino);
- }
- ll_md_real_close(inode, flags);
- }
-
- if (bits & MDS_INODELOCK_UPDATE)
- ll_i2info(inode)->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);
- }
-
- if (inode->i_sb->s_root &&
- inode != inode->i_sb->s_root->d_inode &&
- (bits & MDS_INODELOCK_LOOKUP))
- ll_unhash_aliases(inode);
- iput(inode);
- break;
- }
- default:
- LBUG();
- }
-
- RETURN(0);
+ struct lustre_handle lockh;
+ int rc;
+ ENTRY;
+
+ switch (flag) {
+ case LDLM_CB_BLOCKING:
+ ldlm_lock2handle(lock, &lockh);
+ rc = ldlm_cli_cancel(&lockh, LCF_ASYNC);
+ if (rc < 0) {
+ CDEBUG(D_INODE, "ldlm_cli_cancel: rc = %d\n", rc);
+ RETURN(rc);
+ }
+ break;
+ case LDLM_CB_CANCELING: {
+ struct inode *inode = ll_inode_from_resource_lock(lock);
+ __u64 bits = lock->l_policy_data.l_inodebits.bits;
+
+ /* Inode is set to lock->l_resource->lr_lvb_inode
+ * for mdc - bug 24555 */
+ LASSERT(lock->l_ast_data == NULL);
+
+ if (inode == NULL)
+ break;
+
+ /* Invalidate all dentries associated with this inode */
+ LASSERT(ldlm_is_canceling(lock));
+
+ if (!fid_res_name_eq(ll_inode2fid(inode),
+ &lock->l_resource->lr_name)) {
+ LDLM_ERROR(lock, "data mismatch with object "DFID"(%p)",
+ PFID(ll_inode2fid(inode)), inode);
+ LBUG();
+ }
+
+ if (bits & MDS_INODELOCK_XATTR) {
+ ll_xattr_cache_destroy(inode);
+ bits &= ~MDS_INODELOCK_XATTR;
+ }
+
+ /* For OPEN locks we differentiate between lock modes
+ * LCK_CR, LCK_CW, LCK_PR - bug 22891 */
+ if (bits & MDS_INODELOCK_OPEN)
+ ll_have_md_lock(inode, &bits, lock->l_req_mode);
+
+ if (bits & MDS_INODELOCK_OPEN) {
+ fmode_t fmode;
+
+ switch (lock->l_req_mode) {
+ case LCK_CW:
+ fmode = FMODE_WRITE;
+ break;
+ case LCK_PR:
+ fmode = FMODE_EXEC;
+ break;
+ case LCK_CR:
+ fmode = FMODE_READ;
+ break;
+ default:
+ LDLM_ERROR(lock, "bad lock mode for OPEN lock");
+ LBUG();
+ }
+
+ ll_md_real_close(inode, fmode);
+
+ bits &= ~MDS_INODELOCK_OPEN;
+ }
+
+ if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE |
+ MDS_INODELOCK_LAYOUT | MDS_INODELOCK_PERM))
+ ll_have_md_lock(inode, &bits, LCK_MINMODE);
+
+ if (bits & MDS_INODELOCK_LAYOUT) {
+ struct cl_object_conf conf = {
+ .coc_opc = OBJECT_CONF_INVALIDATE,
+ .coc_inode = inode,
+ };
+
+ rc = ll_layout_conf(inode, &conf);
+ if (rc < 0)
+ CDEBUG(D_INODE, "cannot invalidate layout of "
+ DFID": rc = %d\n",
+ PFID(ll_inode2fid(inode)), rc);
+ }
+
+ if (bits & MDS_INODELOCK_UPDATE) {
+ struct ll_inode_info *lli = ll_i2info(inode);
+
+ spin_lock(&lli->lli_lock);
+ lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
+ spin_unlock(&lli->lli_lock);
+ }
+
+ if ((bits & MDS_INODELOCK_UPDATE) && S_ISDIR(inode->i_mode)) {
+ CDEBUG(D_INODE, "invalidating inode "DFID"\n",
+ PFID(ll_inode2fid(inode)));
+ truncate_inode_pages(inode->i_mapping, 0);
+ ll_invalidate_negative_children(inode);
+ }
+
+ if ((bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) &&
+ inode->i_sb->s_root != NULL &&
+ inode != inode->i_sb->s_root->d_inode)
+ ll_invalidate_aliases(inode);
+
+ iput(inode);
+ break;
+ }
+ default:
+ LBUG();
+ }
+
+ RETURN(0);
}
__u32 ll_i2suppgid(struct inode *i)
{
- if (in_group_p(i->i_gid))
- return (__u32)i->i_gid;
- else
- return (__u32)(-1);
+ if (in_group_p(i->i_gid))
+ return (__u32)i->i_gid;
+ else
+ return (__u32)(-1);
}
/* Pack the required supplementary groups into the supplied groups array.
#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;
+ DECLARE_LL_D_HLIST_NODE_PTR(p);
+
+ if (ll_d_hlist_empty(&inode->i_dentry))
+ return NULL;
+
+ discon_alias = invalid_alias = NULL;
+
+ ll_lock_dcache(inode);
+ ll_d_hlist_for_each_entry(alias, p, &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 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(&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);
- d_rehash_cond(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));
- dget_locked(last_discon);
- spin_unlock(&dcache_lock);
- d_rehash(de);
- d_move(last_discon, de);
- iput(inode);
- return last_discon;
- }
-
- ll_d_add(de, inode);
-
- spin_unlock(&dcache_lock);
-
+ struct dentry *new;
+ int rc;
+
+ if (inode) {
+ new = ll_find_alias(inode, de);
+ if (new) {
+ rc = ll_d_init(new);
+ if (rc < 0) {
+ dput(new);
+ return ERR_PTR(rc);
+ }
+ d_move(new, de);
+ iput(inode);
+ CDEBUG(D_DENTRY,
+ "Reuse dentry %p inode %p refc %d flags %#x\n",
+ new, new->d_inode, d_count(new), new->d_flags);
+ return new;
+ }
+ }
+ rc = ll_d_init(de);
+ if (rc < 0)
+ return ERR_PTR(rc);
+ d_add(de, inode);
+ CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
+ de, de->d_inode, d_count(de), de->d_flags);
return de;
}
-static inline void ll_dop_init(struct dentry *de, int *set)
-{
- lock_dentry(de);
- if (likely(de->d_op != &ll_d_ops)) {
- de->d_op = &ll_init_d_ops;
- *set = 1;
- }
- unlock_dentry(de);
-}
-
-static inline void ll_dop_fini(struct dentry *de, int succ)
-{
- lock_dentry(de);
- if (likely(de->d_op == &ll_init_d_ops)) {
- if (succ)
- de->d_op = &ll_d_ops;
- else
- de->d_op = &ll_fini_d_ops;
- unlock_dentry(de);
- smp_wmb();
- ll_d_wakeup(de);
- } else {
- if (succ)
- de->d_op = &ll_d_ops;
- unlock_dentry(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 set = 0, rc;
- ENTRY;
-
- ll_dop_init(*de, &set);
-
- /* 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;
-
- rc = ll_prep_inode(&inode, request, (*de)->d_sb);
- if (rc) {
- if (set)
- ll_dop_fini(*de, 0);
+ struct it_cb_data *icbd = data;
+ struct dentry **de = icbd->icbd_childp;
+ struct inode *parent = icbd->icbd_parent;
+ struct inode *inode = NULL;
+ __u64 bits = 0;
+ int rc;
+ ENTRY;
+
+ /* NB 1 request reference will be taken away by ll_intent_lock()
+ * when I return */
+ CDEBUG(D_DENTRY, "it %p it_disposition %x\n", it,
+ it->d.lustre.it_disposition);
+ if (!it_disposition(it, DISP_LOOKUP_NEG)) {
+ rc = ll_prep_inode(&inode, request, (*de)->d_sb, it);
+ 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);
- if (set && *de != save)
- ll_dop_fini(save, 0);
- } else {
- /* 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);
- }
+ }
+
+ /* Only hash *de if it is unhashed (new dentry).
+ * Atoimc_open may passin hashed dentries for open.
+ */
+ if (d_unhashed(*de)) {
+ struct dentry *alias;
+
+ alias = ll_splice_alias(inode, *de);
+ if (IS_ERR(alias))
+ RETURN(PTR_ERR(alias));
+ *de = alias;
+ } else if (!it_disposition(it, DISP_LOOKUP_NEG) &&
+ !it_disposition(it, DISP_OPEN_CREATE)) {
+ /* With DISP_OPEN_CREATE dentry will
+ instantiated in ll_create_it. */
+ LASSERT((*de)->d_inode == NULL);
+ d_instantiate(*de, inode);
+ }
+
+ if (!it_disposition(it, DISP_LOOKUP_NEG)) {
+ /* we have lookup look - unhide dentry */
+ if (bits & MDS_INODELOCK_LOOKUP)
+ d_lustre_revalidate(*de);
+ } else if (!it_disposition(it, DISP_OPEN_CREATE)) {
+ /* If file created on server, don't depend on parent UPDATE
+ * lock to unhide it. It is left hidden and next lookup can
+ * find it in ll_splice_alias.
+ */
+ /* 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);
-
- ll_dop_fini(*de, 1);
-
RETURN(0);
}
if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
RETURN(ERR_PTR(-ENAMETOOLONG));
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
- dentry->d_name.len, dentry->d_name.name, parent->i_ino,
- parent->i_generation, parent, LL_IT2STR(it));
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p), intent=%s\n",
+ dentry->d_name.len, dentry->d_name.name,
+ PFID(ll_inode2fid(parent)), parent, LL_IT2STR(it));
if (d_mountpoint(dentry))
CERROR("Tell Peter, lookup on mtpt, it %s\n", LL_IT2STR(it));
ll_frob_intent(&it, &lookup_it);
- /* As do_lookup is called before follow_mount, root dentry may be left
- * 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);
- if (rc)
- RETURN(ERR_PTR(rc));
- }
-
if (it->it_op == IT_GETATTR) {
- rc = ll_statahead_enter(parent, &dentry, 1);
- if (rc >= 0) {
- ll_statahead_exit(dentry, rc);
- if (rc == 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);
}
}
icbd.icbd_childp = &dentry;
icbd.icbd_parent = parent;
- if (it->it_op & IT_CREAT ||
- (it->it_op & IT_OPEN && it->it_create_mode & O_CREAT))
- opc = LUSTRE_OPC_CREATE;
- else
- opc = LUSTRE_OPC_ANY;
+ if (it->it_op & IT_CREAT)
+ opc = LUSTRE_OPC_CREATE;
+ else
+ opc = LUSTRE_OPC_ANY;
op_data = ll_prep_md_op_data(NULL, parent, NULL, dentry->d_name.name,
dentry->d_name.len, lookup_flags, opc,
if (IS_ERR(op_data))
RETURN((void *)op_data);
- it->it_create_mode &= ~current->fs->umask;
+ /* enforce umask if acl disabled or MDS doesn't support umask */
+ if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
+ it->it_create_mode &= ~current_umask();
rc = md_intent_lock(ll_i2mdexp(parent), op_data, NULL, 0, it,
lookup_flags, &req, ll_md_blocking_ast, 0);
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
+#ifdef HAVE_IOP_ATOMIC_OPEN
static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
- struct nameidata *nd)
+ unsigned int flags)
{
- struct dentry *de;
- ENTRY;
+ struct lookup_intent *itp, it = { .it_op = IT_GETATTR };
+ struct dentry *de;
- 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);
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p), flags=%u\n",
+ dentry->d_name.len, dentry->d_name.name,
+ PFID(ll_inode2fid(parent)), parent, flags);
- RETURN(de);
+ /* Optimize away (CREATE && !OPEN). Let .create handle the race. */
+ if ((flags & LOOKUP_CREATE) && !(flags & LOOKUP_OPEN))
+ return NULL;
+
+ if (flags & (LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE))
+ itp = NULL;
+ else
+ itp = ⁢
+ de = ll_lookup_it(parent, dentry, itp, 0);
+
+ if (itp != NULL)
+ ll_intent_release(itp);
+
+ return de;
}
-#else
+
+/*
+ * For cached negative dentry and new dentry, handle lookup/create/open
+ * together.
+ */
+static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
+ struct file *file, unsigned open_flags,
+ umode_t mode, int *opened)
+{
+ struct lookup_intent *it;
+ struct dentry *de;
+ long long lookup_flags = LOOKUP_OPEN;
+ int rc = 0;
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p), file %p,"
+ "open_flags %x, mode %x opened %d\n",
+ dentry->d_name.len, dentry->d_name.name,
+ PFID(ll_inode2fid(dir)), dir, file, open_flags, mode, *opened);
+
+ OBD_ALLOC(it, sizeof(*it));
+ if (!it)
+ RETURN(-ENOMEM);
+
+ it->it_op = IT_OPEN;
+ if (open_flags & O_CREAT) {
+ it->it_op |= IT_CREAT;
+ lookup_flags |= LOOKUP_CREATE;
+ }
+ it->it_create_mode = (mode & S_IALLUGO) | S_IFREG;
+ it->it_flags = (open_flags & ~O_ACCMODE) | OPEN_FMODE(open_flags);
+
+ /* Dentry added to dcache tree in ll_lookup_it */
+ de = ll_lookup_it(dir, dentry, it, lookup_flags);
+ if (IS_ERR(de))
+ rc = PTR_ERR(de);
+ else if (de != NULL)
+ dentry = de;
+
+ if (!rc) {
+ if (it_disposition(it, DISP_OPEN_CREATE)) {
+ /* Dentry instantiated in ll_create_it. */
+ rc = ll_create_it(dir, dentry, mode, it);
+ if (rc) {
+ /* We dget in ll_splice_alias. */
+ if (de != NULL)
+ dput(de);
+ goto out_release;
+ }
+
+ *opened |= FILE_CREATED;
+ }
+ if (dentry->d_inode && it_disposition(it, DISP_OPEN_OPEN)) {
+ /* Open dentry. */
+ if (S_ISFIFO(dentry->d_inode->i_mode)) {
+ /* We cannot call open here as it would
+ * deadlock.
+ */
+ if (it_disposition(it, DISP_ENQ_OPEN_REF))
+ ptlrpc_req_finished(
+ (struct ptlrpc_request *)
+ it->d.lustre.it_data);
+ rc = finish_no_open(file, de);
+ } else {
+ file->private_data = it;
+ rc = finish_open(file, dentry, NULL, opened);
+ /* We dget in ll_splice_alias. finish_open takes
+ * care of dget for fd open.
+ */
+ if (de != NULL)
+ dput(de);
+ }
+ } else {
+ rc = finish_no_open(file, de);
+ }
+ }
+
+out_release:
+ ll_intent_release(it);
+ OBD_FREE(it, sizeof(*it));
+
+ RETURN(rc);
+}
+
+#else /* !HAVE_IOP_ATOMIC_OPEN */
struct lookup_intent *ll_convert_intent(struct open_intent *oit,
int lookup_flags)
{
- struct lookup_intent *it;
-
- OBD_ALLOC(it, sizeof(*it));
- if (!it)
- return ERR_PTR(-ENOMEM);
-
- if (lookup_flags & LOOKUP_OPEN) {
- it->it_op = IT_OPEN;
- if (lookup_flags & LOOKUP_CREATE)
- it->it_op |= IT_CREAT;
- it->it_create_mode = oit->create_mode;
- 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;
+ struct lookup_intent *it;
+
+ OBD_ALLOC(it, sizeof(*it));
+ if (!it)
+ return ERR_PTR(-ENOMEM);
+
+ if (lookup_flags & LOOKUP_OPEN) {
+ it->it_op = IT_OPEN;
+ if (lookup_flags & LOOKUP_CREATE)
+ it->it_op |= IT_CREAT;
+ it->it_create_mode = (oit->create_mode & S_IALLUGO) | S_IFREG;
+ it->it_flags = ll_namei_to_lookup_intent_flag(oit->flags);
+ } else {
+ it->it_op = IT_GETATTR;
+ }
+
+ return it;
}
static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
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))
- /* 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))
+ 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
+#endif /* HAVE_IOP_ATOMIC_OPEN */
/* 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, dir->i_sb);
+ rc = ll_prep_inode(&inode, request, dir->i_sb, it);
if (rc)
GOTO(out, inode = ERR_PTR(rc));
- LASSERT(list_empty(&inode->i_dentry));
+ LASSERT(ll_d_hlist_empty(&inode->i_dentry));
/* We asked for a lock on the directory, but were granted a
* lock on the inode. Since we finally have an inode pointer,
* 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);
+ CDEBUG(D_DLMTRACE, "setting l_ast_data to inode "DFID"(%p)\n",
+ PFID(ll_inode2fid(inode)), inode);
+ ll_set_lock_data(sbi->ll_md_exp, inode, it, NULL);
EXIT;
out:
ptlrpc_req_finished(request);
* with d_instantiate().
*/
static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode,
- struct lookup_intent *it)
+ struct lookup_intent *it)
{
- struct inode *inode;
- int rc = 0;
- ENTRY;
+ struct inode *inode;
+ int rc = 0;
+ ENTRY;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
- dentry->d_name.len, dentry->d_name.name, dir->i_ino,
- dir->i_generation, dir, LL_IT2STR(it));
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p), intent=%s\n",
+ dentry->d_name.len, dentry->d_name.name,
+ PFID(ll_inode2fid(dir)), dir, LL_IT2STR(it));
- rc = it_open_error(DISP_OPEN_CREATE, it);
- if (rc)
- RETURN(rc);
+ rc = it_open_error(DISP_OPEN_CREATE, it);
+ if (rc)
+ RETURN(rc);
- inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
- NULL, 0, mode, 0, it);
- if (IS_ERR(inode)) {
- RETURN(PTR_ERR(inode));
- }
+ inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
+ NULL, 0, mode, 0, it);
+ 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);
+ if (filename_is_volatile(dentry->d_name.name, dentry->d_name.len, NULL))
+ ll_i2info(inode)->lli_volatile = true;
+
+ d_instantiate(dentry, inode);
+ RETURN(0);
}
static void ll_update_times(struct ptlrpc_request *request,
&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 fid "DFID" mtime from %lu to "LPU64
+ "\n", PFID(ll_inode2fid(inode)),
+ 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,
if (IS_ERR(op_data))
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);
- ll_finish_md_op_data(op_data);
+ err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
+ current_fsuid(), current_fsgid(),
+ cfs_curproc_cap_pack(), rdev, &request);
+ ll_finish_md_op_data(op_data);
if (err)
GOTO(err_exit, err);
ll_update_times(request, dir);
if (dchild) {
- err = ll_prep_inode(&inode, request, dchild->d_sb);
+ err = ll_prep_inode(&inode, request, dchild->d_sb, NULL);
if (err)
GOTO(err_exit, err);
- d_drop(dchild);
d_instantiate(dchild, inode);
- EXIT;
}
+ EXIT;
err_exit:
ptlrpc_req_finished(request);
int err;
ENTRY;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p) mode %o dev %x\n",
- name->len, name->name, dir->i_ino, dir->i_generation, dir,
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p) mode %o dev %x\n",
+ name->len, name->name, PFID(ll_inode2fid(dir)), dir,
mode, rdev);
- mode &= ~current->fs->umask;
+ if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
+ mode &= ~current_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
+#ifdef HAVE_IOP_ATOMIC_OPEN
+/*
+ * Plain create. Intent create is handled in atomic_open.
+ */
+static int ll_create_nd(struct inode *dir, struct dentry *dentry,
+ umode_t mode, bool want_excl)
+{
+ int rc;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p), "
+ "flags=%u, excl=%d\n", dentry->d_name.len,
+ dentry->d_name.name, PFID(ll_inode2fid(dir)),
+ dir, mode, want_excl);
+
+ rc = ll_mknod_generic(dir, &dentry->d_name, mode, 0, dentry);
+
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_CREATE, 1);
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, unhashed %d\n",
+ dentry->d_name.len, dentry->d_name.name, d_unhashed(dentry));
+
+ return rc;
+}
+#else /* !HAVE_IOP_ATOMIC_OPEN */
static int ll_create_nd(struct inode *dir, struct dentry *dentry,
- int mode, struct nameidata *nd)
+ ll_umode_t mode, struct nameidata *nd)
{
- struct lookup_intent *it = ll_d2d(dentry)->lld_it;
+ struct ll_dentry_data *lld = ll_d2d(dentry);
+ struct lookup_intent *it = NULL;
int rc;
+ if (lld != NULL)
+ it = lld->lld_it;
+
if (!it)
return ll_mknod_generic(dir, &dentry->d_name, mode, 0, dentry);
- ll_d2d(dentry)->lld_it = NULL;
+ lld->lld_it = NULL;
/* Was there an error? Propagate it! */
if (it->d.lustre.it_status) {
}
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
+#endif /* HAVE_IOP_ATOMIC_OPEN */
static int ll_symlink_generic(struct inode *dir, struct qstr *name,
const char *tgt, struct dentry *dchild)
int err;
ENTRY;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),target=%.*s\n",
- name->len, name->name, dir->i_ino, dir->i_generation,
- dir, 3000, tgt);
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p), target=%.*s\n",
+ name->len, name->name, PFID(ll_inode2fid(dir)),
+ dir, 3000, tgt);
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);
}
int err;
ENTRY;
- CDEBUG(D_VFSTRACE,
- "VFS Op: inode=%lu/%u(%p), dir=%lu/%u(%p), target=%.*s\n",
- src->i_ino, src->i_generation, src, dir->i_ino,
- dir->i_generation, dir, name->len, name->name);
+ CDEBUG(D_VFSTRACE, "VFS Op: inode="DFID"(%p), dir="DFID
+ "(%p), target=%.*s\n", PFID(ll_inode2fid(src)), src,
+ PFID(ll_inode2fid(dir)), dir, name->len, name->name);
op_data = ll_prep_md_op_data(NULL, src, dir, name->name, name->len,
0, LUSTRE_OPC_ANY, NULL);
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);
int err;
ENTRY;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
- name->len, name->name, dir->i_ino, dir->i_generation, dir);
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p)\n",
+ name->len, name->name, PFID(ll_inode2fid(dir)), dir);
- mode = (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask) | S_IFDIR;
- err = ll_new_node(dir, name, NULL, mode, 0, dchild, LUSTRE_OPC_MKDIR);
+ if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
+ mode &= ~current_umask();
+ mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR;
+ err = ll_new_node(dir, name, NULL, mode, 0, dchild, LUSTRE_OPC_MKDIR);
- RETURN(err);
-}
+ if (!err)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKDIR, 1);
-/* Try to find the child dentry by its name.
- If found, put the result fid into @fid. */
-static void ll_get_child_fid(struct inode * dir, struct qstr *name,
- 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) {
- if (child->d_inode)
- *fid = *ll_inode2fid(child->d_inode);
- dput(child);
- }
+ RETURN(err);
}
static int ll_rmdir_generic(struct inode *dir, struct dentry *dparent,
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);
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p)\n",
+ name->len, name->name, PFID(ll_inode2fid(dir)), dir);
if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
RETURN(-EBUSY);
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
- ll_get_child_fid(dir, name, &op_data->op_fid3);
+ if (dchild != NULL && dchild->d_inode != NULL)
+ op_data->op_fid3 = *ll_inode2fid(dchild->d_inode);
+ op_data->op_fid2 = 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);
}
+/**
+ * Remove dir entry
+ **/
+int ll_rmdir_entry(struct inode *dir, char *name, int namelen)
+{
+ struct ptlrpc_request *request = NULL;
+ struct md_op_data *op_data;
+ int rc;
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p)\n",
+ namelen, name, PFID(ll_inode2fid(dir)), dir);
+
+ op_data = ll_prep_md_op_data(NULL, dir, NULL, name, strlen(name),
+ S_IFDIR, LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
+ op_data->op_cli_flags |= CLI_RM_ENTRY;
+ 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, dir);
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_RMDIR, 1);
+ }
+
+ ptlrpc_req_finished(request);
+ RETURN(rc);
+}
+
int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
{
struct mdt_body *body;
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_oi = lsm->lsm_oi;
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));
- OBDO_FREE(oa);
- if (rc)
- CERROR("obd destroy objid "LPX64" error %d\n",
- lsm->lsm_object_id, rc);
- out_free_memmd:
- obd_free_memmd(ll_i2dtexp(dir), &lsm);
- out:
- return rc;
+ 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);
+ if (rc)
+ CERROR("obd destroy objid "DOSTID" error %d\n",
+ POSTID(&lsm->lsm_oi), rc);
+out_free_memmd:
+ obd_free_memmd(ll_i2dtexp(dir), &lsm);
+ OBDO_FREE(oa);
+out:
+ 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)
{
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);
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, dir="DFID"(%p)\n",
+ name->len, name->name, PFID(ll_inode2fid(dir)), dir);
/*
* XXX: unlink bind mountpoint maybe call to here,
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
- 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);
+ if (dchild != NULL && dchild->d_inode != NULL)
+ op_data->op_fid3 = *ll_inode2fid(dchild->d_inode);
+
+ op_data->op_fid2 = 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, dir);
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_UNLINK, 1);
rc = ll_objects_destroy(request, dir);
out:
struct md_op_data *op_data;
int err;
ENTRY;
- CDEBUG(D_VFSTRACE,"VFS Op:oldname=%.*s,src_dir=%lu/%u(%p),newname=%.*s,"
- "tgt_dir=%lu/%u(%p)\n", src_name->len, src_name->name,
- src->i_ino, src->i_generation, src, tgt_name->len,
- tgt_name->name, tgt->i_ino, tgt->i_generation, tgt);
+ CDEBUG(D_VFSTRACE, "VFS Op:oldname=%.*s, src_dir="DFID
+ "(%p), newname=%.*s, tgt_dir="DFID"(%p)\n",
+ src_name->len, src_name->name,
+ PFID(ll_inode2fid(src)), src, tgt_name->len,
+ tgt_name->name, PFID(ll_inode2fid(tgt)), tgt);
if (unlikely(ll_d_mountpoint(src_dparent, src_dchild, src_name) ||
ll_d_mountpoint(tgt_dparent, tgt_dchild, tgt_name)))
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
- ll_get_child_fid(src, src_name, &op_data->op_fid3);
- ll_get_child_fid(tgt, tgt_name, &op_data->op_fid4);
+ if (src_dchild != NULL && src_dchild->d_inode != NULL)
+ op_data->op_fid3 = *ll_inode2fid(src_dchild->d_inode);
+ if (tgt_dchild != NULL && tgt_dchild->d_inode != NULL)
+ op_data->op_fid4 = *ll_inode2fid(tgt_dchild->d_inode);
+
err = md_rename(sbi->ll_md_exp, op_data,
src_name->name, src_name->len,
tgt_name->name, tgt_name->len, &request);
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)
+static int ll_mknod(struct inode *dir, struct dentry *dchild, ll_umode_t mode,
+ dev_t rdev)
{
- return ll_mknod_generic(dir, &dchild->d_name, mode,
- old_encode_dev(rdev), dchild);
+ return ll_mknod_generic(dir, &dchild->d_name, mode,
+ old_encode_dev(rdev), dchild);
}
static int ll_unlink(struct inode * dir, struct dentry *dentry)
{
return ll_unlink_generic(dir, NULL, dentry, &dentry->d_name);
}
-static int ll_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+
+static int ll_mkdir(struct inode *dir, struct dentry *dentry, ll_umode_t mode)
{
return ll_mkdir_generic(dir, &dentry->d_name, mode, dentry);
}
+
static int ll_rmdir(struct inode *dir, struct dentry *dentry)
{
return ll_rmdir_generic(dir, NULL, dentry, &dentry->d_name);
}
+
static int ll_symlink(struct inode *dir, struct dentry *dentry,
const char *oldname)
{
return ll_symlink_generic(dir, &dentry->d_name, oldname, dentry);
}
+
static int ll_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
return ll_link_generic(old_dentry->d_inode, dir, &new_dentry->d_name,
new_dentry);
}
+
static int ll_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
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
+ if (!err)
d_move(old_dentry, new_dentry);
- }
return err;
}
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,
+ .mknod = ll_mknod,
+#ifdef HAVE_IOP_ATOMIC_OPEN
+ .atomic_open = ll_atomic_open,
+#endif
+ .lookup = ll_lookup_nd,
+ .create = ll_create_nd,
+ /* We need all these non-raw things for NFSD, to not patch it. */
+ .unlink = ll_unlink,
+ .mkdir = ll_mkdir,
+ .rmdir = ll_rmdir,
+ .symlink = ll_symlink,
+ .link = ll_link,
+ .rename = ll_rename,
+ .setattr = ll_setattr,
+ .getattr = ll_getattr,
+ .permission = ll_inode_permission,
+ .setxattr = ll_setxattr,
+ .getxattr = ll_getxattr,
+ .listxattr = ll_listxattr,
+ .removexattr = ll_removexattr,
+#ifdef HAVE_IOP_GET_ACL
+ .get_acl = ll_get_acl,
#endif
- .mknod = ll_mknod,
- .lookup = ll_lookup_nd,
- .create = ll_create_nd,
- /* We need all these non-raw things for NFSD, to not patch it. */
- .unlink = ll_unlink,
- .mkdir = ll_mkdir,
- .rmdir = ll_rmdir,
- .symlink = ll_symlink,
- .link = ll_link,
- .rename = ll_rename,
- .setattr = ll_setattr,
- .getattr = ll_getattr,
- .permission = ll_inode_permission,
- .setxattr = ll_setxattr,
- .getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
- .removexattr = ll_removexattr,
};
struct inode_operations ll_special_inode_operations = {
-#ifdef HAVE_VFS_INTENT_PATCHES
- .setattr_raw = ll_setattr_raw,
+ .setattr = ll_setattr,
+ .getattr = ll_getattr,
+ .permission = ll_inode_permission,
+ .setxattr = ll_setxattr,
+ .getxattr = ll_getxattr,
+ .listxattr = ll_listxattr,
+ .removexattr = ll_removexattr,
+#ifdef HAVE_IOP_GET_ACL
+ .get_acl = ll_get_acl,
#endif
- .setattr = ll_setattr,
- .getattr = ll_getattr,
- .permission = ll_inode_permission,
- .setxattr = ll_setxattr,
- .getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
- .removexattr = ll_removexattr,
};