Print this page
NEX-16159 Time spent sharing SMB filesystems could be reduced by optimizing smb_getdataset for default mount points
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Reviewed by: Matt Barden <matt.barden@nexenta.com>
SMB-136 Snapshots not visible in Windows previous versions
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/smbsrv/smbd/smbd_vss.c
+++ new/usr/src/cmd/smbsrv/smbd/smbd_vss.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
24 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright 2016 Martin Matuska. All rights reserved.
26 26 */
27 27
28 28 #include <synch.h>
29 29 #include <pthread.h>
30 30 #include <unistd.h>
31 31 #include <string.h>
32 32 #include <strings.h>
33 33 #include <sys/errno.h>
34 34 #include <libzfs.h>
35 35
36 36 #include <smbsrv/libsmb.h>
37 37 #include <smbsrv/libsmbns.h>
38 38 #include <smbsrv/libmlsvc.h>
39 39 #include <smbsrv/smbinfo.h>
40 40 #include "smbd.h"
41 41
42 42 /*
43 43 * This file supports three basic functions that all use the
44 44 * the zfs_iter_snapshots function to get the snapshot info
45 45 * from ZFS. If the filesystem is not ZFS, the an error is sent
46 46 * to the caller (door functions in this case) with the count of
47 47 * zero in the case of smbd_vss_get_count. Each function
48 48 * is expecting a path that is the root of the dataset.
49 49 * The basic idea is to define a structure for the data and
50 50 * an iterator function that will be called for every snapshot
51 51 * in the dataset that was opened. The iterator function gets
52 52 * a zfs_handle_t(that needs to be closed) for the snapshot
53 53 * and a pointer to the structure of data defined passed to it.
54 54 * If the iterator function returns a non-zero value, no more
55 55 * snapshots will be processed. There is no guarantee in the
56 56 * order in which the snapshots are processed.
57 57 *
58 58 * The structure of this file is:
59 59 * Three structures that are used between the iterator functions
60 60 * and "main" functions
61 61 * The 3 "main" functions
62 62 * Support functions
63 63 * The 3 iterator functions
64 64 */
65 65
66 66 /*
67 67 * The maximum number of snapshots returned per request.
68 68 */
69 69 #define SMBD_VSS_SNAPSHOT_MAX 725
70 70
71 71 static void smbd_vss_time2gmttoken(time_t time, char *gmttoken);
72 72 static int smbd_vss_cmp_time(const void *a, const void *b);
73 73 static int smbd_vss_iterate_count(zfs_handle_t *zhp, void *data);
74 74 static int smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data);
75 75 static int smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data);
76 76
77 77 typedef struct smbd_vss_count {
78 78 int vc_count;
79 79 } smbd_vss_count_t;
80 80
81 81 /*
82 82 * gd_count how many @GMT tokens are expected
83 83 * gd_return_count how many @GMT tokens are being returned
84 84 * gd_gmt_array array of the @GMT token with max size of gd_count
85 85 */
86 86 typedef struct smbd_vss_get_uint64_date {
87 87 int gd_count;
88 88 int gd_return_count;
89 89 uint64_t *gd_gmt_array;
90 90 } smbd_vss_get_uint64_date_t;
91 91
92 92 typedef struct smbd_vss_map_gmttoken {
93 93 time_t mg_snaptime;
94 94 char *mg_snapname;
95 95 } smbd_vss_map_gmttoken_t;
96 96
97 97
98 98 /*
99 99 * path - path of the dataset
100 100 * count - return value of the number of snapshots for the dataset
101 101 */
102 102 int
|
↓ open down ↓ |
68 lines elided |
↑ open up ↑ |
103 103 smbd_vss_get_count(const char *path, uint32_t *count)
104 104 {
105 105 char dataset[MAXPATHLEN];
106 106 libzfs_handle_t *libhd;
107 107 zfs_handle_t *zfshd;
108 108 smbd_vss_count_t vss_count;
109 109
110 110 bzero(&vss_count, sizeof (smbd_vss_count_t));
111 111 *count = 0;
112 112
113 - if (smb_getdataset(path, dataset, MAXPATHLEN) != 0)
113 + if ((libhd = libzfs_init()) == NULL)
114 114 return (-1);
115 115
116 - if ((libhd = libzfs_init()) == NULL)
116 + if (smb_getdataset(libhd, path, dataset, MAXPATHLEN) != 0) {
117 + libzfs_fini(libhd);
117 118 return (-1);
119 + }
118 120
119 121 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) {
120 122 libzfs_fini(libhd);
121 123 return (-1);
122 124 }
123 125
124 126 (void) zfs_iter_snapshots(zfshd, B_FALSE, smbd_vss_iterate_count,
125 127 (void *)&vss_count);
126 128
127 129 if (vss_count.vc_count > SMBD_VSS_SNAPSHOT_MAX)
128 130 vss_count.vc_count = SMBD_VSS_SNAPSHOT_MAX;
129 131
130 132 *count = vss_count.vc_count;
131 133 zfs_close(zfshd);
132 134 libzfs_fini(libhd);
133 135 return (0);
134 136 }
135 137
136 138 /*
137 139 * path - is the path of the dataset
138 140 * count - is the maxium number of GMT tokens allowed to be returned
139 141 * return_count - is how many should be returned
140 142 * num_gmttokens - how many gmttokens in gmttokenp (0 if error)
141 143 * gmttokenp - array of @GMT tokens (even if zero, elements still need
142 144 * to be freed)
143 145 */
144 146
145 147 void
146 148 smbd_vss_get_snapshots(const char *path, uint32_t count,
147 149 uint32_t *return_count, uint32_t *num_gmttokens, char **gmttokenp)
148 150 {
149 151 char dataset[MAXPATHLEN];
150 152 libzfs_handle_t *libhd;
151 153 zfs_handle_t *zfshd;
152 154 smbd_vss_get_uint64_date_t vss_uint64_date;
153 155 int i;
154 156 uint64_t *timep;
155 157
156 158 *return_count = 0;
157 159 *num_gmttokens = 0;
|
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
158 160
159 161 if (count == 0)
160 162 return;
161 163
162 164 if (count > SMBD_VSS_SNAPSHOT_MAX)
163 165 count = SMBD_VSS_SNAPSHOT_MAX;
164 166
165 167 vss_uint64_date.gd_count = count;
166 168 vss_uint64_date.gd_return_count = 0;
167 169 vss_uint64_date.gd_gmt_array = malloc(count * sizeof (uint64_t));
170 +
168 171 if (vss_uint64_date.gd_gmt_array == NULL)
169 172 return;
170 173
171 - if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) {
174 + if ((libhd = libzfs_init()) == NULL) {
172 175 free(vss_uint64_date.gd_gmt_array);
173 176 return;
174 177 }
175 178
176 - if ((libhd = libzfs_init()) == NULL) {
179 + if (smb_getdataset(libhd, path, dataset, MAXPATHLEN) != 0) {
177 180 free(vss_uint64_date.gd_gmt_array);
181 + libzfs_fini(libhd);
178 182 return;
179 183 }
180 184
181 185 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) {
182 186 free(vss_uint64_date.gd_gmt_array);
183 187 libzfs_fini(libhd);
184 188 return;
185 189 }
186 190
187 191 (void) zfs_iter_snapshots(zfshd, B_FALSE,
188 192 smbd_vss_iterate_get_uint64_date, (void *)&vss_uint64_date);
189 193
190 194 *num_gmttokens = vss_uint64_date.gd_return_count;
191 195 *return_count = vss_uint64_date.gd_return_count;
192 196
193 197 /*
194 198 * Sort the list since neither zfs nor the client sorts it.
195 199 */
196 200 qsort((char *)vss_uint64_date.gd_gmt_array,
197 201 vss_uint64_date.gd_return_count,
198 202 sizeof (uint64_t), smbd_vss_cmp_time);
199 203
200 204 timep = vss_uint64_date.gd_gmt_array;
201 205
202 206 for (i = 0; i < vss_uint64_date.gd_return_count; i++) {
203 207 *gmttokenp = malloc(SMB_VSS_GMT_SIZE);
204 208
205 209 if (*gmttokenp)
206 210 smbd_vss_time2gmttoken(*timep, *gmttokenp);
207 211 else
208 212 vss_uint64_date.gd_return_count = 0;
209 213
210 214 timep++;
211 215 gmttokenp++;
212 216 }
213 217
214 218 free(vss_uint64_date.gd_gmt_array);
215 219 zfs_close(zfshd);
216 220 libzfs_fini(libhd);
217 221 }
218 222
219 223 static const char
220 224 smbd_vss_gmttoken_fmt[] = "@GMT-%Y.%m.%d-%H.%M.%S";
221 225
222 226 /*
223 227 * path - path of the dataset for the operation
224 228 * gmttoken - the @GMT token to be looked up
225 229 * toktime - time_t used if gmttoken == NULL
226 230 * snapname - the snapshot name to be returned [MAXPATHLEN]
227 231 *
228 232 * Here we are going to get the snapshot name from the @GMT token
229 233 * The snapname returned by ZFS is : <dataset name>@<snapshot name>
230 234 * So we are going to make sure there is the @ symbol in
231 235 * the right place and then just return the snapshot name
232 236 */
233 237 int
234 238 smbd_vss_map_gmttoken(const char *path, char *gmttoken, time_t toktime,
235 239 char *snapname)
236 240 {
237 241 char dataset[MAXPATHLEN];
238 242 libzfs_handle_t *libhd;
239 243 zfs_handle_t *zfshd;
240 244 smbd_vss_map_gmttoken_t vss_map_gmttoken;
241 245 char *zsnap;
242 246 const char *lsnap;
243 247 struct tm tm;
|
↓ open down ↓ |
56 lines elided |
↑ open up ↑ |
244 248
245 249 if (gmttoken != NULL && *gmttoken == '@' &&
246 250 strptime(gmttoken, smbd_vss_gmttoken_fmt, &tm) != NULL) {
247 251 toktime = timegm(&tm);
248 252 }
249 253
250 254 vss_map_gmttoken.mg_snaptime = toktime;
251 255 vss_map_gmttoken.mg_snapname = snapname;
252 256 *snapname = '\0';
253 257
254 - if (smb_getdataset(path, dataset, MAXPATHLEN) != 0)
258 + if ((libhd = libzfs_init()) == NULL)
255 259 return (-1);
256 260
257 - if ((libhd = libzfs_init()) == NULL)
261 + if (smb_getdataset(libhd, path, dataset, MAXPATHLEN) != 0) {
262 + libzfs_fini(libhd);
258 263 return (-1);
264 + }
259 265
260 266 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) {
261 267 libzfs_fini(libhd);
262 268 return (-1);
263 269 }
264 270
265 271 (void) zfs_iter_snapshots(zfshd, B_FALSE, smbd_vss_iterate_map_gmttoken,
266 272 (void *)&vss_map_gmttoken);
267 273
268 274 /* compare the zfs snapshot name and the local snap name */
269 275 zsnap = snapname;
270 276 lsnap = dataset;
271 277 while ((*lsnap != '\0') && (*zsnap != '\0') && (*lsnap == *zsnap)) {
272 278 zsnap++;
273 279 lsnap++;
274 280 }
275 281
276 282 /* Now we should be passed the dataset name */
277 283 if ((*zsnap == '@') && (*lsnap == '\0')) {
278 284 zsnap++;
279 285 (void) strlcpy(snapname, zsnap, MAXPATHLEN);
280 286 } else {
281 287 *snapname = '\0';
282 288 }
283 289
284 290 zfs_close(zfshd);
285 291 libzfs_fini(libhd);
286 292 return (0);
287 293 }
288 294
289 295 static void
290 296 smbd_vss_time2gmttoken(time_t time, char *gmttoken)
291 297 {
292 298 struct tm t;
293 299
294 300 (void) gmtime_r(&time, &t);
295 301
296 302 (void) strftime(gmttoken, SMB_VSS_GMT_SIZE,
297 303 smbd_vss_gmttoken_fmt, &t);
298 304 }
299 305
300 306 static int
301 307 smbd_vss_cmp_time(const void *a, const void *b)
302 308 {
303 309 if (*(uint64_t *)a < *(uint64_t *)b)
304 310 return (1);
305 311 if (*(uint64_t *)a == *(uint64_t *)b)
306 312 return (0);
307 313 return (-1);
308 314 }
309 315
310 316 /*
311 317 * ZFS snapshot iterator to count snapshots.
312 318 * Note: libzfs expects us to close the handle.
313 319 * Return 0 to continue iterating or non-zreo to terminate the iteration.
314 320 */
315 321 static int
316 322 smbd_vss_iterate_count(zfs_handle_t *zhp, void *data)
317 323 {
318 324 smbd_vss_count_t *vss_data = data;
319 325
320 326 if (vss_data->vc_count < SMBD_VSS_SNAPSHOT_MAX) {
321 327 vss_data->vc_count++;
322 328 zfs_close(zhp);
323 329 return (0);
324 330 }
325 331
326 332 zfs_close(zhp);
327 333 return (-1);
328 334 }
329 335
330 336 /*
331 337 * ZFS snapshot iterator to get snapshot creation time.
332 338 * Note: libzfs expects us to close the handle.
333 339 * Return 0 to continue iterating or non-zreo to terminate the iteration.
334 340 */
335 341 static int
336 342 smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data)
337 343 {
338 344 smbd_vss_get_uint64_date_t *vss_data = data;
339 345 int count;
340 346
341 347 count = vss_data->gd_return_count;
342 348
343 349 if (count < vss_data->gd_count) {
344 350 vss_data->gd_gmt_array[count] =
345 351 zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
346 352 vss_data->gd_return_count++;
347 353 zfs_close(zhp);
348 354 return (0);
349 355 }
350 356
351 357 zfs_close(zhp);
352 358 return (-1);
353 359 }
354 360
355 361 /*
356 362 * ZFS snapshot iterator to map a snapshot creation time to a token.
357 363 * Note: libzfs expects us to close the handle.
358 364 * Return 0 to continue iterating or non-zreo to terminate the iteration.
359 365 */
360 366 static int
361 367 smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data)
362 368 {
363 369 smbd_vss_map_gmttoken_t *vss_data = data;
364 370 time_t time;
365 371
366 372 time = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
367 373 if (time == vss_data->mg_snaptime) {
368 374 (void) strlcpy(vss_data->mg_snapname, zfs_get_name(zhp),
369 375 MAXPATHLEN);
370 376
371 377 /* we found a match, do not process anymore snapshots */
372 378 zfs_close(zhp);
373 379 return (-1);
374 380 }
375 381
376 382 zfs_close(zhp);
377 383 return (0);
378 384 }
|
↓ open down ↓ |
110 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX