Project

General

Profile

Feature #7584 » patch-zpool_labelclear-second_take.txt

Second version of the patch - Ganael Laplanche, 2017-07-13 10:32 AM

 
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..5269d7754c 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,40 @@ 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
+	char *end = NULL;
56
+	long long index = 0;
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 = strtoll(optarg, &end, 10);
72
+			if((end == optarg) || (*end != '\0') ||
73
+			    (index < 0) || (index >= VDEV_LABELS)) {
74
+				(void) fprintf(stderr,
75
+				    gettext("Invalid index value provided\n"));
76
+				return (1);
77
+			}
78
+			start = (unsigned int)index;
79
+			n = 1;
80
+			break;
81
+		case 'c':
82
+			check = B_TRUE;
83
+			break;
84
+		case 'm':
85
+			cherry = B_TRUE;
86
+			break;
87
 		case 'f':
88
 			force = B_TRUE;
89
 			break;
90
@@ -708,8 +741,12 @@ zpool_do_labelclear(int argc, char **argv)
91
 	}
92
 
93
 	if (zpool_read_label(fd, &config) != 0 || config == NULL) {
94
-		(void) fprintf(stderr,
95
-		    gettext("failed to read label from %s\n"), vdev);
96
+		if (force)
97
+			goto wipe_label;
98
+		(void) fprintf(stderr, gettext(
99
+		    "use '-f' to override the following error:\n"
100
+		    "failed to read label from \"%s\"\n"),
101
+		     vdev);
102
 		return (1);
103
 	}
104
 	nvlist_free(config);
105
@@ -762,7 +799,7 @@ zpool_do_labelclear(int argc, char **argv)
106
 	}
107
 
108
 wipe_label:
109
-	ret = zpool_clear_label(fd);
110
+	ret = zpool_clear_n_labels(fd, start, n, check, cherry);
111
 	if (ret != 0) {
112
 		(void) fprintf(stderr,
113
 		    gettext("failed to clear label for %s\n"), vdev);
114
diff --git a/usr/src/common/nvpair/nvpair.c b/usr/src/common/nvpair/nvpair.c
115
index 5881ba54b7..e6aa5b5660 100644
116
--- a/usr/src/common/nvpair/nvpair.c
117
+++ b/usr/src/common/nvpair/nvpair.c
118
@@ -2355,6 +2355,18 @@ nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
119
 }
120
 
121
 int
122
+nvlist_invalidate(char *buf)
123
+{
124
+	if (buf == NULL)
125
+		return (EINVAL);
126
+
127
+	nvs_header_t *nvh = (void *)buf;
128
+	nvh->nvh_encoding = NV_ENCODE_INVALID;
129
+
130
+	return (0);
131
+}
132
+
133
+int
134
 nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
