1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/hfsplus/bnode.c 4 * 5 * Copyright (C) 2001 6 * Brad Boyer (flar@allandria.com) 7 * (C) 2003 Ardis Technologies <roman@ardistech.com> 8 * 9 * Handle basic btree node operations 10 */ 11 12 #include <linux/string.h> 13 #include <linux/slab.h> 14 #include <linux/pagemap.h> 15 #include <linux/fs.h> 16 #include <linux/swap.h> 17 18 #include "hfsplus_fs.h" 19 #include "hfsplus_raw.h" 20 21 22 /* Copy a specified range of bytes from the raw data of a node */ 23 void hfs_bnode_read(struct hfs_bnode *node, void *buf, u32 off, u32 len) 24 { 25 struct page **pagep; 26 u32 l; 27 28 memset(buf, 0, len); 29 30 if (!is_bnode_offset_valid(node, off)) 31 return; 32 33 if (len == 0) { 34 pr_err("requested zero length: " 35 "NODE: id %u, type %#x, height %u, " 36 "node_size %u, offset %u, len %u\n", 37 node->this, node->type, node->height, 38 node->tree->node_size, off, len); 39 return; 40 } 41 42 len = check_and_correct_requested_length(node, off, len); 43 44 off += node->page_offset; 45 pagep = node->page + (off >> PAGE_SHIFT); 46 off &= ~PAGE_MASK; 47 48 l = min_t(u32, len, PAGE_SIZE - off); 49 memcpy_from_page(buf, *pagep, off, l); 50 51 while ((len -= l) != 0) { 52 buf += l; 53 l = min_t(u32, len, PAGE_SIZE); 54 memcpy_from_page(buf, *++pagep, 0, l); 55 } 56 } 57 58 u16 hfs_bnode_read_u16(struct hfs_bnode *node, u32 off) 59 { 60 __be16 data; 61 /* TODO: optimize later... */ 62 hfs_bnode_read(node, &data, off, 2); 63 return be16_to_cpu(data); 64 } 65 66 u8 hfs_bnode_read_u8(struct hfs_bnode *node, u32 off) 67 { 68 u8 data; 69 /* TODO: optimize later... */ 70 hfs_bnode_read(node, &data, off, 1); 71 return data; 72 } 73 74 void hfs_bnode_read_key(struct hfs_bnode *node, void *key, u32 off) 75 { 76 struct hfs_btree *tree; 77 u32 key_len; 78 79 tree = node->tree; 80 if (node->type == HFS_NODE_LEAF || 81 tree->attributes & HFS_TREE_VARIDXKEYS || 82 node->tree->cnid == HFSPLUS_ATTR_CNID) 83 key_len = hfs_bnode_read_u16(node, off) + 2; 84 else 85 key_len = tree->max_key_len + 2; 86 87 if (key_len > sizeof(hfsplus_btree_key) || key_len < 1) { 88 memset(key, 0, sizeof(hfsplus_btree_key)); 89 pr_err("hfsplus: Invalid key length: %u\n", key_len); 90 return; 91 } 92 93 hfs_bnode_read(node, key, off, key_len); 94 } 95 96 void hfs_bnode_write(struct hfs_bnode *node, void *buf, u32 off, u32 len) 97 { 98 struct page **pagep; 99 u32 l; 100 101 if (!is_bnode_offset_valid(node, off)) 102 return; 103 104 if (len == 0) { 105 pr_err("requested zero length: " 106 "NODE: id %u, type %#x, height %u, " 107 "node_size %u, offset %u, len %u\n", 108 node->this, node->type, node->height, 109 node->tree->node_size, off, len); 110 return; 111 } 112 113 len = check_and_correct_requested_length(node, off, len); 114 115 off += node->page_offset; 116 pagep = node->page + (off >> PAGE_SHIFT); 117 off &= ~PAGE_MASK; 118 119 l = min_t(u32, len, PAGE_SIZE - off); 120 memcpy_to_page(*pagep, off, buf, l); 121 set_page_dirty(*pagep); 122 123 while ((len -= l) != 0) { 124 buf += l; 125 l = min_t(u32, len, PAGE_SIZE); 126 memcpy_to_page(*++pagep, 0, buf, l); 127 set_page_dirty(*pagep); 128 } 129 } 130 131 void hfs_bnode_write_u16(struct hfs_bnode *node, u32 off, u16 data) 132 { 133 __be16 v = cpu_to_be16(data); 134 /* TODO: optimize later... */ 135 hfs_bnode_write(node, &v, off, 2); 136 } 137 138 void hfs_bnode_clear(struct hfs_bnode *node, u32 off, u32 len) 139 { 140 struct page **pagep; 141 u32 l; 142 143 if (!is_bnode_offset_valid(node, off)) 144 return; 145 146 if (len == 0) { 147 pr_err("requested zero length: " 148 "NODE: id %u, type %#x, height %u, " 149 "node_size %u, offset %u, len %u\n", 150 node->this, node->type, node->height, 151 node->tree->node_size, off, len); 152 return; 153 } 154 155 len = check_and_correct_requested_length(node, off, len); 156 157 off += node->page_offset; 158 pagep = node->page + (off >> PAGE_SHIFT); 159 off &= ~PAGE_MASK; 160 161 l = min_t(u32, len, PAGE_SIZE - off); 162 memzero_page(*pagep, off, l); 163 set_page_dirty(*pagep); 164 165 while ((len -= l) != 0) { 166 l = min_t(u32, len, PAGE_SIZE); 167 memzero_page(*++pagep, 0, l); 168 set_page_dirty(*pagep); 169 } 170 } 171 172 void hfs_bnode_copy(struct hfs_bnode *dst_node, u32 dst, 173 struct hfs_bnode *src_node, u32 src, u32 len) 174 { 175 struct page **src_page, **dst_page; 176 u32 l; 177 178 hfs_dbg("dst %u, src %u, len %u\n", dst, src, len); 179 if (!len) 180 return; 181 182 len = check_and_correct_requested_length(src_node, src, len); 183 len = check_and_correct_requested_length(dst_node, dst, len); 184 185 src += src_node->page_offset; 186 dst += dst_node->page_offset; 187 src_page = src_node->page + (src >> PAGE_SHIFT); 188 src &= ~PAGE_MASK; 189 dst_page = dst_node->page + (dst >> PAGE_SHIFT); 190 dst &= ~PAGE_MASK; 191 192 if (src == dst) { 193 l = min_t(u32, len, PAGE_SIZE - src); 194 memcpy_page(*dst_page, src, *src_page, src, l); 195 set_page_dirty(*dst_page); 196 197 while ((len -= l) != 0) { 198 l = min_t(u32, len, PAGE_SIZE); 199 memcpy_page(*++dst_page, 0, *++src_page, 0, l); 200 set_page_dirty(*dst_page); 201 } 202 } else { 203 void *src_ptr, *dst_ptr; 204 205 do { 206 dst_ptr = kmap_local_page(*dst_page) + dst; 207 src_ptr = kmap_local_page(*src_page) + src; 208 if (PAGE_SIZE - src < PAGE_SIZE - dst) { 209 l = PAGE_SIZE - src; 210 src = 0; 211 dst += l; 212 } else { 213 l = PAGE_SIZE - dst; 214 src += l; 215 dst = 0; 216 } 217 l = min(len, l); 218 memcpy(dst_ptr, src_ptr, l); 219 kunmap_local(src_ptr); 220 set_page_dirty(*dst_page); 221 kunmap_local(dst_ptr); 222 if (!dst) 223 dst_page++; 224 else 225 src_page++; 226 } while ((len -= l)); 227 } 228 } 229 230 void hfs_bnode_move(struct hfs_bnode *node, u32 dst, u32 src, u32 len) 231 { 232 struct page **src_page, **dst_page; 233 void *src_ptr, *dst_ptr; 234 u32 l; 235 236 hfs_dbg("dst %u, src %u, len %u\n", dst, src, len); 237 if (!len) 238 return; 239 240 len = check_and_correct_requested_length(node, src, len); 241 len = check_and_correct_requested_length(node, dst, len); 242 243 src += node->page_offset; 244 dst += node->page_offset; 245 if (dst > src) { 246 src += len - 1; 247 src_page = node->page + (src >> PAGE_SHIFT); 248 src = (src & ~PAGE_MASK) + 1; 249 dst += len - 1; 250 dst_page = node->page + (dst >> PAGE_SHIFT); 251 dst = (dst & ~PAGE_MASK) + 1; 252 253 if (src == dst) { 254 while (src < len) { 255 dst_ptr = kmap_local_page(*dst_page); 256 src_ptr = kmap_local_page(*src_page); 257 memmove(dst_ptr, src_ptr, src); 258 kunmap_local(src_ptr); 259 set_page_dirty(*dst_page); 260 kunmap_local(dst_ptr); 261 len -= src; 262 src = PAGE_SIZE; 263 src_page--; 264 dst_page--; 265 } 266 src -= len; 267 dst_ptr = kmap_local_page(*dst_page); 268 src_ptr = kmap_local_page(*src_page); 269 memmove(dst_ptr + src, src_ptr + src, len); 270 kunmap_local(src_ptr); 271 set_page_dirty(*dst_page); 272 kunmap_local(dst_ptr); 273 } else { 274 do { 275 dst_ptr = kmap_local_page(*dst_page) + dst; 276 src_ptr = kmap_local_page(*src_page) + src; 277 if (src < dst) { 278 l = src; 279 src = PAGE_SIZE; 280 dst -= l; 281 } else { 282 l = dst; 283 src -= l; 284 dst = PAGE_SIZE; 285 } 286 l = min(len, l); 287 memmove(dst_ptr - l, src_ptr - l, l); 288 kunmap_local(src_ptr); 289 set_page_dirty(*dst_page); 290 kunmap_local(dst_ptr); 291 if (dst == PAGE_SIZE) 292 dst_page--; 293 else 294 src_page--; 295 } while ((len -= l)); 296 } 297 } else { 298 src_page = node->page + (src >> PAGE_SHIFT); 299 src &= ~PAGE_MASK; 300 dst_page = node->page + (dst >> PAGE_SHIFT); 301 dst &= ~PAGE_MASK; 302 303 if (src == dst) { 304 l = min_t(u32, len, PAGE_SIZE - src); 305 306 dst_ptr = kmap_local_page(*dst_page) + src; 307 src_ptr = kmap_local_page(*src_page) + src; 308 memmove(dst_ptr, src_ptr, l); 309 kunmap_local(src_ptr); 310 set_page_dirty(*dst_page); 311 kunmap_local(dst_ptr); 312 313 while ((len -= l) != 0) { 314 l = min_t(u32, len, PAGE_SIZE); 315 dst_ptr = kmap_local_page(*++dst_page); 316 src_ptr = kmap_local_page(*++src_page); 317 memmove(dst_ptr, src_ptr, l); 318 kunmap_local(src_ptr); 319 set_page_dirty(*dst_page); 320 kunmap_local(dst_ptr); 321 } 322 } else { 323 do { 324 dst_ptr = kmap_local_page(*dst_page) + dst; 325 src_ptr = kmap_local_page(*src_page) + src; 326 if (PAGE_SIZE - src < 327 PAGE_SIZE - dst) { 328 l = PAGE_SIZE - src; 329 src = 0; 330 dst += l; 331 } else { 332 l = PAGE_SIZE - dst; 333 src += l; 334 dst = 0; 335 } 336 l = min(len, l); 337 memmove(dst_ptr, src_ptr, l); 338 kunmap_local(src_ptr); 339 set_page_dirty(*dst_page); 340 kunmap_local(dst_ptr); 341 if (!dst) 342 dst_page++; 343 else 344 src_page++; 345 } while ((len -= l)); 346 } 347 } 348 } 349 350 void hfs_bnode_dump(struct hfs_bnode *node) 351 { 352 struct hfs_bnode_desc desc; 353 __be32 cnid; 354 int i, off, key_off; 355 356 hfs_dbg("node %d\n", node->this); 357 hfs_bnode_read(node, &desc, 0, sizeof(desc)); 358 hfs_dbg("next %d, prev %d, type %d, height %d, num_recs %d\n", 359 be32_to_cpu(desc.next), be32_to_cpu(desc.prev), 360 desc.type, desc.height, be16_to_cpu(desc.num_recs)); 361 362 off = node->tree->node_size - 2; 363 for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) { 364 key_off = hfs_bnode_read_u16(node, off); 365 hfs_dbg(" key_off %d", key_off); 366 if (i && node->type == HFS_NODE_INDEX) { 367 int tmp; 368 369 if (node->tree->attributes & HFS_TREE_VARIDXKEYS || 370 node->tree->cnid == HFSPLUS_ATTR_CNID) 371 tmp = hfs_bnode_read_u16(node, key_off) + 2; 372 else 373 tmp = node->tree->max_key_len + 2; 374 hfs_dbg(" (%d", tmp); 375 hfs_bnode_read(node, &cnid, key_off + tmp, 4); 376 hfs_dbg(", cnid %d)", be32_to_cpu(cnid)); 377 } else if (i && node->type == HFS_NODE_LEAF) { 378 int tmp; 379 380 tmp = hfs_bnode_read_u16(node, key_off); 381 hfs_dbg(" (%d)", tmp); 382 } 383 } 384 hfs_dbg("\n"); 385 } 386 387 void hfs_bnode_unlink(struct hfs_bnode *node) 388 { 389 struct hfs_btree *tree; 390 struct hfs_bnode *tmp; 391 __be32 cnid; 392 393 tree = node->tree; 394 if (node->prev) { 395 tmp = hfs_bnode_find(tree, node->prev); 396 if (IS_ERR(tmp)) 397 return; 398 tmp->next = node->next; 399 cnid = cpu_to_be32(tmp->next); 400 hfs_bnode_write(tmp, &cnid, 401 offsetof(struct hfs_bnode_desc, next), 4); 402 hfs_bnode_put(tmp); 403 } else if (node->type == HFS_NODE_LEAF) 404 tree->leaf_head = node->next; 405 406 if (node->next) { 407 tmp = hfs_bnode_find(tree, node->next); 408 if (IS_ERR(tmp)) 409 return; 410 tmp->prev = node->prev; 411 cnid = cpu_to_be32(tmp->prev); 412 hfs_bnode_write(tmp, &cnid, 413 offsetof(struct hfs_bnode_desc, prev), 4); 414 hfs_bnode_put(tmp); 415 } else if (node->type == HFS_NODE_LEAF) 416 tree->leaf_tail = node->prev; 417 418 /* move down? */ 419 if (!node->prev && !node->next) 420 hfs_dbg("btree delete level\n"); 421 if (!node->parent) { 422 tree->root = 0; 423 tree->depth = 0; 424 } 425 426 spin_lock(&tree->hash_lock); 427 set_bit(HFS_BNODE_DELETED, &node->flags); 428 spin_unlock(&tree->hash_lock); 429 } 430 431 static inline int hfs_bnode_hash(u32 num) 432 { 433 num = (num >> 16) + num; 434 num += num >> 8; 435 return num & (NODE_HASH_SIZE - 1); 436 } 437 438 struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid) 439 { 440 struct hfs_bnode *node; 441 442 if (cnid >= tree->node_count) { 443 pr_err("request for non-existent node %d in B*Tree\n", 444 cnid); 445 return NULL; 446 } 447 448 for (node = tree->node_hash[hfs_bnode_hash(cnid)]; 449 node; node = node->next_hash) 450 if (node->this == cnid) 451 return node; 452 return NULL; 453 } 454 455 static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) 456 { 457 struct hfs_bnode *node, *node2; 458 struct address_space *mapping; 459 struct page *page; 460 int block, i, hash; 461 loff_t off; 462 463 if (cnid >= tree->node_count) { 464 pr_err("request for non-existent node %d in B*Tree\n", 465 cnid); 466 return NULL; 467 } 468 469 node = kzalloc_flex(*node, page, tree->pages_per_bnode); 470 if (!node) 471 return NULL; 472 node->tree = tree; 473 node->this = cnid; 474 set_bit(HFS_BNODE_NEW, &node->flags); 475 atomic_set(&node->refcnt, 1); 476 hfs_dbg("cnid %d, node %d, refcnt 1\n", 477 node->tree->cnid, node->this); 478 init_waitqueue_head(&node->lock_wq); 479 spin_lock(&tree->hash_lock); 480 node2 = hfs_bnode_findhash(tree, cnid); 481 if (!node2) { 482 hash = hfs_bnode_hash(cnid); 483 node->next_hash = tree->node_hash[hash]; 484 tree->node_hash[hash] = node; 485 tree->node_hash_cnt++; 486 } else { 487 hfs_bnode_get(node2); 488 spin_unlock(&tree->hash_lock); 489 kfree(node); 490 wait_event(node2->lock_wq, 491 !test_bit(HFS_BNODE_NEW, &node2->flags)); 492 return node2; 493 } 494 spin_unlock(&tree->hash_lock); 495 496 mapping = tree->inode->i_mapping; 497 off = (loff_t)cnid << tree->node_size_shift; 498 block = off >> PAGE_SHIFT; 499 node->page_offset = off & ~PAGE_MASK; 500 for (i = 0; i < tree->pages_per_bnode; block++, i++) { 501 page = read_mapping_page(mapping, block, NULL); 502 if (IS_ERR(page)) 503 goto fail; 504 node->page[i] = page; 505 } 506 507 return node; 508 fail: 509 set_bit(HFS_BNODE_ERROR, &node->flags); 510 return node; 511 } 512 513 void hfs_bnode_unhash(struct hfs_bnode *node) 514 { 515 struct hfs_bnode **p; 516 517 hfs_dbg("cnid %d, node %d, refcnt %d\n", 518 node->tree->cnid, node->this, atomic_read(&node->refcnt)); 519 for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)]; 520 *p && *p != node; p = &(*p)->next_hash) 521 ; 522 BUG_ON(!*p); 523 *p = node->next_hash; 524 node->tree->node_hash_cnt--; 525 } 526 527 /* Load a particular node out of a tree */ 528 struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num) 529 { 530 struct hfs_bnode *node; 531 struct hfs_bnode_desc *desc; 532 int i, rec_off, off, next_off; 533 int entry_size, key_size; 534 535 spin_lock(&tree->hash_lock); 536 node = hfs_bnode_findhash(tree, num); 537 if (node) { 538 hfs_bnode_get(node); 539 spin_unlock(&tree->hash_lock); 540 wait_event(node->lock_wq, 541 !test_bit(HFS_BNODE_NEW, &node->flags)); 542 if (test_bit(HFS_BNODE_ERROR, &node->flags)) 543 goto node_error; 544 return node; 545 } 546 spin_unlock(&tree->hash_lock); 547 node = __hfs_bnode_create(tree, num); 548 if (!node) 549 return ERR_PTR(-ENOMEM); 550 if (test_bit(HFS_BNODE_ERROR, &node->flags)) 551 goto node_error; 552 if (!test_bit(HFS_BNODE_NEW, &node->flags)) 553 return node; 554 555 desc = (struct hfs_bnode_desc *)(kmap_local_page(node->page[0]) + 556 node->page_offset); 557 node->prev = be32_to_cpu(desc->prev); 558 node->next = be32_to_cpu(desc->next); 559 node->num_recs = be16_to_cpu(desc->num_recs); 560 node->type = desc->type; 561 node->height = desc->height; 562 kunmap_local(desc); 563 564 switch (node->type) { 565 case HFS_NODE_HEADER: 566 case HFS_NODE_MAP: 567 if (node->height != 0) 568 goto node_error; 569 break; 570 case HFS_NODE_LEAF: 571 if (node->height != 1) 572 goto node_error; 573 break; 574 case HFS_NODE_INDEX: 575 if (node->height <= 1 || node->height > tree->depth) 576 goto node_error; 577 break; 578 default: 579 goto node_error; 580 } 581 582 rec_off = tree->node_size - 2; 583 off = hfs_bnode_read_u16(node, rec_off); 584 if (off != sizeof(struct hfs_bnode_desc)) 585 goto node_error; 586 for (i = 1; i <= node->num_recs; off = next_off, i++) { 587 rec_off -= 2; 588 next_off = hfs_bnode_read_u16(node, rec_off); 589 if (next_off <= off || 590 next_off > tree->node_size || 591 next_off & 1) 592 goto node_error; 593 entry_size = next_off - off; 594 if (node->type != HFS_NODE_INDEX && 595 node->type != HFS_NODE_LEAF) 596 continue; 597 key_size = hfs_bnode_read_u16(node, off) + 2; 598 if (key_size >= entry_size || key_size & 1) 599 goto node_error; 600 } 601 clear_bit(HFS_BNODE_NEW, &node->flags); 602 wake_up(&node->lock_wq); 603 return node; 604 605 node_error: 606 set_bit(HFS_BNODE_ERROR, &node->flags); 607 clear_bit(HFS_BNODE_NEW, &node->flags); 608 wake_up(&node->lock_wq); 609 hfs_bnode_put(node); 610 return ERR_PTR(-EIO); 611 } 612 613 void hfs_bnode_free(struct hfs_bnode *node) 614 { 615 int i; 616 617 for (i = 0; i < node->tree->pages_per_bnode; i++) 618 if (node->page[i]) 619 put_page(node->page[i]); 620 kfree(node); 621 } 622 623 struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) 624 { 625 struct hfs_bnode *node; 626 struct page **pagep; 627 int i; 628 629 spin_lock(&tree->hash_lock); 630 node = hfs_bnode_findhash(tree, num); 631 spin_unlock(&tree->hash_lock); 632 if (node) { 633 pr_crit("new node %u already hashed?\n", num); 634 WARN_ON(1); 635 return ERR_PTR(-EEXIST); 636 } 637 node = __hfs_bnode_create(tree, num); 638 if (!node) 639 return ERR_PTR(-ENOMEM); 640 if (test_bit(HFS_BNODE_ERROR, &node->flags)) { 641 hfs_bnode_put(node); 642 return ERR_PTR(-EIO); 643 } 644 645 pagep = node->page; 646 memzero_page(*pagep, node->page_offset, 647 min_t(int, PAGE_SIZE, tree->node_size)); 648 set_page_dirty(*pagep); 649 for (i = 1; i < tree->pages_per_bnode; i++) { 650 memzero_page(*++pagep, 0, PAGE_SIZE); 651 set_page_dirty(*pagep); 652 } 653 clear_bit(HFS_BNODE_NEW, &node->flags); 654 wake_up(&node->lock_wq); 655 656 return node; 657 } 658 659 void hfs_bnode_get(struct hfs_bnode *node) 660 { 661 if (node) { 662 atomic_inc(&node->refcnt); 663 hfs_dbg("cnid %d, node %d, refcnt %d\n", 664 node->tree->cnid, node->this, 665 atomic_read(&node->refcnt)); 666 } 667 } 668 669 /* Dispose of resources used by a node */ 670 void hfs_bnode_put(struct hfs_bnode *node) 671 { 672 if (node) { 673 struct hfs_btree *tree = node->tree; 674 int i; 675 676 hfs_dbg("cnid %d, node %d, refcnt %d\n", 677 node->tree->cnid, node->this, 678 atomic_read(&node->refcnt)); 679 BUG_ON(!atomic_read(&node->refcnt)); 680 if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) 681 return; 682 for (i = 0; i < tree->pages_per_bnode; i++) { 683 if (!node->page[i]) 684 continue; 685 mark_page_accessed(node->page[i]); 686 } 687 688 if (test_bit(HFS_BNODE_DELETED, &node->flags)) { 689 hfs_bnode_unhash(node); 690 spin_unlock(&tree->hash_lock); 691 if (hfs_bnode_need_zeroout(tree)) 692 hfs_bnode_clear(node, 0, tree->node_size); 693 hfs_bmap_free(node); 694 hfs_bnode_free(node); 695 return; 696 } 697 spin_unlock(&tree->hash_lock); 698 } 699 } 700 701 /* 702 * Unused nodes have to be zeroed if this is the catalog tree and 703 * a corresponding flag in the volume header is set. 704 */ 705 bool hfs_bnode_need_zeroout(struct hfs_btree *tree) 706 { 707 struct super_block *sb = tree->inode->i_sb; 708 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 709 const u32 volume_attr = be32_to_cpu(sbi->s_vhdr->attributes); 710 711 return volume_attr & HFSPLUS_VOL_UNUSED_NODE_FIX; 712 } 713