projects/linux·blob master · refs

720 lines · 16.9 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * linux/fs/hfsplus/bnode.c
4 *
5 * Copyright (C) 2001
6 * Brad Boyer ([email protected])
7 * (C) 2003 Ardis Technologies <[email protected]>
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 */
23void 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
58u16 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
66u8 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
74void 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
96void 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
131void 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
138void 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
172void 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
230void 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
350void hfs_bnode_dump(struct hfs_bnode *node)
351{
352 struct hfs_bnode_desc desc;
353 __be32 cnid;
354 int i, off, key_off;
355 u16 num_recs;
356
357 hfs_dbg("node %d\n", node->this);
358 hfs_bnode_read(node, &desc, 0, sizeof(desc));
359 num_recs = node->num_recs;
360 hfs_dbg("next %d, prev %d, type %d, height %d, num_recs %d\n",
361 be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
362 desc.type, desc.height, be16_to_cpu(desc.num_recs));
363
364 if (hfs_bnode_num_recs_invalid(node)) {
365 hfs_dbg("invalid num_recs %u\n", num_recs);
366 return;
367 }
368
369 off = node->tree->node_size - 2;
370 for (i = num_recs; i >= 0; off -= 2, i--) {
371 key_off = hfs_bnode_read_u16(node, off);
372 hfs_dbg(" key_off %d", key_off);
373 if (i && node->type == HFS_NODE_INDEX) {
374 int tmp;
375
376 if (node->tree->attributes & HFS_TREE_VARIDXKEYS ||
377 node->tree->cnid == HFSPLUS_ATTR_CNID)
378 tmp = hfs_bnode_read_u16(node, key_off) + 2;
379 else
380 tmp = node->tree->max_key_len + 2;
381 hfs_dbg(" (%d", tmp);
382 hfs_bnode_read(node, &cnid, key_off + tmp, 4);
383 hfs_dbg(", cnid %d)", be32_to_cpu(cnid));
384 } else if (i && node->type == HFS_NODE_LEAF) {
385 int tmp;
386
387 tmp = hfs_bnode_read_u16(node, key_off);
388 hfs_dbg(" (%d)", tmp);
389 }
390 }
391 hfs_dbg("\n");
392}
393
394void hfs_bnode_unlink(struct hfs_bnode *node)
395{
396 struct hfs_btree *tree;
397 struct hfs_bnode *tmp;
398 __be32 cnid;
399
400 tree = node->tree;
401 if (node->prev) {
402 tmp = hfs_bnode_find(tree, node->prev);
403 if (IS_ERR(tmp))
404 return;
405 tmp->next = node->next;
406 cnid = cpu_to_be32(tmp->next);
407 hfs_bnode_write(tmp, &cnid,
408 offsetof(struct hfs_bnode_desc, next), 4);
409 hfs_bnode_put(tmp);
410 } else if (node->type == HFS_NODE_LEAF)
411 tree->leaf_head = node->next;
412
413 if (node->next) {
414 tmp = hfs_bnode_find(tree, node->next);
415 if (IS_ERR(tmp))
416 return;
417 tmp->prev = node->prev;
418 cnid = cpu_to_be32(tmp->prev);
419 hfs_bnode_write(tmp, &cnid,
420 offsetof(struct hfs_bnode_desc, prev), 4);
421 hfs_bnode_put(tmp);
422 } else if (node->type == HFS_NODE_LEAF)
423 tree->leaf_tail = node->prev;
424
425 /* move down? */
426 if (!node->prev && !node->next)
427 hfs_dbg("btree delete level\n");
428 if (!node->parent) {
429 tree->root = 0;
430 tree->depth = 0;
431 }
432
433 spin_lock(&tree->hash_lock);
434 set_bit(HFS_BNODE_DELETED, &node->flags);
435 spin_unlock(&tree->hash_lock);
436}
437
438static inline int hfs_bnode_hash(u32 num)
439{
440 num = (num >> 16) + num;
441 num += num >> 8;
442 return num & (NODE_HASH_SIZE - 1);
443}
444
445struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
446{
447 struct hfs_bnode *node;
448
449 if (cnid >= tree->node_count) {
450 pr_err("request for non-existent node %d in B*Tree\n",
451 cnid);
452 return NULL;
453 }
454
455 for (node = tree->node_hash[hfs_bnode_hash(cnid)];
456 node; node = node->next_hash)
457 if (node->this == cnid)
458 return node;
459 return NULL;
460}
461
462static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
463{
464 struct hfs_bnode *node, *node2;
465 struct address_space *mapping;
466 struct page *page;
467 int block, i, hash;
468 loff_t off;
469
470 if (cnid >= tree->node_count) {
471 pr_err("request for non-existent node %d in B*Tree\n",
472 cnid);
473 return NULL;
474 }
475
476 node = kzalloc_flex(*node, page, tree->pages_per_bnode);
477 if (!node)
478 return NULL;
479 node->tree = tree;
480 node->this = cnid;
481 set_bit(HFS_BNODE_NEW, &node->flags);
482 atomic_set(&node->refcnt, 1);
483 hfs_dbg("cnid %d, node %d, refcnt 1\n",
484 node->tree->cnid, node->this);
485 init_waitqueue_head(&node->lock_wq);
486 spin_lock(&tree->hash_lock);
487 node2 = hfs_bnode_findhash(tree, cnid);
488 if (!node2) {
489 hash = hfs_bnode_hash(cnid);
490 node->next_hash = tree->node_hash[hash];
491 tree->node_hash[hash] = node;
492 tree->node_hash_cnt++;
493 } else {
494 hfs_bnode_get(node2);
495 spin_unlock(&tree->hash_lock);
496 kfree(node);
497 wait_event(node2->lock_wq,
498 !test_bit(HFS_BNODE_NEW, &node2->flags));
499 return node2;
500 }
501 spin_unlock(&tree->hash_lock);
502
503 mapping = tree->inode->i_mapping;
504 off = (loff_t)cnid << tree->node_size_shift;
505 block = off >> PAGE_SHIFT;
506 node->page_offset = off & ~PAGE_MASK;
507 for (i = 0; i < tree->pages_per_bnode; block++, i++) {
508 page = read_mapping_page(mapping, block, NULL);
509 if (IS_ERR(page))
510 goto fail;
511 node->page[i] = page;
512 }
513
514 return node;
515fail:
516 set_bit(HFS_BNODE_ERROR, &node->flags);
517 return node;
518}
519
520void hfs_bnode_unhash(struct hfs_bnode *node)
521{
522 struct hfs_bnode **p;
523
524 hfs_dbg("cnid %d, node %d, refcnt %d\n",
525 node->tree->cnid, node->this, atomic_read(&node->refcnt));
526 for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
527 *p && *p != node; p = &(*p)->next_hash)
528 ;
529 BUG_ON(!*p);
530 *p = node->next_hash;
531 node->tree->node_hash_cnt--;
532}
533
534/* Load a particular node out of a tree */
535struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
536{
537 struct hfs_bnode *node;
538 struct hfs_bnode_desc *desc;
539 int i, rec_off, off, next_off;
540 int entry_size, key_size;
541
542 spin_lock(&tree->hash_lock);
543 node = hfs_bnode_findhash(tree, num);
544 if (node) {
545 hfs_bnode_get(node);
546 spin_unlock(&tree->hash_lock);
547 wait_event(node->lock_wq,
548 !test_bit(HFS_BNODE_NEW, &node->flags));
549 if (test_bit(HFS_BNODE_ERROR, &node->flags))
550 goto node_error;
551 return node;
552 }
553 spin_unlock(&tree->hash_lock);
554 node = __hfs_bnode_create(tree, num);
555 if (!node)
556 return ERR_PTR(-ENOMEM);
557 if (test_bit(HFS_BNODE_ERROR, &node->flags))
558 goto node_error;
559 if (!test_bit(HFS_BNODE_NEW, &node->flags))
560 return node;
561
562 desc = (struct hfs_bnode_desc *)(kmap_local_page(node->page[0]) +
563 node->page_offset);
564 node->prev = be32_to_cpu(desc->prev);
565 node->next = be32_to_cpu(desc->next);
566 node->num_recs = be16_to_cpu(desc->num_recs);
567 node->type = desc->type;
568 node->height = desc->height;
569 kunmap_local(desc);
570
571 if (hfs_bnode_num_recs_invalid(node))
572 goto node_error;
573
574 switch (node->type) {
575 case HFS_NODE_HEADER:
576 case HFS_NODE_MAP:
577 if (node->height != 0)
578 goto node_error;
579 break;
580 case HFS_NODE_LEAF:
581 if (node->height != 1)
582 goto node_error;
583 break;
584 case HFS_NODE_INDEX:
585 if (node->height <= 1 || node->height > tree->depth)
586 goto node_error;
587 break;
588 default:
589 goto node_error;
590 }
591
592 rec_off = tree->node_size - 2;
593 off = hfs_bnode_read_u16(node, rec_off);
594 if (off != sizeof(struct hfs_bnode_desc))
595 goto node_error;
596 for (i = 1; i <= node->num_recs; off = next_off, i++) {
597 rec_off -= 2;
598 next_off = hfs_bnode_read_u16(node, rec_off);
599 if (hfs_brec_offsets_invalid(node, off, next_off))
600 goto node_error;
601 entry_size = next_off - off;
602 if (node->type != HFS_NODE_INDEX &&
603 node->type != HFS_NODE_LEAF)
604 continue;
605 key_size = hfs_bnode_read_u16(node, off) + 2;
606 if (key_size >= entry_size || key_size & 1)
607 goto node_error;
608 }
609 clear_bit(HFS_BNODE_NEW, &node->flags);
610 wake_up(&node->lock_wq);
611 return node;
612
613node_error:
614 set_bit(HFS_BNODE_ERROR, &node->flags);
615 clear_bit(HFS_BNODE_NEW, &node->flags);
616 wake_up(&node->lock_wq);
617 hfs_bnode_put(node);
618 return ERR_PTR(-EIO);
619}
620
621void hfs_bnode_free(struct hfs_bnode *node)
622{
623 int i;
624
625 for (i = 0; i < node->tree->pages_per_bnode; i++)
626 if (node->page[i])
627 put_page(node->page[i]);
628 kfree(node);
629}
630
631struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
632{
633 struct hfs_bnode *node;
634 struct page **pagep;
635 int i;
636
637 spin_lock(&tree->hash_lock);
638 node = hfs_bnode_findhash(tree, num);
639 spin_unlock(&tree->hash_lock);
640 if (node) {
641 pr_crit("new node %u already hashed?\n", num);
642 WARN_ON(1);
643 return ERR_PTR(-EEXIST);
644 }
645 node = __hfs_bnode_create(tree, num);
646 if (!node)
647 return ERR_PTR(-ENOMEM);
648 if (test_bit(HFS_BNODE_ERROR, &node->flags)) {
649 hfs_bnode_put(node);
650 return ERR_PTR(-EIO);
651 }
652
653 pagep = node->page;
654 memzero_page(*pagep, node->page_offset,
655 min_t(int, PAGE_SIZE, tree->node_size));
656 set_page_dirty(*pagep);
657 for (i = 1; i < tree->pages_per_bnode; i++) {
658 memzero_page(*++pagep, 0, PAGE_SIZE);
659 set_page_dirty(*pagep);
660 }
661 clear_bit(HFS_BNODE_NEW, &node->flags);
662 wake_up(&node->lock_wq);
663
664 return node;
665}
666
667void hfs_bnode_get(struct hfs_bnode *node)
668{
669 if (node) {
670 atomic_inc(&node->refcnt);
671 hfs_dbg("cnid %d, node %d, refcnt %d\n",
672 node->tree->cnid, node->this,
673 atomic_read(&node->refcnt));
674 }
675}
676
677/* Dispose of resources used by a node */
678void hfs_bnode_put(struct hfs_bnode *node)
679{
680 if (node) {
681 struct hfs_btree *tree = node->tree;
682 int i;
683
684 hfs_dbg("cnid %d, node %d, refcnt %d\n",
685 node->tree->cnid, node->this,
686 atomic_read(&node->refcnt));
687 BUG_ON(!atomic_read(&node->refcnt));
688 if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
689 return;
690 for (i = 0; i < tree->pages_per_bnode; i++) {
691 if (!node->page[i])
692 continue;
693 mark_page_accessed(node->page[i]);
694 }
695
696 if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
697 hfs_bnode_unhash(node);
698 spin_unlock(&tree->hash_lock);
699 if (hfs_bnode_need_zeroout(tree))
700 hfs_bnode_clear(node, 0, tree->node_size);
701 hfs_bmap_free(node);
702 hfs_bnode_free(node);
703 return;
704 }
705 spin_unlock(&tree->hash_lock);
706 }
707}
708
709/*
710 * Unused nodes have to be zeroed if this is the catalog tree and
711 * a corresponding flag in the volume header is set.
712 */
713bool hfs_bnode_need_zeroout(struct hfs_btree *tree)
714{
715 struct super_block *sb = tree->inode->i_sb;
716 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
717 const u32 volume_attr = be32_to_cpu(sbi->s_vhdr->attributes);
718
719 return volume_attr & HFSPLUS_VOL_UNUSED_NODE_FIX;
720}