.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * This file is part of UBIFS. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2006-2008 Nokia Corporation. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
8 | | - * the Free Software Foundation. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
13 | | - * more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU General Public License along with |
---|
16 | | - * this program; if not, write to the Free Software Foundation, Inc., 51 |
---|
17 | | - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
18 | 6 | * |
---|
19 | 7 | * Author: Adrian Hunter |
---|
20 | 8 | */ |
---|
.. | .. |
---|
54 | 42 | |
---|
55 | 43 | static int dbg_check_orphans(struct ubifs_info *c); |
---|
56 | 44 | |
---|
57 | | -/** |
---|
58 | | - * ubifs_add_orphan - add an orphan. |
---|
59 | | - * @c: UBIFS file-system description object |
---|
60 | | - * @inum: orphan inode number |
---|
61 | | - * |
---|
62 | | - * Add an orphan. This function is called when an inodes link count drops to |
---|
63 | | - * zero. |
---|
64 | | - */ |
---|
65 | | -int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) |
---|
| 45 | +static struct ubifs_orphan *orphan_add(struct ubifs_info *c, ino_t inum, |
---|
| 46 | + struct ubifs_orphan *parent_orphan) |
---|
66 | 47 | { |
---|
67 | 48 | struct ubifs_orphan *orphan, *o; |
---|
68 | 49 | struct rb_node **p, *parent = NULL; |
---|
69 | 50 | |
---|
70 | 51 | orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS); |
---|
71 | 52 | if (!orphan) |
---|
72 | | - return -ENOMEM; |
---|
| 53 | + return ERR_PTR(-ENOMEM); |
---|
73 | 54 | orphan->inum = inum; |
---|
74 | 55 | orphan->new = 1; |
---|
| 56 | + INIT_LIST_HEAD(&orphan->child_list); |
---|
75 | 57 | |
---|
76 | 58 | spin_lock(&c->orphan_lock); |
---|
77 | 59 | if (c->tot_orphans >= c->max_orphans) { |
---|
78 | 60 | spin_unlock(&c->orphan_lock); |
---|
79 | 61 | kfree(orphan); |
---|
80 | | - return -ENFILE; |
---|
| 62 | + return ERR_PTR(-ENFILE); |
---|
81 | 63 | } |
---|
82 | 64 | p = &c->orph_tree.rb_node; |
---|
83 | 65 | while (*p) { |
---|
.. | .. |
---|
91 | 73 | ubifs_err(c, "orphaned twice"); |
---|
92 | 74 | spin_unlock(&c->orphan_lock); |
---|
93 | 75 | kfree(orphan); |
---|
94 | | - return 0; |
---|
| 76 | + return ERR_PTR(-EINVAL); |
---|
95 | 77 | } |
---|
96 | 78 | } |
---|
97 | 79 | c->tot_orphans += 1; |
---|
.. | .. |
---|
100 | 82 | rb_insert_color(&orphan->rb, &c->orph_tree); |
---|
101 | 83 | list_add_tail(&orphan->list, &c->orph_list); |
---|
102 | 84 | list_add_tail(&orphan->new_list, &c->orph_new); |
---|
| 85 | + |
---|
| 86 | + if (parent_orphan) { |
---|
| 87 | + list_add_tail(&orphan->child_list, |
---|
| 88 | + &parent_orphan->child_list); |
---|
| 89 | + } |
---|
| 90 | + |
---|
103 | 91 | spin_unlock(&c->orphan_lock); |
---|
104 | 92 | dbg_gen("ino %lu", (unsigned long)inum); |
---|
| 93 | + return orphan; |
---|
| 94 | +} |
---|
| 95 | + |
---|
| 96 | +static struct ubifs_orphan *lookup_orphan(struct ubifs_info *c, ino_t inum) |
---|
| 97 | +{ |
---|
| 98 | + struct ubifs_orphan *o; |
---|
| 99 | + struct rb_node *p; |
---|
| 100 | + |
---|
| 101 | + p = c->orph_tree.rb_node; |
---|
| 102 | + while (p) { |
---|
| 103 | + o = rb_entry(p, struct ubifs_orphan, rb); |
---|
| 104 | + if (inum < o->inum) |
---|
| 105 | + p = p->rb_left; |
---|
| 106 | + else if (inum > o->inum) |
---|
| 107 | + p = p->rb_right; |
---|
| 108 | + else { |
---|
| 109 | + return o; |
---|
| 110 | + } |
---|
| 111 | + } |
---|
| 112 | + return NULL; |
---|
| 113 | +} |
---|
| 114 | + |
---|
| 115 | +static void __orphan_drop(struct ubifs_info *c, struct ubifs_orphan *o) |
---|
| 116 | +{ |
---|
| 117 | + rb_erase(&o->rb, &c->orph_tree); |
---|
| 118 | + list_del(&o->list); |
---|
| 119 | + c->tot_orphans -= 1; |
---|
| 120 | + |
---|
| 121 | + if (o->new) { |
---|
| 122 | + list_del(&o->new_list); |
---|
| 123 | + c->new_orphans -= 1; |
---|
| 124 | + } |
---|
| 125 | + |
---|
| 126 | + kfree(o); |
---|
| 127 | +} |
---|
| 128 | + |
---|
| 129 | +static void orphan_delete(struct ubifs_info *c, struct ubifs_orphan *orph) |
---|
| 130 | +{ |
---|
| 131 | + if (orph->del) { |
---|
| 132 | + dbg_gen("deleted twice ino %lu", (unsigned long)orph->inum); |
---|
| 133 | + return; |
---|
| 134 | + } |
---|
| 135 | + |
---|
| 136 | + if (orph->cmt) { |
---|
| 137 | + orph->del = 1; |
---|
| 138 | + orph->dnext = c->orph_dnext; |
---|
| 139 | + c->orph_dnext = orph; |
---|
| 140 | + dbg_gen("delete later ino %lu", (unsigned long)orph->inum); |
---|
| 141 | + return; |
---|
| 142 | + } |
---|
| 143 | + |
---|
| 144 | + __orphan_drop(c, orph); |
---|
| 145 | +} |
---|
| 146 | + |
---|
| 147 | +/** |
---|
| 148 | + * ubifs_add_orphan - add an orphan. |
---|
| 149 | + * @c: UBIFS file-system description object |
---|
| 150 | + * @inum: orphan inode number |
---|
| 151 | + * |
---|
| 152 | + * Add an orphan. This function is called when an inodes link count drops to |
---|
| 153 | + * zero. |
---|
| 154 | + */ |
---|
| 155 | +int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) |
---|
| 156 | +{ |
---|
| 157 | + int err = 0; |
---|
| 158 | + ino_t xattr_inum; |
---|
| 159 | + union ubifs_key key; |
---|
| 160 | + struct ubifs_dent_node *xent, *pxent = NULL; |
---|
| 161 | + struct fscrypt_name nm = {0}; |
---|
| 162 | + struct ubifs_orphan *xattr_orphan; |
---|
| 163 | + struct ubifs_orphan *orphan; |
---|
| 164 | + |
---|
| 165 | + orphan = orphan_add(c, inum, NULL); |
---|
| 166 | + if (IS_ERR(orphan)) |
---|
| 167 | + return PTR_ERR(orphan); |
---|
| 168 | + |
---|
| 169 | + lowest_xent_key(c, &key, inum); |
---|
| 170 | + while (1) { |
---|
| 171 | + xent = ubifs_tnc_next_ent(c, &key, &nm); |
---|
| 172 | + if (IS_ERR(xent)) { |
---|
| 173 | + err = PTR_ERR(xent); |
---|
| 174 | + if (err == -ENOENT) |
---|
| 175 | + break; |
---|
| 176 | + kfree(pxent); |
---|
| 177 | + return err; |
---|
| 178 | + } |
---|
| 179 | + |
---|
| 180 | + fname_name(&nm) = xent->name; |
---|
| 181 | + fname_len(&nm) = le16_to_cpu(xent->nlen); |
---|
| 182 | + xattr_inum = le64_to_cpu(xent->inum); |
---|
| 183 | + |
---|
| 184 | + xattr_orphan = orphan_add(c, xattr_inum, orphan); |
---|
| 185 | + if (IS_ERR(xattr_orphan)) { |
---|
| 186 | + kfree(pxent); |
---|
| 187 | + kfree(xent); |
---|
| 188 | + return PTR_ERR(xattr_orphan); |
---|
| 189 | + } |
---|
| 190 | + |
---|
| 191 | + kfree(pxent); |
---|
| 192 | + pxent = xent; |
---|
| 193 | + key_read(c, &xent->key, &key); |
---|
| 194 | + } |
---|
| 195 | + kfree(pxent); |
---|
| 196 | + |
---|
105 | 197 | return 0; |
---|
106 | 198 | } |
---|
107 | 199 | |
---|
.. | .. |
---|
114 | 206 | */ |
---|
115 | 207 | void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum) |
---|
116 | 208 | { |
---|
117 | | - struct ubifs_orphan *o; |
---|
118 | | - struct rb_node *p; |
---|
| 209 | + struct ubifs_orphan *orph, *child_orph, *tmp_o; |
---|
119 | 210 | |
---|
120 | 211 | spin_lock(&c->orphan_lock); |
---|
121 | | - p = c->orph_tree.rb_node; |
---|
122 | | - while (p) { |
---|
123 | | - o = rb_entry(p, struct ubifs_orphan, rb); |
---|
124 | | - if (inum < o->inum) |
---|
125 | | - p = p->rb_left; |
---|
126 | | - else if (inum > o->inum) |
---|
127 | | - p = p->rb_right; |
---|
128 | | - else { |
---|
129 | | - if (o->del) { |
---|
130 | | - spin_unlock(&c->orphan_lock); |
---|
131 | | - dbg_gen("deleted twice ino %lu", |
---|
132 | | - (unsigned long)inum); |
---|
133 | | - return; |
---|
134 | | - } |
---|
135 | | - if (o->cmt) { |
---|
136 | | - o->del = 1; |
---|
137 | | - o->dnext = c->orph_dnext; |
---|
138 | | - c->orph_dnext = o; |
---|
139 | | - spin_unlock(&c->orphan_lock); |
---|
140 | | - dbg_gen("delete later ino %lu", |
---|
141 | | - (unsigned long)inum); |
---|
142 | | - return; |
---|
143 | | - } |
---|
144 | | - rb_erase(p, &c->orph_tree); |
---|
145 | | - list_del(&o->list); |
---|
146 | | - c->tot_orphans -= 1; |
---|
147 | | - if (o->new) { |
---|
148 | | - list_del(&o->new_list); |
---|
149 | | - c->new_orphans -= 1; |
---|
150 | | - } |
---|
151 | | - spin_unlock(&c->orphan_lock); |
---|
152 | | - kfree(o); |
---|
153 | | - dbg_gen("inum %lu", (unsigned long)inum); |
---|
154 | | - return; |
---|
155 | | - } |
---|
| 212 | + |
---|
| 213 | + orph = lookup_orphan(c, inum); |
---|
| 214 | + if (!orph) { |
---|
| 215 | + spin_unlock(&c->orphan_lock); |
---|
| 216 | + ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum); |
---|
| 217 | + dump_stack(); |
---|
| 218 | + |
---|
| 219 | + return; |
---|
156 | 220 | } |
---|
| 221 | + |
---|
| 222 | + list_for_each_entry_safe(child_orph, tmp_o, &orph->child_list, child_list) { |
---|
| 223 | + list_del(&child_orph->child_list); |
---|
| 224 | + orphan_delete(c, child_orph); |
---|
| 225 | + } |
---|
| 226 | + |
---|
| 227 | + orphan_delete(c, orph); |
---|
| 228 | + |
---|
157 | 229 | spin_unlock(&c->orphan_lock); |
---|
158 | | - ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum); |
---|
159 | | - dump_stack(); |
---|
160 | 230 | } |
---|
161 | 231 | |
---|
162 | 232 | /** |
---|
.. | .. |
---|
563 | 633 | { |
---|
564 | 634 | struct ubifs_scan_node *snod; |
---|
565 | 635 | struct ubifs_orph_node *orph; |
---|
| 636 | + struct ubifs_ino_node *ino = NULL; |
---|
566 | 637 | unsigned long long cmt_no; |
---|
567 | 638 | ino_t inum; |
---|
568 | 639 | int i, n, err, first = 1; |
---|
| 640 | + |
---|
| 641 | + ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS); |
---|
| 642 | + if (!ino) |
---|
| 643 | + return -ENOMEM; |
---|
569 | 644 | |
---|
570 | 645 | list_for_each_entry(snod, &sleb->nodes, list) { |
---|
571 | 646 | if (snod->type != UBIFS_ORPH_NODE) { |
---|
572 | 647 | ubifs_err(c, "invalid node type %d in orphan area at %d:%d", |
---|
573 | 648 | snod->type, sleb->lnum, snod->offs); |
---|
574 | 649 | ubifs_dump_node(c, snod->node); |
---|
575 | | - return -EINVAL; |
---|
| 650 | + err = -EINVAL; |
---|
| 651 | + goto out_free; |
---|
576 | 652 | } |
---|
577 | 653 | |
---|
578 | 654 | orph = snod->node; |
---|
.. | .. |
---|
599 | 675 | ubifs_err(c, "out of order commit number %llu in orphan node at %d:%d", |
---|
600 | 676 | cmt_no, sleb->lnum, snod->offs); |
---|
601 | 677 | ubifs_dump_node(c, snod->node); |
---|
602 | | - return -EINVAL; |
---|
| 678 | + err = -EINVAL; |
---|
| 679 | + goto out_free; |
---|
603 | 680 | } |
---|
604 | 681 | dbg_rcvry("out of date LEB %d", sleb->lnum); |
---|
605 | 682 | *outofdate = 1; |
---|
606 | | - return 0; |
---|
| 683 | + err = 0; |
---|
| 684 | + goto out_free; |
---|
607 | 685 | } |
---|
608 | 686 | |
---|
609 | 687 | if (first) |
---|
.. | .. |
---|
611 | 689 | |
---|
612 | 690 | n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3; |
---|
613 | 691 | for (i = 0; i < n; i++) { |
---|
| 692 | + union ubifs_key key1, key2; |
---|
| 693 | + |
---|
614 | 694 | inum = le64_to_cpu(orph->inos[i]); |
---|
615 | | - dbg_rcvry("deleting orphaned inode %lu", |
---|
616 | | - (unsigned long)inum); |
---|
617 | | - err = ubifs_tnc_remove_ino(c, inum); |
---|
618 | | - if (err) |
---|
619 | | - return err; |
---|
| 695 | + |
---|
| 696 | + ino_key_init(c, &key1, inum); |
---|
| 697 | + err = ubifs_tnc_lookup(c, &key1, ino); |
---|
| 698 | + if (err && err != -ENOENT) |
---|
| 699 | + goto out_free; |
---|
| 700 | + |
---|
| 701 | + /* |
---|
| 702 | + * Check whether an inode can really get deleted. |
---|
| 703 | + * linkat() with O_TMPFILE allows rebirth of an inode. |
---|
| 704 | + */ |
---|
| 705 | + if (err == 0 && ino->nlink == 0) { |
---|
| 706 | + dbg_rcvry("deleting orphaned inode %lu", |
---|
| 707 | + (unsigned long)inum); |
---|
| 708 | + |
---|
| 709 | + lowest_ino_key(c, &key1, inum); |
---|
| 710 | + highest_ino_key(c, &key2, inum); |
---|
| 711 | + |
---|
| 712 | + err = ubifs_tnc_remove_range(c, &key1, &key2); |
---|
| 713 | + if (err) |
---|
| 714 | + goto out_ro; |
---|
| 715 | + } |
---|
| 716 | + |
---|
620 | 717 | err = insert_dead_orphan(c, inum); |
---|
621 | 718 | if (err) |
---|
622 | | - return err; |
---|
| 719 | + goto out_free; |
---|
623 | 720 | } |
---|
624 | 721 | |
---|
625 | 722 | *last_cmt_no = cmt_no; |
---|
.. | .. |
---|
631 | 728 | *last_flagged = 0; |
---|
632 | 729 | } |
---|
633 | 730 | |
---|
634 | | - return 0; |
---|
| 731 | + err = 0; |
---|
| 732 | +out_free: |
---|
| 733 | + kfree(ino); |
---|
| 734 | + return err; |
---|
| 735 | + |
---|
| 736 | +out_ro: |
---|
| 737 | + ubifs_ro_mode(c, err); |
---|
| 738 | + kfree(ino); |
---|
| 739 | + return err; |
---|
635 | 740 | } |
---|
636 | 741 | |
---|
637 | 742 | /** |
---|
.. | .. |
---|
744 | 849 | struct rb_root root; |
---|
745 | 850 | }; |
---|
746 | 851 | |
---|
747 | | -static int dbg_find_orphan(struct ubifs_info *c, ino_t inum) |
---|
| 852 | +static bool dbg_find_orphan(struct ubifs_info *c, ino_t inum) |
---|
748 | 853 | { |
---|
749 | | - struct ubifs_orphan *o; |
---|
750 | | - struct rb_node *p; |
---|
| 854 | + bool found = false; |
---|
751 | 855 | |
---|
752 | 856 | spin_lock(&c->orphan_lock); |
---|
753 | | - p = c->orph_tree.rb_node; |
---|
754 | | - while (p) { |
---|
755 | | - o = rb_entry(p, struct ubifs_orphan, rb); |
---|
756 | | - if (inum < o->inum) |
---|
757 | | - p = p->rb_left; |
---|
758 | | - else if (inum > o->inum) |
---|
759 | | - p = p->rb_right; |
---|
760 | | - else { |
---|
761 | | - spin_unlock(&c->orphan_lock); |
---|
762 | | - return 1; |
---|
763 | | - } |
---|
764 | | - } |
---|
| 857 | + found = !!lookup_orphan(c, inum); |
---|
765 | 858 | spin_unlock(&c->orphan_lock); |
---|
766 | | - return 0; |
---|
| 859 | + |
---|
| 860 | + return found; |
---|
767 | 861 | } |
---|
768 | 862 | |
---|
769 | 863 | static int dbg_ins_check_orphan(struct rb_root *root, ino_t inum) |
---|
.. | .. |
---|
885 | 979 | if (c->no_orphs) |
---|
886 | 980 | return 0; |
---|
887 | 981 | |
---|
888 | | - buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL); |
---|
| 982 | + buf = __vmalloc(c->leb_size, GFP_NOFS); |
---|
889 | 983 | if (!buf) { |
---|
890 | 984 | ubifs_err(c, "cannot allocate memory to check orphans"); |
---|
891 | 985 | return 0; |
---|