1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2017 Oracle. All Rights Reserved. 4 * 5 * Author: Darrick J. Wong <darrick.wong@oracle.com> 6 */ 7 #include "ext4.h" 8 #include <linux/fsmap.h> 9 #include "fsmap.h" 10 #include "mballoc.h" 11 #include <linux/sort.h> 12 #include <linux/list_sort.h> 13 #include <trace/events/ext4.h> 14 15 /* Convert an ext4_fsmap to an fsmap. */ 16 void ext4_fsmap_from_internal(struct super_block *sb, struct fsmap *dest, 17 struct ext4_fsmap *src) 18 { 19 dest->fmr_device = src->fmr_device; 20 dest->fmr_flags = src->fmr_flags; 21 dest->fmr_physical = src->fmr_physical << sb->s_blocksize_bits; 22 dest->fmr_owner = src->fmr_owner; 23 dest->fmr_offset = 0; 24 dest->fmr_length = src->fmr_length << sb->s_blocksize_bits; 25 dest->fmr_reserved[0] = 0; 26 dest->fmr_reserved[1] = 0; 27 dest->fmr_reserved[2] = 0; 28 } 29 30 /* Convert an fsmap to an ext4_fsmap. */ 31 void ext4_fsmap_to_internal(struct super_block *sb, struct ext4_fsmap *dest, 32 struct fsmap *src) 33 { 34 dest->fmr_device = src->fmr_device; 35 dest->fmr_flags = src->fmr_flags; 36 dest->fmr_physical = src->fmr_physical >> sb->s_blocksize_bits; 37 dest->fmr_owner = src->fmr_owner; 38 dest->fmr_length = src->fmr_length >> sb->s_blocksize_bits; 39 } 40 41 /* getfsmap query state */ 42 struct ext4_getfsmap_info { 43 struct ext4_fsmap_head *gfi_head; 44 ext4_fsmap_format_t gfi_formatter; /* formatting fn */ 45 void *gfi_format_arg;/* format buffer */ 46 ext4_fsblk_t gfi_next_fsblk; /* next fsblock we expect */ 47 u32 gfi_dev; /* device id */ 48 ext4_group_t gfi_agno; /* bg number, if applicable */ 49 struct ext4_fsmap gfi_low; /* low rmap key */ 50 struct ext4_fsmap gfi_high; /* high rmap key */ 51 struct ext4_fsmap gfi_lastfree; /* free ext at end of last bg */ 52 struct list_head gfi_meta_list; /* fixed metadata list */ 53 bool gfi_last; /* last extent? */ 54 }; 55 56 /* Associate a device with a getfsmap handler. */ 57 struct ext4_getfsmap_dev { 58 int (*gfd_fn)(struct super_block *sb, 59 struct ext4_fsmap *keys, 60 struct ext4_getfsmap_info *info); 61 u32 gfd_dev; 62 }; 63 64 /* Compare two getfsmap device handlers. */ 65 static int ext4_getfsmap_dev_compare(const void *p1, const void *p2) 66 { 67 const struct ext4_getfsmap_dev *d1 = p1; 68 const struct ext4_getfsmap_dev *d2 = p2; 69 70 return d1->gfd_dev - d2->gfd_dev; 71 } 72 73 /* Compare a record against our starting point */ 74 static bool ext4_getfsmap_rec_before_low_key(struct ext4_getfsmap_info *info, 75 struct ext4_fsmap *rec) 76 { 77 return rec->fmr_physical + rec->fmr_length <= 78 info->gfi_low.fmr_physical; 79 } 80 81 /* 82 * Format a reverse mapping for getfsmap, having translated rm_startblock 83 * into the appropriate daddr units. 84 */ 85 static int ext4_getfsmap_helper(struct super_block *sb, 86 struct ext4_getfsmap_info *info, 87 struct ext4_fsmap *rec) 88 { 89 struct ext4_fsmap fmr; 90 struct ext4_sb_info *sbi = EXT4_SB(sb); 91 ext4_fsblk_t rec_fsblk = rec->fmr_physical; 92 ext4_group_t agno; 93 ext4_grpblk_t cno; 94 int error; 95 96 if (fatal_signal_pending(current)) 97 return -EINTR; 98 99 /* 100 * Filter out records that start before our startpoint, if the 101 * caller requested that. 102 */ 103 if (ext4_getfsmap_rec_before_low_key(info, rec)) { 104 rec_fsblk += rec->fmr_length; 105 if (info->gfi_next_fsblk < rec_fsblk) 106 info->gfi_next_fsblk = rec_fsblk; 107 return EXT4_QUERY_RANGE_CONTINUE; 108 } 109 110 /* Are we just counting mappings? */ 111 if (info->gfi_head->fmh_count == 0) { 112 if (info->gfi_head->fmh_entries == UINT_MAX) 113 return EXT4_QUERY_RANGE_ABORT; 114 115 if (rec_fsblk > info->gfi_next_fsblk) 116 info->gfi_head->fmh_entries++; 117 118 if (info->gfi_last) 119 return EXT4_QUERY_RANGE_CONTINUE; 120 121 info->gfi_head->fmh_entries++; 122 123 rec_fsblk += rec->fmr_length; 124 if (info->gfi_next_fsblk < rec_fsblk) 125 info->gfi_next_fsblk = rec_fsblk; 126 return EXT4_QUERY_RANGE_CONTINUE; 127 } 128 129 /* 130 * If the record starts past the last physical block we saw, 131 * then we've found a gap. Report the gap as being owned by 132 * whatever the caller specified is the missing owner. 133 */ 134 if (rec_fsblk > info->gfi_next_fsblk) { 135 if (info->gfi_head->fmh_entries >= info->gfi_head->fmh_count) 136 return EXT4_QUERY_RANGE_ABORT; 137 138 ext4_get_group_no_and_offset(sb, info->gfi_next_fsblk, 139 &agno, &cno); 140 trace_ext4_fsmap_mapping(sb, info->gfi_dev, agno, 141 EXT4_C2B(sbi, cno), 142 rec_fsblk - info->gfi_next_fsblk, 143 EXT4_FMR_OWN_UNKNOWN); 144 145 fmr.fmr_device = info->gfi_dev; 146 fmr.fmr_physical = info->gfi_next_fsblk; 147 fmr.fmr_owner = EXT4_FMR_OWN_UNKNOWN; 148 fmr.fmr_length = rec_fsblk - info->gfi_next_fsblk; 149 fmr.fmr_flags = FMR_OF_SPECIAL_OWNER; 150 error = info->gfi_formatter(&fmr, info->gfi_format_arg); 151 if (error) 152 return error; 153 info->gfi_head->fmh_entries++; 154 } 155 156 if (info->gfi_last) 157 goto out; 158 159 /* Fill out the extent we found */ 160 if (info->gfi_head->fmh_entries >= info->gfi_head->fmh_count) 161 return EXT4_QUERY_RANGE_ABORT; 162 163 ext4_get_group_no_and_offset(sb, rec_fsblk, &agno, &cno); 164 trace_ext4_fsmap_mapping(sb, info->gfi_dev, agno, EXT4_C2B(sbi, cno), 165 rec->fmr_length, rec->fmr_owner); 166 167 fmr.fmr_device = info->gfi_dev; 168 fmr.fmr_physical = rec_fsblk; 169 fmr.fmr_owner = rec->fmr_owner; 170 fmr.fmr_flags = FMR_OF_SPECIAL_OWNER; 171 fmr.fmr_length = rec->fmr_length; 172 error = info->gfi_formatter(&fmr, info->gfi_format_arg); 173 if (error) 174 return error; 175 info->gfi_head->fmh_entries++; 176 177 out: 178 rec_fsblk += rec->fmr_length; 179 if (info->gfi_next_fsblk < rec_fsblk) 180 info->gfi_next_fsblk = rec_fsblk; 181 return EXT4_QUERY_RANGE_CONTINUE; 182 } 183 184 static inline ext4_fsblk_t ext4_fsmap_next_pblk(struct ext4_fsmap *fmr) 185 { 186 return fmr->fmr_physical + fmr->fmr_length; 187 } 188 189 static int ext4_getfsmap_meta_helper(struct super_block *sb, 190 ext4_group_t agno, ext4_grpblk_t start, 191 ext4_grpblk_t len, void *priv) 192 { 193 struct ext4_getfsmap_info *info = priv; 194 struct ext4_fsmap *p; 195 struct ext4_fsmap *tmp; 196 struct ext4_sb_info *sbi = EXT4_SB(sb); 197 ext4_fsblk_t fsb, fs_start, fs_end; 198 int error; 199 200 fs_start = fsb = (EXT4_C2B(sbi, start) + 201 ext4_group_first_block_no(sb, agno)); 202 fs_end = fs_start + EXT4_C2B(sbi, len); 203 204 /* 205 * Return relevant extents from the meta_list. We emit all extents that 206 * partially/fully overlap with the query range 207 */ 208 list_for_each_entry_safe(p, tmp, &info->gfi_meta_list, fmr_list) { 209 if (p->fmr_physical + p->fmr_length <= info->gfi_next_fsblk) { 210 list_del(&p->fmr_list); 211 kfree(p); 212 continue; 213 } 214 if (p->fmr_physical <= fs_end && 215 p->fmr_physical + p->fmr_length > fs_start) { 216 /* Emit the retained free extent record if present */ 217 if (info->gfi_lastfree.fmr_owner) { 218 error = ext4_getfsmap_helper(sb, info, 219 &info->gfi_lastfree); 220 if (error) 221 return error; 222 info->gfi_lastfree.fmr_owner = 0; 223 } 224 error = ext4_getfsmap_helper(sb, info, p); 225 if (error) 226 return error; 227 fsb = p->fmr_physical + p->fmr_length; 228 if (info->gfi_next_fsblk < fsb) 229 info->gfi_next_fsblk = fsb; 230 list_del(&p->fmr_list); 231 kfree(p); 232 continue; 233 } 234 } 235 if (info->gfi_next_fsblk < fsb) 236 info->gfi_next_fsblk = fsb; 237 238 return 0; 239 } 240 241 242 /* Transform a blockgroup's free record into a fsmap */ 243 static int ext4_getfsmap_datadev_helper(struct super_block *sb, 244 ext4_group_t agno, ext4_grpblk_t start, 245 ext4_grpblk_t len, void *priv) 246 { 247 struct ext4_fsmap irec; 248 struct ext4_getfsmap_info *info = priv; 249 struct ext4_fsmap *p; 250 struct ext4_fsmap *tmp; 251 struct ext4_sb_info *sbi = EXT4_SB(sb); 252 ext4_fsblk_t fsb; 253 ext4_fsblk_t fslen; 254 int error; 255 256 fsb = (EXT4_C2B(sbi, start) + ext4_group_first_block_no(sb, agno)); 257 fslen = EXT4_C2B(sbi, len); 258 259 /* If the retained free extent record is set... */ 260 if (info->gfi_lastfree.fmr_owner) { 261 /* ...and abuts this one, lengthen it and return. */ 262 if (ext4_fsmap_next_pblk(&info->gfi_lastfree) == fsb) { 263 info->gfi_lastfree.fmr_length += fslen; 264 return 0; 265 } 266 267 /* 268 * There's a gap between the two free extents; emit the 269 * retained extent prior to merging the meta_list. 270 */ 271 error = ext4_getfsmap_helper(sb, info, &info->gfi_lastfree); 272 if (error) 273 return error; 274 info->gfi_lastfree.fmr_owner = 0; 275 } 276 277 /* Merge in any relevant extents from the meta_list */ 278 list_for_each_entry_safe(p, tmp, &info->gfi_meta_list, fmr_list) { 279 if (p->fmr_physical + p->fmr_length <= info->gfi_next_fsblk) { 280 list_del(&p->fmr_list); 281 kfree(p); 282 } else if (p->fmr_physical < fsb) { 283 error = ext4_getfsmap_helper(sb, info, p); 284 if (error) 285 return error; 286 287 list_del(&p->fmr_list); 288 kfree(p); 289 } 290 } 291 292 irec.fmr_device = 0; 293 irec.fmr_physical = fsb; 294 irec.fmr_length = fslen; 295 irec.fmr_owner = EXT4_FMR_OWN_FREE; 296 irec.fmr_flags = 0; 297 298 /* If this is a free extent at the end of a bg, buffer it. */ 299 if (ext4_fsmap_next_pblk(&irec) == 300 ext4_group_first_block_no(sb, agno + 1)) { 301 info->gfi_lastfree = irec; 302 return 0; 303 } 304 305 /* Otherwise, emit it */ 306 return ext4_getfsmap_helper(sb, info, &irec); 307 } 308 309 /* Execute a getfsmap query against the log device. */ 310 static int ext4_getfsmap_logdev(struct super_block *sb, struct ext4_fsmap *keys, 311 struct ext4_getfsmap_info *info) 312 { 313 journal_t *journal = EXT4_SB(sb)->s_journal; 314 struct ext4_fsmap irec; 315 316 /* Set up search keys */ 317 info->gfi_low = keys[0]; 318 info->gfi_low.fmr_length = 0; 319 320 memset(&info->gfi_high, 0xFF, sizeof(info->gfi_high)); 321 322 trace_ext4_fsmap_low_key(sb, info->gfi_dev, 0, 323 info->gfi_low.fmr_physical, 324 info->gfi_low.fmr_length, 325 info->gfi_low.fmr_owner); 326 327 trace_ext4_fsmap_high_key(sb, info->gfi_dev, 0, 328 info->gfi_high.fmr_physical, 329 info->gfi_high.fmr_length, 330 info->gfi_high.fmr_owner); 331 332 if (keys[0].fmr_physical > 0) 333 return 0; 334 335 /* Fabricate an rmap entry for the external log device. */ 336 irec.fmr_physical = journal->j_blk_offset; 337 irec.fmr_length = journal->j_total_len; 338 irec.fmr_owner = EXT4_FMR_OWN_LOG; 339 irec.fmr_flags = 0; 340 341 return ext4_getfsmap_helper(sb, info, &irec); 342 } 343 344 /* Helper to fill out an ext4_fsmap. */ 345 static inline int ext4_getfsmap_fill(struct list_head *meta_list, 346 ext4_fsblk_t fsb, ext4_fsblk_t len, 347 uint64_t owner) 348 { 349 struct ext4_fsmap *fsm; 350 351 fsm = kmalloc(sizeof(*fsm), GFP_NOFS); 352 if (!fsm) 353 return -ENOMEM; 354 fsm->fmr_device = 0; 355 fsm->fmr_flags = 0; 356 fsm->fmr_physical = fsb; 357 fsm->fmr_owner = owner; 358 fsm->fmr_length = len; 359 list_add_tail(&fsm->fmr_list, meta_list); 360 361 return 0; 362 } 363 364 /* 365 * This function returns the number of file system metadata blocks at 366 * the beginning of a block group, including the reserved gdt blocks. 367 */ 368 static unsigned int ext4_getfsmap_find_sb(struct super_block *sb, 369 ext4_group_t agno, 370 struct list_head *meta_list) 371 { 372 struct ext4_sb_info *sbi = EXT4_SB(sb); 373 ext4_fsblk_t fsb = ext4_group_first_block_no(sb, agno); 374 ext4_fsblk_t len; 375 unsigned long first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); 376 unsigned long metagroup = agno / EXT4_DESC_PER_BLOCK(sb); 377 int error; 378 379 /* Record the superblock. */ 380 if (ext4_bg_has_super(sb, agno)) { 381 error = ext4_getfsmap_fill(meta_list, fsb, 1, EXT4_FMR_OWN_FS); 382 if (error) 383 return error; 384 fsb++; 385 } 386 387 /* Record the group descriptors. */ 388 len = ext4_bg_num_gdb(sb, agno); 389 if (!len) 390 return 0; 391 error = ext4_getfsmap_fill(meta_list, fsb, len, 392 EXT4_FMR_OWN_GDT); 393 if (error) 394 return error; 395 fsb += len; 396 397 /* Reserved GDT blocks */ 398 if (!ext4_has_feature_meta_bg(sb) || metagroup < first_meta_bg) { 399 len = le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks); 400 401 /* 402 * mkfs.ext4 can set s_reserved_gdt_blocks as 0 in some cases, 403 * check for that. 404 */ 405 if (!len) 406 return 0; 407 408 error = ext4_getfsmap_fill(meta_list, fsb, len, 409 EXT4_FMR_OWN_RESV_GDT); 410 if (error) 411 return error; 412 } 413 414 return 0; 415 } 416 417 /* Compare two fsmap items. */ 418 static int ext4_getfsmap_compare(void *priv, 419 const struct list_head *a, 420 const struct list_head *b) 421 { 422 struct ext4_fsmap *fa; 423 struct ext4_fsmap *fb; 424 425 fa = container_of(a, struct ext4_fsmap, fmr_list); 426 fb = container_of(b, struct ext4_fsmap, fmr_list); 427 if (fa->fmr_physical < fb->fmr_physical) 428 return -1; 429 else if (fa->fmr_physical > fb->fmr_physical) 430 return 1; 431 return 0; 432 } 433 434 /* Merge adjacent extents of fixed metadata. */ 435 static void ext4_getfsmap_merge_fixed_metadata(struct list_head *meta_list) 436 { 437 struct ext4_fsmap *p; 438 struct ext4_fsmap *prev = NULL; 439 struct ext4_fsmap *tmp; 440 441 list_for_each_entry_safe(p, tmp, meta_list, fmr_list) { 442 if (!prev) { 443 prev = p; 444 continue; 445 } 446 447 if (prev->fmr_owner == p->fmr_owner && 448 prev->fmr_physical + prev->fmr_length == p->fmr_physical) { 449 prev->fmr_length += p->fmr_length; 450 list_del(&p->fmr_list); 451 kfree(p); 452 } else 453 prev = p; 454 } 455 } 456 457 /* Free a list of fixed metadata. */ 458 static void ext4_getfsmap_free_fixed_metadata(struct list_head *meta_list) 459 { 460 struct ext4_fsmap *p; 461 struct ext4_fsmap *tmp; 462 463 list_for_each_entry_safe(p, tmp, meta_list, fmr_list) { 464 list_del(&p->fmr_list); 465 kfree(p); 466 } 467 } 468 469 /* Find all the fixed metadata in the filesystem. */ 470 static int ext4_getfsmap_find_fixed_metadata(struct super_block *sb, 471 struct list_head *meta_list) 472 { 473 struct ext4_group_desc *gdp; 474 ext4_group_t agno; 475 int error; 476 477 INIT_LIST_HEAD(meta_list); 478 479 /* Collect everything. */ 480 for (agno = 0; agno < EXT4_SB(sb)->s_groups_count; agno++) { 481 gdp = ext4_get_group_desc(sb, agno, NULL); 482 if (!gdp) { 483 error = -EFSCORRUPTED; 484 goto err; 485 } 486 487 /* Superblock & GDT */ 488 error = ext4_getfsmap_find_sb(sb, agno, meta_list); 489 if (error) 490 goto err; 491 492 /* Block bitmap */ 493 error = ext4_getfsmap_fill(meta_list, 494 ext4_block_bitmap(sb, gdp), 1, 495 EXT4_FMR_OWN_BLKBM); 496 if (error) 497 goto err; 498 499 /* Inode bitmap */ 500 error = ext4_getfsmap_fill(meta_list, 501 ext4_inode_bitmap(sb, gdp), 1, 502 EXT4_FMR_OWN_INOBM); 503 if (error) 504 goto err; 505 506 /* Inodes */ 507 error = ext4_getfsmap_fill(meta_list, 508 ext4_inode_table(sb, gdp), 509 EXT4_SB(sb)->s_itb_per_group, 510 EXT4_FMR_OWN_INODES); 511 if (error) 512 goto err; 513 } 514 515 /* Sort the list */ 516 list_sort(NULL, meta_list, ext4_getfsmap_compare); 517 518 /* Merge adjacent extents */ 519 ext4_getfsmap_merge_fixed_metadata(meta_list); 520 521 return 0; 522 err: 523 ext4_getfsmap_free_fixed_metadata(meta_list); 524 return error; 525 } 526 527 /* Execute a getfsmap query against the buddy bitmaps */ 528 static int ext4_getfsmap_datadev(struct super_block *sb, 529 struct ext4_fsmap *keys, 530 struct ext4_getfsmap_info *info) 531 { 532 struct ext4_sb_info *sbi = EXT4_SB(sb); 533 ext4_fsblk_t start_fsb; 534 ext4_fsblk_t end_fsb; 535 ext4_fsblk_t bofs; 536 ext4_fsblk_t eofs; 537 ext4_group_t start_ag; 538 ext4_group_t end_ag; 539 ext4_grpblk_t first_cluster; 540 ext4_grpblk_t last_cluster; 541 struct ext4_fsmap irec; 542 int error = 0; 543 544 bofs = le32_to_cpu(sbi->s_es->s_first_data_block); 545 eofs = ext4_blocks_count(sbi->s_es); 546 if (keys[0].fmr_physical >= eofs) 547 return 0; 548 else if (keys[0].fmr_physical < bofs) 549 keys[0].fmr_physical = bofs; 550 if (keys[1].fmr_physical >= eofs) 551 keys[1].fmr_physical = eofs - 1; 552 if (keys[1].fmr_physical < keys[0].fmr_physical) 553 return 0; 554 start_fsb = keys[0].fmr_physical; 555 end_fsb = keys[1].fmr_physical; 556 557 /* Determine first and last group to examine based on start and end */ 558 ext4_get_group_no_and_offset(sb, start_fsb, &start_ag, &first_cluster); 559 ext4_get_group_no_and_offset(sb, end_fsb, &end_ag, &last_cluster); 560 561 /* 562 * Convert the fsmap low/high keys to bg based keys. Initialize 563 * low to the fsmap low key and max out the high key to the end 564 * of the bg. 565 */ 566 info->gfi_low = keys[0]; 567 info->gfi_low.fmr_physical = EXT4_C2B(sbi, first_cluster); 568 info->gfi_low.fmr_length = 0; 569 570 memset(&info->gfi_high, 0xFF, sizeof(info->gfi_high)); 571 572 /* Assemble a list of all the fixed-location metadata. */ 573 error = ext4_getfsmap_find_fixed_metadata(sb, &info->gfi_meta_list); 574 if (error) 575 goto err; 576 577 /* Query each bg */ 578 for (info->gfi_agno = start_ag; 579 info->gfi_agno <= end_ag; 580 info->gfi_agno++) { 581 /* 582 * Set the bg high key from the fsmap high key if this 583 * is the last bg that we're querying. 584 */ 585 if (info->gfi_agno == end_ag) { 586 info->gfi_high = keys[1]; 587 info->gfi_high.fmr_physical = EXT4_C2B(sbi, 588 last_cluster); 589 info->gfi_high.fmr_length = 0; 590 } 591 592 trace_ext4_fsmap_low_key(sb, info->gfi_dev, info->gfi_agno, 593 info->gfi_low.fmr_physical, 594 info->gfi_low.fmr_length, 595 info->gfi_low.fmr_owner); 596 597 trace_ext4_fsmap_high_key(sb, info->gfi_dev, info->gfi_agno, 598 info->gfi_high.fmr_physical, 599 info->gfi_high.fmr_length, 600 info->gfi_high.fmr_owner); 601 602 error = ext4_mballoc_query_range(sb, info->gfi_agno, 603 EXT4_B2C(sbi, info->gfi_low.fmr_physical), 604 EXT4_B2C(sbi, info->gfi_high.fmr_physical), 605 ext4_getfsmap_meta_helper, 606 ext4_getfsmap_datadev_helper, info); 607 if (error) 608 goto err; 609 610 /* 611 * Set the bg low key to the start of the bg prior to 612 * moving on to the next bg. 613 */ 614 if (info->gfi_agno == start_ag) 615 memset(&info->gfi_low, 0, sizeof(info->gfi_low)); 616 } 617 618 /* Do we have a retained free extent? */ 619 if (info->gfi_lastfree.fmr_owner) { 620 error = ext4_getfsmap_helper(sb, info, &info->gfi_lastfree); 621 if (error) 622 goto err; 623 } 624 625 /* 626 * The dummy record below will cause ext4_getfsmap_helper() to report 627 * any allocated blocks at the end of the range. 628 */ 629 irec.fmr_device = 0; 630 irec.fmr_physical = end_fsb + 1; 631 irec.fmr_length = 0; 632 irec.fmr_owner = EXT4_FMR_OWN_FREE; 633 irec.fmr_flags = 0; 634 635 info->gfi_last = true; 636 error = ext4_getfsmap_helper(sb, info, &irec); 637 if (error) 638 goto err; 639 640 err: 641 ext4_getfsmap_free_fixed_metadata(&info->gfi_meta_list); 642 return error; 643 } 644 645 /* Do we recognize the device? */ 646 static bool ext4_getfsmap_is_valid_device(struct super_block *sb, 647 struct ext4_fsmap *fm) 648 { 649 if (fm->fmr_device == 0 || fm->fmr_device == UINT_MAX || 650 fm->fmr_device == new_encode_dev(sb->s_bdev->bd_dev)) 651 return true; 652 if (EXT4_SB(sb)->s_journal_bdev_file && 653 fm->fmr_device == 654 new_encode_dev(file_bdev(EXT4_SB(sb)->s_journal_bdev_file)->bd_dev)) 655 return true; 656 return false; 657 } 658 659 /* Ensure that the low key is less than the high key. */ 660 static bool ext4_getfsmap_check_keys(struct ext4_fsmap *low_key, 661 struct ext4_fsmap *high_key) 662 { 663 if (low_key->fmr_device > high_key->fmr_device) 664 return false; 665 if (low_key->fmr_device < high_key->fmr_device) 666 return true; 667 668 if (low_key->fmr_physical > high_key->fmr_physical) 669 return false; 670 if (low_key->fmr_physical < high_key->fmr_physical) 671 return true; 672 673 if (low_key->fmr_owner > high_key->fmr_owner) 674 return false; 675 if (low_key->fmr_owner < high_key->fmr_owner) 676 return true; 677 678 return false; 679 } 680 681 #define EXT4_GETFSMAP_DEVS 2 682 /* 683 * Get filesystem's extents as described in head, and format for 684 * output. Calls formatter to fill the user's buffer until all 685 * extents are mapped, until the passed-in head->fmh_count slots have 686 * been filled, or until the formatter short-circuits the loop, if it 687 * is tracking filled-in extents on its own. 688 * 689 * Key to Confusion 690 * ---------------- 691 * There are multiple levels of keys and counters at work here: 692 * _fsmap_head.fmh_keys -- low and high fsmap keys passed in; 693 * these reflect fs-wide block addrs. 694 * dkeys -- fmh_keys used to query each device; 695 * these are fmh_keys but w/ the low key 696 * bumped up by fmr_length. 697 * _getfsmap_info.gfi_next_fsblk-- next fs block we expect to see; this 698 * is how we detect gaps in the fsmap 699 * records and report them. 700 * _getfsmap_info.gfi_low/high -- per-bg low/high keys computed from 701 * dkeys; used to query the free space. 702 */ 703 int ext4_getfsmap(struct super_block *sb, struct ext4_fsmap_head *head, 704 ext4_fsmap_format_t formatter, void *arg) 705 { 706 struct ext4_fsmap dkeys[2]; /* per-dev keys */ 707 struct ext4_getfsmap_dev handlers[EXT4_GETFSMAP_DEVS]; 708 struct ext4_getfsmap_info info = { NULL }; 709 int i; 710 int error = 0; 711 712 if (head->fmh_iflags & ~FMH_IF_VALID) 713 return -EINVAL; 714 if (!ext4_getfsmap_is_valid_device(sb, &head->fmh_keys[0]) || 715 !ext4_getfsmap_is_valid_device(sb, &head->fmh_keys[1])) 716 return -EINVAL; 717 718 head->fmh_entries = 0; 719 720 /* Set up our device handlers. */ 721 memset(handlers, 0, sizeof(handlers)); 722 handlers[0].gfd_dev = new_encode_dev(sb->s_bdev->bd_dev); 723 handlers[0].gfd_fn = ext4_getfsmap_datadev; 724 if (EXT4_SB(sb)->s_journal_bdev_file) { 725 handlers[1].gfd_dev = new_encode_dev( 726 file_bdev(EXT4_SB(sb)->s_journal_bdev_file)->bd_dev); 727 handlers[1].gfd_fn = ext4_getfsmap_logdev; 728 } 729 730 sort(handlers, EXT4_GETFSMAP_DEVS, sizeof(struct ext4_getfsmap_dev), 731 ext4_getfsmap_dev_compare, NULL); 732 733 /* 734 * To continue where we left off, we allow userspace to use the 735 * last mapping from a previous call as the low key of the next. 736 * This is identified by a non-zero length in the low key. We 737 * have to increment the low key in this scenario to ensure we 738 * don't return the same mapping again, and instead return the 739 * very next mapping. 740 * 741 * Bump the physical offset as there can be no other mapping for 742 * the same physical block range. 743 */ 744 dkeys[0] = head->fmh_keys[0]; 745 dkeys[0].fmr_physical += dkeys[0].fmr_length; 746 dkeys[0].fmr_owner = 0; 747 dkeys[0].fmr_length = 0; 748 memset(&dkeys[1], 0xFF, sizeof(struct ext4_fsmap)); 749 750 if (!ext4_getfsmap_check_keys(dkeys, &head->fmh_keys[1])) 751 return -EINVAL; 752 753 info.gfi_next_fsblk = head->fmh_keys[0].fmr_physical + 754 head->fmh_keys[0].fmr_length; 755 info.gfi_formatter = formatter; 756 info.gfi_format_arg = arg; 757 info.gfi_head = head; 758 759 /* For each device we support... */ 760 for (i = 0; i < EXT4_GETFSMAP_DEVS; i++) { 761 /* Is this device within the range the user asked for? */ 762 if (!handlers[i].gfd_fn) 763 continue; 764 if (head->fmh_keys[0].fmr_device > handlers[i].gfd_dev) 765 continue; 766 if (head->fmh_keys[1].fmr_device < handlers[i].gfd_dev) 767 break; 768 769 /* 770 * If this device number matches the high key, we have 771 * to pass the high key to the handler to limit the 772 * query results. If the device number exceeds the 773 * low key, zero out the low key so that we get 774 * everything from the beginning. 775 */ 776 if (handlers[i].gfd_dev == head->fmh_keys[1].fmr_device) 777 dkeys[1] = head->fmh_keys[1]; 778 if (handlers[i].gfd_dev > head->fmh_keys[0].fmr_device) 779 memset(&dkeys[0], 0, sizeof(struct ext4_fsmap)); 780 781 info.gfi_dev = handlers[i].gfd_dev; 782 info.gfi_last = false; 783 info.gfi_agno = -1; 784 error = handlers[i].gfd_fn(sb, dkeys, &info); 785 if (error) 786 break; 787 info.gfi_next_fsblk = 0; 788 } 789 790 head->fmh_oflags = FMH_OF_DEV_T; 791 return error; 792 } 793