📄 statahead.c
字号:
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Copyright (c) 2007 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/mm.h>#include <linux/smp_lock.h>#include <linux/highmem.h>#include <linux/pagemap.h>#define DEBUG_SUBSYSTEM S_LLITE#include <obd_support.h>#include <lustre_lite.h>#include <lustre_dlm.h>#include <linux/lustre_version.h>#include "llite_internal.h"struct ll_sai_entry { struct list_head se_list; unsigned int se_index; int se_stat;};enum { SA_ENTRY_UNSTATED = 0, SA_ENTRY_STATED};static unsigned int sai_generation = 0;static spinlock_t sai_generation_lock = SPIN_LOCK_UNLOCKED;static struct ll_statahead_info *ll_sai_alloc(void){ struct ll_statahead_info *sai; OBD_ALLOC_PTR(sai); if (!sai) return NULL; spin_lock(&sai_generation_lock); sai->sai_generation = ++sai_generation; if (unlikely(sai_generation == 0)) sai->sai_generation = ++sai_generation; spin_unlock(&sai_generation_lock); atomic_set(&sai->sai_refcount, 1); sai->sai_max = LL_SA_RPC_MIN; cfs_waitq_init(&sai->sai_waitq); cfs_waitq_init(&sai->sai_thread.t_ctl_waitq); CFS_INIT_LIST_HEAD(&sai->sai_entries); return sai;}static inline struct ll_statahead_info *ll_sai_get(struct ll_statahead_info *sai){ LASSERT(sai); atomic_inc(&sai->sai_refcount); return sai;}static void ll_sai_put(struct ll_statahead_info *sai){ struct inode *inode = sai->sai_inode; struct ll_inode_info *lli = ll_i2info(inode); ENTRY; if (atomic_dec_and_lock(&sai->sai_refcount, &lli->lli_lock)) { struct ll_sai_entry *entry, *next; lli->lli_sai = NULL; spin_unlock(&lli->lli_lock); LASSERT(sai->sai_thread.t_flags & SVC_STOPPED); if (sai->sai_sent > sai->sai_replied) CDEBUG(D_READA,"statahead for dir %lu/%u does not " "finish: [sent:%u] [replied:%u]\n", inode->i_ino, inode->i_generation, sai->sai_sent, sai->sai_replied); list_for_each_entry_safe(entry, next, &sai->sai_entries, se_list) { list_del(&entry->se_list); OBD_FREE_PTR(entry); } OBD_FREE_PTR(sai); iput(inode); } EXIT;}static struct ll_sai_entry *ll_sai_entry_get(struct ll_statahead_info *sai, unsigned int index, int stat){ struct ll_inode_info *lli = ll_i2info(sai->sai_inode); struct ll_sai_entry *entry; ENTRY; OBD_ALLOC_PTR(entry); if (entry == NULL) RETURN(ERR_PTR(-ENOMEM)); CDEBUG(D_READA, "alloc sai entry %p index %u, stat %d\n", entry, index, stat); entry->se_index = index; entry->se_stat = stat; spin_lock(&lli->lli_lock); list_add_tail(&entry->se_list, &sai->sai_entries); spin_unlock(&lli->lli_lock); RETURN(entry);}/* * inside lli_lock * return value: * 0: can not find the entry with the index * 1: it is the first entry * 2: it is not the first entry */static intll_sai_entry_set(struct ll_statahead_info *sai, unsigned int index, int stat){ struct ll_sai_entry *entry; int rc = 0; ENTRY; if (list_empty(&sai->sai_entries)) RETURN(0); entry = list_entry(sai->sai_entries.next, struct ll_sai_entry, se_list); if (entry->se_index == index) GOTO(out, rc = 1); while (entry->se_list.next != &sai->sai_entries && entry->se_index < index) { entry = list_entry(entry->se_list.next, struct ll_sai_entry, se_list); if (entry->se_index == index) GOTO(out, rc = 2); } EXIT;out: if (rc) { LASSERT(entry->se_stat == SA_ENTRY_UNSTATED); entry->se_stat = stat; } return rc;}/* * Check whether first entry was stated already or not. * No need to hold lli_lock, for: * (1) it is me that remove entry from the list * (2) the statahead thread only add new entry to the list tail */static int ll_sai_entry_stated(struct ll_statahead_info *sai){ struct ll_sai_entry *entry; int rc = 0; ENTRY; if (!list_empty(&sai->sai_entries)) { entry = list_entry(sai->sai_entries.next, struct ll_sai_entry, se_list); rc = (entry->se_stat != SA_ENTRY_UNSTATED); } RETURN(rc);}static void ll_sai_entry_put(struct ll_statahead_info *sai){ struct ll_inode_info *lli = ll_i2info(sai->sai_inode); struct ll_sai_entry *entry; ENTRY; spin_lock(&lli->lli_lock); if (!list_empty(&sai->sai_entries)) { entry = list_entry(sai->sai_entries.next, struct ll_sai_entry, se_list); list_del(&entry->se_list); OBD_FREE_PTR(entry); } spin_unlock(&lli->lli_lock); EXIT;}/* finish lookup/revalidate */static int ll_statahead_interpret(struct obd_export *exp, struct ptlrpc_request *req, struct md_enqueue_info *minfo, int rc){ struct lookup_intent *it = &minfo->mi_it; struct dentry *dentry = minfo->mi_dentry; struct inode *dir = dentry->d_parent->d_inode; struct ll_inode_info *lli = ll_i2info(dir); struct ll_statahead_info *sai = NULL; ENTRY; CDEBUG(D_READA, "interpret statahead %.*s rc %d\n", dentry->d_name.len, dentry->d_name.name, rc); spin_lock(&lli->lli_lock); if (unlikely(lli->lli_sai == NULL || lli->lli_sai->sai_generation != minfo->mi_generation)) { spin_unlock(&lli->lli_lock); GOTO(out_free, rc = -ESTALE); } else { sai = ll_sai_get(lli->lli_sai); spin_unlock(&lli->lli_lock); } if (rc || dir == NULL) GOTO(out, rc); if (dentry->d_inode == NULL) { /* lookup */ struct dentry *save = dentry; struct it_cb_data icbd = { .icbd_parent = dir, .icbd_childp = &dentry }; rc = lookup_it_finish(req, DLM_REPLY_REC_OFF, it, &icbd); if (!rc) /* * Here dentry->d_inode might be NULL, * because the entry may have been removed before * we start doing stat ahead. */ ll_lookup_finish_locks(it, dentry); if (dentry != save) dput(save); } else { /* revalidate */ struct mds_body *body; body = lustre_msg_buf(req->rq_repmsg, DLM_REPLY_REC_OFF, sizeof(*body)); if (memcmp(&minfo->mi_data.fid2, &body->fid1, sizeof(body->fid1))) { ll_unhash_aliases(dentry->d_inode); GOTO(out, rc = -EAGAIN); } rc = revalidate_it_finish(req, DLM_REPLY_REC_OFF, it, dentry); if (rc) { ll_unhash_aliases(dentry->d_inode); GOTO(out, rc); } spin_lock(&dcache_lock); lock_dentry(dentry); __d_drop(dentry);#ifdef DCACHE_LUSTRE_INVALID dentry->d_flags &= ~DCACHE_LUSTRE_INVALID;#endif unlock_dentry(dentry); d_rehash_cond(dentry, 0); spin_unlock(&dcache_lock); ll_lookup_finish_locks(it, dentry); } EXIT;out: if (sai != NULL) { int first; sai->sai_replied++; spin_lock(&lli->lli_lock); first = ll_sai_entry_set(sai, (unsigned int)(long)minfo->mi_cbdata, SA_ENTRY_STATED); /* * wake up the "ls -l" process only when the first entry * returned. */ spin_unlock(&lli->lli_lock); if (first == 1) cfs_waitq_signal(&sai->sai_waitq); else if (first == 0) CDEBUG(D_READA, "can't find sai entry for dir " "%lu/%u generation %u index %d\n", dir->i_ino, dir->i_generation,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -