linux/fs/ntfs/index.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * index.c - NTFS kernel index handling.  Part of the Linux-NTFS project.
   4 *
   5 * Copyright (c) 2004-2005 Anton Altaparmakov
   6 */
   7
   8#include <linux/slab.h>
   9
  10#include "aops.h"
  11#include "collate.h"
  12#include "debug.h"
  13#include "index.h"
  14#include "ntfs.h"
  15
  16/**
  17 * ntfs_index_ctx_get - allocate and initialize a new index context
  18 * @idx_ni:     ntfs index inode with which to initialize the context
  19 *
  20 * Allocate a new index context, initialize it with @idx_ni and return it.
  21 * Return NULL if allocation failed.
  22 *
  23 * Locking:  Caller must hold i_mutex on the index inode.
  24 */
  25ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni)
  26{
  27        ntfs_index_context *ictx;
  28
  29        ictx = kmem_cache_alloc(ntfs_index_ctx_cache, GFP_NOFS);
  30        if (ictx)
  31                *ictx = (ntfs_index_context){ .idx_ni = idx_ni };
  32        return ictx;
  33}
  34
  35/**
  36 * ntfs_index_ctx_put - release an index context
  37 * @ictx:       index context to free
  38 *
  39 * Release the index context @ictx, releasing all associated resources.
  40 *
  41 * Locking:  Caller must hold i_mutex on the index inode.
  42 */
  43void ntfs_index_ctx_put(ntfs_index_context *ictx)
  44{
  45        if (ictx->entry) {
  46                if (ictx->is_in_root) {
  47                        if (ictx->actx)
  48                                ntfs_attr_put_search_ctx(ictx->actx);
  49                        if (ictx->base_ni)
  50                                unmap_mft_record(ictx->base_ni);
  51                } else {
  52                        struct page *page = ictx->page;
  53                        if (page) {
  54                                BUG_ON(!PageLocked(page));
  55                                unlock_page(page);
  56                                ntfs_unmap_page(page);
  57                        }
  58                }
  59        }
  60        kmem_cache_free(ntfs_index_ctx_cache, ictx);
  61        return;
  62}
  63
  64/**
  65 * ntfs_index_lookup - find a key in an index and return its index entry
  66 * @key:        [IN] key for which to search in the index
  67 * @key_len:    [IN] length of @key in bytes
  68 * @ictx:       [IN/OUT] context describing the index and the returned entry
  69 *
  70 * Before calling ntfs_index_lookup(), @ictx must have been obtained from a
  71 * call to ntfs_index_ctx_get().
  72 *
  73 * Look for the @key in the index specified by the index lookup context @ictx.
  74 * ntfs_index_lookup() walks the contents of the index looking for the @key.
  75 *
  76 * If the @key is found in the index, 0 is returned and @ictx is setup to
  77 * describe the index entry containing the matching @key.  @ictx->entry is the
  78 * index entry and @ictx->data and @ictx->data_len are the index entry data and
  79 * its length in bytes, respectively.
  80 *
  81 * If the @key is not found in the index, -ENOENT is returned and @ictx is
  82 * setup to describe the index entry whose key collates immediately after the
  83 * search @key, i.e. this is the position in the index at which an index entry
  84 * with a key of @key would need to be inserted.
  85 *
  86 * If an error occurs return the negative error code and @ictx is left
  87 * untouched.
  88 *
  89 * When finished with the entry and its data, call ntfs_index_ctx_put() to free
  90 * the context and other associated resources.
  91 *
  92 * If the index entry was modified, call flush_dcache_index_entry_page()
  93 * immediately after the modification and either ntfs_index_entry_mark_dirty()
  94 * or ntfs_index_entry_write() before the call to ntfs_index_ctx_put() to
  95 * ensure that the changes are written to disk.
  96 *
  97 * Locking:  - Caller must hold i_mutex on the index inode.
  98 *           - Each page cache page in the index allocation mapping must be
  99 *             locked whilst being accessed otherwise we may find a corrupt
 100 *             page due to it being under ->writepage at the moment which
 101 *             applies the mst protection fixups before writing out and then
 102 *             removes them again after the write is complete after which it 
 103 *             unlocks the page.
 104 */
 105int ntfs_index_lookup(const void *key, const int key_len,
 106                ntfs_index_context *ictx)
 107{
 108        VCN vcn, old_vcn;
 109        ntfs_inode *idx_ni = ictx->idx_ni;
 110        ntfs_volume *vol = idx_ni->vol;
 111        struct super_block *sb = vol->sb;
 112        ntfs_inode *base_ni = idx_ni->ext.base_ntfs_ino;
 113        MFT_RECORD *m;
 114        INDEX_ROOT *ir;
 115        INDEX_ENTRY *ie;
 116        INDEX_ALLOCATION *ia;
 117        u8 *index_end, *kaddr;
 118        ntfs_attr_search_ctx *actx;
 119        struct address_space *ia_mapping;
 120        struct page *page;
 121        int rc, err = 0;
 122
 123        ntfs_debug("Entering.");
 124        BUG_ON(!NInoAttr(idx_ni));
 125        BUG_ON(idx_ni->type != AT_INDEX_ALLOCATION);
 126        BUG_ON(idx_ni->nr_extents != -1);
 127        BUG_ON(!base_ni);
 128        BUG_ON(!key);
 129        BUG_ON(key_len <= 0);
 130        if (!ntfs_is_collation_rule_supported(
 131                        idx_ni->itype.index.collation_rule)) {
 132                ntfs_error(sb, "Index uses unsupported collation rule 0x%x.  "
 133                                "Aborting lookup.", le32_to_cpu(
 134                                idx_ni->itype.index.collation_rule));
 135                return -EOPNOTSUPP;
 136        }
 137        /* Get hold of the mft record for the index inode. */
 138        m = map_mft_record(base_ni);
 139        if (IS_ERR(m)) {
 140                ntfs_error(sb, "map_mft_record() failed with error code %ld.",
 141                                -PTR_ERR(m));
 142                return PTR_ERR(m);
 143        }
 144        actx = ntfs_attr_get_search_ctx(base_ni, m);
 145        if (unlikely(!actx)) {
 146                err = -ENOMEM;
 147                goto err_out;
 148        }
 149        /* Find the index root attribute in the mft record. */
 150        err = ntfs_attr_lookup(AT_INDEX_ROOT, idx_ni->name, idx_ni->name_len,
 151                        CASE_SENSITIVE, 0, NULL, 0, actx);
 152        if (unlikely(err)) {
 153                if (err == -ENOENT) {
 154                        ntfs_error(sb, "Index root attribute missing in inode "
 155                                        "0x%lx.", idx_ni->mft_no);
 156                        err = -EIO;
 157                }
 158                goto err_out;
 159        }
 160        /* Get to the index root value (it has been verified in read_inode). */
 161        ir = (INDEX_ROOT*)((u8*)actx->attr +
 162                        le16_to_cpu(actx->attr->data.resident.value_offset));
 163        index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
 164        /* The first index entry. */
 165        ie = (INDEX_ENTRY*)((u8*)&ir->index +
 166                        le32_to_cpu(ir->index.entries_offset));
 167        /*
 168         * Loop until we exceed valid memory (corruption case) or until we
 169         * reach the last entry.
 170         */
 171        for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
 172                /* Bounds checks. */
 173                if ((u8*)ie < (u8*)actx->mrec || (u8*)ie +
 174                                sizeof(INDEX_ENTRY_HEADER) > index_end ||
 175                                (u8*)ie + le16_to_cpu(ie->length) > index_end)
 176                        goto idx_err_out;
 177                /*
 178                 * The last entry cannot contain a key.  It can however contain
 179                 * a pointer to a child node in the B+tree so we just break out.
 180                 */
 181                if (ie->flags & INDEX_ENTRY_END)
 182                        break;
 183                /* Further bounds checks. */
 184                if ((u32)sizeof(INDEX_ENTRY_HEADER) +
 185                                le16_to_cpu(ie->key_length) >
 186                                le16_to_cpu(ie->data.vi.data_offset) ||
 187                                (u32)le16_to_cpu(ie->data.vi.data_offset) +
 188                                le16_to_cpu(ie->data.vi.data_length) >
 189                                le16_to_cpu(ie->length))
 190                        goto idx_err_out;
 191                /* If the keys match perfectly, we setup @ictx and return 0. */
 192                if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
 193                                &ie->key, key_len)) {
 194ir_done:
 195                        ictx->is_in_root = true;
 196                        ictx->ir = ir;
 197                        ictx->actx = actx;
 198                        ictx->base_ni = base_ni;
 199                        ictx->ia = NULL;
 200                        ictx->page = NULL;
 201done:
 202                        ictx->entry = ie;
 203                        ictx->data = (u8*)ie +
 204                                        le16_to_cpu(ie->data.vi.data_offset);
 205                        ictx->data_len = le16_to_cpu(ie->data.vi.data_length);
 206                        ntfs_debug("Done.");
 207                        return err;
 208                }
 209                /*
 210                 * Not a perfect match, need to do full blown collation so we
 211                 * know which way in the B+tree we have to go.
 212                 */
 213                rc = ntfs_collate(vol, idx_ni->itype.index.collation_rule, key,
 214                                key_len, &ie->key, le16_to_cpu(ie->key_length));
 215                /*
 216                 * If @key collates before the key of the current entry, there
 217                 * is definitely no such key in this index but we might need to
 218                 * descend into the B+tree so we just break out of the loop.
 219                 */
 220                if (rc == -1)
 221                        break;
 222                /*
 223                 * A match should never happen as the memcmp() call should have
 224                 * cought it, but we still treat it correctly.
 225                 */
 226                if (!rc)
 227                        goto ir_done;
 228                /* The keys are not equal, continue the search. */
 229        }
 230        /*
 231         * We have finished with this index without success.  Check for the
 232         * presence of a child node and if not present setup @ictx and return
 233         * -ENOENT.
 234         */
 235        if (!(ie->flags & INDEX_ENTRY_NODE)) {
 236                ntfs_debug("Entry not found.");
 237                err = -ENOENT;
 238                goto ir_done;
 239        } /* Child node present, descend into it. */
 240        /* Consistency check: Verify that an index allocation exists. */
 241        if (!NInoIndexAllocPresent(idx_ni)) {
 242                ntfs_error(sb, "No index allocation attribute but index entry "
 243                                "requires one.  Inode 0x%lx is corrupt or "
 244                                "driver bug.", idx_ni->mft_no);
 245                goto err_out;
 246        }
 247        /* Get the starting vcn of the index_block holding the child node. */
 248        vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
 249        ia_mapping = VFS_I(idx_ni)->i_mapping;
 250        /*
 251         * We are done with the index root and the mft record.  Release them,
 252         * otherwise we deadlock with ntfs_map_page().
 253         */
 254        ntfs_attr_put_search_ctx(actx);
 255        unmap_mft_record(base_ni);
 256        m = NULL;
 257        actx = NULL;
 258descend_into_child_node:
 259        /*
 260         * Convert vcn to index into the index allocation attribute in units
 261         * of PAGE_SIZE and map the page cache page, reading it from
 262         * disk if necessary.
 263         */
 264        page = ntfs_map_page(ia_mapping, vcn <<
 265                        idx_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
 266        if (IS_ERR(page)) {
 267                ntfs_error(sb, "Failed to map index page, error %ld.",
 268                                -PTR_ERR(page));
 269                err = PTR_ERR(page);
 270                goto err_out;
 271        }
 272        lock_page(page);
 273        kaddr = (u8*)page_address(page);
 274fast_descend_into_child_node:
 275        /* Get to the index allocation block. */
 276        ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
 277                        idx_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
 278        /* Bounds checks. */
 279        if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
 280                ntfs_error(sb, "Out of bounds check failed.  Corrupt inode "
 281                                "0x%lx or driver bug.", idx_ni->mft_no);
 282                goto unm_err_out;
 283        }
 284        /* Catch multi sector transfer fixup errors. */
 285        if (unlikely(!ntfs_is_indx_record(ia->magic))) {
 286                ntfs_error(sb, "Index record with vcn 0x%llx is corrupt.  "
 287                                "Corrupt inode 0x%lx.  Run chkdsk.",
 288                                (long long)vcn, idx_ni->mft_no);
 289                goto unm_err_out;
 290        }
 291        if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
 292                ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
 293                                "different from expected VCN (0x%llx).  Inode "
 294                                "0x%lx is corrupt or driver bug.",
 295                                (unsigned long long)
 296                                sle64_to_cpu(ia->index_block_vcn),
 297                                (unsigned long long)vcn, idx_ni->mft_no);
 298                goto unm_err_out;
 299        }
 300        if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
 301                        idx_ni->itype.index.block_size) {
 302                ntfs_error(sb, "Index buffer (VCN 0x%llx) of inode 0x%lx has "
 303                                "a size (%u) differing from the index "
 304                                "specified size (%u).  Inode is corrupt or "
 305                                "driver bug.", (unsigned long long)vcn,
 306                                idx_ni->mft_no,
 307                                le32_to_cpu(ia->index.allocated_size) + 0x18,
 308                                idx_ni->itype.index.block_size);
 309                goto unm_err_out;
 310        }
 311        index_end = (u8*)ia + idx_ni->itype.index.block_size;
 312        if (index_end > kaddr + PAGE_SIZE) {
 313                ntfs_error(sb, "Index buffer (VCN 0x%llx) of inode 0x%lx "
 314                                "crosses page boundary.  Impossible!  Cannot "
 315                                "access!  This is probably a bug in the "
 316                                "driver.", (unsigned long long)vcn,
 317                                idx_ni->mft_no);
 318                goto unm_err_out;
 319        }
 320        index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
 321        if (index_end > (u8*)ia + idx_ni->itype.index.block_size) {
 322                ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of inode "
 323                                "0x%lx exceeds maximum size.",
 324                                (unsigned long long)vcn, idx_ni->mft_no);
 325                goto unm_err_out;
 326        }
 327        /* The first index entry. */
 328        ie = (INDEX_ENTRY*)((u8*)&ia->index +
 329                        le32_to_cpu(ia->index.entries_offset));
 330        /*
 331         * Iterate similar to above big loop but applied to index buffer, thus
 332         * loop until we exceed valid memory (corruption case) or until we
 333         * reach the last entry.
 334         */
 335        for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
 336                /* Bounds checks. */
 337                if ((u8*)ie < (u8*)ia || (u8*)ie +
 338                                sizeof(INDEX_ENTRY_HEADER) > index_end ||
 339                                (u8*)ie + le16_to_cpu(ie->length) > index_end) {
 340                        ntfs_error(sb, "Index entry out of bounds in inode "
 341                                        "0x%lx.", idx_ni->mft_no);
 342                        goto unm_err_out;
 343                }
 344                /*
 345                 * The last entry cannot contain a key.  It can however contain
 346                 * a pointer to a child node in the B+tree so we just break out.
 347                 */
 348                if (ie->flags & INDEX_ENTRY_END)
 349                        break;
 350                /* Further bounds checks. */
 351                if ((u32)sizeof(INDEX_ENTRY_HEADER) +
 352                                le16_to_cpu(ie->key_length) >
 353                                le16_to_cpu(ie->data.vi.data_offset) ||
 354                                (u32)le16_to_cpu(ie->data.vi.data_offset) +
 355                                le16_to_cpu(ie->data.vi.data_length) >
 356                                le16_to_cpu(ie->length)) {
 357                        ntfs_error(sb, "Index entry out of bounds in inode "
 358                                        "0x%lx.", idx_ni->mft_no);
 359                        goto unm_err_out;
 360                }
 361                /* If the keys match perfectly, we setup @ictx and return 0. */
 362                if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
 363                                &ie->key, key_len)) {
 364ia_done:
 365                        ictx->is_in_root = false;
 366                        ictx->actx = NULL;
 367                        ictx->base_ni = NULL;
 368                        ictx->ia = ia;
 369                        ictx->page = page;
 370                        goto done;
 371                }
 372                /*
 373                 * Not a perfect match, need to do full blown collation so we
 374                 * know which way in the B+tree we have to go.
 375                 */
 376                rc = ntfs_collate(vol, idx_ni->itype.index.collation_rule, key,
 377                                key_len, &ie->key, le16_to_cpu(ie->key_length));
 378                /*
 379                 * If @key collates before the key of the current entry, there
 380                 * is definitely no such key in this index but we might need to
 381                 * descend into the B+tree so we just break out of the loop.
 382                 */
 383                if (rc == -1)
 384                        break;
 385                /*
 386                 * A match should never happen as the memcmp() call should have
 387                 * cought it, but we still treat it correctly.
 388                 */
 389                if (!rc)
 390                        goto ia_done;
 391                /* The keys are not equal, continue the search. */
 392        }
 393        /*
 394         * We have finished with this index buffer without success.  Check for
 395         * the presence of a child node and if not present return -ENOENT.
 396         */
 397        if (!(ie->flags & INDEX_ENTRY_NODE)) {
 398                ntfs_debug("Entry not found.");
 399                err = -ENOENT;
 400                goto ia_done;
 401        }
 402        if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
 403                ntfs_error(sb, "Index entry with child node found in a leaf "
 404                                "node in inode 0x%lx.", idx_ni->mft_no);
 405                goto unm_err_out;
 406        }
 407        /* Child node present, descend into it. */
 408        old_vcn = vcn;
 409        vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
 410        if (vcn >= 0) {
 411                /*
 412                 * If vcn is in the same page cache page as old_vcn we recycle
 413                 * the mapped page.
 414                 */
 415                if (old_vcn << vol->cluster_size_bits >>
 416                                PAGE_SHIFT == vcn <<
 417                                vol->cluster_size_bits >>
 418                                PAGE_SHIFT)
 419                        goto fast_descend_into_child_node;
 420                unlock_page(page);
 421                ntfs_unmap_page(page);
 422                goto descend_into_child_node;
 423        }
 424        ntfs_error(sb, "Negative child node vcn in inode 0x%lx.",
 425                        idx_ni->mft_no);
 426unm_err_out:
 427        unlock_page(page);
 428        ntfs_unmap_page(page);
 429err_out:
 430        if (!err)
 431                err = -EIO;
 432        if (actx)
 433                ntfs_attr_put_search_ctx(actx);
 434        if (m)
 435                unmap_mft_record(base_ni);
 436        return err;
 437idx_err_out:
 438        ntfs_error(sb, "Corrupt index.  Aborting lookup.");
 439        goto err_out;
 440}
 441