Project

General

Profile

Feature #7584 » patch-zpool_labelclear-Illumos-9185393.txt

Patch for rev. 9185393 - Ganael Laplanche, 2016-11-15 08:47 AM

 
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);
(1-1/3)