From: yury Date: Tue, 25 Jul 2006 17:05:57 +0000 (+0000) Subject: - many fixes in readdir proto. X-Git-Tag: v1_8_0_110~486^2~1335 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=71e6192487e03c71878ab7485467334f2bd434aa;p=fs%2Flustre-release.git - many fixes in readdir proto. --- diff --git a/lustre/include/lustre/lustre_idl.h b/lustre/include/lustre/lustre_idl.h index eaf8e4d..c525140 100644 --- a/lustre/include/lustre/lustre_idl.h +++ b/lustre/include/lustre/lustre_idl.h @@ -262,6 +262,24 @@ static inline void fid_le_to_cpu(struct lu_fid *fid) fid->f_ver = le32_to_cpu(fid_ver(fid)); } +#define LU_NAME_LEN 255 + +/* + * lustre directory entry. This is used for sending directory content to the + * client, where it later gets converted to what Linux expects. + */ +struct lu_dir_entry { + struct lu_fid de_fid; /* file fid */ + __u16 de_rec_len; /* rec len */ + __u16 de_name_len; /* name len */ + char de_name[LU_NAME_LEN]; /* file name */ +}; + +#define LU_DIR_PAD 4 +#define LU_DIR_ROUND (LU_DIR_PAD - 1) + +#define LU_DIR_REC_LEN(len) ((sizeof(struct lu_fid) + 2*sizeof(__u16) + \ + len + 1 + LU_DIR_ROUND) & ~LU_DIR_ROUND) #define MEA_MAGIC_LAST_CHAR 0xb2221ca1 #define MEA_MAGIC_ALL_CHARS 0xb222a11c diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index cedbf0e..43e828b 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -49,8 +49,6 @@ #include #include "llite_internal.h" -typedef struct ext2_dir_entry_2 ext2_dirent; - #define PageChecked(page) test_bit(PG_checked, &(page)->flags) #define SetPageChecked(page) set_bit(PG_checked, &(page)->flags) @@ -75,8 +73,8 @@ static int ll_dir_readpage(struct file *file, struct page *page) LASSERT (body != NULL); /* checked by md_readpage() */ LASSERT_REPSWABBED (request, 0); /* swabbed by md_readpage() */ - LASSERT((body->valid & OBD_MD_FLSIZE) != 0); - inode->i_size = body->size; + if (body->valid & OBD_MD_FLSIZE) + inode->i_size = body->size; SetPageUptodate(page); } ptlrpc_req_finished(request); @@ -90,113 +88,26 @@ struct address_space_operations ll_dir_aops = { .readpage = ll_dir_readpage, }; -/* - * ext2 uses block-sized chunks. Arguably, sector-sized ones would be - * more robust, but we have what we have - */ -static inline unsigned ext2_chunk_size(struct inode *inode) +static inline unsigned long dir_pages(struct inode *inode) { - return inode->i_sb->s_blocksize; + return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; } -static inline void ext2_put_page(struct page *page) +static inline unsigned ll_chunk_size(struct inode *inode) { - kunmap(page); - page_cache_release(page); + return inode->i_sb->s_blocksize; } -static inline unsigned long dir_pages(struct inode *inode) +static void ll_check_page(struct inode *dir, struct page *page) { - return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; + /* XXX: check page format later */ + SetPageChecked(page); } - -static void ext2_check_page(struct inode *dir, struct page *page) +static inline void ll_put_page(struct page *page) { - unsigned chunk_size = ext2_chunk_size(dir); - char *kaddr = page_address(page); - // u32 max_inumber = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count); - unsigned offs, rec_len; - unsigned limit = PAGE_CACHE_SIZE; - ext2_dirent *p; - char *error; - - if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) { - limit = dir->i_size & ~PAGE_CACHE_MASK; - if (limit & (chunk_size - 1)) { - CERROR("limit %d dir size %lld index %ld\n", - limit, dir->i_size, page->index); - goto Ebadsize; - } - for (offs = limit; offsrec_len = cpu_to_le16(chunk_size); - p->name_len = 0; - p->inode = 0; - } - if (!limit) - goto out; - } - for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) { - p = (ext2_dirent *)(kaddr + offs); - rec_len = le16_to_cpu(p->rec_len); - - if (rec_len < EXT2_DIR_REC_LEN(1)) - goto Eshort; - if (rec_len & 3) - goto Ealign; - if (rec_len < EXT2_DIR_REC_LEN(p->name_len)) - goto Enamelen; - if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1)) - goto Espan; - // if (le32_to_cpu(p->inode) > max_inumber) - //goto Einumber; - } - if (offs != limit) - goto Eend; -out: - SetPageChecked(page); - return; - - /* Too bad, we had an error */ - -Ebadsize: - CERROR("%s: directory %lu/%u size %llu is not a multiple of %u\n", - ll_i2mdexp(dir)->exp_obd->obd_name, dir->i_ino, - dir->i_generation, dir->i_size, chunk_size); - goto fail; -Eshort: - error = "rec_len is smaller than minimal"; - goto bad_entry; -Ealign: - error = "unaligned directory entry"; - goto bad_entry; -Enamelen: - error = "rec_len is too small for name_len"; - goto bad_entry; -Espan: - error = "directory entry across blocks"; - goto bad_entry; - //Einumber: - // error = "inode out of bounds"; -bad_entry: - CERROR("%s: bad entry in directory %lu/%u: %s - " - "offset=%lu+%u, inode=%lu, rec_len=%d, name_len=%d\n", - ll_i2mdexp(dir)->exp_obd->obd_name, dir->i_ino, - dir->i_generation, error, (page->index<inode), - rec_len, p->name_len); - goto fail; -Eend: - p = (ext2_dirent *)(kaddr + offs); - CERROR("ext2_check_page" - "entry in directory #%lu spans the page boundary" - "offset=%lu, inode=%lu\n", - dir->i_ino, (page->index<inode)); -fail: - SetPageChecked(page); - SetPageError(page); + kunmap(page); + page_cache_release(page); } static struct page *ll_get_dir_page(struct inode *dir, unsigned long n) @@ -241,7 +152,7 @@ static struct page *ll_get_dir_page(struct inode *dir, unsigned long n) if (!PageUptodate(page)) goto fail; if (!PageChecked(page)) - ext2_check_page(dir, page); + ll_check_page(dir, page); if (PageError(page)) goto fail; @@ -250,67 +161,38 @@ out_unlock: return page; fail: - ext2_put_page(page); + ll_put_page(page); page = ERR_PTR(-EIO); goto out_unlock; } -/* - * p is at least 6 bytes before the end of page - */ -static inline ext2_dirent *ext2_next_entry(ext2_dirent *p) -{ - return (ext2_dirent *)((char*)p + le16_to_cpu(p->rec_len)); -} - -static inline unsigned -ext2_validate_entry(char *base, unsigned offset, unsigned mask) +static inline struct lu_dir_entry *ll_next_entry(struct lu_dir_entry *p) { - ext2_dirent *de = (ext2_dirent*)(base + offset); - ext2_dirent *p = (ext2_dirent*)(base + (offset&mask)); - while ((char*)p < (char*)de) - p = ext2_next_entry(p); - return (char *)p - base; + return (struct lu_dir_entry *)((char *)p + le16_to_cpu(p->de_rec_len)); } -static unsigned char ext2_filetype_table[EXT2_FT_MAX] = { - [EXT2_FT_UNKNOWN] DT_UNKNOWN, - [EXT2_FT_REG_FILE] DT_REG, - [EXT2_FT_DIR] DT_DIR, - [EXT2_FT_CHRDEV] DT_CHR, - [EXT2_FT_BLKDEV] DT_BLK, - [EXT2_FT_FIFO] DT_FIFO, - [EXT2_FT_SOCK] DT_SOCK, - [EXT2_FT_SYMLINK] DT_LNK, -}; - - int ll_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *inode = filp->f_dentry->d_inode; loff_t pos = filp->f_pos; - // XXX struct super_block *sb = inode->i_sb; unsigned offset = pos & ~PAGE_CACHE_MASK; unsigned long n = pos >> PAGE_CACHE_SHIFT; unsigned long npages = dir_pages(inode); - unsigned chunk_mask = ~(ext2_chunk_size(inode)-1); - unsigned char *types = ext2_filetype_table; - int need_revalidate = (filp->f_version != inode->i_version); int rc = 0; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) pos %llu/%llu\n", inode->i_ino, inode->i_generation, inode, pos, inode->i_size); - if (pos > inode->i_size - EXT2_DIR_REC_LEN(1)) + if (pos > inode->i_size - LU_DIR_REC_LEN(1)) RETURN(0); for ( ; n < npages; n++, offset = 0) { char *kaddr, *limit; - ext2_dirent *de; + struct lu_dir_entry *de; struct page *page; - CDEBUG(D_EXT2,"read %lu of dir %lu/%u page %lu/%lu size %llu\n", + CDEBUG(D_VFSTRACE,"read %lu of dir %lu/%u page %lu/%lu size %llu\n", PAGE_CACHE_SIZE, inode->i_ino, inode->i_generation, n, npages, inode->i_size); page = ll_get_dir_page(inode, n); @@ -326,32 +208,29 @@ int ll_readdir(struct file *filp, void *dirent, filldir_t filldir) } kaddr = page_address(page); - if (need_revalidate) { - /* page already checked from ll_get_dir_page() */ - offset = ext2_validate_entry(kaddr, offset, chunk_mask); - need_revalidate = 0; - } - de = (ext2_dirent *)(kaddr+offset); - limit = kaddr + PAGE_CACHE_SIZE - EXT2_DIR_REC_LEN(1); - for ( ;(char*)de <= limit; de = ext2_next_entry(de)) { - if (de->inode) { + + de = (struct lu_dir_entry *)(kaddr + offset); + limit = kaddr + PAGE_CACHE_SIZE - LU_DIR_REC_LEN(1); + for ( ;(char*)de <= limit; de = ll_next_entry(de)) { + if (fid_oid(&de->de_fid) && fid_seq(&de->de_fid)) { + struct ll_sb_info *sbi = ll_i2sbi(inode); int over; rc = 0; /* no error if we return something */ offset = (char *)de - kaddr; - over = filldir(dirent, de->name, de->name_len, - (n<inode), - types[de->file_type & - (EXT2_FT_MAX - 1)]); + fid_le_to_cpu(&de->de_fid); + over = filldir(dirent, de->de_name, de->de_name_len, + (n << PAGE_CACHE_SHIFT) | offset, + ll_fid_build_ino(sbi, &de->de_fid), + 0); if (over) { - ext2_put_page(page); + ll_put_page(page); GOTO(done, rc); } } } - ext2_put_page(page); + ll_put_page(page); } done: diff --git a/lustre/osd/osd_handler.c b/lustre/osd/osd_handler.c index 4cb1023..77765db 100644 --- a/lustre/osd/osd_handler.c +++ b/lustre/osd/osd_handler.c @@ -891,6 +891,10 @@ int osd_readpage(const struct lu_context *ctxt, struct dt_object *dt, struct lu_rdpg *rdpg) { struct osd_object *obj = osd_dt_obj(dt); + int i, rc, tmpcount, tmpsize = 0; + struct dt_it_ops *iops; + struct dt_it *it; + LASSERT(lu_object_exists(ctxt, &dt->do_lu)); LASSERT(osd_invariant(obj)); @@ -913,10 +917,66 @@ int osd_readpage(const struct lu_context *ctxt, rdpg->rp_size = obj->oo_inode->i_size; /* - * XXX: here should be filling pages by dir data in ext3 format and - * ->rp_pages already should be allocated. + * iterating directory and fill pages from @rdpg */ - return 0; + iops = &dt->do_index_ops->dio_it; + it = iops->init(ctxt, dt); + if (it == NULL) + return -ENOMEM; + + rc = iops->get(ctxt, it, (const void *)""); + if (rc > 0) { + for (i = 0, tmpcount = rdpg->rp_count; + i < rdpg->rp_npages; i++, tmpcount -= tmpsize) { + struct lu_dir_entry *entry, *last; + int page_space = PAGE_SIZE; + + tmpsize = tmpcount > PAGE_SIZE ? PAGE_SIZE : tmpcount; + entry = kmap(rdpg->rp_pages[i]); + last = entry; + + for (rc = 0; rc == 0; ) { + rc = iops->next(ctxt, it); + + if (rc == 0) { + struct lu_fid *fid; + char *name; + int len; + + fid = (void *)iops->rec(ctxt, it); + name = (void *)iops->key(ctxt, it); + len = iops->key_size(ctxt, it); + + entry->de_fid = *fid; + fid_cpu_to_le(&entry->de_fid); + + entry->de_name_len = cpu_to_le16(len + 1); + entry->de_rec_len = cpu_to_le16(LU_DIR_REC_LEN(len + 1)); + + strncpy(entry->de_name, name, len); + entry->de_name[len] = '\0'; + + page_space -= LU_DIR_REC_LEN(len + 1); + last = entry; + + entry = (struct lu_dir_entry *)((char *)entry + + LU_DIR_REC_LEN(len + 1)); + } + } + /* last entry fills whole space in the page */ + if (page_space < PAGE_SIZE) + last->de_rec_len += page_space; + kunmap(rdpg->rp_pages[i]); + } + iops->put(ctxt, it); + + rc = 0; + } else if (rc == 0) { + rc = -EIO; + } + iops->fini(ctxt, it); + + return rc; } static struct dt_object_operations osd_obj_ops = {