⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dcache.c

📁 lustre 1.6.5 source code
💻 C
📖 第 1 页 / 共 2 页
字号:
                /* We used to check for MDS_INODELOCK_OPEN here, but in fact                 * just having LOOKUP lock is enough to justify inode is the                 * same. And if inode is the same and we have suitable                 * openhandle, then there is no point in doing another OPEN RPC                 * just to throw away newly received openhandle.                 * There are no security implications too, if file owner or                 * access mode is change, LOOKUP lock is revoked */                if (it->it_flags & FMODE_WRITE) {                        och_p = &lli->lli_mds_write_och;                        och_usecount = &lli->lli_open_fd_write_count;                } else if (it->it_flags & FMODE_EXEC) {                        och_p = &lli->lli_mds_exec_och;                        och_usecount = &lli->lli_open_fd_exec_count;                } else {                        och_p = &lli->lli_mds_read_och;                        och_usecount = &lli->lli_open_fd_read_count;                }                /* Check for the proper lock. */                if (!ll_have_md_lock(inode, MDS_INODELOCK_LOOKUP))                        goto do_lock;                down(&lli->lli_och_sem);                if (*och_p) { /* Everything is open already, do nothing */                        /*(*och_usecount)++;  Do not let them steal our open                                              handle from under us */                        /* XXX The code above was my original idea, but in case                           we have the handle, but we cannot use it due to later                           checks (e.g. O_CREAT|O_EXCL flags set), nobody                           would decrement counter increased here. So we just                           hope the lock won't be invalidated in between. But                           if it would be, we'll reopen the open request to                           MDS later during file open path */                        up(&lli->lli_och_sem);                        RETURN(1);                } else {                        up(&lli->lli_och_sem);                }        }        if (it->it_op == IT_GETATTR)                first = ll_statahead_enter(de->d_parent->d_inode, &de, 0);do_lock:        it->it_create_mode &= ~current->fs->umask;        rc = mdc_intent_lock(exp, &op_data, NULL, 0, it, lookup_flags,                             &req, ll_mdc_blocking_ast, 0);        if (it->it_op == IT_GETATTR && !first)                ll_statahead_exit(de, rc);        /* If req is NULL, then mdc_intent_lock only tried to do a lock match;         * if all was well, it will return 1 if it found locks, 0 otherwise. */        if (req == NULL && rc >= 0) {                if (!rc)                        goto do_lookup;                GOTO(out, rc);        }        if (rc < 0) {                if (rc != -ESTALE) {                        CDEBUG(D_INFO, "ll_intent_lock: rc %d : it->it_status "                               "%d\n", rc, it->d.lustre.it_status);                }                GOTO(out, rc = 0);        }revalidate_finish:        rc = revalidate_it_finish(req, DLM_REPLY_REC_OFF, it, de);        if (rc != 0) {                ll_intent_release(it);                GOTO(out, rc = 0);        }        if ((it->it_op & IT_OPEN) && de->d_inode &&             !S_ISREG(de->d_inode->i_mode) &&             !S_ISDIR(de->d_inode->i_mode)) {                ll_release_openhandle(de, it);        }        rc = 1;        /* unfortunately ll_intent_lock may cause a callback and revoke our         * dentry */        spin_lock(&dcache_lock);        lock_dentry(de);        __d_drop(de);        unlock_dentry(de);        d_rehash_cond(de, 0);        spin_unlock(&dcache_lock); out:        /* We do not free request as it may be reused during following lookup         * (see comment in mdc/mdc_locks.c::mdc_intent_lock()), request will         * be freed in ll_lookup_it or in ll_intent_release. But if         * request was not completed, we need to free it. (bug 5154, 9903) */        if (req != NULL && !it_disposition(it, DISP_ENQ_COMPLETE))                ptlrpc_req_finished(req);        if (rc == 0) {#ifdef DCACHE_LUSTRE_INVALID                ll_unhash_aliases(de->d_inode);                /* done in ll_unhash_aliases()                dentry->d_flags |= DCACHE_LUSTRE_INVALID; */#else                /* We do not want d_invalidate to kill all child dentries too */                d_drop(de);#endif        } else {                CDEBUG(D_DENTRY, "revalidated 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));                ll_lookup_finish_locks(it, de);#ifdef DCACHE_LUSTRE_INVALID                lock_dentry(de);                de->d_flags &= ~DCACHE_LUSTRE_INVALID;                unlock_dentry(de);#endif        }        RETURN(rc);/* This part is here to combat evil-evil race in real_lookup on 2.6 kernels. * The race details are: We enter do_lookup() looking for some name, * there is nothing in dcache for this name yet and d_lookup() returns NULL. * We proceed to real_lookup(), and while we do this, another process does * open on the same file we looking up (most simple reproducer), open succeeds * and the dentry is added. Now back to us. In real_lookup() we do d_lookup() * again and suddenly find the dentry, so we call d_revalidate on it, but there * is no lock, so without this code we would return 0, but unpatched * real_lookup just returns -ENOENT in such a case instead of retrying the * lookup. Once this is dealt with in real_lookup(), all of this ugly mess * can go and we can just check locks in ->d_revalidate without doing any * RPCs ever. */do_lookup:        if (it != &lookup_it) {                ll_lookup_finish_locks(it, de);                it = &lookup_it;        }        /*do real lookup here */        ll_prepare_mdc_op_data(&op_data, de->d_parent->d_inode, NULL,                               de->d_name.name, de->d_name.len, 0, NULL);        rc = mdc_intent_lock(exp, &op_data, NULL, 0,  it, 0, &req,                             ll_mdc_blocking_ast, 0);        if (rc >= 0) {                struct mds_body *mds_body = lustre_msg_buf(req->rq_repmsg,                                                           DLM_REPLY_REC_OFF,                                                           sizeof(*mds_body));                struct ll_fid fid = { 0 };                if (de->d_inode)                         ll_inode2fid(&fid, de->d_inode);                /* see if we got same inode, if not - return error */                if(!memcmp(&fid, &mds_body->fid1, sizeof(struct ll_fid)))                        goto revalidate_finish;                ll_intent_release(it);        }        GOTO(out, rc = 0);out_sa:        /*         * For rc == 1 case, should not return directly to prevent losing         * statahead windows; for rc == 0 case, the "lookup" will be done later.         */        if (it && it->it_op == IT_GETATTR && rc == 1) {                first = ll_statahead_enter(de->d_parent->d_inode, &de, 0);                if (!first)                        ll_statahead_exit(de, rc);        }        return rc;}/*static*/ void ll_pin(struct dentry *de, struct vfsmount *mnt, int flag){        struct inode *inode= de->d_inode;        struct ll_sb_info *sbi = ll_i2sbi(inode);        struct ll_dentry_data *ldd = ll_d2d(de);        struct obd_client_handle *handle;        int rc = 0;        ENTRY;        LASSERT(ldd);        lock_kernel();        /* Strictly speaking this introduces an additional race: the         * increments should wait until the rpc has returned.         * However, given that at present the function is void, this         * issue is moot. */        if (flag == 1 && (++ldd->lld_mnt_count) > 1) {                unlock_kernel();                EXIT;                return;        }        if (flag == 0 && (++ldd->lld_cwd_count) > 1) {                unlock_kernel();                EXIT;                return;        }        unlock_kernel();        handle = (flag) ? &ldd->lld_mnt_och : &ldd->lld_cwd_och;        rc = obd_pin(sbi->ll_mdc_exp, inode->i_ino, inode->i_generation,                     inode->i_mode & S_IFMT, handle, flag);        if (rc) {                lock_kernel();                memset(handle, 0, sizeof(*handle));                if (flag == 0)                        ldd->lld_cwd_count--;                else                        ldd->lld_mnt_count--;                unlock_kernel();        }        EXIT;        return;}/*static*/ void ll_unpin(struct dentry *de, struct vfsmount *mnt, int flag){        struct ll_sb_info *sbi = ll_i2sbi(de->d_inode);        struct ll_dentry_data *ldd = ll_d2d(de);        struct obd_client_handle handle;        int count, rc = 0;        ENTRY;        LASSERT(ldd);        lock_kernel();        /* Strictly speaking this introduces an additional race: the         * increments should wait until the rpc has returned.         * However, given that at present the function is void, this         * issue is moot. */        handle = (flag) ? ldd->lld_mnt_och : ldd->lld_cwd_och;        if (handle.och_magic != OBD_CLIENT_HANDLE_MAGIC) {                /* the "pin" failed */                unlock_kernel();                EXIT;                return;        }        if (flag)                count = --ldd->lld_mnt_count;        else                count = --ldd->lld_cwd_count;        unlock_kernel();        if (count != 0) {                EXIT;                return;        }        rc = obd_unpin(sbi->ll_mdc_exp, &handle, flag);        EXIT;        return;}#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))#ifdef HAVE_VFS_INTENT_PATCHESstatic int ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd){        int rc;        ENTRY;        if (nd && nd->flags & LOOKUP_LAST && !(nd->flags & LOOKUP_LINK_NOTLAST))                rc = ll_revalidate_it(dentry, nd->flags, &nd->intent);        else                rc = ll_revalidate_it(dentry, 0, NULL);        RETURN(rc);}#elseint ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd){        int rc;        ENTRY;        if (nd && !(nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))) {                struct lookup_intent *it;                it = ll_convert_intent(&nd->intent.open, nd->flags);                if (IS_ERR(it))                        RETURN(0);                if (it->it_op == (IT_OPEN|IT_CREAT))                        if (nd->intent.open.flags & O_EXCL) {                                CDEBUG(D_VFSTRACE, "create O_EXCL, returning 0\n");                                rc = 0;                                goto out_it;                        }                rc = ll_revalidate_it(dentry, nd->flags, it);                if (rc && (nd->flags & LOOKUP_OPEN) &&                    it_disposition(it, DISP_OPEN_OPEN)) {/*Open*/#ifdef HAVE_FILE_IN_STRUCT_INTENT// XXX Code duplication with ll_lookup_nd                        if (S_ISFIFO(dentry->d_inode->i_mode)) {                                // We cannot call open here as it would                                // deadlock.                                ptlrpc_req_finished(                                               (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))                                        rc = 0;#endif                        }#else                        ll_release_openhandle(dentry, it);#endif /* HAVE_FILE_IN_STRUCT_INTENT */                }                if (!rc && (nd->flags & LOOKUP_CREATE) &&                    it_disposition(it, DISP_OPEN_CREATE)) {                        /* We created something but we may only return                         * negative dentry here, so save request in dentry,                         * if lookup will be called later on, it will                         * pick the request, otherwise it would be freed                         * with dentry */                        ll_d2d(dentry)->lld_it = it;                        it = NULL; /* avoid freeing */                }                        out_it:                if (it) {                        ll_intent_release(it);                        OBD_FREE(it, sizeof(*it));                }        } else {                rc = ll_revalidate_it(dentry, 0, NULL);        }        RETURN(rc);}#endif#endifstruct dentry_operations ll_d_ops = {#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))        .d_revalidate = ll_revalidate_nd,#else        .d_revalidate_it = ll_revalidate_it,#endif        .d_release = ll_release,        .d_delete = ll_ddelete,#ifdef DCACHE_LUSTRE_INVALID        .d_compare = ll_dcompare,#endif#if 0        .d_pin = ll_pin,        .d_unpin = ll_unpin,#endif};static int ll_fini_revalidate_nd(struct dentry *dentry, struct nameidata *nd){        ENTRY;        /* need lookup */        RETURN(0);}struct dentry_operations ll_fini_d_ops = {        .d_revalidate = ll_fini_revalidate_nd,        .d_release = ll_release,};/* * It is for the following race condition: * When someone (maybe statahead thread) adds the dentry to the dentry hash * table, the dentry's "d_op" maybe NULL, at the same time, another (maybe * "ls -l") process finds such dentry by "do_lookup()" without "do_revalidate()" * called. It causes statahead window lost, and maybe other issues. --Fan Yong */static int ll_init_revalidate_nd(struct dentry *dentry, struct nameidata *nd){        struct l_wait_info lwi = { 0 };        struct ll_dentry_data *lld;        ENTRY;        ll_set_dd(dentry);        lld = ll_d2d(dentry);        if (unlikely(lld == NULL))                RETURN(-ENOMEM);        l_wait_event(lld->lld_waitq, dentry->d_op != &ll_init_d_ops, &lwi);        if (likely(dentry->d_op == &ll_d_ops))                RETURN(ll_revalidate_nd(dentry, nd));        else                RETURN(dentry->d_op == &ll_fini_d_ops ? 0 : -EINVAL);}struct dentry_operations ll_init_d_ops = {        .d_revalidate = ll_init_revalidate_nd,        .d_release = ll_release,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -