+ struct inode *inode = filp->f_dentry->d_inode;
+ struct ll_inode_info *info = ll_i2info(inode);
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct ll_file_data *fd = LUSTRE_FPRIVATE(filp);
+ __u64 pos = fd->fd_dir.lfd_pos;
+ int api32 = ll_need_32bit_api(sbi);
+ int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
+ struct page *page;
+ struct ll_dir_chain chain;
+ int done;
+ int shift;
+ int rc;
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) pos %lu/%llu 32bit_api %d\n",
+ inode->i_ino, inode->i_generation, inode,
+ (unsigned long)pos, i_size_read(inode), api32);
+
+ if (pos == MDS_DIR_END_OFF)
+ /*
+ * end-of-file.
+ */
+ RETURN(0);
+
+ rc = 0;
+ done = 0;
+ shift = 0;
+ ll_dir_chain_init(&chain);
+
+ fd->fd_dir.lfd_next = pos;
+ page = ll_get_dir_page(filp, inode, pos, &chain);
+
+ while (rc == 0 && !done) {
+ struct lu_dirpage *dp;
+ struct lu_dirent *ent;
+
+ if (!IS_ERR(page)) {
+ /*
+ * If page is empty (end of directory is reached),
+ * use this value.
+ */
+ __u64 hash = MDS_DIR_END_OFF;
+ __u64 next;
+
+ dp = page_address(page);
+ for (ent = lu_dirent_start(dp); ent != NULL && !done;
+ ent = lu_dirent_next(ent)) {
+ __u16 type;
+ int namelen;
+ struct lu_fid fid;
+ __u64 lhash;
+ __u64 ino;
+
+ /*
+ * XXX: implement correct swabbing here.
+ */
+
+ hash = le64_to_cpu(ent->lde_hash);
+ if (hash < pos)
+ /*
+ * Skip until we find target hash
+ * value.
+ */
+ continue;
+
+ namelen = le16_to_cpu(ent->lde_namelen);
+ if (namelen == 0)
+ /*
+ * Skip dummy record.
+ */
+ continue;
+
+ if (api32 && hash64)
+ lhash = hash >> 32;
+ else
+ lhash = hash;
+ fid_le_to_cpu(&fid, &ent->lde_fid);
+ ino = cl_fid_build_ino(&fid, api32);
+ type = ll_dirent_type_get(ent);
+ /* For 'll_nfs_get_name_filldir()', it will try
+ * to access the 'ent' through its 'lde_name',
+ * so the parameter 'name' for 'filldir()' must
+ * be part of the 'ent'. */
+ done = filldir(cookie, ent->lde_name, namelen,
+ lhash, ino, type);
+ }
+ next = le64_to_cpu(dp->ldp_hash_end);
+ if (!done) {
+ pos = next;
+ if (pos == MDS_DIR_END_OFF) {
+ /*
+ * End of directory reached.
+ */
+ done = 1;
+ ll_release_page(page, 0);
+ } else if (1 /* chain is exhausted*/) {
+ /*
+ * Normal case: continue to the next
+ * page.
+ */
+ ll_release_page(page,
+ le32_to_cpu(dp->ldp_flags) &
+ LDF_COLLIDE);
+ fd->fd_dir.lfd_next = pos;
+ page = ll_get_dir_page(filp, inode, pos,
+ &chain);
+ } else {
+ /*
+ * go into overflow page.
+ */
+ LASSERT(le32_to_cpu(dp->ldp_flags) &
+ LDF_COLLIDE);
+ ll_release_page(page, 1);
+ }
+ } else {
+ pos = hash;
+ ll_release_page(page, 0);
+ }
+ } else {
+ rc = PTR_ERR(page);
+ CERROR("error reading dir "DFID" at %lu: rc %d\n",
+ PFID(&info->lli_fid), (unsigned long)pos, rc);
+ }
+ }
+
+ fd->fd_dir.lfd_pos = pos;
+ if (pos == MDS_DIR_END_OFF) {
+ if (api32)
+ filp->f_pos = LL_DIR_END_OFF_32BIT;
+ else
+ filp->f_pos = LL_DIR_END_OFF;
+ } else {
+ if (api32 && hash64)
+ filp->f_pos = pos >> 32;
+ else
+ filp->f_pos = pos;
+ }
+ filp->f_version = inode->i_version;
+ touch_atime(filp->f_vfsmnt, filp->f_dentry);
+
+ ll_dir_chain_fini(&chain);
+
+ RETURN(rc);