Project

General

Profile

Feature #7584 » patch-zpool_labelclear-take_three.txt

Ganael Laplanche, 2017-07-16 12:23 PM

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