Skip to content

Commit 99918d3

Browse files
committed
Implement lzc_list_iter()
Signed-off-by: Richard Yao <ryao@gentoo.org>
1 parent 2360aa3 commit 99918d3

File tree

3 files changed

+175
-112
lines changed

3 files changed

+175
-112
lines changed

include/libzfs_core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
extern "C" {
3636
#endif
3737

38+
typedef int (*lzc_iter_f)(nvlist_t *, void *);
39+
3840
int libzfs_core_init(void);
3941
void libzfs_core_fini(void);
4042

@@ -47,6 +49,7 @@ int lzc_pool_tryimport(nvlist_t *, nvlist_t *, nvlist_t **);
4749
int lzc_pool_stats(const char *, nvlist_t *, nvlist_t **);
4850

4951
int lzc_list(const char *, nvlist_t *);
52+
int lzc_list_iter(const char *, nvlist_t *, lzc_iter_f, void *);
5053
int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
5154
int lzc_create(const char *, dmu_objset_type_t, nvlist_t *);
5255
int lzc_clone(const char *, const char *, nvlist_t *);

lib/libzfs/libzfs_iter.c

Lines changed: 86 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,75 @@ zfs_type_to_nvl(zfs_type_t type)
8181
return (nvl);
8282
}
8383

