📄 dcache.c
字号:
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Copyright (c) 2001-2003 Cluster File Systems, Inc. * * This file is part of Lustre, http://www.lustre.org. * * 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. * * 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. * * 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. */#include <linux/fs.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/quotaops.h>#define DEBUG_SUBSYSTEM S_LLITE#include <obd_support.h>#include <lustre_lite.h>#include <lustre/lustre_idl.h>#include <lustre_dlm.h>#include <linux/lustre_version.h>#include "llite_internal.h"/* should NOT be called with the dcache lock, see fs/dcache.c */static void ll_release(struct dentry *de){ struct ll_dentry_data *lld; ENTRY; LASSERT(de != NULL); lld = ll_d2d(de); if (lld == NULL) { /* NFS copies the de->d_op methods (bug 4655) */ EXIT; return; }#ifndef HAVE_VFS_INTENT_PATCHES if (lld->lld_it) { ll_intent_release(lld->lld_it); OBD_FREE(lld->lld_it, sizeof(*lld->lld_it)); }#endif LASSERT(lld->lld_cwd_count == 0); LASSERT(lld->lld_mnt_count == 0); OBD_FREE(de->d_fsdata, sizeof(*lld)); EXIT;}#ifdef DCACHE_LUSTRE_INVALID/* Compare if two dentries are the same. Don't match if the existing dentry * is marked DCACHE_LUSTRE_INVALID. Returns 1 if different, 0 if the same. * * This avoids a race where ll_lookup_it() instantiates a dentry, but we get * an AST before calling d_revalidate_it(). The dentry still exists (marked * INVALID) so d_lookup() matches it, but we have no lock on it (so * lock_match() fails) and we spin around real_lookup(). */int ll_dcompare(struct dentry *parent, struct qstr *d_name, struct qstr *name){ struct dentry *dchild; ENTRY; if (d_name->len != name->len) RETURN(1); if (memcmp(d_name->name, name->name, name->len)) RETURN(1); /* XXX: d_name must be in-dentry structure */ dchild = container_of(d_name, struct dentry, d_name); /* ugh */ if (dchild->d_flags & DCACHE_LUSTRE_INVALID) { CDEBUG(D_DENTRY,"INVALID dentry %p not matched, was bug 3784\n", dchild); RETURN(1); } RETURN(0);}#endif/* should NOT be called with the dcache lock, see fs/dcache.c */static int ll_ddelete(struct dentry *de){ ENTRY; LASSERT(de);#ifndef DCACHE_LUSTRE_INVALID#define DCACHE_LUSTRE_INVALID 0#endif CDEBUG(D_DENTRY, "%s dentry %.*s (%p, parent %p, inode %p) %s%s\n", (de->d_flags & DCACHE_LUSTRE_INVALID ? "deleting" : "keeping"), de->d_name.len, de->d_name.name, de, de->d_parent, de->d_inode, d_unhashed(de) ? "" : "hashed,", list_empty(&de->d_subdirs) ? "" : "subdirs");#if DCACHE_LUSTRE_INVALID == 0#undef DCACHE_LUSTRE_INVALID#endif RETURN(0);}void ll_set_dd(struct dentry *de){ ENTRY; LASSERT(de != NULL); CDEBUG(D_DENTRY, "ldd on 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)); if (de->d_fsdata == NULL) { struct ll_dentry_data *lld; OBD_ALLOC(lld, sizeof(struct ll_dentry_data)); if (likely(lld != NULL)) { cfs_waitq_init(&lld->lld_waitq); lock_dentry(de); if (likely(de->d_fsdata == NULL)) de->d_fsdata = lld; else OBD_FREE(lld, sizeof(struct ll_dentry_data)); unlock_dentry(de); } } EXIT;}void ll_intent_drop_lock(struct lookup_intent *it){ struct lustre_handle *handle; if (it->it_op && it->d.lustre.it_lock_mode) { handle = (struct lustre_handle *)&it->d.lustre.it_lock_handle; CDEBUG(D_DLMTRACE, "releasing lock with cookie "LPX64 " from it %p\n", handle->cookie, it); ldlm_lock_decref(handle, it->d.lustre.it_lock_mode); /* bug 494: intent_release may be called multiple times, from * this thread and we don't want to double-decref this lock */ it->d.lustre.it_lock_mode = 0; }}void ll_intent_release(struct lookup_intent *it){ ENTRY; ll_intent_drop_lock(it);#ifdef HAVE_VFS_INTENT_PATCHES it->it_magic = 0; it->it_op_release = 0;#endif /* We are still holding extra reference on a request, need to free it */ if (it_disposition(it, DISP_ENQ_OPEN_REF)) /* open req for llfile_open*/ ptlrpc_req_finished(it->d.lustre.it_data); if (it_disposition(it, DISP_ENQ_CREATE_REF)) /* create rec */ ptlrpc_req_finished(it->d.lustre.it_data); if (it_disposition(it, DISP_ENQ_COMPLETE)) /* saved req from revalidate * to lookup */ ptlrpc_req_finished(it->d.lustre.it_data); it->d.lustre.it_disposition = 0; it->d.lustre.it_data = NULL; EXIT;}/* Drop dentry if it is not used already, unhash otherwise. Should be called with dcache lock held! Returns: 1 if dentry was dropped, 0 if unhashed. */int ll_drop_dentry(struct dentry *dentry){ lock_dentry(dentry); if (atomic_read(&dentry->d_count) == 0) { CDEBUG(D_DENTRY, "deleting dentry %.*s (%p) parent %p " "inode %p\n", dentry->d_name.len, dentry->d_name.name, dentry, dentry->d_parent, dentry->d_inode); dget_locked(dentry); __d_drop(dentry); unlock_dentry(dentry); spin_unlock(&dcache_lock); dput(dentry); spin_lock(&dcache_lock); return 1; } /* disconected dentry can not be find without lookup, because we * not need his to unhash or mark invalid. */ if (dentry->d_flags & DCACHE_DISCONNECTED) { unlock_dentry(dentry); RETURN (0); }#ifdef DCACHE_LUSTRE_INVALID if (!(dentry->d_flags & DCACHE_LUSTRE_INVALID)) {#else if (!d_unhashed(dentry)) {#endif CDEBUG(D_DENTRY, "unhashing dentry %.*s (%p) parent %p " "inode %p refc %d\n", dentry->d_name.len, dentry->d_name.name, dentry, dentry->d_parent, dentry->d_inode, atomic_read(&dentry->d_count)); /* actually we don't unhash the dentry, rather just * mark it inaccessible for to __d_lookup(). otherwise * sys_getcwd() could return -ENOENT -bzzz */#ifdef DCACHE_LUSTRE_INVALID dentry->d_flags |= DCACHE_LUSTRE_INVALID;#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) __d_drop(dentry); if (dentry->d_inode) { /* Put positive dentries to orphan list */ list_add(&dentry->d_hash, &ll_i2sbi(dentry->d_inode)->ll_orphan_dentry_list); }#endif#else if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) __d_drop(dentry);#endif } unlock_dentry(dentry); return 0;}void ll_unhash_aliases(struct inode *inode){ struct list_head *tmp, *head; ENTRY; if (inode == NULL) { CERROR("unexpected NULL inode, tell phil\n"); return; } CDEBUG(D_INODE, "marking dentries for ino %lu/%u(%p) invalid\n", inode->i_ino, inode->i_generation, inode); head = &inode->i_dentry; spin_lock(&dcache_lock);restart: tmp = head; while ((tmp = tmp->next) != head) { struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); if (dentry->d_name.len == 1 && dentry->d_name.name[0] == '/') { CERROR("called on root (?) dentry=%p, inode=%p " "ino=%lu\n", dentry, inode, inode->i_ino); lustre_dump_dentry(dentry, 1); libcfs_debug_dumpstack(NULL); } else if (d_mountpoint(dentry)) { /* For mountpoints we skip removal of the dentry which happens solely because we have a lock on it obtained when this dentry was not a mountpoint yet */ CDEBUG(D_DENTRY, "Skippind mountpoint dentry removal " "%.*s (%p) parent %p\n", dentry->d_name.len, dentry->d_name.name, dentry, dentry->d_parent); continue; } if (ll_drop_dentry(dentry)) goto restart; } spin_unlock(&dcache_lock); EXIT;}int revalidate_it_finish(struct ptlrpc_request *request, int offset, struct lookup_intent *it, struct dentry *de){ int rc = 0; ENTRY; if (!request) RETURN(0); if (it_disposition(it, DISP_LOOKUP_NEG)) RETURN(-ENOENT); rc = ll_prep_inode(ll_i2sbi(de->d_inode)->ll_osc_exp, &de->d_inode, request, offset, NULL); RETURN(rc);}void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry){ LASSERT(it != NULL); LASSERT(dentry != NULL); if (it->d.lustre.it_lock_mode && dentry->d_inode != NULL) { struct inode *inode = dentry->d_inode; 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); } /* drop lookup or getattr locks immediately */ if (it->it_op == IT_LOOKUP || it->it_op == IT_GETATTR) {#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) /* on 2.6 there are situation when several lookups and * revalidations may be requested during single operation. * therefore, we don't release intent here -bzzz */ ll_intent_drop_lock(it);#else ll_intent_release(it);#endif }}void ll_frob_intent(struct lookup_intent **itp, struct lookup_intent *deft){ struct lookup_intent *it = *itp;#if defined(HAVE_VFS_INTENT_PATCHES)&&(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) if (it) { LASSERTF(it->it_magic == INTENT_MAGIC, "bad intent magic: %x\n", it->it_magic); }#endif if (!it || it->it_op == IT_GETXATTR) it = *itp = deft;#ifdef HAVE_VFS_INTENT_PATCHES it->it_op_release = ll_intent_release;#endif}int ll_revalidate_it(struct dentry *de, int lookup_flags, struct lookup_intent *it){ struct mdc_op_data op_data; struct ptlrpc_request *req = NULL; struct lookup_intent lookup_it = { .it_op = IT_LOOKUP }; struct obd_export *exp; int first = 0, rc; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:name=%s,intent=%s\n", de->d_name.name, LL_IT2STR(it)); if (de->d_inode == NULL) { /* We can only use negative dentries if this is stat or lookup, for opens and stuff we do need to query server. */ /* If there is IT_CREAT in intent op set, then we must throw away this negative dentry and actually do the request to kernel to create whatever needs to be created (if possible)*/ if (it && (it->it_op & IT_CREAT)) RETURN(0);#ifdef DCACHE_LUSTRE_INVALID if (de->d_flags & DCACHE_LUSTRE_INVALID) RETURN(0);#endif rc = ll_have_md_lock(de->d_parent->d_inode, MDS_INODELOCK_UPDATE); GOTO(out_sa, rc); } exp = ll_i2mdcexp(de->d_inode); /* Never execute intents for mount points. * Attributes will be fixed up in ll_inode_revalidate_it */ if (d_mountpoint(de)) GOTO(out_sa, rc = 1); /* Root of the lustre tree. Always valid. * Attributes will be fixed up in ll_inode_revalidate_it */ if (de == de->d_sb->s_root) GOTO(out_sa, rc = 1); OBD_FAIL_TIMEOUT(OBD_FAIL_MDC_REVALIDATE_PAUSE, 5); ll_frob_intent(&it, &lookup_it); LASSERT(it); ll_prepare_mdc_op_data(&op_data, de->d_parent->d_inode, de->d_inode, de->d_name.name, de->d_name.len, 0, NULL); if ((it->it_op == IT_OPEN) && de->d_inode) { struct inode *inode = de->d_inode; struct ll_inode_info *lli = ll_i2info(inode); struct obd_client_handle **och_p; __u64 *och_usecount;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -