1: /*
2: * Copy the index root attribute value to a buffer so that we can put
3: * the search context and unmap the mft record before calling the
4: * filldir() callback. We need to do this because of NFSd which calls
5: * ->lookup() from its filldir callback() and this causes NTFS to
6: * deadlock as ntfs_lookup() maps the mft record of the directory and
7: * we have got it mapped here already. The only solution is for us to
8: * unmap the mft record here so that a call to ntfs_lookup() is able to
9: * map the mft record without deadlocking.
10: */
11: rc = le32_to_cpu(ctx->attr->data.resident.value_length);
12: ir = kmalloc(rc, GFP_NOFS);
13: if (unlikely(!ir)) {
14: err = -ENOMEM;
15: goto err_out;
16: }
17: /* Copy the index root value (it has been verified in read_inode). */
18: memcpy(ir, (u8*)ctx->attr +
19: le16_to_cpu(ctx->attr->data.resident.value_offset), rc);
20: ntfs_attr_put_search_ctx(ctx);
21: unmap_mft_record(ndir);
22: ctx = NULL;
23: m = NULL;
24: index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
25: /* The first index entry. */
26: ie = (INDEX_ENTRY*)((u8*)&ir->index +
27: le32_to_cpu(ir->index.entries_offset));
28: /*
29: * Loop until we exceed valid memory (corruption case) or until we
30: * reach the last entry or until filldir tells us it has had enough
31: * or signals an error (both covered by the rc test).
32: */
33: for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
34: ntfs_debug("In index root, offset 0x%zx.", (u8*)ie - (u8*)ir);
35: /* Bounds checks. */
36: if (unlikely((u8*)ie < (u8*)ir || (u8*)ie +
37: sizeof(INDEX_ENTRY_HEADER) > index_end ||
38: (u8*)ie + le16_to_cpu(ie->key_length) >
39: index_end))
40: goto err_out;
41: /* The last entry cannot contain a name. */
42: if (ie->flags & INDEX_ENTRY_END)
43: break;
44: /* Skip index root entry if continuing previous readdir. */
45: if (ir_pos > (u8*)ie - (u8*)ir)
46: continue;
47: /* Advance the position even if going to skip the entry. */
48: fpos = (u8*)ie - (u8*)ir;
49: /* Submit the name to the filldir callback. */
50: rc = ntfs_filldir(vol, fpos, ndir, NULL, ie, name, dirent,
51: filldir);
52: if (rc) {
53: kfree(ir);
54: goto abort;
55: }
56: }