1
|
diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c
|
2
|
index 82b9672..4edf541 100644
|
3
|
--- a/usr/src/cmd/zpool/zpool_main.c
|
4
|
+++ b/usr/src/cmd/zpool/zpool_main.c
|
5
|
@@ -36,6 +36,7 @@
|
6
|
#include <libgen.h>
|
7
|
#include <libintl.h>
|
8
|
#include <libuutil.h>
|
9
|
+#include <limits.h>
|
10
|
#include <locale.h>
|
11
|
#include <stdio.h>
|
12
|
#include <stdlib.h>
|
13
|
@@ -47,6 +48,7 @@
|
14
|
#include <zone.h>
|
15
|
#include <zfs_prop.h>
|
16
|
#include <sys/fs/zfs.h>
|
17
|
+#include <sys/vdev_impl.h>
|
18
|
#include <sys/stat.h>
|
19
|
|
20
|
#include <libzfs.h>
|
21
|
@@ -233,7 +235,8 @@ get_usage(zpool_help_t idx)
|
22
|
return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
|
23
|
"[count]]\n"));
|
24
|
case HELP_LABELCLEAR:
|
25
|
- return (gettext("\tlabelclear [-f] <vdev>\n"));
|
26
|
+ return (gettext("\tlabelclear [-b | -e | -i index] [-c] [-m] "
|
27
|
+ "[-f] <vdev>\n"));
|
28
|
case HELP_LIST:
|
29
|
return (gettext("\tlist [-Hp] [-o property[,...]] "
|
30
|
"[-T d|u] [pool] ... [interval [count]]\n"));
|
31
|
@@ -643,10 +646,40 @@ zpool_do_labelclear(int argc, char **argv)
|
32
|
pool_state_t state;
|
33
|
boolean_t inuse = B_FALSE;
|
34
|
boolean_t force = B_FALSE;
|
35
|
+ boolean_t check = B_FALSE;
|
36
|
+ boolean_t cherry = B_FALSE;
|
37
|
+ unsigned int start = 0, n = VDEV_LABELS;
|
38
|
+ char *end = NULL;
|
39
|
+ long long index = 0;
|
40
|
|
41
|
/* check options */
|
42
|
- while ((c = getopt(argc, argv, "f")) != -1) {
|
43
|
+ while ((c = getopt(argc, argv, "bei:cmf")) != -1) {
|
44
|
switch (c) {
|
45
|
+ case 'b':
|
46
|
+ start = 0;
|
47
|
+ n = VDEV_LABELS / 2;
|
48
|
+ break;
|
49
|
+ case 'e':
|
50
|
+ start = VDEV_LABELS / 2;
|
51
|
+ n = VDEV_LABELS / 2;
|
52
|
+ break;
|
53
|
+ case 'i':
|
54
|
+ index = strtoll(optarg, &end, 10);
|
55
|
+ if((end == optarg) || (*end != '\0') ||
|
56
|
+ (index < 0) || (index >= VDEV_LABELS)) {
|
57
|
+ (void) fprintf(stderr,
|
58
|
+ gettext("Invalid index value provided\n"));
|
59
|
+ return (1);
|
60
|
+ }
|
61
|
+ start = (unsigned int)index;
|
62
|
+ n = 1;
|
63
|
+ break;
|
64
|
+ case 'c':
|
65
|
+ check = B_TRUE;
|
66
|
+ break;
|
67
|
+ case 'm':
|
68
|
+ cherry = B_TRUE;
|
69
|
+ break;
|
70
|
case 'f':
|
71
|
force = B_TRUE;
|
72
|
break;
|
73
|
@@ -699,8 +732,12 @@ zpool_do_labelclear(int argc, char **argv)
|
74
|
}
|
75
|
|
76
|
if (zpool_read_label(fd, &config) != 0 || config == NULL) {
|
77
|
- (void) fprintf(stderr,
|
78
|
- gettext("failed to read label from %s\n"), vdev);
|
79
|
+ if (force)
|
80
|
+ goto wipe_label;
|
81
|
+ (void) fprintf(stderr, gettext(
|
82
|
+ "use '-f' to override the following error:\n"
|
83
|
+ "failed to read label from \"%s\"\n"),
|
84
|
+ vdev);
|
85
|
return (1);
|
86
|
}
|
87
|
nvlist_free(config);
|
88
|
@@ -753,7 +790,7 @@ zpool_do_labelclear(int argc, char **argv)
|
89
|
}
|
90
|
|
91
|
wipe_label:
|
92
|
- ret = zpool_clear_label(fd);
|
93
|
+ ret = zpool_clear_n_labels(fd, start, n, check, cherry);
|
94
|
if (ret != 0) {
|
95
|
(void) fprintf(stderr,
|
96
|
gettext("failed to clear label for %s\n"), vdev);
|
97
|
diff --git a/usr/src/common/nvpair/nvpair.c b/usr/src/common/nvpair/nvpair.c
|
98
|
index 2c1bcfa..36dc02b 100644
|
99
|
--- a/usr/src/common/nvpair/nvpair.c
|
100
|
+++ b/usr/src/common/nvpair/nvpair.c
|
101
|
@@ -2353,6 +2353,18 @@ nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
|
102
|
}
|
103
|
|
104
|
int
|
105
|
+nvlist_invalidate(char *buf)
|
106
|
+{
|
107
|
+ if (buf == NULL)
|
108
|
+ return (EINVAL);
|
109
|
+
|
110
|
+ nvs_header_t *nvh = (void *)buf;
|
111
|
+ nvh->nvh_encoding = NV_ENCODE_INVALID;
|
112
|
+
|
113
|
+ return (0);
|
114
|
+}
|
115
|
+
|
116
|
+int
|
117
|
nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
|
118
|
{
|
119
|
return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
|
120
|
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
|
121
|
index 9baff24..022634f 100644
|
122
|
--- a/usr/src/lib/libzfs/common/libzfs.h
|
123
|
+++ b/usr/src/lib/libzfs/common/libzfs.h
|
124
|
@@ -746,6 +746,7 @@ extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
|
125
|
* Label manipulation.
|
126
|
*/
|
127
|
extern int zpool_read_label(int, nvlist_t **);
|
128
|
+extern int zpool_clear_n_labels(int, unsigned int, unsigned int, boolean_t, boolean_t);
|
129
|
extern int zpool_clear_label(int);
|
130
|
|
131
|
/* is this zvol valid for use as a dump device? */
|
132
|
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c
|
133
|
index b73a71e..87aac2c 100644
|
134
|
--- a/usr/src/lib/libzfs/common/libzfs_import.c
|
135
|
+++ b/usr/src/lib/libzfs/common/libzfs_import.c
|
136
|
@@ -1084,36 +1084,68 @@ zpool_open_func(void *arg)
|
137
|
}
|
138
|
|
139
|
/*
|
140
|
- * Given a file descriptor, clear (zero) the label information.
|
141
|
+ * Given a file descriptor, a starting label and a number of labels to clear,
|
142
|
+ * clear (zero) the label information.
|
143
|
*/
|
144
|
int
|
145
|
-zpool_clear_label(int fd)
|
146
|
+zpool_clear_n_labels(int fd, unsigned int start, unsigned int n,
|
147
|
+ boolean_t check, boolean_t cherry)
|
148
|
{
|
149
|
struct stat64 statbuf;
|
150
|
- int l;
|
151
|
- vdev_label_t *label;
|
152
|
+ unsigned int l, end;
|
153
|
+ vdev_label_t label;
|
154
|
uint64_t size;
|
155
|
|
156
|
+ char *buf = label.vl_vdev_phys.vp_nvlist;
|
157
|
+ size_t buflen = sizeof (label.vl_vdev_phys.vp_nvlist);
|
158
|
+
|
159
|
if (fstat64(fd, &statbuf) == -1)
|
160
|
return (0);
|
161
|
size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
|
162
|
|
163
|
- if ((label = calloc(sizeof (vdev_label_t), 1)) == NULL)
|
164
|
+ end = start + n;
|
165
|
+ if (end > VDEV_LABELS)
|
166
|
return (-1);
|
167
|
|
168
|
- for (l = 0; l < VDEV_LABELS; l++) {
|
169
|
- if (pwrite64(fd, label, sizeof (vdev_label_t),
|
170
|
- label_offset(size, l)) != sizeof (vdev_label_t)) {
|
171
|
- free(label);
|
172
|
- return (-1);
|
173
|
+ for (l = start; l < end; l++) {
|
174
|
+ if ((check == B_TRUE) || (cherry == B_TRUE)) {
|
175
|
+ if (pread64(fd, &label, sizeof (vdev_label_t),
|
176
|
+ label_offset(size, l)) != sizeof (vdev_label_t))
|
177
|
+ return (-1);
|
178
|
+
|
179
|
+ if (check == B_TRUE) {
|
180
|
+ nvlist_t *config = NULL;
|
181
|
+ if (nvlist_unpack(buf, buflen, &config, 0) != 0)
|
182
|
+ return (-1);
|
183
|
+ nvlist_free(config);
|
184
|
+ }
|
185
|
+ }
|
186
|
+
|
187
|
+ if (cherry == B_TRUE) {
|
188
|
+ if (nvlist_invalidate(buf) != 0)
|
189
|
+ return (-1);
|
190
|
+ } else {
|
191
|
+ memset(&label, 0, sizeof (vdev_label_t));
|
192
|
}
|
193
|
+
|
194
|
+ if (pwrite64(fd, &label, sizeof (vdev_label_t),
|
195
|
+ label_offset(size, l)) != sizeof (vdev_label_t))
|
196
|
+ return (-1);
|
197
|
}
|
198
|
|
199
|
- free(label);
|
200
|
return (0);
|
201
|
}
|
202
|
|
203
|
/*
|
204
|
+ * Given a file descriptor, clear (zero) the label information.
|
205
|
+ */
|
206
|
+int
|
207
|
+zpool_clear_label(int fd)
|
208
|
+{
|
209
|
+ return (zpool_clear_n_labels(fd, 0, VDEV_LABELS, B_FALSE, B_FALSE));
|
210
|
+}
|
211
|
+
|
212
|
+/*
|
213
|
* Given a list of directories to search, find all pools stored on disk. This
|
214
|
* includes partial pools which are not available to import. If no args are
|
215
|
* given (argc is 0), then the default directory (/dev/dsk) is searched.
|
216
|
diff --git a/usr/src/man/man1m/zpool.1m b/usr/src/man/man1m/zpool.1m
|
217
|
index eadb548..fc20f5c 100644
|
218
|
--- a/usr/src/man/man1m/zpool.1m
|
219
|
+++ b/usr/src/man/man1m/zpool.1m
|
220
|
@@ -104,6 +104,9 @@
|
221
|
.Op Ar interval Op Ar count
|
222
|
.Nm
|
223
|
.Cm labelclear
|
224
|
+.Op Fl b | Fl e | Fl i Ar index
|
225
|
+.Op Fl c
|
226
|
+.Op Fl m
|
227
|
.Op Fl f
|
228
|
.Ar device
|
229
|
.Nm
|
230
|
@@ -1159,6 +1162,9 @@ pool, in addition to the pool-wide statistics.
|
231
|
.It Xo
|
232
|
.Nm
|
233
|
.Cm labelclear
|
234
|
+.Op Fl b | Fl e | Fl i Ar index
|
235
|
+.Op Fl c
|
236
|
+.Op Fl m
|
237
|
.Op Fl f
|
238
|
.Ar device
|
239
|
.Xc
|
240
|
@@ -1166,8 +1172,29 @@ Removes ZFS label information from the specified
|
241
|
.Ar device .
|
242
|
The
|
243
|
.Ar device
|
244
|
-must not be part of an active pool configuration.
|
245
|
+must not be part of an active pool configuration. Options
|
246
|
+.Fl b ,
|
247
|
+.Fl e
|
248
|
+and
|
249
|
+.Fl i
|
250
|
+can be used for clearing specific labels. They are mutually exclusive and the
|
251
|
+last one will supersede others, if any.
|
252
|
.Bl -tag -width Ds
|
253
|
+.It Fl b
|
254
|
+Only remove ZFS labels located at the beginning of
|
255
|
+.Ar device .
|
256
|
+.It Fl e
|
257
|
+Only remove ZFS labels located at the end of
|
258
|
+.Ar device .
|
259
|
+.It Fl i Ar index
|
260
|
+Remove a single label entry located at position
|
261
|
+.Ar index .
|
262
|
+.It Fl c
|
263
|
+Check label integrity before doing anything.
|
264
|
+.It Fl m
|
265
|
+Perform minimal operation needed to invalidate a label instead of blindly
|
266
|
+erasing every single byte. This reduces (but does not annihilate) the risks of
|
267
|
+overriding important on-disk data.
|
268
|
.It Fl f
|
269
|
Treat exported or foreign devices as inactive.
|
270
|
.El
|
271
|
diff --git a/usr/src/uts/common/sys/nvpair.h b/usr/src/uts/common/sys/nvpair.h
|
272
|
index e4d637b..36f2dd4 100644
|
273
|
--- a/usr/src/uts/common/sys/nvpair.h
|
274
|
+++ b/usr/src/uts/common/sys/nvpair.h
|
275
|
@@ -98,6 +98,7 @@ typedef struct nvlist {
|
276
|
#define NV_VERSION 0
|
277
|
|
278
|
/* nvlist pack encoding */
|
279
|
+#define NV_ENCODE_INVALID (-1)
|
280
|
#define NV_ENCODE_NATIVE 0
|
281
|
#define NV_ENCODE_XDR 1
|
282
|
|
283
|
@@ -153,6 +154,7 @@ void nv_alloc_fini(nv_alloc_t *);
|
284
|
/* list management */
|
285
|
int nvlist_alloc(nvlist_t **, uint_t, int);
|
286
|
void nvlist_free(nvlist_t *);
|
287
|
+int nvlist_invalidate(char *);
|
288
|
int nvlist_size(nvlist_t *, size_t *, int);
|
289
|
int nvlist_pack(nvlist_t *, char **, size_t *, int, int);
|
290
|
int nvlist_unpack(char *, size_t, nvlist_t **, int);
|