uboot/fs/btrfs/inode.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * BTRFS filesystem implementation for U-Boot
   4 *
   5 * 2017 Marek BehĂșn, CZ.NIC, kabel@kernel.org
   6 */
   7
   8#include <linux/kernel.h>
   9#include <malloc.h>
  10#include <memalign.h>
  11#include "btrfs.h"
  12#include "disk-io.h"
  13#include "volumes.h"
  14
  15/*
  16 * Read the content of symlink inode @ino of @root, into @target.
  17 * NOTE: @target will not be \0 termiated, caller should handle it properly.
  18 *
  19 * Return the number of read data.
  20 * Return <0 for error.
  21 */
  22int btrfs_readlink(struct btrfs_root *root, u64 ino, char *target)
  23{
  24        struct btrfs_path path;
  25        struct btrfs_key key;
  26        struct btrfs_file_extent_item *fi;
  27        int ret;
  28
  29        key.objectid = ino;
  30        key.type = BTRFS_EXTENT_DATA_KEY;
  31        key.offset = 0;
  32        btrfs_init_path(&path);
  33
  34        ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
  35        if (ret < 0)
  36                return ret;
  37        if (ret > 0) {
  38                ret = -ENOENT;
  39                goto out;
  40        }
  41        fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
  42                            struct btrfs_file_extent_item);
  43        if (btrfs_file_extent_type(path.nodes[0], fi) !=
  44            BTRFS_FILE_EXTENT_INLINE) {
  45                ret = -EUCLEAN;
  46                error("Extent for symlink %llu must be INLINE type!", ino);
  47                goto out;
  48        }
  49        if (btrfs_file_extent_compression(path.nodes[0], fi) !=
  50            BTRFS_COMPRESS_NONE) {
  51                ret = -EUCLEAN;
  52                error("Extent for symlink %llu must not be compressed!", ino);
  53                goto out;
  54        }
  55        if (btrfs_file_extent_ram_bytes(path.nodes[0], fi) >=
  56            root->fs_info->sectorsize) {
  57                ret = -EUCLEAN;
  58                error("Symlink %llu extent data too large (%llu)!\n",
  59                        ino, btrfs_file_extent_ram_bytes(path.nodes[0], fi));
  60                goto out;
  61        }
  62        read_extent_buffer(path.nodes[0], target,
  63                        btrfs_file_extent_inline_start(fi),
  64                        btrfs_file_extent_ram_bytes(path.nodes[0], fi));
  65        ret = btrfs_file_extent_ram_bytes(path.nodes[0], fi);
  66out:
  67        btrfs_release_path(&path);
  68        return ret;
  69}
  70
  71static int lookup_root_ref(struct btrfs_fs_info *fs_info,
  72                           u64 rootid, u64 *root_ret, u64 *dir_ret)
  73{
  74        struct btrfs_root *root = fs_info->tree_root;
  75        struct btrfs_root_ref *root_ref;
  76        struct btrfs_path path;
  77        struct btrfs_key key;
  78        int ret;
  79
  80        btrfs_init_path(&path);
  81        key.objectid = rootid;
  82        key.type = BTRFS_ROOT_BACKREF_KEY;
  83        key.offset = (u64)-1;
  84
  85        ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
  86        if (ret < 0)
  87                return ret;
  88        /* Should not happen */
  89        if (ret == 0) {
  90                ret = -EUCLEAN;
  91                goto out;
  92        }
  93        ret = btrfs_previous_item(root, &path, rootid, BTRFS_ROOT_BACKREF_KEY);
  94        if (ret < 0)
  95                goto out;
  96        if (ret > 0) {
  97                ret = -ENOENT;
  98                goto out;
  99        }
 100        btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
 101        root_ref = btrfs_item_ptr(path.nodes[0], path.slots[0],
 102                                  struct btrfs_root_ref);
 103        *root_ret = key.offset;
 104        *dir_ret = btrfs_root_ref_dirid(path.nodes[0], root_ref);
 105out:
 106        btrfs_release_path(&path);
 107        return ret;
 108}
 109
 110/*
 111 * To get the parent inode of @ino of @root.
 112 *
 113 * @root_ret and @ino_ret will be filled.
 114 *
 115 * NOTE: This function is not reliable. It can only get one parent inode.
 116 * The get the proper parent inode, we need a full VFS inodes stack to
 117 * resolve properly.
 118 */
 119static int get_parent_inode(struct btrfs_root *root, u64 ino,
 120                            struct btrfs_root **root_ret, u64 *ino_ret)
 121{
 122        struct btrfs_fs_info *fs_info = root->fs_info;
 123        struct btrfs_path path;
 124        struct btrfs_key key;
 125        int ret;
 126
 127        if (ino == BTRFS_FIRST_FREE_OBJECTID) {
 128                u64 parent_root = -1;
 129
 130                /* It's top level already, no more parent */
 131                if (root->root_key.objectid == BTRFS_FS_TREE_OBJECTID) {
 132                        *root_ret = fs_info->fs_root;
 133                        *ino_ret = BTRFS_FIRST_FREE_OBJECTID;
 134                        return 0;
 135                }
 136
 137                ret = lookup_root_ref(fs_info, root->root_key.objectid,
 138                                      &parent_root, ino_ret);
 139                if (ret < 0)
 140                        return ret;
 141
 142                key.objectid = parent_root;
 143                key.type = BTRFS_ROOT_ITEM_KEY;
 144                key.offset = (u64)-1;
 145                *root_ret = btrfs_read_fs_root(fs_info, &key);
 146                if (IS_ERR(*root_ret))
 147                        return PTR_ERR(*root_ret);
 148
 149                return 0;
 150        }
 151
 152        btrfs_init_path(&path);
 153        key.objectid = ino;
 154        key.type = BTRFS_INODE_REF_KEY;
 155        key.offset = (u64)-1;
 156
 157        ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
 158        if (ret < 0)
 159                return ret;
 160        /* Should not happen */
 161        if (ret == 0) {
 162                ret = -EUCLEAN;
 163                goto out;
 164        }
 165        ret = btrfs_previous_item(root, &path, ino, BTRFS_INODE_REF_KEY);
 166        if (ret < 0)
 167                goto out;
 168        if (ret > 0) {
 169                ret = -ENOENT;
 170                goto out;
 171        }
 172        btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
 173        *root_ret = root;
 174        *ino_ret = key.offset;
 175out:
 176        btrfs_release_path(&path);
 177        return ret;
 178}
 179
 180static inline int next_length(const char *path)
 181{
 182        int res = 0;
 183        while (*path != '\0' && *path != '/') {
 184                ++res;
 185                ++path;
 186                if (res > BTRFS_NAME_LEN)
 187                        break;
 188        }
 189        return res;
 190}
 191
 192static inline const char *skip_current_directories(const char *cur)
 193{
 194        while (1) {
 195                if (cur[0] == '/')
 196                        ++cur;
 197                else if (cur[0] == '.' && cur[1] == '/')
 198                        cur += 2;
 199                else
 200                        break;
 201        }
 202
 203        return cur;
 204}
 205
 206/*
 207 * Resolve one filename of @ino of @root.
 208 *
 209 * key_ret:     The child key (either INODE_ITEM or ROOT_ITEM type)
 210 * type_ret:    BTRFS_FT_* of the child inode.
 211 *
 212 * Return 0 with above members filled.
 213 * Return <0 for error.
 214 */
 215static int resolve_one_filename(struct btrfs_root *root, u64 ino,
 216                                const char *name, int namelen,
 217                                struct btrfs_key *key_ret, u8 *type_ret)
 218{
 219        struct btrfs_dir_item *dir_item;
 220        struct btrfs_path path;
 221        int ret = 0;
 222
 223        btrfs_init_path(&path);
 224
 225        dir_item = btrfs_lookup_dir_item(NULL, root, &path, ino, name,
 226                                         namelen, 0);
 227        if (IS_ERR(dir_item)) {
 228                ret = PTR_ERR(dir_item);
 229                goto out;
 230        }
 231
 232        btrfs_dir_item_key_to_cpu(path.nodes[0], dir_item, key_ret);
 233        *type_ret = btrfs_dir_type(path.nodes[0], dir_item);
 234out:
 235        btrfs_release_path(&path);
 236        return ret;
 237}
 238
 239/*
 240 * Resolve a full path @filename. The start point is @ino of @root.
 241 *
 242 * The result will be filled into @root_ret, @ino_ret and @type_ret.
 243 */
 244int btrfs_lookup_path(struct btrfs_root *root, u64 ino, const char *filename,
 245                        struct btrfs_root **root_ret, u64 *ino_ret,
 246                        u8 *type_ret, int symlink_limit)
 247{
 248        struct btrfs_fs_info *fs_info = root->fs_info;
 249        struct btrfs_root *next_root;
 250        struct btrfs_key key;
 251        const char *cur = filename;
 252        u64 next_ino;
 253        u8 next_type;
 254        u8 type = BTRFS_FT_UNKNOWN;
 255        int len;
 256        int ret = 0;
 257
 258        /* If the path is absolute path, also search from fs root */
 259        if (*cur == '/') {
 260                root = fs_info->fs_root;
 261                ino = btrfs_root_dirid(&root->root_item);
 262                type = BTRFS_FT_DIR;
 263        }
 264
 265        while (*cur != '\0') {
 266                cur = skip_current_directories(cur);
 267
 268                len = next_length(cur);
 269                if (len > BTRFS_NAME_LEN) {
 270                        error("%s: Name too long at \"%.*s\"", __func__,
 271                               BTRFS_NAME_LEN, cur);
 272                        return -ENAMETOOLONG;
 273                }
 274
 275                if (len == 1 && cur[0] == '.')
 276                        break;
 277
 278                if (len == 2 && cur[0] == '.' && cur[1] == '.') {
 279                        /* Go one level up */
 280                        ret = get_parent_inode(root, ino, &next_root, &next_ino);
 281                        if (ret < 0)
 282                                return ret;
 283                        root = next_root;
 284                        ino = next_ino;
 285                        goto next;
 286                }
 287
 288                if (!*cur)
 289                        break;
 290
 291                ret = resolve_one_filename(root, ino, cur, len, &key, &type);
 292                if (ret < 0)
 293                        return ret;
 294
 295                if (key.type == BTRFS_ROOT_ITEM_KEY) {
 296                        /* Child inode is a subvolume */
 297
 298                        next_root = btrfs_read_fs_root(fs_info, &key);
 299                        if (IS_ERR(next_root))
 300                                return PTR_ERR(next_root);
 301                        root = next_root;
 302                        ino = btrfs_root_dirid(&root->root_item);
 303                } else if (type == BTRFS_FT_SYMLINK && symlink_limit >= 0) {
 304                        /* Child inode is a symlink */
 305
 306                        char *target;
 307
 308                        if (symlink_limit == 0) {
 309                                error("%s: Too much symlinks!", __func__);
 310                                return -EMLINK;
 311                        }
 312                        target = malloc(fs_info->sectorsize);
 313                        if (!target)
 314                                return -ENOMEM;
 315                        ret = btrfs_readlink(root, key.objectid, target);
 316                        if (ret < 0) {
 317                                free(target);
 318                                return ret;
 319                        }
 320                        target[ret] = '\0';
 321
 322                        ret = btrfs_lookup_path(root, ino, target, &next_root,
 323                                                &next_ino, &next_type,
 324                                                symlink_limit);
 325                        if (ret < 0)
 326                                return ret;
 327                        root = next_root;
 328                        ino = next_ino;
 329                        type = next_type;
 330                } else {
 331                        /* Child inode is an inode */
 332                        ino = key.objectid;
 333                }
 334next:
 335                cur += len;
 336        }
 337
 338        /* We haven't found anything, but still get no error? */
 339        if (type == BTRFS_FT_UNKNOWN && !ret)
 340                ret = -EUCLEAN;
 341
 342        if (!ret) {
 343                *root_ret = root;
 344                *ino_ret = ino;
 345                *type_ret = type;
 346        }
 347
 348        return ret;
 349}
 350
 351/*
 352 * Read out inline extent.
 353 *
 354 * Since inline extent should only exist for offset 0, no need for extra
 355 * parameters.
 356 * Truncating should be handled by the caller.
 357 *
 358 * Return the number of bytes read.
 359 * Return <0 for error.
 360 */
 361int btrfs_read_extent_inline(struct btrfs_path *path,
 362                             struct btrfs_file_extent_item *fi, char *dest)
 363{
 364        struct extent_buffer *leaf = path->nodes[0];
 365        int slot = path->slots[0];
 366        char *cbuf = NULL;
 367        char *dbuf = NULL;
 368        u32 csize;
 369        u32 dsize;
 370        int ret;
 371
 372        csize = btrfs_file_extent_inline_item_len(leaf, btrfs_item_nr(slot));
 373        if (btrfs_file_extent_compression(leaf, fi) == BTRFS_COMPRESS_NONE) {
 374                /* Uncompressed, just read it out */
 375                read_extent_buffer(leaf, dest,
 376                                btrfs_file_extent_inline_start(fi),
 377                                csize);
 378                return csize;
 379        }
 380
 381        /* Compressed extent, prepare the compressed and data buffer */
 382        dsize = btrfs_file_extent_ram_bytes(leaf, fi);
 383        cbuf = malloc(csize);
 384        dbuf = malloc(dsize);
 385        if (!cbuf || !dbuf) {
 386                ret = -ENOMEM;
 387                goto out;
 388        }
 389        read_extent_buffer(leaf, cbuf, btrfs_file_extent_inline_start(fi),
 390                           csize);
 391        ret = btrfs_decompress(btrfs_file_extent_compression(leaf, fi),
 392                               cbuf, csize, dbuf, dsize);
 393        if (ret < 0) {
 394                ret = -EIO;
 395                goto out;
 396        }
 397        /*
 398         * The compressed part ends before sector boundary, the remaining needs
 399         * to be zeroed out.
 400         */
 401        if (ret < dsize)
 402                memset(dbuf + ret, 0, dsize - ret);
 403        memcpy(dest, dbuf, dsize);
 404        ret = dsize;
 405out:
 406        free(cbuf);
 407        free(dbuf);
 408        return ret;
 409}
 410
 411/*
 412 * Read out regular extent.
 413 *
 414 * Truncating should be handled by the caller.
 415 *
 416 * @offset and @len should not cross the extent boundary.
 417 * Return the number of bytes read.
 418 * Return <0 for error.
 419 */
 420int btrfs_read_extent_reg(struct btrfs_path *path,
 421                          struct btrfs_file_extent_item *fi, u64 offset,
 422                          int len, char *dest)
 423{
 424        struct extent_buffer *leaf = path->nodes[0];
 425        struct btrfs_fs_info *fs_info = leaf->fs_info;
 426        struct btrfs_key key;
 427        u64 extent_num_bytes;
 428        u64 disk_bytenr;
 429        u64 read;
 430        char *cbuf = NULL;
 431        char *dbuf = NULL;
 432        u32 csize;
 433        u32 dsize;
 434        bool finished = false;
 435        int num_copies;
 436        int i;
 437        int slot = path->slots[0];
 438        int ret;
 439
 440        btrfs_item_key_to_cpu(leaf, &key, slot);
 441        extent_num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
 442        ASSERT(IS_ALIGNED(offset, fs_info->sectorsize) &&
 443               IS_ALIGNED(len, fs_info->sectorsize));
 444        ASSERT(offset >= key.offset &&
 445               offset + len <= key.offset + extent_num_bytes);
 446
 447        /* Preallocated or hole , fill @dest with zero */
 448        if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_PREALLOC ||
 449            btrfs_file_extent_disk_bytenr(leaf, fi) == 0) {
 450                memset(dest, 0, len);
 451                return len;
 452        }
 453
 454        if (btrfs_file_extent_compression(leaf, fi) == BTRFS_COMPRESS_NONE) {
 455                u64 logical;
 456
 457                logical = btrfs_file_extent_disk_bytenr(leaf, fi) +
 458                          btrfs_file_extent_offset(leaf, fi) +
 459                          offset - key.offset;
 460                read = len;
 461
 462                num_copies = btrfs_num_copies(fs_info, logical, len);
 463                for (i = 1; i <= num_copies; i++) {
 464                        ret = read_extent_data(fs_info, dest, logical, &read, i);
 465                        if (ret < 0 || read != len)
 466                                continue;
 467                        finished = true;
 468                        break;
 469                }
 470                if (!finished)
 471                        return -EIO;
 472                return len;
 473        }
 474
 475        csize = btrfs_file_extent_disk_num_bytes(leaf, fi);
 476        dsize = btrfs_file_extent_ram_bytes(leaf, fi);
 477        disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
 478        num_copies = btrfs_num_copies(fs_info, disk_bytenr, csize);
 479
 480        cbuf = malloc_cache_aligned(csize);
 481        dbuf = malloc_cache_aligned(dsize);
 482        if (!cbuf || !dbuf) {
 483                ret = -ENOMEM;
 484                goto out;
 485        }
 486        /* For compressed extent, we must read the whole on-disk extent */
 487        for (i = 1; i <= num_copies; i++) {
 488                read = csize;
 489                ret = read_extent_data(fs_info, cbuf, disk_bytenr,
 490                                       &read, i);
 491                if (ret < 0 || read != csize)
 492                        continue;
 493                finished = true;
 494                break;
 495        }
 496        if (!finished) {
 497                ret = -EIO;
 498                goto out;
 499        }
 500
 501        ret = btrfs_decompress(btrfs_file_extent_compression(leaf, fi), cbuf,
 502                               csize, dbuf, dsize);
 503        if (ret < 0) {
 504                ret = -EIO;
 505                goto out;
 506        }
 507        /*
 508         * The compressed part ends before sector boundary, the remaining needs
 509         * to be zeroed out.
 510         */
 511        if (ret < dsize)
 512                memset(dbuf + ret, 0, dsize - ret);
 513        /* Then copy the needed part */
 514        memcpy(dest,
 515               dbuf + btrfs_file_extent_offset(leaf, fi) + offset - key.offset,
 516               len);
 517        ret = len;
 518out:
 519        free(cbuf);
 520        free(dbuf);
 521        return ret;
 522}
 523
 524/*
 525 * Get the first file extent that covers bytenr @file_offset.
 526 *
 527 * @file_offset must be aligned to sectorsize.
 528 *
 529 * return 0 for found, and path points to the file extent.
 530 * return >0 for not found, and fill @next_offset.
 531 * @next_offset can be 0 if there is no next file extent.
 532 * return <0 for error.
 533 */
 534static int lookup_data_extent(struct btrfs_root *root, struct btrfs_path *path,
 535                              u64 ino, u64 file_offset, u64 *next_offset)
 536{
 537        struct btrfs_key key;
 538        struct btrfs_file_extent_item *fi;
 539        u8 extent_type;
 540        int ret = 0;
 541
 542        ASSERT(IS_ALIGNED(file_offset, root->fs_info->sectorsize));
 543        key.objectid = ino;
 544        key.type = BTRFS_EXTENT_DATA_KEY;
 545        key.offset = file_offset;
 546
 547        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 548        /* Error or we're already at the file extent */
 549        if (ret <= 0)
 550                return ret;
 551        /* Check previous file extent */
 552        ret = btrfs_previous_item(root, path, ino, BTRFS_EXTENT_DATA_KEY);
 553        if (ret < 0)
 554                return ret;
 555        if (ret > 0)
 556                goto check_next;
 557        /* Now the key.offset must be smaller than @file_offset */
 558        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
 559        if (key.objectid != ino ||
 560            key.type != BTRFS_EXTENT_DATA_KEY)
 561                goto check_next;
 562
 563        fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
 564                            struct btrfs_file_extent_item);
 565        extent_type = btrfs_file_extent_type(path->nodes[0], fi);
 566        if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
 567                if (file_offset == 0)
 568                        return 0;
 569                /* Inline extent should be the only extent, no next extent. */
 570                *next_offset = 0;
 571                return 1;
 572        }
 573
 574        /* This file extent covers @file_offset */
 575        if (key.offset <= file_offset && key.offset +
 576            btrfs_file_extent_num_bytes(path->nodes[0], fi) > file_offset)
 577                return 0;
 578check_next:
 579        ret = btrfs_next_item(root, path);
 580        if (ret < 0)
 581                return ret;
 582        if (ret > 0) {
 583                *next_offset = 0;
 584                return 1;
 585        }
 586
 587        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
 588        fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
 589                            struct btrfs_file_extent_item);
 590        /* Next next data extent */
 591        if (key.objectid != ino ||
 592            key.type != BTRFS_EXTENT_DATA_KEY) {
 593                *next_offset = 0;
 594                return 1;
 595        }
 596        /* Current file extent already beyond @file_offset */
 597        if (key.offset > file_offset) {
 598                *next_offset = key.offset;
 599                return 1;
 600        }
 601        /* This file extent covers @file_offset */
 602        if (key.offset <= file_offset && key.offset +
 603            btrfs_file_extent_num_bytes(path->nodes[0], fi) > file_offset)
 604                return 0;
 605        /* This file extent ends before @file_offset, check next */
 606        ret = btrfs_next_item(root, path);
 607        if (ret < 0)
 608                return ret;
 609        if (ret > 0) {
 610                *next_offset = 0;
 611                return 1;
 612        }
 613        btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
 614        if (key.type != BTRFS_EXTENT_DATA_KEY || key.objectid != ino) {
 615                *next_offset = 0;
 616                return 1;
 617        }
 618        *next_offset = key.offset;
 619        return 1;
 620}
 621
 622static int read_and_truncate_page(struct btrfs_path *path,
 623                                  struct btrfs_file_extent_item *fi,
 624                                  int start, int len, char *dest)
 625{
 626        struct extent_buffer *leaf = path->nodes[0];
 627        struct btrfs_fs_info *fs_info = leaf->fs_info;
 628        u64 aligned_start = round_down(start, fs_info->sectorsize);
 629        u8 extent_type;
 630        char *buf;
 631        int page_off = start - aligned_start;
 632        int page_len = fs_info->sectorsize - page_off;
 633        int ret;
 634
 635        ASSERT(start + len <= aligned_start + fs_info->sectorsize);
 636        buf = malloc_cache_aligned(fs_info->sectorsize);
 637        if (!buf)
 638                return -ENOMEM;
 639
 640        extent_type = btrfs_file_extent_type(leaf, fi);
 641        if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
 642                ret = btrfs_read_extent_inline(path, fi, buf);
 643                if (ret < 0) {
 644                        free(buf);
 645                        return ret;
 646                }
 647                memcpy(dest, buf + page_off, min3(page_len, ret, len));
 648                free(buf);
 649                return len;
 650        }
 651
 652        ret = btrfs_read_extent_reg(path, fi,
 653                        round_down(start, fs_info->sectorsize),
 654                        fs_info->sectorsize, buf);
 655        if (ret < 0) {
 656                free(buf);
 657                return ret;
 658        }
 659        memcpy(dest, buf + page_off, min(page_len, len));
 660        free(buf);
 661        return len;
 662}
 663
 664int btrfs_file_read(struct btrfs_root *root, u64 ino, u64 file_offset, u64 len,
 665                    char *dest)
 666{
 667        struct btrfs_fs_info *fs_info = root->fs_info;
 668        struct btrfs_file_extent_item *fi;
 669        struct btrfs_path path;
 670        struct btrfs_key key;
 671        u64 aligned_start = round_down(file_offset, fs_info->sectorsize);
 672        u64 aligned_end = round_down(file_offset + len, fs_info->sectorsize);
 673        u64 next_offset;
 674        u64 cur = aligned_start;
 675        int ret = 0;
 676
 677        btrfs_init_path(&path);
 678
 679        /* Set the whole dest all zero, so we won't need to bother holes */
 680        memset(dest, 0, len);
 681
 682        /* Read out the leading unaligned part */
 683        if (aligned_start != file_offset) {
 684                ret = lookup_data_extent(root, &path, ino, aligned_start,
 685                                         &next_offset);
 686                if (ret < 0)
 687                        goto out;
 688                if (ret == 0) {
 689                        /* Read the unaligned part out*/
 690                        fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
 691                                        struct btrfs_file_extent_item);
 692                        ret = read_and_truncate_page(&path, fi, file_offset,
 693                                        round_up(file_offset, fs_info->sectorsize) -
 694                                        file_offset, dest);
 695                        if (ret < 0)
 696                                goto out;
 697                        cur += fs_info->sectorsize;
 698                } else {
 699                        /* The whole file is a hole */
 700                        if (!next_offset) {
 701                                memset(dest, 0, len);
 702                                return len;
 703                        }
 704                        cur = next_offset;
 705                }
 706        }
 707
 708        /* Read the aligned part */
 709        while (cur < aligned_end) {
 710                u64 extent_num_bytes;
 711                u8 type;
 712
 713                btrfs_release_path(&path);
 714                ret = lookup_data_extent(root, &path, ino, cur, &next_offset);
 715                if (ret < 0)
 716                        goto out;
 717                if (ret > 0) {
 718                        /* No next, direct exit */
 719                        if (!next_offset) {
 720                                ret = 0;
 721                                goto out;
 722                        }
 723                        /*
 724                         * Find a extent gap, mostly caused by NO_HOLE feature.
 725                         * Just to next offset directly.
 726                         */
 727                        if (next_offset > cur) {
 728                                cur = next_offset;
 729                                continue;
 730                        }
 731                }
 732                fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
 733                                    struct btrfs_file_extent_item);
 734                btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
 735                type = btrfs_file_extent_type(path.nodes[0], fi);
 736                if (type == BTRFS_FILE_EXTENT_INLINE) {
 737                        ret = btrfs_read_extent_inline(&path, fi, dest);
 738                        goto out;
 739                }
 740                /* Skip holes, as we have zeroed the dest */
 741                if (type == BTRFS_FILE_EXTENT_PREALLOC ||
 742                    btrfs_file_extent_disk_bytenr(path.nodes[0], fi) == 0) {
 743                        cur = key.offset + btrfs_file_extent_num_bytes(
 744                                        path.nodes[0], fi);
 745                        continue;
 746                }
 747
 748                /* Read the remaining part of the extent */
 749                extent_num_bytes = btrfs_file_extent_num_bytes(path.nodes[0],
 750                                                               fi);
 751                ret = btrfs_read_extent_reg(&path, fi, cur,
 752                                min(extent_num_bytes, aligned_end - cur),
 753                                dest + cur - file_offset);
 754                if (ret < 0)
 755                        goto out;
 756                cur += min(extent_num_bytes, aligned_end - cur);
 757        }
 758
 759        /* Read the tailing unaligned part*/
 760        if (file_offset + len != aligned_end) {
 761                btrfs_release_path(&path);
 762                ret = lookup_data_extent(root, &path, ino, aligned_end,
 763                                         &next_offset);
 764                /* <0 is error, >0 means no extent */
 765                if (ret)
 766                        goto out;
 767                fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
 768                                    struct btrfs_file_extent_item);
 769                ret = read_and_truncate_page(&path, fi, aligned_end,
 770                                file_offset + len - aligned_end,
 771                                dest + aligned_end - file_offset);
 772        }
 773out:
 774        btrfs_release_path(&path);
 775        if (ret < 0)
 776                return ret;
 777        return len;
 778}
 779