84+
typedef struct zfs_iter_cb_data {
85+
libzfs_handle_t *zicb_hdl;
86+
zfs_handle_t zicb_zhp;
87+
void *zicb_data;
88+
zfs_iter_f zicb_func;
89+
zfs_cmd_t zicb_zc;
90+
} zfs_iter_cb_data_t;
91+
92+
int
93+
zfs_iter_cb(nvlist_t *nvl, void *data)
94+
{
95+
nvlist_t *nvl_prop, *nvl_dds;
96+
zfs_iter_cb_data_t *cb = data;
97+
zfs_handle_t *nzhp;
98+
char *name;
99+
int ret;
100+
101+
if ((ret = nvlist_lookup_nvlist(nvl, "properties", &nvl_prop))
102+
!= 0 ||
103+
(ret = nvlist_lookup_string(nvl, "name", &name)) != 0 ||
104+
(ret = nvlist_lookup_nvlist(nvl, "dmu_objset_stats",
105+
&nvl_dds)) != 0 ||
106+
(ret = dmu_objset_stat_nvlts(nvl_dds, &cb->zicb_zc.zc_objset_stats))
107+
!= 0) {
108+
return (EINVAL);
109+
}
110+
111+
strlcpy(cb->zicb_zc.zc_name, name, sizeof (cb->zicb_zc.zc_name));
112+
113+
cb->zicb_zc.zc_nvlist_dst_size = fnvlist_size(nvl_prop);
114+
if ((ret = zcmd_expand_dst_nvlist(cb->zicb_hdl, &cb->zicb_zc))) {
115+
if (ret == -1)
116+
ret = ENOMEM;
117+
return (ret);
118+
}
119+
120+
ret = nvlist_pack(nvl_prop, (char **) &cb->zicb_zc.zc_nvlist_dst,
121+
&cb->zicb_zc.zc_nvlist_dst_size, NV_ENCODE_NATIVE, 0);
122+
123+
cb->zicb_zc.zc_nvlist_dst_filled = B_TRUE;
124+
125+
/*
126+
* Errors here do not make sense, so we bail.
127+
*/
128+
if (strchr(name, '#') != NULL) {
129+
zfs_handle_t *zhp = &cb->zicb_zhp;
130+
zhp->zfs_hdl = cb->zicb_hdl;
131+
switch (cb->zicb_zc.zc_objset_stats.dds_type) {
132+
case DMU_OST_ZFS:
133+
zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
134+
break;
135+
case DMU_OST_ZVOL:
136+
zhp->zfs_head_type = ZFS_TYPE_VOLUME;
137+
break;
138+
default:
139+
return (EINVAL);
140+
}
141+
nzhp = make_bookmark_handle(zhp, name, nvl_prop);
142+
} else if ((ret != 0) ||
143+
(nzhp = make_dataset_handle_zc(cb->zicb_hdl, &cb->zicb_zc)) == NULL)
144+
return (EINVAL);
145+
146+
ret = (*cb->zicb_func)(nzhp, cb->zicb_data);
147+
148+
zfs_close(nzhp);
149+
150+
return (ret);
151+
}
152+
84153
/*
85154
* Iterate over all children filesystems
86155
*/
@@ -89,28 +158,14 @@ zfs_iter_generic(libzfs_handle_t *hdl, const char *name, zfs_type_t type,
89158
int64_t mindepth, int64_t maxdepth, boolean_t depth_specified,
90159
zfs_iter_f func, void *data)
91160
{
92-
zfs_cmd_t zc = {"\0"};
93-
zfs_handle_t *nzhp;
94-
nvlist_t *tnvl;
95-
nvlist_t *opts;
96-
int fildes[2];
97-
zfs_pipe_record_t zpr;
161+
zfs_iter_cb_data_t cb_data;
162+
nvlist_t *tnvl, *opts;
98163
int ret;
99164

100-
if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
165+
bzero(&cb_data.zicb_zc, sizeof (cb_data.zicb_zc));
166+
if (zcmd_alloc_dst_nvlist(hdl, &cb_data.zicb_zc, 0) != 0)
101167
return (-1);
102168

103-
ret = pipe(fildes);
104-
if (ret == -1) {
105-
switch (errno) {
106-
default:
107-
ret = zfs_standard_error(hdl, errno,
108-
dgettext(TEXT_DOMAIN,
109-
"cannot iterate filesystems"));
110-
break;
111-
}
112-
}
113-
114169
opts = fnvlist_alloc();
115170
if (depth_specified) {
116171
switch (maxdepth) {
@@ -119,7 +174,8 @@ zfs_iter_generic(libzfs_handle_t *hdl, const char *name, zfs_type_t type,
119174
default:
120175
if (maxdepth < 0) {
121176
fnvlist_free(opts);
122-
return (-1);
177+
ret = -1;
178+
goto out;
123179
}
124180
fnvlist_add_uint64(opts, "maxrecurse", maxdepth);
125181
}
@@ -129,105 +185,23 @@ zfs_iter_generic(libzfs_handle_t *hdl, const char *name, zfs_type_t type,
129185

130186
tnvl = zfs_type_to_nvl(type);
131187
fnvlist_add_nvlist(opts, "type", tnvl);
132-
fnvlist_add_int32(opts, "fd", fildes[1]);
133-
134-
if ((ret = lzc_list(name, opts)) != 0) {
135-
fnvlist_free(opts);
136-
close(fildes[0]);
137-
close(fildes[1]);
138-
return (ret);
139-
}
140-
fnvlist_free(tnvl);
141-
fnvlist_free(opts);
142-
143-
while ((ret = read(fildes[0], &zpr,
144-
sizeof (zfs_pipe_record_t))) == sizeof (uint64_t) &&
145-
zpr.zpr_data_size != 0 && zpr.zpr_err == 0) {
146-
nvlist_t *nvl, *nvl_prop, *nvl_dds;
147-
char *name;
148-
#ifdef _LITTLE_ENDIAN
149-
uint32_t size = (zpr.zpr_endian) ? zpr.zpr_data_size :
150-
BSWAP_32(zpr.zpr_data_size);
151-
#else
152-
uint32_t size = (zpr.zpr_endian) ? BSWAP_32(zpr.zpr_data_size) :
153-
zpr.zpr_data_size;
154-
#endif
155-
char *buf = umem_alloc(size, UMEM_NOFAIL);
156-
157-
ret = read(fildes[0], buf, size);
158-
159-
if (size != ret || (ret = nvlist_unpack(buf +
160-
zpr.zpr_header_size, size, &nvl, 0)) != 0) {
161-
umem_free(buf, size);
162-
goto out;
163-
}
164-
165-
if ((ret = nvlist_lookup_nvlist(nvl, "properties", &nvl_prop))
166-
!= 0 ||
167-
(ret = nvlist_lookup_string(nvl, "name", &name)) != 0 ||
168-
(ret = nvlist_lookup_nvlist(nvl, "dmu_objset_stats",
169-
&nvl_dds)) != 0 ||
170-
(ret = dmu_objset_stat_nvlts(nvl_dds, &zc.zc_objset_stats))
171-
!= 0) {
172-
ret = EINVAL;
173-
umem_free(buf, size);
174-
goto out;
175-
}
176-
177-
strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
178-
umem_free(buf, size);
179-
180-
zc.zc_nvlist_dst_size = fnvlist_size(nvl_prop);
181-
if ((ret = zcmd_expand_dst_nvlist(hdl, &zc))) {
182-
if (ret == -1)
183-
ret = ENOMEM;
184-
goto out;
185-
}
186188

187-
ret = nvlist_pack(nvl_prop, (char **) &zc.zc_nvlist_dst,
188-
&zc.zc_nvlist_dst_size, NV_ENCODE_NATIVE, 0);
189+
cb_data.zicb_hdl = hdl;
190+
cb_data.zicb_func = func;
191+
cb_data.zicb_data = data;
189192

190-
zc.zc_nvlist_dst_filled = B_TRUE;
193+
ret = lzc_list_iter(name, opts, &zfs_iter_cb, &cb_data);
191194

192-
/*
193-
* Errors here do not make sense, so we bail.
194-
*/
195-
if (strchr(name, '#') != NULL) {
196-
zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
197-
if (zhp == NULL) {
198-
ret = ENOMEM;
199-
goto out;
200-
}
201-
zhp->zfs_hdl = hdl;
202-
switch (zc.zc_objset_stats.dds_type) {
203-
case DMU_OST_ZFS:
204-
zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
205-
break;
206-
case DMU_OST_ZVOL:
207-
zhp->zfs_head_type = ZFS_TYPE_VOLUME;
208-
break;
209-
default:
210-
ret = EINVAL;
211-
goto out;
212-
}
213-
nzhp = make_bookmark_handle(zhp, name, nvl_prop);
214-
free(zhp);
215-
if (nzhp == NULL)
216-
continue;
217-
} else if ((ret != 0) ||
218-
(nzhp = make_dataset_handle_zc(hdl, &zc)) == NULL) {
219-
ret = EINVAL;
220-
goto out;
221-
}
195+
if (ret)
196+
(void) zfs_standard_error(hdl, ret, dgettext(TEXT_DOMAIN,
197+
"cannot iterate filesystems"));
222198

223-
if ((ret = func(nzhp, data)) != 0)
224-
goto out;
225-
}
226199

200+
fnvlist_free(tnvl);
201+
fnvlist_free(opts);
227202
out:
228-
close(fildes[0]);
229-
close(fildes[1]);
230-
zcmd_free_nvlists(&zc);
203+
zcmd_free_nvlists(&cb_data.zicb_zc);
204+
231205
return ((ret < 0) ? ret : 0);
232206
}
233207

lib/libzfs_core/libzfs_core.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,5 +1109,91 @@ lzc_list(const char *name, nvlist_t *opts)
11091109

11101110
error = lzc_ioctl("zfs_list", name, innvl, opts, NULL, 0);
11111111

1112+
fnvlist_free(innvl);
1113+
11121114
return (error);
11131115
}
1116+
1117+
/*
1118+
* Helper function to iterate over all filesystems.
1119+
* Excluding the "fd" option, the same options that are passed to lzc_list must
1120+
* be passed to this.
1121+
*/
1122+
int
1123+
lzc_list_iter(const char *name, nvlist_t *opts, lzc_iter_f func, void *data)
1124+
{
1125+
zfs_pipe_record_t zpr;
1126+
int fildes[2];
1127+
int ret;
1128+
int buf_len = 0;
1129+
char *buf = NULL;
1130+
1131+
ret = pipe(fildes);
1132+
if (ret == -1)
1133+
return (errno);
1134+
1135+
ret = nvlist_add_int32(opts, "fd", fildes[1]);
1136+
1137+
if (ret != 0)
1138+
goto out;
1139+
1140+
if ((ret = lzc_list(name, opts)) != 0)
1141+
return (ret);
1142+
1143+
while ((ret = read(fildes[0], &zpr,
1144+
sizeof (zfs_pipe_record_t))) == sizeof (uint64_t)) {
1145+
nvlist_t *nvl;
1146+
#ifdef _LITTLE_ENDIAN
1147+
uint32_t size = (zpr.zpr_endian) ? zpr.zpr_data_size :
1148+
BSWAP_32(zpr.zpr_data_size);
1149+
#else
1150+
uint32_t size = (zpr.zpr_endian) ? BSWAP_32(zpr.zpr_data_size) :
1151+
zpr.zpr_data_size;
1152+
#endif
1153+
if (zpr.zpr_data_size == 0) {
1154+
ret = 0;
1155+
break;
1156+
}
1157+
1158+
if (zpr.zpr_err != 0) {
1159+
ret = zpr.zpr_err;
1160+
break;
1161+
}
1162+
1163+
if (size > buf_len) {
1164+
if (buf)
1165+
umem_free(buf, size);
1166+
buf = umem_alloc(size, UMEM_NOFAIL);
1167+
buf_len = size;
1168+
}
1169+
1170+
ret = read(fildes[0], buf, size);
1171+
if (ret == -1)
1172+
break;
1173+
1174+
if (size != ret)
1175+
ret = EINVAL;
1176+
1177+
if ((ret = nvlist_unpack(buf +
1178+
zpr.zpr_header_size, size, &nvl, 0)) != 0)
1179+
break;
1180+
1181+
ret = func(nvl, data);
1182+
1183+
fnvlist_free(nvl);
1184+
1185+
if (ret != 0)
1186+
break;
1187+
}
1188+
1189+
if (ret == -1)
1190+
ret = errno;
1191+
1192+
if (buf)
1193+
umem_free(buf, buf_len);
1194+
1195+
out:
1196+
close(fildes[0]);
1197+
close(fildes[1]);
1198+
return (ret);
1199+
}

0 commit comments

Comments
 (0)