Skip to content

Commit 6bff273

Browse files
ilovezfslundman
authored andcommitted
macOS: improve handling of invariant disks
Don't prepend /dev to all paths not starting with /dev as InvariantDisks places its symlinks in /var/run/disk/by-* not /dev/disk/by-*. Also, merge in some tweaks from Linux's zpool_vdev_os.c such as only using O_EXCL with spares.
1 parent b3030e7 commit 6bff273

File tree

2 files changed

+51
-29
lines changed

2 files changed

+51
-29
lines changed

cmd/zpool/os/macos/zpool_vdev_os.c

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -88,25 +88,41 @@ check_slice(const char *path, int force, boolean_t isspare)
8888
return (0);
8989
}
9090

91+
/*
92+
* Validate that a disk including all partitions are safe to use.
93+
*
94+
* For EFI labeled disks this can done relatively easily with the libefi
95+
* library. The partition numbers are extracted from the label and used
96+
* to generate the expected /dev/ paths. Each partition can then be
97+
* checked for conflicts.
98+
*
99+
* For non-EFI labeled disks (MBR/EBR/etc) the same process is possible
100+
* but due to the lack of a readily available libraries this scanning is
101+
* not implemented. Instead only the device path as given is checked.
102+
*/
91103
static int
92104
check_disk(const char *path, int force,
93105
boolean_t isspare, boolean_t iswholedisk)
94106
{
95107
struct dk_gpt *vtoc;
96108
char slice_path[MAXPATHLEN];
97109
int err = 0;
98-
int slice_err = 0;
99110
int fd, i;
111+
int flags = O_RDONLY|O_DIRECT;
100112

101113
if (!iswholedisk)
102114
return (check_slice(path, force, isspare));
103115

104-
if ((fd = open(path, O_RDONLY|O_DIRECT)) < 0) {
105-
check_error(errno);
116+
/* only spares can be shared, other devices require exclusive access */
117+
if (!isspare)
118+
flags |= O_EXCL;
119+
120+
if ((fd = open(path, flags)) < 0) {
106121
return (-1);
107122
}
123+
108124
/*
109-
* Expected to fail for non-EFI labled disks. Just check the device
125+
* Expected to fail for non-EFI labeled disks. Just check the device
110126
* as given and do not attempt to detect and scan partitions.
111127
*/
112128
err = efi_alloc_and_read(fd, &vtoc);
@@ -125,25 +141,25 @@ check_disk(const char *path, int force,
125141
(void) close(fd);
126142

127143
if (force) {
128-
/* Partitions will no be created using the backup */
144+
/* Partitions will now be created using the backup */
129145
return (0);
130146
} else {
131147
vdev_error(gettext("%s contains a corrupt primary "
132148
"EFI label.\n"), path);
133149
return (-1);
134150
}
135151
}
152+
136153
for (i = 0; i < vtoc->efi_nparts; i++) {
137154
if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED ||
138155
uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))
139156
continue;
140157
(void) snprintf(slice_path, sizeof (slice_path),
141158
"%ss%d", path, i+1);
142-
slice_err = check_slice(slice_path, force, isspare);
143159

144-
// Latch the first error that occurs
145-
if (err == 0)
146-
err = slice_err;
160+
err = check_slice(slice_path, force, isspare);
161+
if (err)
162+
break;
147163
}
148164

149165
efi_free(vtoc);
@@ -152,19 +168,12 @@ check_disk(const char *path, int force,
152168
return (err);
153169
}
154170

155-
156171
int
157-
check_device(const char *name, boolean_t force,
172+
check_device(const char *path, boolean_t force,
158173
boolean_t isspare, boolean_t iswholedisk)
159174
{
160-
char path[MAXPATHLEN];
161175
int error;
162176

163-
if (strncmp(name, _PATH_DEV, sizeof (_PATH_DEV) - 1) != 0)
164-
snprintf(path, sizeof (path), "%s%s", _PATH_DEV, name);
165-
else
166-
strlcpy(path, name, sizeof (path));
167-
168177
error = check_disk(path, force, isspare, iswholedisk);
169178
if (error != 0)
170179
return (error);

lib/libzutil/os/macos/zutil_device_path_os.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@
3131

3232
#include <libzutil.h>
3333

34-
/*
35-
* We don't strip/append partitions on FreeBSD.
36-
*/
37-
3834
/*
3935
* Note: The caller must free the returned string.
4036
*/
@@ -43,6 +39,7 @@ zfs_strip_partition(char *dev)
4339
{
4440
unsigned int disk, slice;
4541
char *partless;
42+
char whole_disk[MAXPATHLEN];
4643

4744
partless = strdup(dev);
4845

@@ -52,6 +49,16 @@ zfs_strip_partition(char *dev)
5249
r = strrchr(partless, 's');
5350
if (r != NULL)
5451
*r = 0;
52+
} else if ((sscanf(partless, "%[^:]:%u", whole_disk, &slice)) == 2) {
53+
char *r;
54+
r = strrchr(partless, ':');
55+
if (r != NULL) {
56+
if (strchr(partless, '@')) { // by-path
57+
if (slice == 1)
58+
r[1] = '0';
59+
} else // by-serial
60+
*r = 0;
61+
}
5562
}
5663

5764
return (partless);
@@ -61,23 +68,29 @@ int
6168
zfs_append_partition(char *path, size_t max_len)
6269
{
6370
int len = strlen(path);
71+
char dpath[max_len];
72+
if (strncmp(path, "/var/", 5) == 0) {
73+
(void) strlcpy(dpath, "/private", max_len);
74+
(void) strlcat(dpath, path, max_len);
75+
} else
76+
strlcpy(dpath, path, max_len);
6477

65-
if (strncmp(path, "/private/var/run/disk/by-id", 27) == 0) {
78+
79+
if (strncmp(dpath, "/private/var/run/disk/by-id", 27) == 0) {
6680
return (len);
67-
} else if (strncmp(path, "/private/var/run/disk/by-path", 29) == 0) {
81+
} else if (strncmp(dpath, "/private/var/run/disk/by-path", 29) == 0) {
6882
if (path[len - 1] == '0' &&
6983
path[len - 2] == ':')
7084
path[len - 1] = '1';
71-
else
72-
return (-1); /* should have ended with ":0" */
7385

74-
} else if (strncmp(path, "/private/var/run/disk/by-serial", 31) == 0) {
86+
} else if (strncmp(dpath, "/private/var/run/disk/by-serial", 31) == 0) {
7587
if (len + 2 >= max_len)
7688
return (-1);
7789

78-
(void) strcat(path, ":1");
79-
len += 2;
80-
90+
if (strchr(path, ':') == NULL) {
91+
(void) strcat(path, ":1");
92+
len += 2;
93+
}
8194
} else {
8295

8396
if (len + 2 >= max_len)

0 commit comments

Comments
 (0)