135
 {
136
 	return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
137
diff --git a/usr/src/lib/libnvpair/mapfile-vers b/usr/src/lib/libnvpair/mapfile-vers
138
index 0403964e05..f1f3c265ed 100644
139
--- a/usr/src/lib/libnvpair/mapfile-vers
140
+++ b/usr/src/lib/libnvpair/mapfile-vers
141
@@ -198,6 +198,7 @@ SYMBOL_VERSION SUNW_1.1 {
142
 	nvlist_alloc;
143
 	nvlist_dup;
144
 	nvlist_free;
145
+	nvlist_invalidate;
146
 	nvlist_lookup_boolean;
147
 	nvlist_lookup_byte;
148
 	nvlist_lookup_byte_array;
149
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
150
index 5f81aa2048..31009ef9c1 100644
151
--- a/usr/src/lib/libzfs/common/libzfs.h
152
+++ b/usr/src/lib/libzfs/common/libzfs.h
153
@@ -763,6 +763,8 @@ extern int zpool_in_use(libzfs_handle_t *, int, pool_state_t *, char **,
154
  * Label manipulation.
155
  */
156
 extern int zpool_read_label(int, nvlist_t **);
157
+extern int zpool_clear_n_labels(int, unsigned int, unsigned int, boolean_t,
158
+    boolean_t);
159
 extern int zpool_clear_label(int);
160
 
161
 /* is this zvol valid for use as a dump device? */
162
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c
163
index 496ba2c321..a924d49884 100644
164
--- a/usr/src/lib/libzfs/common/libzfs_import.c
165
+++ b/usr/src/lib/libzfs/common/libzfs_import.c
166
@@ -1063,36 +1063,68 @@ zpool_open_func(void *arg)
167
 }
168
 
169
 /*
170
- * Given a file descriptor, clear (zero) the label information.
171
+ * Given a file descriptor, a starting label and a number of labels to clear,
172
+ * clear (zero) the label information.
173
  */
174
 int
175
-zpool_clear_label(int fd)
176
+zpool_clear_n_labels(int fd, unsigned int start, unsigned int n,
177
+    boolean_t check, boolean_t cherry)
178
 {
179
 	struct stat64 statbuf;
180
-	int l;
181
-	vdev_label_t *label;
182
+	unsigned int l, end;
183
+	vdev_label_t label;
184
 	uint64_t size;
185
 
186
+	char *buf = label.vl_vdev_phys.vp_nvlist;
187
+	size_t buflen = sizeof (label.vl_vdev_phys.vp_nvlist);
188
+
189
 	if (fstat64(fd, &statbuf) == -1)
190
 		return (0);
191
 	size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
192
 
193
-	if ((label = calloc(sizeof (vdev_label_t), 1)) == NULL)
194
+	end = start + n;
195
+	if (end > VDEV_LABELS)
196
 		return (-1);
197
 
198
-	for (l = 0; l < VDEV_LABELS; l++) {
199
-		if (pwrite64(fd, label, sizeof (vdev_label_t),
200
-		    label_offset(size, l)) != sizeof (vdev_label_t)) {
201
-			free(label);
202
-			return (-1);
203
+	for (l = start; l < end; l++) {
204
+		if ((check == B_TRUE) || (cherry == B_TRUE)) {
205
+			if (pread64(fd, &label, sizeof (vdev_label_t),
206
+			    label_offset(size, l)) != sizeof (vdev_label_t))
207
+				return (-1);
208
+
209
+			if (check == B_TRUE) {
210
+				nvlist_t *config = NULL;
211
+				if (nvlist_unpack(buf, buflen, &config, 0) != 0)
212
+					return (-1);
213
+				nvlist_free(config);
214
+			}
215
+		}
216
+
217
+		if (cherry == B_TRUE) {
218
+			if (nvlist_invalidate(buf) != 0)
219
+				return (-1);
220
+		} else {
221
+			memset(&label, 0, sizeof (vdev_label_t));
222
 		}
223
+
224
+		if (pwrite64(fd, &label, sizeof (vdev_label_t),
225
+		    label_offset(size, l)) != sizeof (vdev_label_t))
226
+			return (-1);
227
 	}
228
 
229
-	free(label);
230
 	return (0);
231
 }
232
 
233
 /*
234
+ * Given a file descriptor, clear (zero) the label information.
235
+ */
236
+int
237
+zpool_clear_label(int fd)
238
+{
239
+	return (zpool_clear_n_labels(fd, 0, VDEV_LABELS, B_FALSE, B_FALSE));
240
+}
241
+
242
+/*
243
  * Given a list of directories to search, find all pools stored on disk.  This
244
  * includes partial pools which are not available to import.  If no args are
245
  * given (argc is 0), then the default directory (/dev/dsk) is searched.
246
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
247
index 7fa722a532..ed8682805a 100644
248
--- a/usr/src/lib/libzfs/common/mapfile-vers
249
+++ b/usr/src/lib/libzfs/common/mapfile-vers
250
@@ -180,6 +180,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
251
 	zfs_zpl_version_map;
252
 	zpool_add;
253
 	zpool_clear;
254
+	zpool_clear_n_labels;
255
 	zpool_clear_label;
256
 	zpool_close;
257
 	zpool_create;
258
diff --git a/usr/src/man/man1m/zpool.1m b/usr/src/man/man1m/zpool.1m
259
index 61e456ad04..bf8c80de3c 100644
260
--- a/usr/src/man/man1m/zpool.1m
261
+++ b/usr/src/man/man1m/zpool.1m
262
@@ -105,6 +105,9 @@
263
 .Op Ar interval Op Ar count
264
 .Nm
265
 .Cm labelclear
266
+.Op Fl b | Fl e | Fl i Ar index
267
+.Op Fl c
268
+.Op Fl m
269
 .Op Fl f
270
 .Ar device
271
 .Nm
272
@@ -1275,6 +1278,9 @@ pool, in addition to the pool-wide statistics.
273
 .It Xo
274
 .Nm
275
 .Cm labelclear
276
+.Op Fl b | Fl e | Fl i Ar index
277
+.Op Fl c
278
+.Op Fl m
279
 .Op Fl f
280
 .Ar device
281
 .Xc
282
@@ -1283,7 +1289,30 @@ Removes ZFS label information from the specified
283
 The
284
 .Ar device
285
 must not be part of an active pool configuration.
286
+Options
287
+.Fl b ,
288
+.Fl e
289
+and
290
+.Fl i
291
+can be used for clearing specific labels.
292
+They are mutually exclusive and the last one will supersede others, if any.
293
 .Bl -tag -width Ds
294
+.It Fl b
295
+Only remove ZFS labels located at the beginning of
296
+.Ar device .
297
+.It Fl e
298
+Only remove ZFS labels located at the end of
299
+.Ar device .
300
+.It Fl i Ar index
301
+Remove a single label entry located at position
302
+.Ar index .
303
+.It Fl c
304
+Check label integrity before doing anything.
305
+.It Fl m
306
+Perform minimal operation needed to invalidate a label instead of blindly
307
+erasing every single byte.
308
+This reduces (but does not annihilate) the risks of overriding important
309
+on-disk data.
310
 .It Fl f
311
 Treat exported or foreign devices as inactive.
312
 .El
313
diff --git a/usr/src/uts/common/sys/nvpair.h b/usr/src/uts/common/sys/nvpair.h
314
index e4d637b007..36f2dd41ea 100644
315
--- a/usr/src/uts/common/sys/nvpair.h
316
+++ b/usr/src/uts/common/sys/nvpair.h
317
@@ -98,6 +98,7 @@ typedef struct nvlist {
318
 #define	NV_VERSION	0
319
 
320
 /* nvlist pack encoding */
321
+#define	NV_ENCODE_INVALID	(-1)
322
 #define	NV_ENCODE_NATIVE	0
323
 #define	NV_ENCODE_XDR		1
324
 
325
@@ -153,6 +154,7 @@ void nv_alloc_fini(nv_alloc_t *);
326
 /* list management */
327
 int nvlist_alloc(nvlist_t **, uint_t, int);
328
 void nvlist_free(nvlist_t *);
329
+int nvlist_invalidate(char *);
330
 int nvlist_size(nvlist_t *, size_t *, int);
331
 int nvlist_pack(nvlist_t *, char **, size_t *, int, int);
332
 int nvlist_unpack(char *, size_t, nvlist_t **, int);
(2-2/3)