- ldlm_policy_data_t policy = {.l_inodebits = {MDS_INODELOCK_UPDATE} };
- struct address_space *mapping = dir->i_mapping;
- struct lustre_handle lockh;
- struct lu_dirpage *dp;
- struct page *page;
- ldlm_mode_t mode;
- int rc;
- __u64 start = 0;
- __u64 end = 0;
- __u64 lhash = hash;
- struct ll_inode_info *lli = ll_i2info(dir);
-
- mode = LCK_PR;
- rc = md_lock_match(ll_i2sbi(dir)->ll_md_exp, LDLM_FL_BLOCK_GRANTED,
- ll_inode2fid(dir), LDLM_IBITS, &policy, mode, &lockh);
- if (!rc) {
- struct ldlm_enqueue_info einfo = { LDLM_IBITS, mode,
- ll_md_blocking_ast, ldlm_completion_ast,
- NULL, NULL, dir };
- struct lookup_intent it = { .it_op = IT_READDIR };
- struct ptlrpc_request *request;
- struct md_op_data *op_data;
-
- op_data = ll_prep_md_op_data(NULL, dir, NULL, NULL, 0, 0,
- LUSTRE_OPC_ANY, NULL);
- if (IS_ERR(op_data))
- return (void *)op_data;
-
- rc = md_enqueue(ll_i2sbi(dir)->ll_md_exp, &einfo, &it,
- op_data, &lockh, NULL, 0, NULL, 0);
-
- ll_finish_md_op_data(op_data);
-
- request = (struct ptlrpc_request *)it.d.lustre.it_data;
- if (request)
- ptlrpc_req_finished(request);
- if (rc < 0) {
- CERROR("lock enqueue: "DFID" at "LPU64": rc %d\n",
- PFID(ll_inode2fid(dir)), hash, rc);
- return ERR_PTR(rc);
- }
- } else {
- /* for cross-ref object, l_ast_data of the lock may not be set,
- * we reset it here */
- md_set_lock_data(ll_i2sbi(dir)->ll_md_exp, &lockh.cookie,
- dir, NULL);
- }
- ldlm_lock_dump_handle(D_OTHER, &lockh);
-
- cfs_down(&lli->lli_readdir_sem);
- page = ll_dir_page_locate(dir, &lhash, &start, &end);
- if (IS_ERR(page)) {
- CERROR("dir page locate: "DFID" at "LPU64": rc %ld\n",
- PFID(ll_inode2fid(dir)), lhash, PTR_ERR(page));
- GOTO(out_unlock, page);
- }
-
- if (page != NULL) {
- /*
- * XXX nikita: not entirely correct handling of a corner case:
- * suppose hash chain of entries with hash value HASH crosses
- * border between pages P0 and P1. First both P0 and P1 are
- * cached, seekdir() is called for some entry from the P0 part
- * of the chain. Later P0 goes out of cache. telldir(HASH)
- * happens and finds P1, as it starts with matching hash
- * value. Remaining entries from P0 part of the chain are
- * skipped. (Is that really a bug?)
- *
- * Possible solutions: 0. don't cache P1 is such case, handle
- * it as an "overflow" page. 1. invalidate all pages at
- * once. 2. use HASH|1 as an index for P1.
- */
- if (exact && lhash != start) {
- /*
- * readdir asked for a page starting _exactly_ from
- * given hash, but cache contains stale page, with
- * entries with smaller hash values. Stale page should
- * be invalidated, and new one fetched.
- */
- CDEBUG(D_OTHER, "Stale readpage page %p: "
- "start = "LPX64",end = "LPX64"hash ="LPX64"\n",
- page, start, end, lhash);
- ll_release_page(page, lhash, start, end);
- } else {
- GOTO(hash_collision, page);
- }
- }
-
- page = read_cache_page(mapping, hash_x_index(hash),
- (filler_t*)mapping->a_ops->readpage, filp);
- if (IS_ERR(page)) {
- CERROR("read cache page: "DFID" at "LPU64": rc %ld\n",
- PFID(ll_inode2fid(dir)), hash, PTR_ERR(page));
- GOTO(out_unlock, page);
- }
-
- wait_on_page(page);
- (void)kmap(page);
- if (!PageUptodate(page)) {
- CERROR("page not updated: "DFID" at "LPU64": rc %d\n",
- PFID(ll_inode2fid(dir)), hash, -5);
- goto fail;
- }
- if (!PageChecked(page))
- ll_check_page(dir, page);
- if (PageError(page)) {
- CERROR("page error: "DFID" at "LPU64": rc %d\n",
- PFID(ll_inode2fid(dir)), hash, -5);
- goto fail;
- }
-hash_collision:
- dp = page_address(page);
-#if BITS_PER_LONG == 32
- start = le64_to_cpu(dp->ldp_hash_start) >> 32;
- end = le64_to_cpu(dp->ldp_hash_end) >> 32;
- lhash = hash >> 32;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct ll_file_data *lfd = LUSTRE_FPRIVATE(filp);
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
+ int api32 = ll_need_32bit_api(sbi);
+ struct md_op_data *op_data;
+ __u64 pos;
+ int rc;
+ ENTRY;
+
+ if (lfd != NULL)
+ pos = lfd->lfd_pos;
+ else
+ pos = 0;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p) pos/size"
+ "%lu/%llu 32bit_api %d\n", PFID(ll_inode2fid(inode)),
+ inode, (unsigned long)pos, i_size_read(inode), api32);
+
+ if (pos == MDS_DIR_END_OFF)
+ /*
+ * end-of-file.
+ */
+ GOTO(out, rc = 0);
+
+ op_data = ll_prep_md_op_data(NULL, inode, inode, NULL, 0, 0,
+ LUSTRE_OPC_ANY, inode);
+ if (IS_ERR(op_data))
+ GOTO(out, rc = PTR_ERR(op_data));
+
+ if (unlikely(op_data->op_mea1 != NULL)) {
+ /* This is only needed for striped dir to fill ..,
+ * see lmv_read_entry */
+ if (filp->f_dentry->d_parent != NULL &&
+ filp->f_dentry->d_parent->d_inode != NULL) {
+ __u64 ibits = MDS_INODELOCK_UPDATE;
+ struct inode *parent =
+ filp->f_dentry->d_parent->d_inode;
+
+ if (ll_have_md_lock(parent, &ibits, LCK_MINMODE))
+ op_data->op_fid3 = *ll_inode2fid(parent);
+ }
+
+ /* If it can not find in cache, do lookup .. on the master
+ * object */
+ if (fid_is_zero(&op_data->op_fid3)) {
+ rc = ll_dir_get_parent_fid(inode, &op_data->op_fid3);
+ if (rc != 0)
+ RETURN(rc);
+ }
+ }
+ op_data->op_hash_offset = pos;
+ op_data->op_max_pages = sbi->ll_md_brw_pages;
+#ifdef HAVE_DIR_CONTEXT
+ ctx->pos = pos;
+ rc = ll_dir_read(inode, op_data, ctx);
+ pos = ctx->pos;