]> git.proxmox.com Git - ceph.git/blob - ceph/src/pmdk/src/common/set_badblocks.c
import ceph 16.2.7
[ceph.git] / ceph / src / pmdk / src / common / set_badblocks.c
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2018-2020, Intel Corporation */
3
4 /*
5 * set_badblocks.c - common part of implementation of bad blocks API
6 */
7 #define _GNU_SOURCE
8
9 #include <fcntl.h>
10 #include <inttypes.h>
11 #include <errno.h>
12
13 #include "file.h"
14 #include "os.h"
15 #include "out.h"
16 #include "set_badblocks.h"
17 #include "badblocks.h"
18
19 /* helper structure for badblocks_check_file_cb() */
20 struct check_file_cb {
21 int n_files_bbs; /* number of files with bad blocks */
22 int create; /* poolset is just being created */
23 };
24
25 /*
26 * badblocks_check_file_cb -- (internal) callback checking bad blocks
27 * in the given file
28 */
29 static int
30 badblocks_check_file_cb(struct part_file *pf, void *arg)
31 {
32 LOG(3, "part_file %p arg %p", pf, arg);
33
34 struct check_file_cb *pcfcb = arg;
35
36 if (pf->is_remote) {
37 /*
38 * Remote replicas are checked for bad blocks
39 * while opening in util_pool_open_remote().
40 */
41 return 0;
42 }
43
44 int exists = util_file_exists(pf->part->path);
45 if (exists < 0)
46 return -1;
47
48 if (!exists)
49 /* the part does not exist, so it has no bad blocks */
50 return 0;
51
52 int ret = badblocks_check_file(pf->part->path);
53 if (ret < 0) {
54 ERR("checking the pool file for bad blocks failed -- '%s'",
55 pf->part->path);
56 return -1;
57 }
58
59 if (ret > 0) {
60 ERR("part file contains bad blocks -- '%s'", pf->part->path);
61 pcfcb->n_files_bbs++;
62 pf->part->has_bad_blocks = 1;
63 }
64
65 return 0;
66 }
67
68 /*
69 * badblocks_check_poolset -- checks if the pool set contains bad blocks
70 *
71 * Return value:
72 * -1 error
73 * 0 pool set does not contain bad blocks
74 * 1 pool set contains bad blocks
75 */
76 int
77 badblocks_check_poolset(struct pool_set *set, int create)
78 {
79 LOG(3, "set %p create %i", set, create);
80
81 struct check_file_cb cfcb;
82
83 cfcb.n_files_bbs = 0;
84 cfcb.create = create;
85
86 if (util_poolset_foreach_part_struct(set, badblocks_check_file_cb,
87 &cfcb)) {
88 return -1;
89 }
90
91 if (cfcb.n_files_bbs) {
92 LOG(1, "%i pool file(s) contain bad blocks", cfcb.n_files_bbs);
93 set->has_bad_blocks = 1;
94 }
95
96 return (cfcb.n_files_bbs > 0);
97 }
98
99 /*
100 * badblocks_clear_poolset_cb -- (internal) callback clearing bad blocks
101 * in the given file
102 */
103 static int
104 badblocks_clear_poolset_cb(struct part_file *pf, void *arg)
105 {
106 LOG(3, "part_file %p arg %p", pf, arg);
107
108 int *create = arg;
109
110 if (pf->is_remote) { /* XXX not supported yet */
111 LOG(1,
112 "WARNING: clearing bad blocks in remote replicas is not supported yet -- '%s:%s'",
113 pf->remote->node_addr, pf->remote->pool_desc);
114 return 0;
115 }
116
117 if (*create) {
118 /*
119 * Poolset is just being created - check if file exists
120 * and if we can read it.
121 */
122 int exists = util_file_exists(pf->part->path);
123 if (exists < 0)
124 return -1;
125
126 if (!exists)
127 return 0;
128 }
129
130 int ret = badblocks_clear_all(pf->part->path);
131 if (ret < 0) {
132 ERR("clearing bad blocks in the pool file failed -- '%s'",
133 pf->part->path);
134 errno = EIO;
135 return -1;
136 }
137
138 pf->part->has_bad_blocks = 0;
139
140 return 0;
141 }
142
143 /*
144 * badblocks_clear_poolset -- clears bad blocks in the pool set
145 */
146 int
147 badblocks_clear_poolset(struct pool_set *set, int create)
148 {
149 LOG(3, "set %p create %i", set, create);
150
151 if (util_poolset_foreach_part_struct(set, badblocks_clear_poolset_cb,
152 &create)) {
153 return -1;
154 }
155
156 set->has_bad_blocks = 0;
157
158 return 0;
159 }
160
161 /*
162 * badblocks_recovery_file_alloc -- allocate name of bad block recovery file,
163 * the allocated name has to be freed
164 * using Free()
165 */
166 char *
167 badblocks_recovery_file_alloc(const char *file, unsigned rep, unsigned part)
168 {
169 LOG(3, "file %s rep %u part %u", file, rep, part);
170
171 char bbs_suffix[64];
172 char *path;
173
174 sprintf(bbs_suffix, "_r%u_p%u_badblocks.txt", rep, part);
175
176 size_t len_file = strlen(file);
177 size_t len_bbs_suffix = strlen(bbs_suffix);
178 size_t len_path = len_file + len_bbs_suffix;
179
180 path = Malloc(len_path + 1);
181 if (path == NULL) {
182 ERR("!Malloc");
183 return NULL;
184 }
185
186 strcpy(path, file);
187 strcat(path, bbs_suffix);
188
189 return path;
190 }
191
192 /*
193 * badblocks_recovery_file_exists -- check if any bad block recovery file exists
194 *
195 * Returns:
196 * 0 when there are no bad block recovery files and
197 * 1 when there is at least one bad block recovery file.
198 */
199 int
200 badblocks_recovery_file_exists(struct pool_set *set)
201 {
202 LOG(3, "set %p", set);
203
204 int recovery_file_exists = 0;
205
206 for (unsigned r = 0; r < set->nreplicas; ++r) {
207 struct pool_replica *rep = set->replica[r];
208
209 /* XXX: not supported yet */
210 if (rep->remote)
211 continue;
212
213 for (unsigned p = 0; p < rep->nparts; ++p) {
214 const char *path = PART(rep, p)->path;
215
216 int exists = util_file_exists(path);
217 if (exists < 0)
218 return -1;
219
220 if (!exists) {
221 /* part file does not exist - skip it */
222 continue;
223 }
224
225 char *rec_file =
226 badblocks_recovery_file_alloc(set->path, r, p);
227 if (rec_file == NULL) {
228 LOG(1,
229 "allocating name of bad block recovery file failed");
230 return -1;
231 }
232
233 exists = util_file_exists(rec_file);
234 if (exists < 0) {
235 Free(rec_file);
236 return -1;
237 }
238
239 if (exists) {
240 LOG(3, "bad block recovery file exists: %s",
241 rec_file);
242
243 recovery_file_exists = 1;
244 }
245
246 Free(rec_file);
247
248 if (recovery_file_exists)
249 return 1;
250 }
251 }
252
253 return 0;
254 }