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

📄 dir.c

📁 lustre 1.6.5 source code
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Directory code for lustre client. * *  Copyright (C) 2002--2007 Cluster File Systems, Inc. * *   This file is part of the Lustre file system, http://www.lustre.org *   Lustre is a trademark of Cluster File Systems, Inc. * *   You may have signed or agreed to another license before downloading *   this software.  If so, you are bound by the terms and conditions *   of that agreement, and the following does not apply to you.  See the *   LICENSE file included with this distribution for more information. * *   If you did not agree to a different license, then this copy of Lustre *   is open source 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. * *   In either case, 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 *   license text for more details. * */#include <linux/fs.h>#include <linux/pagemap.h>#include <linux/mm.h>#include <linux/version.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))# include <linux/locks.h>   // for wait_on_buffer#else# include <linux/buffer_head.h>   // for wait_on_buffer#endif#define DEBUG_SUBSYSTEM S_LLITE#include <obd_support.h>#include <obd_class.h>#include <lustre_lib.h>#include <lustre/lustre_idl.h>#include <lustre_lite.h>#include <lustre_dlm.h>#include "llite_internal.h"/* * Directory entries are currently in the same format as ext2/ext3, but will * be changed in the future to accomodate FIDs */#define LL_DIR_NAME_LEN (255)static const int LL_DIR_PAD = 4;struct ll_dir_entry {        /* number of inode, referenced by this entry */	__le32	lde_inode;        /* total record length, multiple of LL_DIR_PAD */	__le16	lde_rec_len;        /* length of name */	__u8	lde_name_len;        /* file type: regular, directory, device, etc. */	__u8	lde_file_type;        /* name. NOT NUL-terminated */	char	lde_name[LL_DIR_NAME_LEN];};static inline unsigned ll_dir_rec_len(unsigned name_len){        return (name_len + 8 + LL_DIR_PAD - 1) & ~(LL_DIR_PAD - 1);}#ifndef HAVE_PAGE_CHECKED#ifdef HAVE_PG_FS_MISC#define PageChecked(page)        test_bit(PG_fs_misc, &(page)->flags)#define SetPageChecked(page)     set_bit(PG_fs_misc, &(page)->flags)#else#error PageChecked or PageFsMisc not defined in kernel#endif#endif/* returns the page unlocked, but with a reference */static int ll_dir_readpage(struct file *file, struct page *page){        struct inode *inode = page->mapping->host;        struct ll_fid mdc_fid;        __u64 offset;        struct ptlrpc_request *request;        struct mds_body *body;        int rc = 0;        ENTRY;        offset = (__u64)page->index << CFS_PAGE_SHIFT;        CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) off "LPU64"\n",               inode->i_ino, inode->i_generation, inode, offset);        mdc_pack_fid(&mdc_fid, inode->i_ino, inode->i_generation, S_IFDIR);        rc = mdc_readpage(ll_i2sbi(inode)->ll_mdc_exp, &mdc_fid,                          offset, page, &request);        if (!rc) {                body = lustre_msg_buf(request->rq_repmsg, REPLY_REC_OFF,                                      sizeof(*body));                LASSERT(body != NULL); /* checked by mdc_readpage() */                /* swabbed by mdc_readpage() */                LASSERT(lustre_rep_swabbed(request, REPLY_REC_OFF));                if (body->size != i_size_read(inode)) {                        ll_inode_size_lock(inode, 0);                        i_size_write(inode, body->size);                        ll_inode_size_unlock(inode, 0);                }                SetPageUptodate(page);        }        ptlrpc_req_finished(request);        unlock_page(page);        EXIT;        return rc;}struct address_space_operations ll_dir_aops = {        .readpage  = ll_dir_readpage,};static inline unsigned ll_dir_page_mask(struct inode *inode){        return ~(inode->i_sb->s_blocksize - 1);}/* * Check consistency of a single entry. */static int ll_dir_check_entry(struct inode *dir, struct ll_dir_entry *ent,                              unsigned offset, unsigned rec_len, pgoff_t index){        const char *msg;        /*         * Consider adding more checks.         */        if (unlikely(rec_len < ll_dir_rec_len(1)))                msg = "entry is too short";        else if (unlikely(rec_len & 3))                msg = "wrong alignment";        else if (unlikely(rec_len < ll_dir_rec_len(ent->lde_name_len)))                msg = "rec_len doesn't match name_len";        else if (unlikely(((offset + rec_len - 1) ^ offset) &                          ll_dir_page_mask(dir)))                msg = "directory entry across blocks";        else                return 0;        CERROR("%s: bad entry in directory %lu/%u: %s - "               "offset=%lu+%u, inode=%lu, rec_len=%d,"               " name_len=%d\n", ll_i2mdcexp(dir)->exp_obd->obd_name,               dir->i_ino, dir->i_generation, msg,               index << CFS_PAGE_SHIFT,               offset, (unsigned long)le32_to_cpu(ent->lde_inode),               rec_len, ent->lde_name_len);        return -EIO;}static inline struct ll_dir_entry *ll_entry_at(void *base, unsigned offset){        return (struct ll_dir_entry *)(base + offset);}static void ll_dir_check_page(struct inode *dir, struct page *page){        int      err;        unsigned size = dir->i_sb->s_blocksize;        char    *addr = page_address(page);        unsigned off;        unsigned limit;        unsigned reclen;        struct ll_dir_entry *ent;        err = 0;        if ((i_size_read(dir) >> CFS_PAGE_SHIFT) == (__u64)page->index) {                /*                 * Last page.                 */                limit = i_size_read(dir) & ~CFS_PAGE_MASK;                if (limit & (size - 1)) {                        CERROR("%s: dir %lu/%u size %llu doesn't match %u\n",                               ll_i2mdcexp(dir)->exp_obd->obd_name, dir->i_ino,                               dir->i_generation, i_size_read(dir), size);                        err++;                } else {                        /*                         * Place dummy forwarding entries to streamline                         * ll_readdir().                         */                        for (off = limit; off < CFS_PAGE_SIZE; off += size) {                                ent = ll_entry_at(addr, off);                                ent->lde_rec_len = cpu_to_le16(size);                                ent->lde_name_len = 0;                                ent->lde_inode = 0;                        }                }        } else                limit = CFS_PAGE_SIZE;        for (off = 0;             !err && off <= limit - ll_dir_rec_len(1); off += reclen) {                ent    = ll_entry_at(addr, off);                reclen = le16_to_cpu(ent->lde_rec_len);                err    = ll_dir_check_entry(dir, ent, off, reclen, page->index);        }        if (!err && off != limit) {                ent = ll_entry_at(addr, off);                CERROR("%s: entry in directory %lu/%u spans the page boundary "                       "offset="LPU64"+%u, inode=%lu\n",                       ll_i2mdcexp(dir)->exp_obd->obd_name,                       dir->i_ino, dir->i_generation,                       (__u64)page->index << CFS_PAGE_SHIFT,                       off, (unsigned long)le32_to_cpu(ent->lde_inode));                err++;        }        if (err)                SetPageError(page);        SetPageChecked(page);}struct page *ll_get_dir_page(struct inode *dir, unsigned long n){        struct ldlm_res_id res_id =                { .name = { dir->i_ino, (__u64)dir->i_generation} };        struct lustre_handle lockh;        struct obd_device *obddev = class_exp2obd(ll_i2sbi(dir)->ll_mdc_exp);        struct address_space *mapping = dir->i_mapping;        struct page *page;        ldlm_policy_data_t policy = {.l_inodebits = {MDS_INODELOCK_UPDATE} };        int rc;        rc = ldlm_lock_match(obddev->obd_namespace, LDLM_FL_BLOCK_GRANTED,                             &res_id, LDLM_IBITS, &policy, LCK_CR, &lockh);        if (!rc) {                struct lookup_intent it = { .it_op = IT_READDIR };                struct ldlm_enqueue_info einfo = { LDLM_IBITS, LCK_CR,                       ll_mdc_blocking_ast, ldlm_completion_ast, NULL, dir };                struct ptlrpc_request *request;                struct mdc_op_data data;                ll_prepare_mdc_op_data(&data, dir, NULL, NULL, 0, 0, NULL);                rc = mdc_enqueue(ll_i2sbi(dir)->ll_mdc_exp, &einfo, &it,                                 &data, &lockh, NULL, 0, 0);                request = (struct ptlrpc_request *)it.d.lustre.it_data;                if (request)                        ptlrpc_req_finished(request);                if (rc < 0) {                        CERROR("lock enqueue: rc: %d\n", rc);                        return ERR_PTR(rc);                }        }        ldlm_lock_dump_handle(D_OTHER, &lockh);        page = read_cache_page(mapping, n,                               (filler_t*)mapping->a_ops->readpage, NULL);        if (IS_ERR(page))                GOTO(out_unlock, page);        wait_on_page(page);        (void)kmap(page);        if (!PageUptodate(page))                goto fail;        if (!PageChecked(page))                ll_dir_check_page(dir, page);        if (PageError(page))                goto fail;out_unlock:        ldlm_lock_decref(&lockh, LCK_CR);        return page;fail:        kunmap(page);        page_cache_release(page);        page = ERR_PTR(-EIO);        goto out_unlock;}/* * p is at least 6 bytes before the end of page */static inline struct ll_dir_entry *ll_dir_next_entry(struct ll_dir_entry *p){        return ll_entry_at(p, le16_to_cpu(p->lde_rec_len));}static inline unsigned ll_dir_validate_entry(char *base, unsigned offset,                                             unsigned mask){        struct ll_dir_entry *de = ll_entry_at(base, offset);        struct ll_dir_entry *p  = ll_entry_at(base, offset & mask);        while (p < de && p->lde_rec_len > 0)                p = ll_dir_next_entry(p);        return (char *)p - base;}/* * File type constants. The same as in ext2 for compatibility. */enum {        LL_DIR_FT_UNKNOWN,        LL_DIR_FT_REG_FILE,        LL_DIR_FT_DIR,        LL_DIR_FT_CHRDEV,        LL_DIR_FT_BLKDEV,        LL_DIR_FT_FIFO,        LL_DIR_FT_SOCK,        LL_DIR_FT_SYMLINK,        LL_DIR_FT_MAX};static unsigned char ll_dir_filetype_table[LL_DIR_FT_MAX] = {        [LL_DIR_FT_UNKNOWN]  = DT_UNKNOWN,        [LL_DIR_FT_REG_FILE] = DT_REG,        [LL_DIR_FT_DIR]      = DT_DIR,        [LL_DIR_FT_CHRDEV]   = DT_CHR,        [LL_DIR_FT_BLKDEV]   = DT_BLK,        [LL_DIR_FT_FIFO]     = DT_FIFO,        [LL_DIR_FT_SOCK]     = DT_SOCK,        [LL_DIR_FT_SYMLINK]  = DT_LNK,};/* * Process one page. Returns: * *     -ve: filldir commands readdir to stop. *     +ve: number of entries submitted to filldir. *       0: no live entries on this page. */int ll_readdir_page(char *addr, __u64 base, unsigned *offset,                    filldir_t filldir, void *cookie){        struct ll_dir_entry *de;        char *end;        int nr;        de = ll_entry_at(addr, *offset);        end = addr + CFS_PAGE_SIZE - ll_dir_rec_len(1);        for (nr = 0 ;(char*)de <= end; de = ll_dir_next_entry(de)) {                if (de->lde_inode != 0) {                        nr++;                        *offset = (char *)de - addr;                        if (filldir(cookie, de->lde_name, de->lde_name_len,                                    base | *offset, le32_to_cpu(de->lde_inode),                                    ll_dir_filetype_table[de->lde_file_type &                                                          (LL_DIR_FT_MAX - 1)]))                                return -1;                }

⌨️ 快捷键说明

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