-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
*
- * Copyright (c) 2002, 2003 Cluster File Systems, Inc.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
*
- * This file is part of Lustre, http://www.lustre.org.
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
*
- * Lustre is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
*
- * Lustre is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
*
- * You should have received a copy of the GNU General Public License
- * along with Lustre; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Copyright (c) 2011, 2013, Intel Corporation.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
*/
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/quotaops.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
+#include <linux/security.h>
#define DEBUG_SUBSYSTEM S_LLITE
#include <obd_support.h>
+#include <lustre_fid.h>
#include <lustre_lite.h>
#include <lustre_dlm.h>
-#include <linux/lustre_version.h>
+#include <lustre_ver.h>
#include "llite_internal.h"
-/* methods */
+static int ll_create_it(struct inode *, struct dentry *,
+ int, struct lookup_intent *);
-/* called from iget{4,5_locked}->find_inode() under inode_lock spinlock */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static int ll_test_inode(struct inode *inode, unsigned long ino, void *opaque)
-#else
-static int ll_test_inode(struct inode *inode, void *opaque)
-#endif
+/*
+ * Check if we have something mounted at the named dchild.
+ * In such a case there would always be dentry present.
+ */
+static int ll_d_mountpoint(struct dentry *dparent, struct dentry *dchild,
+ struct qstr *name)
{
- static int last_ino, last_gen, last_count;
- struct lustre_md *md = opaque;
-
- if (!(md->body->valid & (OBD_MD_FLGENER | OBD_MD_FLID))) {
- CERROR("MDS body missing inum or generation\n");
- return 0;
- }
-
- if (last_ino == md->body->ino && last_gen == md->body->generation &&
- last_count < 500) {
- last_count++;
- } else {
- if (last_count > 1)
- CDEBUG(D_VFSTRACE, "compared %u/%u %u times\n",
- last_ino, last_gen, last_count);
- last_count = 0;
- last_ino = md->body->ino;
- last_gen = md->body->generation;
- CDEBUG(D_VFSTRACE,
- "comparing inode %p ino %lu/%u to body "LPU64"/%u\n",
- inode, inode->i_ino, inode->i_generation,
- md->body->ino, md->body->generation);
- }
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
- if (inode->i_ino != md->body->ino)
- return 0;
-#endif
- if (inode->i_generation != md->body->generation) {
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct ll_inode_info *lli = ll_i2info(inode);
-
- if (inode->i_state & (I_FREEING | I_CLEAR))
- return 0;
- if (inode->i_nlink == 0)
- return 0;
-
- /* add "duplicate" inode into deathrow for destroy */
- spin_lock(&sbi->ll_deathrow_lock);
- if (list_empty(&lli->lli_dead_list)) {
- atomic_inc(&inode->i_count);
- list_add(&lli->lli_dead_list, &sbi->ll_deathrow);
+ int mounted = 0;
+
+ if (unlikely(dchild)) {
+ mounted = d_mountpoint(dchild);
+ } else if (dparent) {
+ dchild = d_lookup(dparent, name);
+ if (dchild) {
+ mounted = d_mountpoint(dchild);
+ dput(dchild);
}
- spin_unlock(&sbi->ll_deathrow_lock);
-
- return 0;
}
-
- /* Apply the attributes in 'opaque' to this inode */
- if (!(inode->i_state & (I_FREEING | I_CLEAR)))
- ll_update_inode(inode, md);
- return 1;
+ return mounted;
}
-extern struct dentry_operations ll_d_ops;
-
int ll_unlock(__u32 mode, struct lustre_handle *lockh)
{
ENTRY;
RETURN(0);
}
-/* Get an inode by inode number (already instantiated by the intent lookup).
- * Returns inode or NULL
- */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
-int ll_set_inode(struct inode *inode, void *opaque)
+
+/* called from iget5_locked->find_inode() under inode_lock spinlock */
+static int ll_test_inode(struct inode *inode, void *opaque)
+{
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct lustre_md *md = opaque;
+
+ if (unlikely(!(md->body->valid & OBD_MD_FLID))) {
+ CERROR("MDS body missing FID\n");
+ return 0;
+ }
+
+ if (!lu_fid_eq(&lli->lli_fid, &md->body->fid1))
+ return 0;
+
+ return 1;
+}
+
+static int ll_set_inode(struct inode *inode, void *opaque)
{
- ll_read_inode2(inode, opaque);
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct mdt_body *body = ((struct lustre_md *)opaque)->body;
+
+ if (unlikely(!(body->valid & OBD_MD_FLID))) {
+ CERROR("MDS body missing FID\n");
+ return -EINVAL;
+ }
+
+ lli->lli_fid = body->fid1;
+ if (unlikely(!(body->valid & OBD_MD_FLTYPE))) {
+ CERROR("Can not initialize inode "DFID" without object type: "
+ "valid = "LPX64"\n", PFID(&lli->lli_fid), body->valid);
+ return -EINVAL;
+ }
+
+ inode->i_mode = (inode->i_mode & ~S_IFMT) | (body->mode & S_IFMT);
+ if (unlikely(inode->i_mode == 0)) {
+ CERROR("Invalid inode "DFID" type\n", PFID(&lli->lli_fid));
+ return -EINVAL;
+ }
+
+ ll_lli_init(lli);
+
return 0;
}
+
+/*
+ * Get an inode by inode number (already instantiated by the intent lookup).
+ * Returns inode or NULL
+ */
struct inode *ll_iget(struct super_block *sb, ino_t hash,
struct lustre_md *md)
{
- struct inode *inode;
+ struct inode *inode;
+ ENTRY;
LASSERT(hash != 0);
inode = iget5_locked(sb, hash, ll_test_inode, ll_set_inode, md);
if (inode) {
- if (inode->i_state & I_NEW)
- unlock_new_inode(inode);
- CDEBUG(D_VFSTRACE, "inode: %lu/%u(%p)\n", inode->i_ino,
- inode->i_generation, inode);
+ if (inode->i_state & I_NEW) {
+ int rc = 0;
+
+ ll_read_inode2(inode, md);
+ 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: %p for "DFID"\n",
+ inode, PFID(&md->body->fid1));
}
-
- return inode;
+ RETURN(inode);
}
-#else
-struct inode *ll_iget(struct super_block *sb, ino_t hash,
- struct lustre_md *md)
+
+static void ll_invalidate_negative_children(struct inode *dir)
{
- struct inode *inode;
- LASSERT(hash != 0);
- inode = iget4(sb, hash, ll_test_inode, md);
- if (inode)
- CDEBUG(D_VFSTRACE, "inode: %lu/%u(%p)\n", inode->i_ino,
- inode->i_generation, inode);
- return inode;
+ struct dentry *dentry, *tmp_subdir;
+ struct ll_d_hlist_node *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);
}
-#endif
-int ll_mdc_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
- void *data, int flag)
+int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
+ void *data, int flag)
{
int rc;
struct lustre_handle lockh;
switch (flag) {
case LDLM_CB_BLOCKING:
ldlm_lock2handle(lock, &lockh);
- rc = ldlm_cli_cancel(&lockh);
+ rc = ldlm_cli_cancel(&lockh, LCF_ASYNC);
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);
+ struct inode *inode = ll_inode_from_resource_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;
+
+ /* Inode is set to lock->l_resource->lr_lvb_inode
+ * for mdc - bug 24555 */
+ LASSERT(lock->l_ast_data == NULL);
/* Invalidate all dentries associated with this inode */
if (inode == NULL)
break;
- if (lock->l_resource->lr_name.name[0] != inode->i_ino ||
- lock->l_resource->lr_name.name[1] != inode->i_generation) {
- LDLM_ERROR(lock, "data mismatch with ino %lu/%u (%p)",
- inode->i_ino, inode->i_generation, inode);
- }
+ LASSERT(lock->l_flags & LDLM_FL_CANCELING);
+ /* 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 | MDS_INODELOCK_PERM))
+ 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 (!fid_res_name_eq(fid, &lock->l_resource->lr_name))
+ LDLM_ERROR(lock, "data mismatch with object "
+ DFID" (%p)", PFID(fid), inode);
if (bits & MDS_INODELOCK_OPEN) {
int flags = 0;
break;
case LCK_PR:
flags = FMODE_EXEC;
- if (!FMODE_EXEC)
- CERROR("open PR lock without FMODE_EXEC\n");
break;
case LCK_CR:
flags = FMODE_READ;
"%d, inode %ld\n", lock->l_req_mode,
inode->i_ino);
}
- ll_mdc_real_close(inode, flags);
+ ll_md_real_close(inode, flags);
}
- if (bits & MDS_INODELOCK_UPDATE)
- clear_bit(LLI_F_HAVE_MDS_SIZE_LOCK,
- &(ll_i2info(inode)->lli_flags));
+ lli = ll_i2info(inode);
+ if (bits & MDS_INODELOCK_LAYOUT) {
+ struct cl_object_conf conf = { { 0 } };
+
+ conf.coc_opc = OBJECT_CONF_INVALIDATE;
+ conf.coc_inode = inode;
+ rc = ll_layout_conf(inode, &conf);
+ if (rc)
+ CDEBUG(D_INODE, "invaliding layout %d.\n", rc);
+ }
+
+ if (bits & MDS_INODELOCK_UPDATE) {
+ spin_lock(&lli->lli_lock);
+ lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
+ spin_unlock(&lli->lli_lock);
+ }
if (S_ISDIR(inode->i_mode) &&
(bits & MDS_INODELOCK_UPDATE)) {
- struct dentry *dentry, *tmp, *dir;
- struct list_head *list;
-
CDEBUG(D_INODE, "invalidating inode %lu\n",
inode->i_ino);
truncate_inode_pages(inode->i_mapping, 0);
+ ll_invalidate_negative_children(inode);
+ }
- /* Drop possible cached negative dentries */
- list = &inode->i_dentry;
- dir = NULL;
- spin_lock(&dcache_lock);
-
- /* It is possible to have several dentries (with
- racer?) */
- while ((list = list->next) != &inode->i_dentry) {
- dir = list_entry(list, struct dentry, d_alias);
-#ifdef LUSTRE_KERNEL_VERSION
- if (!(dir->d_flags & DCACHE_LUSTRE_INVALID))
-#else
- if (!d_unhashed(dir))
-#endif
- break;
-
- dir = NULL;
- }
-
- if (dir) {
-restart:
- list_for_each_entry_safe(dentry, tmp,
- &dir->d_subdirs,
- d_child)
- {
- /* XXX Print some debug here? */
- if (!dentry->d_inode)
- /* Negative dentry. If we were
- dropping dcache lock, go
- throught the list again */
- if (ll_drop_dentry(dentry))
- goto restart;
- }
- }
- spin_unlock(&dcache_lock);
- }
-
- 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 | MDS_INODELOCK_PERM)))
+ ll_invalidate_aliases(inode);
iput(inode);
break;
}
RETURN(0);
}
-int ll_mdc_cancel_unused(struct lustre_handle *conn, struct inode *inode,
- int flags, void *opaque)
+__u32 ll_i2suppgid(struct inode *i)
{
- struct ldlm_res_id res_id =
- { .name = {inode->i_ino, inode->i_generation} };
- struct obd_device *obddev = class_conn2obd(conn);
- ENTRY;
-
- RETURN(ldlm_cli_cancel_unused(obddev->obd_namespace, &res_id, flags,
- opaque));
+ if (cfs_curproc_is_in_groups(i->i_gid))
+ return (__u32)i->i_gid;
+ else
+ return (__u32)(-1);
}
/* Pack the required supplementary groups into the supplied groups array.
* array in case it might be useful. Not needed if doing an MDS-side upcall. */
void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2)
{
+#if 0
int i;
+#endif
LASSERT(i1 != NULL);
LASSERT(suppgids != NULL);
- if (in_group_p(i1->i_gid))
- suppgids[0] = i1->i_gid;
- else
- suppgids[0] = -1;
+ suppgids[0] = ll_i2suppgid(i1);
- if (i2) {
- if (in_group_p(i2->i_gid))
- suppgids[1] = i2->i_gid;
+ if (i2)
+ suppgids[1] = ll_i2suppgid(i2);
else
suppgids[1] = -1;
- } else {
- suppgids[1] = -1;
- }
+#if 0
for (i = 0; i < current_ngroups; i++) {
if (suppgids[0] == -1) {
if (current_groups[i] != suppgids[1])
}
break;
}
+#endif
}
-int ll_prepare_mdc_op_data(struct mdc_op_data *data, struct inode *i1,
- struct inode *i2, const char *name, int namelen,
- int mode)
-{
- LASSERT(i1);
-
- if (namelen > ll_i2sbi(i1)->ll_namelen)
- return -ENAMETOOLONG;
- ll_i2gids(data->suppgids, i1, i2);
- ll_inode2fid(&data->fid1, i1);
-
- if (i2)
- ll_inode2fid(&data->fid2, i2);
- else
- memset(&data->fid2, 0, sizeof(data->fid2));
-
- data->name = name;
- data->namelen = namelen;
- data->create_mode = mode;
- data->mod_time = CURRENT_SECONDS;
-
- return 0;
-}
-
-static void ll_d_add(struct dentry *de, struct inode *inode)
+/*
+ * try to reuse three types of dentry:
+ * 1. unhashed alias, this one is unhashed by d_invalidate (but it may be valid
+ * by concurrent .revalidate).
+ * 2. INVALID alias (common case for no valid ldlm lock held, but this flag may
+ * be cleared by others calling d_lustre_revalidate).
+ * 3. DISCONNECTED alias.
+ */
+static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
{
- CDEBUG(D_DENTRY, "adding inode %p to dentry %p\n", inode, de);
- /* d_instantiate */
- if (!list_empty(&de->d_alias)) {
- spin_unlock(&dcache_lock);
- CERROR("dentry %.*s %p alias next %p, prev %p\n",
- de->d_name.len, de->d_name.name, de,
- de->d_alias.next, de->d_alias.prev);
- LBUG();
- }
- if (inode)
- list_add(&de->d_alias, &inode->i_dentry);
- de->d_inode = inode;
-
- /* d_rehash */
- if (!d_unhashed(de)) {
- spin_unlock(&dcache_lock);
- CERROR("dentry %.*s %p hash next %p\n",
- de->d_name.len, de->d_name.name, de, de->d_hash.next);
- LBUG();
- }
- __d_rehash(de, 0);
+ struct dentry *alias, *discon_alias, *invalid_alias;
+ struct ll_d_hlist_node *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 be 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`s
- * trigered 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.
*/
-struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
+struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
{
- struct list_head *tmp;
- struct dentry *dentry;
- struct dentry *last_discon = NULL;
-
- spin_lock(&dcache_lock);
- list_for_each(tmp, &inode->i_dentry) {
- dentry = list_entry(tmp, struct dentry, d_alias);
-
- /* We are called here with 'de' already on the aliases list. */
- if (unlikely(dentry == de)) {
- CERROR("whoops\n");
- continue;
- }
-
- if (dentry->d_flags & DCACHE_DISCONNECTED) {
- LASSERT(last_discon == NULL);
- last_discon = dentry;
- continue;
- }
-
- if (dentry->d_parent != de->d_parent)
- continue;
-
- if (dentry->d_name.hash != de->d_name.hash)
- continue;
-
- if (dentry->d_name.len != de->d_name.len)
- continue;
-
- if (memcmp(dentry->d_name.name, de->d_name.name,
- de->d_name.len) != 0)
- continue;
-
- dget_locked(dentry);
- lock_dentry(dentry);
- __d_drop(dentry);
-#ifdef LUSTRE_KERNEL_VERSION
- dentry->d_flags &= ~DCACHE_LUSTRE_INVALID;
-#endif
- unlock_dentry(dentry);
- __d_rehash(dentry, 0); /* avoid taking dcache_lock inside */
- spin_unlock(&dcache_lock);
- iput(inode);
- CDEBUG(D_DENTRY, "alias dentry %.*s (%p) parent %p inode %p "
- "refc %d\n", de->d_name.len, de->d_name.name, de,
- de->d_parent, de->d_inode, atomic_read(&de->d_count));
- return dentry;
- }
- if (last_discon) {
- CDEBUG(D_DENTRY,"Reuse disconected 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;
+
+ 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;
+ }
+ }
+ ll_dops_init(de, 1, 1);
+ __d_lustre_invalidate(de);
+ d_add(de, inode);
+ CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
+ de, de->d_inode, d_refcount(de), de->d_flags);
return de;
}
-static int lookup_it_finish(struct ptlrpc_request *request, int offset,
- struct lookup_intent *it, void *data)
+int ll_lookup_it_finish(struct ptlrpc_request *request,
+ struct lookup_intent *it, void *data)
{
struct it_cb_data *icbd = data;
struct dentry **de = icbd->icbd_childp;
struct inode *parent = icbd->icbd_parent;
- struct ll_sb_info *sbi = ll_i2sbi(parent);
struct inode *inode = NULL;
- int rc;
-
- /* NB 1 request reference will be taken away by ll_intent_lock()
- * when I return */
- if (!it_disposition(it, DISP_LOOKUP_NEG)) {
- ENTRY;
-
- rc = ll_prep_inode(sbi->ll_osc_exp, &inode, request, offset,
- (*de)->d_sb);
+ __u64 bits = 0;
+ int rc;
+ ENTRY;
+
+ /* NB 1 request reference will be taken away by ll_intent_lock()
+ * when I return */
+ 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);
- mdc_set_lock_data(&it->d.lustre.it_lock_handle, inode);
+ ll_set_lock_data(ll_i2sbi(parent)->ll_md_exp, inode, it, &bits);
/* We used to query real size from OSTs here, but actually
this is not needed. For stat() calls size would be updated
Everybody else who needs correct file size would call
ll_glimpse_size or some equivalent themselves anyway.
Also see bug 7198. */
- *de = ll_find_alias(inode, *de);
- } else {
- ENTRY;
- /* Check that parent has UPDATE lock. If there is none, we
- cannot afford to hash this dentry (done by ll_d_add) as it
- might get picked up later when UPDATE lock will appear */
- if (ll_have_md_lock(parent, MDS_INODELOCK_UPDATE)) {
- spin_lock(&dcache_lock);
- ll_d_add(*de, inode);
- spin_unlock(&dcache_lock);
- } else {
- /* 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))
+ *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 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);
- (*de)->d_op = &ll_d_ops;
-
RETURN(0);
}
static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
struct lookup_intent *it, int lookup_flags)
{
+ struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
struct dentry *save = dentry, *retval;
- struct mdc_op_data op_data;
- struct it_cb_data icbd;
struct ptlrpc_request *req = NULL;
- struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
+ struct md_op_data *op_data;
+ struct it_cb_data icbd;
+ __u32 opc;
int rc;
ENTRY;
+ 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));
* not valid, revalidate it here. */
if (parent->i_sb->s_root && (parent->i_sb->s_root->d_inode == parent) &&
(it->it_op & (IT_OPEN | IT_CREAT))) {
- rc = ll_inode_revalidate_it(parent->i_sb->s_root, it);
+ rc = ll_inode_revalidate_it(parent->i_sb->s_root, it,
+ MDS_INODELOCK_LOOKUP);
if (rc)
RETURN(ERR_PTR(rc));
}
+ if (it->it_op == IT_GETATTR) {
+ rc = ll_statahead_enter(parent, &dentry, 0);
+ if (rc == 1) {
+ if (dentry == save)
+ GOTO(out, retval = NULL);
+ GOTO(out, retval = dentry);
+ }
+ }
+
icbd.icbd_childp = &dentry;
icbd.icbd_parent = parent;
- rc = ll_prepare_mdc_op_data(&op_data, parent, NULL, dentry->d_name.name,
- dentry->d_name.len, lookup_flags);
- if (rc)
- RETURN(ERR_PTR(rc));
+ 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;
- it->it_create_mode &= ~current->fs->umask;
+ op_data = ll_prep_md_op_data(NULL, parent, NULL, dentry->d_name.name,
+ dentry->d_name.len, lookup_flags, opc,
+ NULL);
+ if (IS_ERR(op_data))
+ RETURN((void *)op_data);
- rc = mdc_intent_lock(ll_i2mdcexp(parent), &op_data, NULL, 0, it,
- lookup_flags, &req, ll_mdc_blocking_ast, 0);
+ /* 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 &= ~cfs_curproc_umask();
+ rc = md_intent_lock(ll_i2mdexp(parent), op_data, NULL, 0, it,
+ lookup_flags, &req, ll_md_blocking_ast, 0);
+ ll_finish_md_op_data(op_data);
if (rc < 0)
GOTO(out, retval = ERR_PTR(rc));
- rc = lookup_it_finish(req, DLM_REPLY_REC_OFF, it, &icbd);
+ rc = ll_lookup_it_finish(req, it, &icbd);
if (rc != 0) {
ll_intent_release(it);
GOTO(out, retval = ERR_PTR(rc));
out:
if (req)
ptlrpc_req_finished(req);
+ if (it->it_op == IT_GETATTR && (retval == NULL || retval == dentry))
+ ll_statahead_mark(parent, dentry);
return retval;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-#ifdef LUSTRE_KERNEL_VERSION
+#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;
-
- 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);
+ struct lookup_intent *itp, it = { .it_op = IT_GETATTR };
+ struct dentry *de;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),flags=%u\n",
+ dentry->d_name.len, dentry->d_name.name, parent->i_ino,
+ parent->i_generation, parent, flags);
+
+ /* Optimize away (CREATE && !OPEN). Let .create handle the race. */
+ if ((flags & LOOKUP_CREATE ) && !(flags & LOOKUP_OPEN)) {
+ ll_dops_init(dentry, 1, 1);
+ __d_lustre_invalidate(dentry);
+ d_add(dentry, NULL);
+ 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;
+}
- RETURN(de);
+/*
+ * 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=%lu/%u(%p),file %p,"
+ "open_flags %x,mode %x opened %d\n",
+ dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dir->i_generation, dir, file, open_flags, mode, *opened);
+
+ OBD_ALLOC(it, sizeof(*it));
+ if (!it)
+ RETURN(-ENOMEM);
+
+ it->it_op = IT_OPEN;
+ if (mode) {
+ 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
+
+#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)) {
+ /* 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
-#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(sbi->ll_osc_exp, &inode, request, DLM_REPLY_REC_OFF,
- 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);
- mdc_set_lock_data(&it->d.lustre.it_lock_handle, 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;
- struct ptlrpc_request *request = it->d.lustre.it_data;
- 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=%lu/%u(%p),intent=%s\n",
+ dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dir->i_generation, dir, LL_IT2STR(it));
- rc = it_open_error(DISP_OPEN_CREATE, it);
- if (rc)
- RETURN(rc);
-
- mdc_store_inode_generation(request, DLM_INTENT_REC_OFF,
- DLM_REPLY_REC_OFF);
- 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));
- }
+ rc = it_open_error(DISP_OPEN_CREATE, it);
+ if (rc)
+ RETURN(rc);
- d_instantiate(dentry, inode);
- /* Negative dentry may be unhashed if parent does not have UPDATE lock,
- * but some callers, e.g. do_coredump, expect dentry to be hashed after
- * successful create. Hash it here. */
- spin_lock(&dcache_lock);
- if (d_unhashed(dentry))
- __d_rehash(dentry, 0);
- spin_unlock(&dcache_lock);
- RETURN(0);
+ 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));
+
+ 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, int offset,
+static void ll_update_times(struct ptlrpc_request *request,
struct inode *inode)
{
- struct mds_body *body = lustre_msg_buf(request->rq_repmsg, offset,
- sizeof(*body));
- LASSERT(body);
+ struct mdt_body *body = req_capsule_server_get(&request->rq_pill,
+ &RMF_MDT_BODY);
- /* mtime is always updated with ctime, but can be set in past.
- As write and utime(2) may happen within 1 second, and utime's
- mtime has a priority over write's one, so take mtime from mds
- for the same ctimes. */
+ LASSERT(body);
+ if (body->valid & OBD_MD_FLMTIME &&
+ body->mtime > LTIME_S(inode->i_mtime)) {
+ CDEBUG(D_INODE, "setting ino %lu mtime from %lu to "LPU64"\n",
+ inode->i_ino, LTIME_S(inode->i_mtime), body->mtime);
+ LTIME_S(inode->i_mtime) = body->mtime;
+ }
if (body->valid & OBD_MD_FLCTIME &&
- body->ctime >= LTIME_S(inode->i_ctime)) {
+ body->ctime > LTIME_S(inode->i_ctime))
LTIME_S(inode->i_ctime) = body->ctime;
-
- if (body->valid & OBD_MD_FLMTIME) {
- CDEBUG(D_INODE, "setting ino %lu mtime from %lu "
- "to "LPU64"\n", inode->i_ino,
- LTIME_S(inode->i_mtime), body->mtime);
- LTIME_S(inode->i_mtime) = body->mtime;
- }
- }
}
static int ll_new_node(struct inode *dir, struct qstr *name,
- char *tgt, int mode,
- int rdev, struct dentry *dchild)
+ const char *tgt, int mode, int rdev,
+ struct dentry *dchild, __u32 opc)
{
struct ptlrpc_request *request = NULL;
+ struct md_op_data *op_data;
struct inode *inode = NULL;
struct ll_sb_info *sbi = ll_i2sbi(dir);
- struct mdc_op_data op_data;
int tgt_len = 0;
int err;
ENTRY;
if (unlikely(tgt != NULL))
- tgt_len = strlen(tgt)+1;
+ tgt_len = strlen(tgt) + 1;
- err = ll_prepare_mdc_op_data(&op_data, dir, NULL, name->name,
- name->len, 0);
- if (err)
- GOTO(err_exit, err);
+ op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
+ name->len, 0, opc, NULL);
+ if (IS_ERR(op_data))
+ GOTO(err_exit, err = PTR_ERR(op_data));
- err = mdc_create(sbi->ll_mdc_exp, &op_data, tgt, tgt_len,
- mode, current->fsuid, current->fsgid,
- current->cap_effective, rdev, &request);
+ err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
+ cfs_curproc_fsuid(), cfs_curproc_fsgid(),
+ cfs_curproc_cap_pack(), rdev, &request);
+ ll_finish_md_op_data(op_data);
if (err)
GOTO(err_exit, err);
- ll_update_times(request, REPLY_REC_OFF, dir);
+ ll_update_times(request, dir);
if (dchild) {
- err = ll_prep_inode(sbi->ll_osc_exp, &inode, request,
- REPLY_REC_OFF, 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);
return err;
}
-
static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode,
unsigned rdev, struct dentry *dchild)
{
name->len, name->name, dir->i_ino, dir->i_generation, dir,
mode, rdev);
- mode &= ~current->fs->umask;
+ if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
+ mode &= ~cfs_curproc_umask();
switch (mode & S_IFMT) {
case 0:
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
- err = ll_new_node(dir, name, NULL, mode, rdev, dchild);
+ err = ll_new_node(dir, name, NULL, mode, rdev, dchild,
+ LUSTRE_OPC_MKNOD);
break;
case S_IFDIR:
err = -EPERM;
default:
err = -EINVAL;
}
+
+ if (!err)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKNOD, 1);
+
RETURN(err);
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
-#ifndef LUSTRE_KERNEL_VERSION
-static int ll_create_nd(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+#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=%lu/%u(%p),"
+ "flags=%u, excl=%d\n",
+ dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dir->i_generation, 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,
+ ll_umode_t mode, struct nameidata *nd)
{
struct lookup_intent *it = ll_d2d(dentry)->lld_it;
int rc;
}
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
+#endif /* HAVE_IOP_ATOMIC_OPEN */
static int ll_symlink_generic(struct inode *dir, struct qstr *name,
const char *tgt, struct dentry *dchild)
dir, 3000, tgt);
err = ll_new_node(dir, name, (char *)tgt, S_IFLNK | S_IRWXUGO,
- 0, dchild);
+ 0, dchild, LUSTRE_OPC_SYMLINK);
+
+ if (!err)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_SYMLINK, 1);
+
RETURN(err);
}
static int ll_link_generic(struct inode *src, struct inode *dir,
struct qstr *name, struct dentry *dchild)
{
+ struct ll_sb_info *sbi = ll_i2sbi(dir);
struct ptlrpc_request *request = NULL;
- struct mdc_op_data op_data;
+ struct md_op_data *op_data;
int err;
- struct ll_sb_info *sbi = ll_i2sbi(dir);
ENTRY;
CDEBUG(D_VFSTRACE,
src->i_ino, src->i_generation, src, dir->i_ino,
dir->i_generation, dir, name->len, name->name);
- err = ll_prepare_mdc_op_data(&op_data, src, dir, name->name,
- name->len, 0);
+ op_data = ll_prep_md_op_data(NULL, src, dir, name->name, name->len,
+ 0, LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
+
+ err = md_link(sbi->ll_md_exp, op_data, &request);
+ ll_finish_md_op_data(op_data);
if (err)
GOTO(out, err);
- err = mdc_link(sbi->ll_mdc_exp, &op_data, &request);
- if (err)
- GOTO(out, err);
-
- if (dchild) {
- d_drop(dchild);
- }
- ll_update_times(request, REPLY_REC_OFF, dir);
+ ll_update_times(request, dir);
+ ll_stats_ops_tally(sbi, LPROC_LL_LINK, 1);
EXIT;
out:
ptlrpc_req_finished(request);
RETURN(err);
}
-static int ll_mkdir_generic(struct inode *dir, struct qstr *name, int mode,
- struct dentry *dchild)
+static int ll_mkdir_generic(struct inode *dir, struct qstr *name,
+ int mode, struct dentry *dchild)
{
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);
- mode = (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask) | S_IFDIR;
- err = ll_new_node(dir, name, NULL, mode, 0, dchild);
+ if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
+ mode &= ~cfs_curproc_umask();
+ mode = (mode & (S_IRWXUGO|S_ISVTX)) | 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);
}
+/* 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 = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_alias);
+ child = d_lookup(parent, name);
+ if (child) {
+ if (child->d_inode)
+ *fid = *ll_inode2fid(child->d_inode);
+ dput(child);
+ }
+}
+
static int ll_rmdir_generic(struct inode *dir, struct dentry *dparent,
- struct qstr *name)
+ struct dentry *dchild, struct qstr *name)
{
struct ptlrpc_request *request = NULL;
- struct mdc_op_data op_data;
- struct dentry *dentry;
+ 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);
- /* Check if we have something mounted at the dir we are going to delete
- * In such a case there would always be dentry present. */
- if (dparent) {
- dentry = d_lookup(dparent, name);
- if (dentry) {
- int mounted = d_mountpoint(dentry);
- dput(dentry);
- if (mounted)
- GOTO(out, rc = -EBUSY);
- }
+ if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
+ RETURN(-EBUSY);
+
+ op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name, name->len,
+ S_IFDIR, LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
+
+ ll_get_child_fid(dir, name, &op_data->op_fid3);
+ 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) {
+ ll_update_times(request, dir);
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_RMDIR, 1);
}
- rc = ll_prepare_mdc_op_data(&op_data, dir, NULL, name->name,
- name->len, S_IFDIR);
- if (rc)
- GOTO(out, rc);
- rc = mdc_unlink(ll_i2sbi(dir)->ll_mdc_exp, &op_data, &request);
- if (rc)
- GOTO(out, rc);
- ll_update_times(request, REPLY_REC_OFF, dir);
-
- EXIT;
-out:
ptlrpc_req_finished(request);
- return(rc);
+ 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=%lu/%u(%p)\n",
+ namelen, name, dir->i_ino, dir->i_generation, 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 mds_body *body;
+ struct mdt_body *body;
struct lov_mds_md *eadata;
struct lov_stripe_md *lsm = NULL;
struct obd_trans_info oti = { 0 };
struct obdo *oa;
+ struct obd_capa *oc = NULL;
int rc;
ENTRY;
/* req is swabbed so this is safe */
- body = lustre_msg_buf(request->rq_repmsg, REPLY_REC_OFF, sizeof(*body));
-
+ body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
if (!(body->valid & OBD_MD_FLEASIZE))
RETURN(0);
* to this file. Use this EA to unlink the objects on the OST.
* It's opaque so we don't swab here; we leave it to obd_unpackmd() to
* check it is complete and sensible. */
- eadata = lustre_swab_repbuf(request, REPLY_REC_OFF + 1,
- body->eadatasize, NULL);
+ eadata = req_capsule_server_sized_get(&request->rq_pill, &RMF_MDT_MD,
+ body->eadatasize);
LASSERT(eadata != NULL);
- if (eadata == NULL) {
- CERROR("Can't unpack MDS EA data\n");
- GOTO(out, rc = -EPROTO);
- }
- rc = obd_unpackmd(ll_i2obdexp(dir), &lsm, eadata, body->eadatasize);
+ rc = obd_unpackmd(ll_i2dtexp(dir), &lsm, eadata, body->eadatasize);
if (rc < 0) {
CERROR("obd_unpackmd: %d\n", rc);
GOTO(out, rc);
}
LASSERT(rc >= sizeof(*lsm));
- rc = obd_checkmd(ll_i2obdexp(dir), ll_i2mdcexp(dir), lsm);
- if (rc)
- GOTO(out_free_memmd, rc);
-
- oa = obdo_alloc();
+ OBDO_ALLOC(oa);
if (oa == NULL)
GOTO(out_free_memmd, rc = -ENOMEM);
- oa->o_id = lsm->lsm_object_id;
+ oa->o_oi = lsm->lsm_oi;
oa->o_mode = body->mode & S_IFMT;
- oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE;
+ oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLGROUP;
if (body->valid & OBD_MD_FLCOOKIE) {
oa->o_valid |= OBD_MD_FLCOOKIE;
oti.oti_logcookies =
- lustre_msg_buf(request->rq_repmsg, REPLY_REC_OFF + 2,
- sizeof(struct llog_cookie) *
- lsm->lsm_stripe_count);
+ req_capsule_server_sized_get(&request->rq_pill,
+ &RMF_LOGCOOKIES,
+ sizeof(struct llog_cookie) *
+ lsm->lsm_stripe_count);
if (oti.oti_logcookies == NULL) {
oa->o_valid &= ~OBD_MD_FLCOOKIE;
body->valid &= ~OBD_MD_FLCOOKIE;
}
}
- rc = obd_destroy(ll_i2obdexp(dir), oa, lsm, &oti, ll_i2mdcexp(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_i2obdexp(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;
}
-static int ll_unlink_generic(struct inode * dir, struct qstr *name)
+/* 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 ptlrpc_request *request = NULL;
- struct mdc_op_data op_data;
+ 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);
- rc = ll_prepare_mdc_op_data(&op_data, dir, NULL, name->name,
- name->len, 0);
- if (rc)
- GOTO(out, rc);
- rc = mdc_unlink(ll_i2sbi(dir)->ll_mdc_exp, &op_data, &request);
- if (rc)
- GOTO(out, rc);
+ /*
+ * XXX: unlink bind mountpoint maybe call to here,
+ * just check it as vfs_unlink does.
+ */
+ if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
+ RETURN(-EBUSY);
+
+ op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
+ name->len, 0, LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
- ll_update_times(request, REPLY_REC_OFF, dir);
+ ll_get_child_fid(dir, name, &op_data->op_fid3);
+ 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);
- if (rc)
- GOTO(out, rc);
- EXIT;
out:
ptlrpc_req_finished(request);
- return(rc);
+ RETURN(rc);
}
-static int ll_rename_generic(struct inode *src, struct qstr *src_name,
- struct inode *tgt, struct qstr *tgt_name)
+static int ll_rename_generic(struct inode *src, struct dentry *src_dparent,
+ struct dentry *src_dchild, struct qstr *src_name,
+ struct inode *tgt, struct dentry *tgt_dparent,
+ struct dentry *tgt_dchild, struct qstr *tgt_name)
{
struct ptlrpc_request *request = NULL;
struct ll_sb_info *sbi = ll_i2sbi(src);
- struct mdc_op_data op_data;
+ 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);
- err = ll_prepare_mdc_op_data(&op_data, src, tgt, NULL, 0, 0);
- if (err)
- GOTO(out, err);
- err = mdc_rename(sbi->ll_mdc_exp, &op_data,
- src_name->name, src_name->len,
- tgt_name->name, tgt_name->len, &request);
- if (err)
- GOTO(out, err);
- ll_update_times(request, REPLY_REC_OFF, src);
- ll_update_times(request, REPLY_REC_OFF, tgt);
- err = ll_objects_destroy(request, src);
- if (err)
- GOTO(out, err);
+ if (unlikely(ll_d_mountpoint(src_dparent, src_dchild, src_name) ||
+ ll_d_mountpoint(tgt_dparent, tgt_dchild, tgt_name)))
+ RETURN(-EBUSY);
+
+ op_data = ll_prep_md_op_data(NULL, src, tgt, NULL, 0, 0,
+ LUSTRE_OPC_ANY, NULL);
+ 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);
+ err = md_rename(sbi->ll_md_exp, op_data,
+ src_name->name, src_name->len,
+ tgt_name->name, tgt_name->len, &request);
+ ll_finish_md_op_data(op_data);
+ 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);
+ }
- EXIT;
-out:
ptlrpc_req_finished(request);
- return(err);
-}
-
-#ifdef LUSTRE_KERNEL_VERSION
-static int ll_mknod_raw(struct nameidata *nd, int mode, dev_t rdev)
-{
- return ll_mknod_generic(nd->dentry->d_inode, &nd->last, mode,rdev,NULL);
-}
-static int ll_rename_raw(struct nameidata *srcnd, struct nameidata *tgtnd)
-{
- return ll_rename_generic(srcnd->dentry->d_inode, &srcnd->last,
- tgtnd->dentry->d_inode, &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, &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->last);
+ RETURN(err);
}
-#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);
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
static int ll_unlink(struct inode * dir, struct dentry *dentry)
{
- return ll_unlink_generic(dir, &dentry->d_name);
+ 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->d_name);
+ 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);
+ 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)
{
- return ll_rename_generic(old_dir, &old_dentry->d_name, new_dir,
+ int err;
+ err = ll_rename_generic(old_dir, NULL,
+ old_dentry, &old_dentry->d_name,
+ new_dir, NULL, new_dentry,
&new_dentry->d_name);
-}
+ if (!err) {
+#ifndef HAVE_FS_RENAME_DOES_D_MOVE
+ if (!S_ISDIR(old_dentry->d_inode->i_mode))
#endif
+ d_move(old_dentry, new_dentry);
+ }
+ return err;
+}
struct inode_operations ll_dir_inode_operations = {
-#ifdef LUSTRE_KERNEL_VERSION
- .link_raw = ll_link_raw,
- .unlink_raw = ll_unlink_raw,
- .symlink_raw = ll_symlink_raw,
- .mkdir_raw = ll_mkdir_raw,
- .rmdir_raw = ll_rmdir_raw,
- .mknod_raw = ll_mknod_raw,
- .rename_raw = ll_rename_raw,
- .setattr = ll_setattr,
- .setattr_raw = ll_setattr_raw,
+ .mknod = ll_mknod,
+#ifdef HAVE_IOP_ATOMIC_OPEN
+ .atomic_open = ll_atomic_open,
#endif
- .mknod = ll_mknod,
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
- .create_it = ll_create_it,
- .lookup_it = ll_lookup_it,
- .revalidate_it = ll_inode_revalidate_it,
-#else
- .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,
+ .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
- .permission = ll_inode_permission,
- .setxattr = ll_setxattr,
- .getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
- .removexattr = ll_removexattr,
};
struct inode_operations ll_special_inode_operations = {
-#ifdef LUSTRE_KERNEL_VERSION
- .setattr_raw = ll_setattr_raw,
-#endif
- .setattr = ll_setattr,
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
- .getattr = ll_getattr,
-#else
- .revalidate_it = ll_inode_revalidate_it,
+ .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
- .permission = ll_inode_permission,
- .setxattr = ll_setxattr,
- .getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
- .removexattr = ll_removexattr,
};