X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fnamei.c;h=e73f203851822357ba9010d2972c01c4562cfcb2;hp=a5177decd45087d4a122ca4de3221604ede9f01e;hb=f5fb215365791507ec98796ea624abeafa31901c;hpb=8ea153bf8f66d81c7da24b9c349bcba92fe351df diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index a5177de..e73f203 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -1,6 +1,4 @@ -/* -*- 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. @@ -26,8 +24,10 @@ * 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/ @@ -37,10 +37,10 @@ #include #include #include -#include #include #include #include +#include #define DEBUG_SUBSYSTEM S_LLITE @@ -49,7 +49,6 @@ #include #include #include -#include #include "llite_internal.h" /* @@ -111,6 +110,20 @@ static int ll_set_inode(struct inode *inode, void *opaque) } 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; } @@ -130,10 +143,12 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash, if (inode) { if (inode->i_state & I_NEW) { - int rc; + int rc = 0; ll_read_inode2(inode, md); - rc = cl_inode_init(inode, md); + 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); @@ -143,42 +158,35 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash, } else unlock_new_inode(inode); } else if (!(inode->i_state & (I_FREEING | I_CLEAR))) - ll_update_inode(inode, md); + 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) +static void ll_invalidate_negative_children(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); + 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) { @@ -197,23 +205,24 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, 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) || @@ -243,21 +252,30 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, 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; } @@ -270,7 +288,7 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, __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); @@ -313,110 +331,78 @@ void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2) #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); - 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); - lock_dentry(last_discon); - last_discon->d_flags |= DCACHE_LUSTRE_INVALID; - unlock_dentry(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; - } - de->d_flags |= DCACHE_LUSTRE_INVALID; - 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; } @@ -426,25 +412,19 @@ int ll_lookup_it_finish(struct ptlrpc_request *request, 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; - __u32 bits; + __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, &bits); + 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 @@ -452,53 +432,27 @@ int ll_lookup_it_finish(struct ptlrpc_request *request, 2.4 and vfs_getattr_it->ll_getattr()->ll_inode_revalidate_it() in 2.6 Everybody else who needs correct file size would call - cl_glimpse_size or some equivalent themselves anyway. + 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; - } - } - /* we have lookup look - unhide dentry */ - if (bits & MDS_INODELOCK_LOOKUP) { - lock_dentry(*de); - (*de)->d_flags &= ~(DCACHE_LUSTRE_INVALID); - unlock_dentry(*de); - } - } 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, NULL); - spin_unlock(&dcache_lock); - } else { - /* negative lookup - and don't have update lock to - * parent */ - lock_dentry(*de); - (*de)->d_flags |= DCACHE_LUSTRE_INVALID; - unlock_dentry(*de); - - (*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); @@ -513,7 +467,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, 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) @@ -532,17 +486,18 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, * 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(parent, 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); } } @@ -561,7 +516,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *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); @@ -575,9 +530,6 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, GOTO(out, retval = ERR_PTR(rc)); } - if (first == -EEXIST) - ll_statahead_mark(parent, dentry); - if ((it->it_op & IT_OPEN) && dentry->d_inode && !S_ISREG(dentry->d_inode->i_mode) && !S_ISDIR(dentry->d_inode->i_mode)) { @@ -592,24 +544,11 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry, 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) { @@ -623,20 +562,12 @@ struct lookup_intent *ll_convert_intent(struct open_intent *oit, 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; } @@ -649,14 +580,13 @@ 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)) +#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; @@ -664,7 +594,9 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry, 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); + 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); @@ -678,7 +610,6 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry, 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. @@ -686,31 +617,18 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry, (struct ptlrpc_request *) it->d.lustre.it_data); } else { -#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 */ - 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 - nd->intent.open.file->private_data = it; - (void)lookup_instantiate_filp(nd,dentry, - NULL); -#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. @@ -732,7 +650,6 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry, 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, @@ -762,8 +679,7 @@ 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, NULL); + ll_set_lock_data(sbi->ll_md_exp, inode, it, NULL); EXIT; out: ptlrpc_req_finished(request); @@ -801,18 +717,10 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode, 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); } @@ -823,21 +731,15 @@ 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 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, @@ -861,7 +763,7 @@ 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) @@ -874,10 +776,9 @@ static int ll_new_node(struct inode *dir, struct qstr *name, if (err) GOTO(err_exit, err); - d_drop(dchild); d_instantiate(dchild, inode); - EXIT; } + EXIT; err_exit: ptlrpc_req_finished(request); @@ -894,7 +795,7 @@ static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode, 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: @@ -913,10 +814,13 @@ static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode, 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) { @@ -935,32 +839,24 @@ static int ll_create_nd(struct inode *dir, struct dentry *dentry, } 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) @@ -974,6 +870,10 @@ static int ll_symlink_generic(struct inode *dir, struct qstr *name, 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); } @@ -1000,10 +900,9 @@ static int ll_link_generic(struct inode *src, struct inode *dir, 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); @@ -1020,9 +919,12 @@ static int ll_mkdir_generic(struct inode *dir, struct qstr *name, 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); } @@ -1064,8 +966,11 @@ static int ll_rmdir_generic(struct inode *dir, struct dentry *dparent, 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); } @@ -1106,16 +1011,12 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir) } 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; @@ -1138,7 +1039,8 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir) GOTO(out_free_memmd, rc); } - rc = obd_destroy(ll_i2dtexp(dir), oa, lsm, &oti, ll_i2mdexp(dir), oc); + rc = obd_destroy(NULL, ll_i2dtexp(dir), oa, lsm, &oti, + ll_i2mdexp(dir), oc); capa_put(oc); OBDO_FREE(oa); if (rc) @@ -1150,6 +1052,10 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir) 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) { @@ -1179,6 +1085,7 @@ static int ll_unlink_generic(struct inode *dir, struct dentry *dparent, 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: @@ -1219,6 +1126,7 @@ static int ll_rename_generic(struct inode *src, struct dentry *src_dparent, 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); } @@ -1227,43 +1135,6 @@ static int ll_rename_generic(struct inode *src, struct dentry *src_dparent, 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) { @@ -1312,17 +1183,6 @@ static int ll_rename(struct inode *old_dir, struct dentry *old_dentry, } 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, @@ -1343,9 +1203,6 @@ struct inode_operations ll_dir_inode_operations = { }; 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,