Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Copyright (C) 2024, Huawei Technologies Co, Ltd.
4 : *
5 : * Authors: Huang Xiaojia <huangxiaojia2@huawei.com>
6 : * Zhihao Cheng <chengzhihao1@huawei.com>
7 : */
8 :
9 : #include <stdio.h>
10 : #include <stdlib.h>
11 : #include <sys/stat.h>
12 :
13 : #include "linux_err.h"
14 : #include "kmem.h"
15 : #include "ubifs.h"
16 : #include "defs.h"
17 : #include "debug.h"
18 : #include "key.h"
19 : #include "fsck.ubifs.h"
20 :
21 : #define LOST_FOUND_DIR_NAME "lost+found"
22 : #define MAX_REPEAT_NAME_RETRY_TIMES 10000000
23 :
24 : /**
25 : * check_and_create_lost_found - Check and create the lost+found directory.
26 : * @c: UBIFS file-system description object
27 : *
28 : * This function checks whether the lost+found directory exists and creates a
29 : * new one if no valid lost+found existing. If there is a valid lost+found
30 : * directory, inode number is stored in @FSCK(c)->lost_and_found. Returns zero
31 : * in case of success, a negative error code in case of failure.
32 : */
33 37 : int check_and_create_lost_found(struct ubifs_info *c)
34 : {
35 : struct ubifs_inode *root_ui, *lost_found_ui;
36 : struct fscrypt_name nm;
37 37 : int err = 0;
38 :
39 37 : root_ui = ubifs_lookup_by_inum(c, UBIFS_ROOT_INO);
40 37 : if (IS_ERR(root_ui)) {
41 0 : err = PTR_ERR(root_ui);
42 : /* Previous step ensures that the root dir is valid. */
43 0 : ubifs_assert(c, err != -ENOENT);
44 : return err;
45 : }
46 :
47 37 : if (root_ui->flags & UBIFS_CRYPT_FL) {
48 1 : ubifs_msg(c, "The root dir is encrypted, skip checking lost+found");
49 : goto free_root;
50 : }
51 :
52 36 : fname_name(&nm) = LOST_FOUND_DIR_NAME;
53 36 : fname_len(&nm) = strlen(LOST_FOUND_DIR_NAME);
54 36 : lost_found_ui = ubifs_lookup(c, root_ui, &nm);
55 36 : if (IS_ERR(lost_found_ui)) {
56 30 : err = PTR_ERR(lost_found_ui);
57 30 : if (err != -ENOENT)
58 : goto free_root;
59 :
60 : /* Not found. Create a new lost+found. */
61 30 : err = ubifs_mkdir(c, root_ui, &nm, S_IRUGO | S_IWUSR | S_IXUSR);
62 30 : if (err < 0) {
63 0 : if (err == -ENOSPC) {
64 0 : ubifs_msg(c, "No free space to create lost+found");
65 : err = 0;
66 : }
67 : goto free_root;
68 : }
69 30 : lost_found_ui = ubifs_lookup(c, root_ui, &nm);
70 30 : if (IS_ERR(lost_found_ui)) {
71 0 : err = PTR_ERR(lost_found_ui);
72 0 : ubifs_assert(c, err != -ENOENT);
73 : goto free_root;
74 : }
75 30 : FSCK(c)->lost_and_found = lost_found_ui->vfs_inode.inum;
76 30 : ubifs_msg(c, "Create the lost+found");
77 12 : } else if (!(lost_found_ui->flags & UBIFS_CRYPT_FL) &&
78 6 : S_ISDIR(lost_found_ui->vfs_inode.mode)) {
79 3 : FSCK(c)->lost_and_found = lost_found_ui->vfs_inode.inum;
80 : } else {
81 3 : ubifs_msg(c, "The type of lost+found is %s%s",
82 : ubifs_get_type_name(ubifs_get_dent_type(lost_found_ui->vfs_inode.mode)),
83 : lost_found_ui->flags & UBIFS_CRYPT_FL ? ", encrypted" : "");
84 : }
85 :
86 : kfree(lost_found_ui);
87 37 : free_root:
88 37 : kfree(root_ui);
89 37 : return err;
90 : }
91 :
92 830 : static int handle_disonnected_file(struct ubifs_info *c,
93 : struct scanned_file *file)
94 : {
95 830 : int err = 0;
96 :
97 830 : if (FSCK(c)->lost_and_found) {
98 202 : unsigned int index = 0;
99 : char file_name[UBIFS_MAX_NLEN + 1];
100 : struct fscrypt_name nm;
101 202 : struct ubifs_inode *ui = NULL, *lost_found_ui = NULL;
102 :
103 202 : lost_found_ui = ubifs_lookup_by_inum(c, FSCK(c)->lost_and_found);
104 202 : if (IS_ERR(lost_found_ui)) {
105 0 : err = PTR_ERR(lost_found_ui);
106 0 : ubifs_assert(c, err != -ENOENT);
107 202 : return err;
108 : }
109 202 : ui = ubifs_lookup_by_inum(c, file->inum);
110 202 : if (IS_ERR(ui)) {
111 0 : err = PTR_ERR(ui);
112 0 : ubifs_assert(c, err != -ENOENT);
113 : goto free_lost_found_ui;
114 : }
115 :
116 205 : while (index < MAX_REPEAT_NAME_RETRY_TIMES) {
117 : struct ubifs_inode *target_ui;
118 :
119 205 : err = snprintf(file_name, sizeof(file_name),
120 : "INO_%lu_%u", file->inum, index);
121 205 : if (err < 0)
122 : goto free_ui;
123 205 : fname_name(&nm) = file_name;
124 205 : fname_len(&nm) = strlen(file_name);
125 205 : target_ui = ubifs_lookup(c, lost_found_ui, &nm);
126 205 : if (IS_ERR(target_ui)) {
127 202 : err = PTR_ERR(target_ui);
128 202 : if (err == -ENOENT)
129 : break;
130 : goto free_ui;
131 : }
132 3 : kfree(target_ui);
133 3 : index++;
134 : }
135 :
136 202 : if (err != -ENOENT) {
137 0 : err = 0;
138 0 : kfree(ui);
139 0 : kfree(lost_found_ui);
140 0 : log_out(c, "Too many duplicated names(%u) in lost+found for inum %lu",
141 : index, file->inum);
142 0 : goto delete_file;
143 : }
144 :
145 : /* Try to recover disconnected file into lost+found. */
146 202 : err = ubifs_link_recovery(c, lost_found_ui, ui, &nm);
147 202 : if (err && err == -ENOSPC) {
148 0 : err = 0;
149 0 : log_out(c, "No free space to recover disconnected file");
150 0 : goto delete_file;
151 : }
152 382 : dbg_fsck("recover disconnected file %lu, in %s",
153 : file->inum, c->dev_name);
154 :
155 224 : free_ui:
156 : kfree(ui);
157 202 : free_lost_found_ui:
158 202 : kfree(lost_found_ui);
159 202 : return err;
160 : } else
161 628 : log_out(c, "No valid lost+found");
162 :
163 628 : delete_file:
164 628 : if (fix_problem(c, DISCONNECTED_FILE_CANNOT_BE_RECOVERED, file))
165 628 : err = delete_file(c, file);
166 : return err;
167 : }
168 :
169 : /**
170 : * handle_disonnected_files - Handle disconnected files.
171 : * @c: UBIFS file-system description object
172 : *
173 : * This function tries to recover disonnected files into lost+found directory.
174 : * If there is no free space left to recover the disconnected files, fsck may
175 : * delete the files to make filesystem be consistent. Returns zero in case of
176 : * success, a negative error code in case of failure.
177 : */
178 37 : int handle_disonnected_files(struct ubifs_info *c)
179 : {
180 37 : int err, ret = 0;
181 : struct scanned_file *file;
182 :
183 1771 : while (!list_empty(&FSCK(c)->disconnected_files)) {
184 830 : file = list_entry(FSCK(c)->disconnected_files.next,
185 : struct scanned_file, list);
186 :
187 1660 : list_del(&file->list);
188 830 : err = handle_disonnected_file(c, file);
189 830 : if (err)
190 0 : ret = ret ? ret : err;
191 830 : destroy_file_content(c, file);
192 : kfree(file);
193 : }
194 :
195 37 : return ret;
196 : }
|