diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index 5b9955ee5e084513ae9860152c60218d3ad27f88..fef5f0f4e012d3010fb3e2d8f64b23bbe8977ef4 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -47,32 +47,6 @@ #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) @@ -165,11 +139,6 @@ static int ll_dir_check_entry(struct inode *dir, struct ll_dir_entry *ent, 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; @@ -283,20 +252,11 @@ out_unlock: return page; fail: - kunmap(page); - page_cache_release(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 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) { @@ -429,8 +389,7 @@ int ll_readdir(struct file *filp, void *dirent, filldir_t filldir) } done = ll_readdir_page(kaddr, idx << CFS_PAGE_SHIFT, &offset, filldir, dirent); - kunmap(page); - page_cache_release(page); + ll_put_page(page); if (done > 0) /* * Some entries were sent to the user space, return diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index f98f79e30d85575ffc4f45affe93c6a03e577869..65ab7f9c8948e0459519810484e461c41787ca99 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -5,7 +5,6 @@ #ifndef LLITE_INTERNAL_H #define LLITE_INTERNAL_H -#include <linux/ext2_fs.h> #ifdef CONFIG_FS_POSIX_ACL # include <linux/fs.h> #ifdef HAVE_XATTR_ACL @@ -48,6 +47,26 @@ static inline struct lookup_intent *ll_nd2it(struct nameidata *nd) } #endif +/* + * 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) +#define 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]; +}; + struct ll_dentry_data { int lld_cwd_count; int lld_mnt_count; @@ -504,27 +523,26 @@ extern struct file_operations ll_dir_operations; extern struct inode_operations ll_dir_inode_operations; struct page *ll_get_dir_page(struct inode *dir, unsigned long n); -/* - * p is at least 6 bytes before the end of page - */ -typedef struct ext2_dir_entry_2 ext2_dirent; -static inline ext2_dirent *ext2_next_entry(ext2_dirent *p) +static inline unsigned ll_dir_rec_len(unsigned name_len) { - return (ext2_dirent *)((char*)p + le16_to_cpu(p->rec_len)); + return (name_len + 8 + LL_DIR_PAD - 1) & ~(LL_DIR_PAD - 1); } -static inline unsigned -ext2_validate_entry(char *base, unsigned offset, unsigned mask) +static inline struct ll_dir_entry *ll_entry_at(void *base, unsigned offset) +{ + return (struct ll_dir_entry *)((char *)base + offset); +} + +/* + * 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) { - 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 ll_entry_at(p, le16_to_cpu(p->lde_rec_len)); } -static inline void ext2_put_page(struct page *page) +static inline void ll_put_page(struct page *page) { kunmap(page); page_cache_release(page); diff --git a/lustre/llite/statahead.c b/lustre/llite/statahead.c index 1e45dd985f6bfd2cbbc89213fd670891d451823f..6262dd08a5b4d9ce046a86a191163215bc74f38f 100644 --- a/lustre/llite/statahead.c +++ b/lustre/llite/statahead.c @@ -457,7 +457,7 @@ static inline void ll_name2qstr(struct qstr *this, const char *name, int namelen this->hash = end_name_hash(hash); } -static int ll_statahead_one(struct dentry *parent, ext2_dirent *de) +static int ll_statahead_one(struct dentry *parent, struct ll_dir_entry *de) { struct inode *dir = parent->d_inode; struct ll_inode_info *lli = ll_i2info(dir); @@ -483,7 +483,7 @@ static int ll_statahead_one(struct dentry *parent, ext2_dirent *de) if (IS_ERR(se)) RETURN(PTR_ERR(se)); - ll_name2qstr(&name, de->name, de->name_len); + ll_name2qstr(&name, de->lde_name, de->lde_name_len); dentry = d_lookup(parent, &name); if (!dentry) { dentry = d_alloc(parent, &name); @@ -569,7 +569,7 @@ static int ll_statahead_thread(void *arg) struct l_wait_info lwi = { 0 }; unsigned long npages; char *kaddr, *limit; - ext2_dirent *de; + struct ll_dir_entry *de; struct page *page; npages = dir_pages(dir); @@ -590,18 +590,18 @@ static int ll_statahead_thread(void *arg) } kaddr = page_address(page); - limit = kaddr + CFS_PAGE_SIZE - EXT2_DIR_REC_LEN(1); - de = (ext2_dirent *)kaddr; + limit = kaddr + CFS_PAGE_SIZE - ll_dir_rec_len(1); + de = (struct ll_dir_entry *)kaddr; if (!index) { - de = ext2_next_entry(de); /* skip "." */ - de = ext2_next_entry(de); /* skip ".." */ + de = ll_dir_next_entry(de); /* skip "." */ + de = ll_dir_next_entry(de); /* skip ".." */ } - for (; (char*)de <= limit; de = ext2_next_entry(de)) { - if (!de->inode) + for (; (char*)de <= limit; de = ll_dir_next_entry(de)) { + if (!de->lde_inode) continue; - if (de->name[0] == '.' && !sai->sai_ls_all) { + if (de->lde_name[0] == '.' && !sai->sai_ls_all) { /* skip hidden files */ sai->sai_skip_hidden++; continue; @@ -618,17 +618,17 @@ static int ll_statahead_thread(void *arg) &lwi); if (unlikely(sa_check_stop(sai))) { - ext2_put_page(page); + ll_put_page(page); GOTO(out, rc); } rc = ll_statahead_one(parent, de); if (rc < 0) { - ext2_put_page(page); + ll_put_page(page); GOTO(out, rc); } } - ext2_put_page(page); + ll_put_page(page); index++; } EXIT; @@ -698,12 +698,12 @@ enum { static int is_first_dirent(struct inode *dir, struct dentry *dentry) { - struct qstr *d_name = &dentry->d_name; - unsigned long npages, index = 0; - struct page *page; - ext2_dirent *de; - char *kaddr, *limit; - int rc = LS_NONE_FIRST_DE, dot_de; + struct qstr *d_name = &dentry->d_name; + unsigned long npages, index = 0; + struct page *page; + struct ll_dir_entry *de; + char *kaddr, *limit; + int rc = LS_NONE_FIRST_DE, dot_de; ENTRY; while (1) { @@ -724,18 +724,29 @@ static int is_first_dirent(struct inode *dir, struct dentry *dentry) } kaddr = page_address(page); - limit = kaddr + CFS_PAGE_SIZE - EXT2_DIR_REC_LEN(1); - de = (ext2_dirent *)kaddr; + limit = kaddr + CFS_PAGE_SIZE - ll_dir_rec_len(1); + de = (struct ll_dir_entry *)kaddr; if (!index) { - de = ext2_next_entry(de); /* skip "." */ - de = ext2_next_entry(de); /* skip ".." */ + if (unlikely(!(de->lde_name_len == 1 && + strncmp(de->lde_name, ".", 1) == 0))) + CWARN("Maybe got bad on-disk dir: %lu\n", + dir->i_ino); + /* skip "." or ingore bad entry */ + de = ll_dir_next_entry(de); + + if (unlikely(!(de->lde_name_len == 2 && + strncmp(de->lde_name, "..", 2) == 0))) + CWARN("Maybe got bad on-disk dir: %lu\n", + dir->i_ino); + /* skip ".." or ingore bad entry */ + de = ll_dir_next_entry(de); } - for (; (char*)de <= limit; de = ext2_next_entry(de)) { - if (!de->inode) + for (; (char*)de <= limit; de = ll_dir_next_entry(de)) { + if (!de->lde_inode) continue; - if (de->name[0] == '.') + if (de->lde_name[0] == '.') dot_de = 1; else dot_de = 0; @@ -743,19 +754,19 @@ static int is_first_dirent(struct inode *dir, struct dentry *dentry) if (dot_de && d_name->name[0] != '.') { CDEBUG(D_READA, "%.*s skip hidden file %.*s\n", d_name->len, d_name->name, - de->name_len, de->name); + de->lde_name_len, de->lde_name); continue; } - if (d_name->len == de->name_len && - !strncmp(d_name->name, de->name, d_name->len)) + if (d_name->len == de->lde_name_len && + !strncmp(d_name->name, de->lde_name, d_name->len)) rc = LS_FIRST_DE + dot_de; else rc = LS_NONE_FIRST_DE; - ext2_put_page(page); + ll_put_page(page); RETURN(rc); } - ext2_put_page(page); + ll_put_page(page); index++; } RETURN(rc);