Print this page
re #13613 rb4516 Tunables needs volatile keyword
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs3_vfsops.c
+++ new/usr/src/uts/common/fs/nfs/nfs3_vfsops.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
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 * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
23 24 */
24 25
25 26 /*
26 27 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
27 28 * All rights reserved.
28 29 */
29 30
30 31 #include <sys/param.h>
31 32 #include <sys/types.h>
32 33 #include <sys/systm.h>
33 34 #include <sys/cred.h>
34 35 #include <sys/vfs.h>
35 36 #include <sys/vfs_opreg.h>
36 37 #include <sys/vnode.h>
37 38 #include <sys/pathname.h>
38 39 #include <sys/sysmacros.h>
39 40 #include <sys/kmem.h>
40 41 #include <sys/mkdev.h>
41 42 #include <sys/mount.h>
42 43 #include <sys/mntent.h>
43 44 #include <sys/statvfs.h>
44 45 #include <sys/errno.h>
45 46 #include <sys/debug.h>
46 47 #include <sys/cmn_err.h>
47 48 #include <sys/utsname.h>
48 49 #include <sys/bootconf.h>
49 50 #include <sys/modctl.h>
50 51 #include <sys/acl.h>
51 52 #include <sys/flock.h>
52 53 #include <sys/policy.h>
53 54 #include <sys/zone.h>
54 55 #include <sys/class.h>
55 56 #include <sys/socket.h>
56 57 #include <sys/netconfig.h>
57 58 #include <sys/tsol/tnet.h>
58 59
59 60 #include <rpc/types.h>
60 61 #include <rpc/auth.h>
61 62 #include <rpc/clnt.h>
62 63
63 64 #include <nfs/nfs.h>
64 65 #include <nfs/nfs_clnt.h>
65 66 #include <nfs/rnode.h>
66 67 #include <nfs/mount.h>
67 68 #include <nfs/nfs_acl.h>
68 69
69 70 #include <fs/fs_subr.h>
70 71
71 72 /*
72 73 * From rpcsec module (common/rpcsec).
73 74 */
74 75 extern int sec_clnt_loadinfo(struct sec_data *, struct sec_data **, model_t);
75 76 extern void sec_clnt_freeinfo(struct sec_data *);
76 77
77 78 /*
78 79 * The order and contents of this structure must be kept in sync with that of
79 80 * rfsreqcnt_v3_tmpl in nfs_stats.c
80 81 */
81 82 static char *rfsnames_v3[] = {
82 83 "null", "getattr", "setattr", "lookup", "access", "readlink", "read",
83 84 "write", "create", "mkdir", "symlink", "mknod", "remove", "rmdir",
84 85 "rename", "link", "readdir", "readdirplus", "fsstat", "fsinfo",
85 86 "pathconf", "commit"
86 87 };
87 88
88 89 /*
89 90 * This table maps from NFS protocol number into call type.
90 91 * Zero means a "Lookup" type call
91 92 * One means a "Read" type call
92 93 * Two means a "Write" type call
93 94 * This is used to select a default time-out.
94 95 */
95 96 static uchar_t call_type_v3[] = {
96 97 0, 0, 1, 0, 0, 0, 1,
97 98 2, 2, 2, 2, 2, 2, 2,
98 99 2, 2, 1, 2, 0, 0, 0,
99 100 2 };
100 101
101 102 /*
102 103 * Similar table, but to determine which timer to use
103 104 * (only real reads and writes!)
104 105 */
105 106 static uchar_t timer_type_v3[] = {
106 107 0, 0, 0, 0, 0, 0, 1,
107 108 2, 0, 0, 0, 0, 0, 0,
108 109 0, 0, 1, 1, 0, 0, 0,
109 110 0 };
110 111
111 112 /*
112 113 * This table maps from NFS protocol number into a call type
113 114 * for the semisoft mount option.
114 115 * Zero means do not repeat operation.
115 116 * One means repeat.
116 117 */
117 118 static uchar_t ss_call_type_v3[] = {
118 119 0, 0, 1, 0, 0, 0, 0,
119 120 1, 1, 1, 1, 1, 1, 1,
120 121 1, 1, 0, 0, 0, 0, 0,
121 122 1 };
122 123
123 124 /*
124 125 * nfs3 vfs operations.
125 126 */
126 127 static int nfs3_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
127 128 static int nfs3_unmount(vfs_t *, int, cred_t *);
128 129 static int nfs3_root(vfs_t *, vnode_t **);
129 130 static int nfs3_statvfs(vfs_t *, struct statvfs64 *);
130 131 static int nfs3_sync(vfs_t *, short, cred_t *);
131 132 static int nfs3_vget(vfs_t *, vnode_t **, fid_t *);
132 133 static int nfs3_mountroot(vfs_t *, whymountroot_t);
133 134 static void nfs3_freevfs(vfs_t *);
134 135
135 136 static int nfs3rootvp(vnode_t **, vfs_t *, struct servinfo *,
136 137 int, cred_t *, zone_t *);
137 138
138 139 /*
139 140 * Initialize the vfs structure
140 141 */
141 142
142 143 static int nfs3fstyp;
143 144 vfsops_t *nfs3_vfsops;
144 145
145 146 /*
146 147 * Debug variable to check for rdma based
147 148 * transport startup and cleanup. Controlled
148 149 * through /etc/system. Off by default.
149 150 */
150 151 extern int rdma_debug;
151 152
152 153 int
153 154 nfs3init(int fstyp, char *name)
154 155 {
155 156 static const fs_operation_def_t nfs3_vfsops_template[] = {
156 157 VFSNAME_MOUNT, { .vfs_mount = nfs3_mount },
157 158 VFSNAME_UNMOUNT, { .vfs_unmount = nfs3_unmount },
158 159 VFSNAME_ROOT, { .vfs_root = nfs3_root },
159 160 VFSNAME_STATVFS, { .vfs_statvfs = nfs3_statvfs },
160 161 VFSNAME_SYNC, { .vfs_sync = nfs3_sync },
161 162 VFSNAME_VGET, { .vfs_vget = nfs3_vget },
162 163 VFSNAME_MOUNTROOT, { .vfs_mountroot = nfs3_mountroot },
163 164 VFSNAME_FREEVFS, { .vfs_freevfs = nfs3_freevfs },
164 165 NULL, NULL
165 166 };
166 167 int error;
167 168
168 169 error = vfs_setfsops(fstyp, nfs3_vfsops_template, &nfs3_vfsops);
169 170 if (error != 0) {
170 171 zcmn_err(GLOBAL_ZONEID, CE_WARN,
171 172 "nfs3init: bad vfs ops template");
172 173 return (error);
173 174 }
174 175
175 176 error = vn_make_ops(name, nfs3_vnodeops_template, &nfs3_vnodeops);
176 177 if (error != 0) {
177 178 (void) vfs_freevfsops_by_type(fstyp);
178 179 zcmn_err(GLOBAL_ZONEID, CE_WARN,
179 180 "nfs3init: bad vnode ops template");
180 181 return (error);
181 182 }
182 183
183 184 nfs3fstyp = fstyp;
184 185
185 186 return (0);
186 187 }
187 188
188 189 void
189 190 nfs3fini(void)
190 191 {
191 192 }
192 193
193 194 static void
194 195 nfs3_free_args(struct nfs_args *nargs, nfs_fhandle *fh)
195 196 {
196 197
197 198 if (fh)
198 199 kmem_free(fh, sizeof (*fh));
199 200
200 201 if (nargs->knconf) {
201 202 if (nargs->knconf->knc_protofmly)
202 203 kmem_free(nargs->knconf->knc_protofmly, KNC_STRSIZE);
203 204 if (nargs->knconf->knc_proto)
204 205 kmem_free(nargs->knconf->knc_proto, KNC_STRSIZE);
205 206 kmem_free(nargs->knconf, sizeof (*nargs->knconf));
206 207 nargs->knconf = NULL;
207 208 }
208 209
209 210 if (nargs->fh) {
210 211 kmem_free(nargs->fh, strlen(nargs->fh) + 1);
211 212 nargs->fh = NULL;
212 213 }
213 214
214 215 if (nargs->hostname) {
215 216 kmem_free(nargs->hostname, strlen(nargs->hostname) + 1);
216 217 nargs->hostname = NULL;
217 218 }
218 219
219 220 if (nargs->addr) {
220 221 if (nargs->addr->buf) {
221 222 ASSERT(nargs->addr->len);
222 223 kmem_free(nargs->addr->buf, nargs->addr->len);
223 224 }
224 225 kmem_free(nargs->addr, sizeof (struct netbuf));
225 226 nargs->addr = NULL;
226 227 }
227 228
228 229 if (nargs->syncaddr) {
229 230 ASSERT(nargs->syncaddr->len);
230 231 if (nargs->syncaddr->buf) {
231 232 ASSERT(nargs->syncaddr->len);
232 233 kmem_free(nargs->syncaddr->buf, nargs->syncaddr->len);
233 234 }
234 235 kmem_free(nargs->syncaddr, sizeof (struct netbuf));
235 236 nargs->syncaddr = NULL;
236 237 }
237 238
238 239 if (nargs->netname) {
239 240 kmem_free(nargs->netname, strlen(nargs->netname) + 1);
240 241 nargs->netname = NULL;
241 242 }
242 243
243 244 if (nargs->nfs_ext_u.nfs_extA.secdata) {
244 245 sec_clnt_freeinfo(nargs->nfs_ext_u.nfs_extA.secdata);
245 246 nargs->nfs_ext_u.nfs_extA.secdata = NULL;
246 247 }
247 248 }
248 249
249 250 static int
250 251 nfs3_copyin(char *data, int datalen, struct nfs_args *nargs, nfs_fhandle *fh)
251 252 {
252 253
253 254 int error;
254 255 size_t nlen; /* length of netname */
255 256 size_t hlen; /* length of hostname */
256 257 char netname[MAXNETNAMELEN+1]; /* server's netname */
257 258 struct netbuf addr; /* server's address */
258 259 struct netbuf syncaddr; /* AUTH_DES time sync addr */
259 260 struct knetconfig *knconf; /* transport knetconfig structure */
260 261 struct sec_data *secdata = NULL; /* security data */
261 262 STRUCT_DECL(nfs_args, args); /* nfs mount arguments */
262 263 STRUCT_DECL(knetconfig, knconf_tmp);
263 264 STRUCT_DECL(netbuf, addr_tmp);
264 265 int flags;
265 266 char *p, *pf;
266 267 char *userbufptr;
267 268
268 269
269 270 bzero(nargs, sizeof (*nargs));
270 271
271 272 STRUCT_INIT(args, get_udatamodel());
272 273 bzero(STRUCT_BUF(args), SIZEOF_STRUCT(nfs_args, DATAMODEL_NATIVE));
273 274 if (copyin(data, STRUCT_BUF(args), MIN(datalen, STRUCT_SIZE(args))))
274 275 return (EFAULT);
275 276
276 277 nargs->wsize = STRUCT_FGET(args, wsize);
277 278 nargs->rsize = STRUCT_FGET(args, rsize);
278 279 nargs->timeo = STRUCT_FGET(args, timeo);
279 280 nargs->retrans = STRUCT_FGET(args, retrans);
280 281 nargs->acregmin = STRUCT_FGET(args, acregmin);
281 282 nargs->acregmax = STRUCT_FGET(args, acregmax);
282 283 nargs->acdirmin = STRUCT_FGET(args, acdirmin);
283 284 nargs->acdirmax = STRUCT_FGET(args, acdirmax);
284 285
285 286 flags = STRUCT_FGET(args, flags);
286 287 nargs->flags = flags;
287 288
288 289 addr.buf = NULL;
289 290 syncaddr.buf = NULL;
290 291
291 292 /*
292 293 * Allocate space for a knetconfig structure and
293 294 * its strings and copy in from user-land.
294 295 */
295 296 knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP);
296 297 STRUCT_INIT(knconf_tmp, get_udatamodel());
297 298 if (copyin(STRUCT_FGETP(args, knconf), STRUCT_BUF(knconf_tmp),
298 299 STRUCT_SIZE(knconf_tmp))) {
299 300 kmem_free(knconf, sizeof (*knconf));
300 301 return (EFAULT);
301 302 }
302 303
303 304 knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics);
304 305 knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly);
305 306 knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto);
306 307 if (get_udatamodel() != DATAMODEL_LP64) {
307 308 knconf->knc_rdev = expldev(STRUCT_FGET(knconf_tmp, knc_rdev));
308 309 } else {
309 310 knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev);
310 311 }
311 312
312 313 pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
313 314 p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
314 315 error = copyinstr(knconf->knc_protofmly, pf, KNC_STRSIZE, NULL);
315 316 if (error) {
316 317 kmem_free(pf, KNC_STRSIZE);
317 318 kmem_free(p, KNC_STRSIZE);
318 319 kmem_free(knconf, sizeof (*knconf));
319 320 return (error);
320 321 }
321 322
322 323 error = copyinstr(knconf->knc_proto, p, KNC_STRSIZE, NULL);
323 324 if (error) {
324 325 kmem_free(pf, KNC_STRSIZE);
325 326 kmem_free(p, KNC_STRSIZE);
326 327 kmem_free(knconf, sizeof (*knconf));
327 328 return (error);
328 329 }
329 330
330 331
331 332 knconf->knc_protofmly = pf;
332 333 knconf->knc_proto = p;
333 334
334 335 nargs->knconf = knconf;
335 336 /*
336 337 * Get server address
337 338 */
338 339 STRUCT_INIT(addr_tmp, get_udatamodel());
339 340 if (copyin(STRUCT_FGETP(args, addr), STRUCT_BUF(addr_tmp),
340 341 STRUCT_SIZE(addr_tmp))) {
341 342 error = EFAULT;
342 343 goto errout;
343 344 }
344 345
345 346 nargs->addr = kmem_alloc(sizeof (struct netbuf), KM_SLEEP);
346 347 userbufptr = STRUCT_FGETP(addr_tmp, buf);
347 348 addr.len = STRUCT_FGET(addr_tmp, len);
348 349 addr.buf = kmem_alloc(addr.len, KM_SLEEP);
349 350 addr.maxlen = addr.len;
350 351 if (copyin(userbufptr, addr.buf, addr.len)) {
351 352 kmem_free(addr.buf, addr.len);
352 353 error = EFAULT;
353 354 goto errout;
354 355 }
355 356 bcopy(&addr, nargs->addr, sizeof (struct netbuf));
356 357
357 358 /*
358 359 * Get the root fhandle
359 360 */
360 361
361 362 if (copyin(STRUCT_FGETP(args, fh), fh, sizeof (nfs_fhandle))) {
362 363 error = EFAULT;
363 364 goto errout;
364 365 }
365 366
366 367
367 368 /*
368 369 * Get server's hostname
369 370 */
370 371 if (flags & NFSMNT_HOSTNAME) {
371 372 error = copyinstr(STRUCT_FGETP(args, hostname), netname,
372 373 sizeof (netname), &hlen);
373 374 if (error)
374 375 goto errout;
375 376 nargs->hostname = kmem_zalloc(hlen, KM_SLEEP);
376 377 (void) strcpy(nargs->hostname, netname);
377 378 } else {
378 379 nargs->hostname = NULL;
379 380 }
380 381
381 382
382 383 /*
383 384 * If there are syncaddr and netname data, load them in. This is
384 385 * to support data needed for NFSV4 when AUTH_DH is the negotiated
385 386 * flavor via SECINFO. (instead of using MOUNT protocol in V3).
386 387 */
387 388 netname[0] = '\0';
388 389 if (flags & NFSMNT_SECURE) {
389 390 if (STRUCT_FGETP(args, syncaddr) == NULL) {
390 391 error = EINVAL;
391 392 goto errout;
392 393 }
393 394 /* get syncaddr */
394 395 STRUCT_INIT(addr_tmp, get_udatamodel());
395 396 if (copyin(STRUCT_FGETP(args, syncaddr), STRUCT_BUF(addr_tmp),
396 397 STRUCT_SIZE(addr_tmp))) {
397 398 error = EINVAL;
398 399 goto errout;
399 400 }
400 401 userbufptr = STRUCT_FGETP(addr_tmp, buf);
401 402 syncaddr.len = STRUCT_FGET(addr_tmp, len);
402 403 syncaddr.buf = kmem_alloc(syncaddr.len, KM_SLEEP);
403 404 syncaddr.maxlen = syncaddr.len;
404 405 if (copyin(userbufptr, syncaddr.buf, syncaddr.len)) {
405 406 kmem_free(syncaddr.buf, syncaddr.len);
406 407 error = EFAULT;
407 408 goto errout;
408 409 }
409 410
410 411 nargs->syncaddr = kmem_alloc(sizeof (struct netbuf), KM_SLEEP);
411 412 bcopy(&syncaddr, nargs->syncaddr, sizeof (struct netbuf));
412 413
413 414 ASSERT(STRUCT_FGETP(args, netname));
414 415
415 416 if (copyinstr(STRUCT_FGETP(args, netname), netname,
416 417 sizeof (netname), &nlen)) {
417 418 error = EFAULT;
418 419 goto errout;
419 420 }
420 421
421 422 netname[nlen] = '\0';
422 423 nargs->netname = kmem_zalloc(nlen, KM_SLEEP);
423 424 (void) strcpy(nargs->netname, netname);
424 425 }
425 426
426 427 /*
427 428 * Get the extention data which has the security data structure.
428 429 * This includes data for AUTH_SYS as well.
429 430 */
430 431 if (flags & NFSMNT_NEWARGS) {
431 432 nargs->nfs_args_ext = STRUCT_FGET(args, nfs_args_ext);
432 433 if (nargs->nfs_args_ext == NFS_ARGS_EXTA ||
433 434 nargs->nfs_args_ext == NFS_ARGS_EXTB) {
434 435 /*
435 436 * Indicating the application is using the new
436 437 * sec_data structure to pass in the security
437 438 * data.
438 439 */
439 440 if (STRUCT_FGETP(args,
440 441 nfs_ext_u.nfs_extA.secdata) != NULL) {
441 442 error = sec_clnt_loadinfo(
442 443 (struct sec_data *)STRUCT_FGETP(args,
443 444 nfs_ext_u.nfs_extA.secdata), &secdata,
444 445 get_udatamodel());
445 446 }
446 447 nargs->nfs_ext_u.nfs_extA.secdata = secdata;
447 448 }
448 449 }
449 450
450 451 if (error)
451 452 goto errout;
452 453
453 454 /*
454 455 * Failover support:
455 456 *
456 457 * We may have a linked list of nfs_args structures,
457 458 * which means the user is looking for failover. If
458 459 * the mount is either not "read-only" or "soft",
459 460 * we want to bail out with EINVAL.
460 461 */
461 462 if (nargs->nfs_args_ext == NFS_ARGS_EXTB)
462 463 nargs->nfs_ext_u.nfs_extB.next =
463 464 STRUCT_FGETP(args, nfs_ext_u.nfs_extB.next);
464 465
465 466 errout:
466 467 if (error)
467 468 nfs3_free_args(nargs, fh);
468 469
469 470 return (error);
470 471 }
471 472
472 473
473 474 /*
474 475 * nfs mount vfsop
475 476 * Set up mount info record and attach it to vfs struct.
476 477 */
477 478 static int
478 479 nfs3_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
479 480 {
480 481 struct nfs_args *args = NULL;
481 482 nfs_fhandle *fhandle = NULL;
482 483 char *data = uap->dataptr;
483 484 int error;
484 485 vnode_t *rtvp; /* the server's root */
485 486 mntinfo_t *mi; /* mount info, pointed at by vfs */
486 487 size_t nlen; /* length of netname */
487 488 struct knetconfig *knconf; /* transport knetconfig structure */
488 489 struct knetconfig *rdma_knconf; /* rdma transport structure */
489 490 rnode_t *rp;
490 491 struct servinfo *svp; /* nfs server info */
491 492 struct servinfo *svp_tail = NULL; /* previous nfs server info */
492 493 struct servinfo *svp_head; /* first nfs server info */
493 494 struct servinfo *svp_2ndlast; /* 2nd last in server info list */
494 495 struct sec_data *secdata; /* security data */
495 496 int flags, addr_type;
496 497 zone_t *zone = nfs_zone();
497 498 zone_t *mntzone = NULL;
498 499
499 500
500 501 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
501 502 return (EPERM);
502 503
503 504 if (mvp->v_type != VDIR)
504 505 return (ENOTDIR);
505 506
506 507 /*
507 508 * get arguments
508 509 *
509 510 * nfs_args is now versioned and is extensible, so
510 511 * uap->datalen might be different from sizeof (args)
511 512 * in a compatible situation.
512 513 */
513 514
514 515 more:
515 516
516 517 if (!(uap->flags & MS_SYSSPACE)) {
517 518 if (args == NULL)
518 519 args = kmem_alloc(sizeof (struct nfs_args), KM_SLEEP);
519 520 else {
520 521 nfs3_free_args(args, fhandle);
521 522 fhandle = NULL;
522 523 }
523 524 if (fhandle == NULL)
524 525 fhandle = kmem_alloc(sizeof (nfs_fhandle), KM_SLEEP);
525 526 error = nfs3_copyin(data, uap->datalen, args, fhandle);
526 527 if (error) {
527 528 if (args)
528 529 kmem_free(args, sizeof (*args));
529 530 return (error);
530 531 }
531 532 } else {
532 533 args = (struct nfs_args *)data;
533 534 fhandle = (nfs_fhandle *)args->fh;
534 535 }
535 536
536 537
537 538 flags = args->flags;
538 539
539 540 if (uap->flags & MS_REMOUNT) {
540 541 size_t n;
541 542 char name[FSTYPSZ];
542 543
543 544 if (uap->flags & MS_SYSSPACE) {
544 545 error = copystr(uap->fstype, name, FSTYPSZ, &n);
545 546 } else {
546 547 nfs3_free_args(args, fhandle);
547 548 kmem_free(args, sizeof (*args));
548 549 error = copyinstr(uap->fstype, name, FSTYPSZ, &n);
549 550 }
550 551 if (error) {
551 552 if (error == ENAMETOOLONG)
552 553 return (EINVAL);
553 554 return (error);
554 555 }
555 556
556 557 /*
557 558 * This check is to ensure that the request is a
558 559 * genuine nfs remount request.
559 560 */
560 561
561 562 if (strncmp(name, "nfs", 3) != 0)
562 563 return (EINVAL);
563 564
564 565 /*
565 566 * If the request changes the locking type, disallow the
566 567 * remount,
567 568 * because it's questionable whether we can transfer the
568 569 * locking state correctly.
569 570 */
570 571
571 572 if ((mi = VFTOMI(vfsp)) != NULL) {
572 573 uint_t new_mi_llock;
573 574 uint_t old_mi_llock;
574 575
575 576 new_mi_llock = (flags & NFSMNT_LLOCK) ? 1 : 0;
576 577 old_mi_llock = (mi->mi_flags & MI_LLOCK) ? 1 : 0;
577 578 if (old_mi_llock != new_mi_llock)
578 579 return (EBUSY);
579 580 }
580 581 return (0);
581 582 }
582 583
583 584 mutex_enter(&mvp->v_lock);
584 585 if (!(uap->flags & MS_OVERLAY) &&
585 586 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
586 587 mutex_exit(&mvp->v_lock);
587 588 if (!(uap->flags & MS_SYSSPACE)) {
588 589 nfs3_free_args(args, fhandle);
589 590 kmem_free(args, sizeof (*args));
590 591 }
591 592 return (EBUSY);
592 593 }
593 594 mutex_exit(&mvp->v_lock);
594 595
595 596 /* make sure things are zeroed for errout: */
596 597 rtvp = NULL;
597 598 mi = NULL;
598 599 secdata = NULL;
599 600
600 601 /*
601 602 * A valid knetconfig structure is required.
602 603 */
603 604 if (!(flags & NFSMNT_KNCONF)) {
604 605 if (!(uap->flags & MS_SYSSPACE)) {
605 606 nfs3_free_args(args, fhandle);
606 607 kmem_free(args, sizeof (*args));
607 608 }
608 609 return (EINVAL);
609 610 }
610 611
611 612 if ((strlen(args->knconf->knc_protofmly) >= KNC_STRSIZE) ||
612 613 (strlen(args->knconf->knc_proto) >= KNC_STRSIZE)) {
613 614 if (!(uap->flags & MS_SYSSPACE)) {
614 615 nfs3_free_args(args, fhandle);
615 616 kmem_free(args, sizeof (*args));
616 617 }
617 618 return (EINVAL);
618 619 }
619 620
620 621 /*
621 622 * Allocate a servinfo struct.
622 623 */
623 624 svp = kmem_zalloc(sizeof (*svp), KM_SLEEP);
624 625 mutex_init(&svp->sv_lock, NULL, MUTEX_DEFAULT, NULL);
625 626 if (svp_tail) {
626 627 svp_2ndlast = svp_tail;
627 628 svp_tail->sv_next = svp;
628 629 } else {
629 630 svp_head = svp;
630 631 svp_2ndlast = svp;
631 632 }
632 633
633 634 svp_tail = svp;
634 635
635 636 svp->sv_knconf = args->knconf;
636 637 args->knconf = NULL;
637 638
638 639 if (args->addr == NULL || args->addr->buf == NULL) {
639 640 error = EINVAL;
640 641 goto errout;
641 642 }
642 643
643 644 svp->sv_addr.maxlen = args->addr->maxlen;
644 645 svp->sv_addr.len = args->addr->len;
645 646 svp->sv_addr.buf = args->addr->buf;
646 647 args->addr->buf = NULL;
647 648
648 649 /*
649 650 * Check the root fhandle length
650 651 */
651 652 ASSERT(fhandle);
652 653 if (fhandle->fh_len > NFS3_FHSIZE || fhandle->fh_len == 0) {
653 654 error = EINVAL;
654 655 #ifdef DEBUG
655 656 zcmn_err(getzoneid(), CE_WARN,
656 657 "nfs3_mount: got an invalid fhandle. fh_len = %d",
657 658 fhandle->fh_len);
658 659 fhandle->fh_len = NFS_FHANDLE_LEN;
659 660 nfs_printfhandle(fhandle);
660 661 #endif
661 662 goto errout;
662 663 }
663 664
664 665 bcopy(&fhandle->fh_buf, &svp->sv_fhandle.fh_buf, fhandle->fh_len);
665 666 svp->sv_fhandle.fh_len = fhandle->fh_len;
666 667
667 668 /*
668 669 * Get server's hostname
669 670 */
670 671 if (flags & NFSMNT_HOSTNAME) {
671 672 if (args->hostname == NULL) {
672 673 error = EINVAL;
673 674 goto errout;
674 675 }
675 676 svp->sv_hostnamelen = strlen(args->hostname) + 1;
676 677 svp->sv_hostname = args->hostname;
677 678 args->hostname = NULL;
678 679 } else {
679 680 char *p = "unknown-host";
680 681 svp->sv_hostnamelen = strlen(p) + 1;
681 682 svp->sv_hostname = kmem_zalloc(svp->sv_hostnamelen, KM_SLEEP);
682 683 (void) strcpy(svp->sv_hostname, p);
683 684 }
684 685
685 686
686 687 /*
687 688 * RDMA MOUNT SUPPORT FOR NFS v3:
688 689 * Establish, is it possible to use RDMA, if so overload the
689 690 * knconf with rdma specific knconf and free the orignal.
690 691 */
691 692 if ((flags & NFSMNT_TRYRDMA) || (flags & NFSMNT_DORDMA)) {
692 693 /*
693 694 * Determine the addr type for RDMA, IPv4 or v6.
694 695 */
695 696 if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET) == 0)
696 697 addr_type = AF_INET;
697 698 else if (strcmp(svp->sv_knconf->knc_protofmly, NC_INET6) == 0)
698 699 addr_type = AF_INET6;
699 700
700 701 if (rdma_reachable(addr_type, &svp->sv_addr,
701 702 &rdma_knconf) == 0) {
702 703 /*
703 704 * If successful, hijack the orignal knconf and
704 705 * replace with a new one, depending on the flags.
705 706 */
706 707 svp->sv_origknconf = svp->sv_knconf;
707 708 svp->sv_knconf = rdma_knconf;
708 709 knconf = rdma_knconf;
709 710 } else {
710 711 if (flags & NFSMNT_TRYRDMA) {
711 712 #ifdef DEBUG
712 713 if (rdma_debug)
713 714 zcmn_err(getzoneid(), CE_WARN,
714 715 "no RDMA onboard, revert\n");
715 716 #endif
716 717 }
717 718
718 719 if (flags & NFSMNT_DORDMA) {
719 720 /*
720 721 * If proto=rdma is specified and no RDMA
721 722 * path to this server is avialable then
722 723 * ditch this server.
723 724 * This is not included in the mountable
724 725 * server list or the replica list.
725 726 * Check if more servers are specified;
726 727 * Failover case, otherwise bail out of mount.
727 728 */
728 729 if (args->nfs_args_ext == NFS_ARGS_EXTB &&
729 730 args->nfs_ext_u.nfs_extB.next != NULL) {
730 731 data = (char *)
731 732 args->nfs_ext_u.nfs_extB.next;
732 733 if (uap->flags & MS_RDONLY &&
733 734 !(flags & NFSMNT_SOFT)) {
734 735 if (svp_head->sv_next == NULL) {
735 736 svp_tail = NULL;
736 737 svp_2ndlast = NULL;
737 738 sv_free(svp_head);
738 739 goto more;
739 740 } else {
740 741 svp_tail = svp_2ndlast;
741 742 svp_2ndlast->sv_next =
742 743 NULL;
743 744 sv_free(svp);
744 745 goto more;
745 746 }
746 747 }
747 748 } else {
748 749 /*
749 750 * This is the last server specified
750 751 * in the nfs_args list passed down
751 752 * and its not rdma capable.
752 753 */
753 754 if (svp_head->sv_next == NULL) {
754 755 /*
755 756 * Is this the only one
756 757 */
757 758 error = EINVAL;
758 759 #ifdef DEBUG
759 760 if (rdma_debug)
760 761 zcmn_err(getzoneid(),
761 762 CE_WARN,
762 763 "No RDMA srv");
763 764 #endif
764 765 goto errout;
765 766 } else {
766 767 /*
767 768 * There is list, since some
768 769 * servers specified before
769 770 * this passed all requirements
770 771 */
771 772 svp_tail = svp_2ndlast;
772 773 svp_2ndlast->sv_next = NULL;
773 774 sv_free(svp);
774 775 goto proceed;
775 776 }
776 777 }
777 778 }
778 779 }
779 780 }
780 781
781 782 /*
782 783 * Get the extention data which has the new security data structure.
783 784 */
784 785 if (flags & NFSMNT_NEWARGS) {
785 786 switch (args->nfs_args_ext) {
786 787 case NFS_ARGS_EXTA:
787 788 case NFS_ARGS_EXTB:
788 789 /*
789 790 * Indicating the application is using the new
790 791 * sec_data structure to pass in the security
791 792 * data.
792 793 */
793 794 secdata = args->nfs_ext_u.nfs_extA.secdata;
794 795 if (args->nfs_ext_u.nfs_extA.secdata == NULL) {
795 796 error = EINVAL;
796 797 } else {
797 798 /*
798 799 * Need to validate the flavor here if
799 800 * sysspace, userspace was already
800 801 * validate from the nfs_copyin function.
801 802 */
802 803 switch (secdata->rpcflavor) {
803 804 case AUTH_NONE:
804 805 case AUTH_UNIX:
805 806 case AUTH_LOOPBACK:
806 807 case AUTH_DES:
807 808 case RPCSEC_GSS:
808 809 args->nfs_ext_u.nfs_extA.secdata = NULL;
809 810 break;
810 811 default:
811 812 error = EINVAL;
812 813 goto errout;
813 814 }
814 815 }
815 816 break;
816 817
817 818 default:
818 819 error = EINVAL;
819 820 break;
820 821 }
821 822 } else if (flags & NFSMNT_SECURE) {
822 823 /*
823 824 * Keep this for backward compatibility to support
824 825 * NFSMNT_SECURE/NFSMNT_RPCTIMESYNC flags.
825 826 */
826 827 if (args->syncaddr == NULL || args->syncaddr->buf == NULL) {
827 828 error = EINVAL;
828 829 goto errout;
829 830 }
830 831 /*
831 832 * Move security related data to the sec_data structure.
832 833 */
833 834 {
834 835 dh_k4_clntdata_t *data;
835 836 char *pf, *p;
836 837 secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
837 838 if (flags & NFSMNT_RPCTIMESYNC)
838 839 secdata->flags |= AUTH_F_RPCTIMESYNC;
839 840 data = kmem_alloc(sizeof (*data), KM_SLEEP);
840 841 bcopy(args->syncaddr, &data->syncaddr,
841 842 sizeof (*args->syncaddr));
842 843
843 844 /*
844 845 * duplicate the knconf information for the
845 846 * new opaque data.
846 847 */
847 848 data->knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP);
848 849 *data->knconf = *knconf;
849 850 pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
850 851 p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
851 852 bcopy(knconf->knc_protofmly, pf, KNC_STRSIZE);
852 853 bcopy(knconf->knc_proto, pf, KNC_STRSIZE);
853 854 data->knconf->knc_protofmly = pf;
854 855 data->knconf->knc_proto = p;
855 856
856 857 nlen = strlen(args->hostname) + 1;
857 858 /* move server netname to the sec_data structure */
858 859 if (nlen != 0) {
859 860 data->netname = kmem_alloc(nlen, KM_SLEEP);
860 861 bcopy(args->hostname, data->netname, nlen);
861 862 data->netnamelen = nlen;
862 863 }
863 864 secdata->secmod = secdata->rpcflavor = AUTH_DES;
864 865 secdata->data = (caddr_t)data;
865 866 }
866 867 } else {
867 868 secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
868 869 secdata->secmod = secdata->rpcflavor = AUTH_UNIX;
869 870 secdata->data = NULL;
870 871 }
871 872
872 873 svp->sv_secdata = secdata;
873 874 if (error)
874 875 goto errout;
875 876
876 877 /*
877 878 * See bug 1180236.
878 879 * If mount secure failed, we will fall back to AUTH_NONE
879 880 * and try again. nfs3rootvp() will turn this back off.
880 881 *
881 882 * The NFS Version 3 mount uses the FSINFO and GETATTR
882 883 * procedures. The server should not care if these procedures
883 884 * have the proper security flavor, so if mount retries using
884 885 * AUTH_NONE that does not require a credential setup for root
885 886 * then the automounter would work without requiring root to be
886 887 * keylogged into AUTH_DES.
887 888 */
888 889 if (secdata->rpcflavor != AUTH_UNIX &&
889 890 secdata->rpcflavor != AUTH_LOOPBACK)
890 891 secdata->flags |= AUTH_F_TRYNONE;
891 892
892 893 /*
893 894 * Failover support:
894 895 *
895 896 * We may have a linked list of nfs_args structures,
896 897 * which means the user is looking for failover. If
897 898 * the mount is either not "read-only" or "soft",
898 899 * we want to bail out with EINVAL.
899 900 */
900 901 if (args->nfs_args_ext == NFS_ARGS_EXTB &&
901 902 args->nfs_ext_u.nfs_extB.next != NULL) {
902 903 if (uap->flags & MS_RDONLY && !(flags & NFSMNT_SOFT)) {
903 904 data = (char *)args->nfs_ext_u.nfs_extB.next;
904 905 goto more;
905 906 }
906 907 error = EINVAL;
907 908 goto errout;
908 909 }
909 910
910 911 /*
911 912 * Determine the zone we're being mounted into.
912 913 */
913 914 zone_hold(mntzone = zone); /* start with this assumption */
914 915 if (getzoneid() == GLOBAL_ZONEID) {
915 916 zone_rele(mntzone);
916 917 mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
917 918 ASSERT(mntzone != NULL);
918 919 if (mntzone != zone) {
919 920 error = EBUSY;
920 921 goto errout;
921 922 }
922 923 }
923 924
924 925 if (is_system_labeled()) {
925 926 error = nfs_mount_label_policy(vfsp, &svp->sv_addr,
926 927 svp->sv_knconf, cr);
927 928
928 929 if (error > 0)
929 930 goto errout;
930 931
931 932 if (error == -1) {
932 933 /* change mount to read-only to prevent write-down */
933 934 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
934 935 }
935 936 }
936 937
937 938 /*
938 939 * Stop the mount from going any further if the zone is going away.
939 940 */
940 941 if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
941 942 error = EBUSY;
942 943 goto errout;
943 944 }
944 945
945 946 /*
946 947 * Get root vnode.
947 948 */
948 949 proceed:
949 950 error = nfs3rootvp(&rtvp, vfsp, svp_head, flags, cr, mntzone);
950 951
951 952 if (error)
952 953 goto errout;
953 954
954 955 /*
955 956 * Set option fields in the mount info record
956 957 */
957 958 mi = VTOMI(rtvp);
958 959
959 960 if (svp_head->sv_next)
960 961 mi->mi_flags |= MI_LLOCK;
961 962
962 963 error = nfs_setopts(rtvp, DATAMODEL_NATIVE, args);
963 964
964 965 errout:
965 966 if (rtvp != NULL) {
966 967 if (error) {
967 968 rp = VTOR(rtvp);
968 969 if (rp->r_flags & RHASHED)
969 970 rp_rmhash(rp);
970 971 }
971 972 VN_RELE(rtvp);
972 973 }
973 974
974 975 if (error) {
975 976 sv_free(svp_head);
976 977 if (mi != NULL) {
977 978 nfs_async_stop(vfsp);
978 979 nfs_async_manager_stop(vfsp);
979 980 if (mi->mi_io_kstats) {
980 981 kstat_delete(mi->mi_io_kstats);
981 982 mi->mi_io_kstats = NULL;
982 983 }
983 984 if (mi->mi_ro_kstats) {
984 985 kstat_delete(mi->mi_ro_kstats);
985 986 mi->mi_ro_kstats = NULL;
986 987 }
987 988 nfs_free_mi(mi);
988 989 }
989 990 }
990 991
991 992
992 993 if (!(uap->flags & MS_SYSSPACE)) {
|
↓ open down ↓ |
960 lines elided |
↑ open up ↑ |
993 994 nfs3_free_args(args, fhandle);
994 995 kmem_free(args, sizeof (*args));
995 996 }
996 997
997 998 if (mntzone != NULL)
998 999 zone_rele(mntzone);
999 1000
1000 1001 return (error);
1001 1002 }
1002 1003
1003 -static int nfs3_dynamic = 0; /* global variable to enable dynamic retrans. */
1004 -static ushort_t nfs3_max_threads = 8; /* max number of active async threads */
1005 -uint_t nfs3_bsize = 32 * 1024; /* client `block' size */
1006 -static uint_t nfs3_async_clusters = 1; /* # of reqs from each async queue */
1007 -static uint_t nfs3_cots_timeo = NFS_COTS_TIMEO;
1004 +volatile int nfs3_dynamic = 0; /* global variable to enable dynamic retrans. */
1005 +volatile ushort_t nfs3_max_threads = 8; /* max number of active async threads */
1006 +volatile uint_t nfs3_bsize = 32 * 1024; /* client `block' size */
1007 +volatile uint_t nfs3_async_clusters = 1; /* # of reqs from each async queue */
1008 +volatile uint_t nfs3_cots_timeo = NFS_COTS_TIMEO;
1008 1009
1009 1010 static int
1010 1011 nfs3rootvp(vnode_t **rtvpp, vfs_t *vfsp, struct servinfo *svp,
1011 1012 int flags, cred_t *cr, zone_t *zone)
1012 1013 {
1013 1014 vnode_t *rtvp;
1014 1015 mntinfo_t *mi;
1015 1016 dev_t nfs_dev;
1016 1017 struct vattr va;
1017 1018 struct FSINFO3args args;
1018 1019 struct FSINFO3res res;
1019 1020 int error;
1020 1021 int douprintf;
1021 1022 rnode_t *rp;
1022 1023 int i;
1023 1024 uint_t max_transfer_size;
1024 1025 struct nfs_stats *nfsstatsp;
1025 1026 cred_t *lcr = NULL, *tcr = cr;
1026 1027
1027 1028 nfsstatsp = zone_getspecific(nfsstat_zone_key, nfs_zone());
1028 1029 ASSERT(nfsstatsp != NULL);
1029 1030
1030 1031 ASSERT(nfs_zone() == zone);
1031 1032 /*
1032 1033 * Create a mount record and link it to the vfs struct.
1033 1034 */
1034 1035 mi = kmem_zalloc(sizeof (*mi), KM_SLEEP);
1035 1036 mutex_init(&mi->mi_lock, NULL, MUTEX_DEFAULT, NULL);
1036 1037 mutex_init(&mi->mi_remap_lock, NULL, MUTEX_DEFAULT, NULL);
1037 1038 mi->mi_flags = MI_ACL | MI_EXTATTR;
1038 1039 if (!(flags & NFSMNT_SOFT))
1039 1040 mi->mi_flags |= MI_HARD;
1040 1041 if ((flags & NFSMNT_SEMISOFT))
1041 1042 mi->mi_flags |= MI_SEMISOFT;
1042 1043 if ((flags & NFSMNT_NOPRINT))
1043 1044 mi->mi_flags |= MI_NOPRINT;
1044 1045 if (flags & NFSMNT_INT)
1045 1046 mi->mi_flags |= MI_INT;
1046 1047 mi->mi_retrans = NFS_RETRIES;
1047 1048 if (svp->sv_knconf->knc_semantics == NC_TPI_COTS_ORD ||
1048 1049 svp->sv_knconf->knc_semantics == NC_TPI_COTS)
1049 1050 mi->mi_timeo = nfs3_cots_timeo;
1050 1051 else
1051 1052 mi->mi_timeo = NFS_TIMEO;
1052 1053 mi->mi_prog = NFS_PROGRAM;
1053 1054 mi->mi_vers = NFS_V3;
1054 1055 mi->mi_rfsnames = rfsnames_v3;
1055 1056 mi->mi_reqs = nfsstatsp->nfs_stats_v3.rfsreqcnt_ptr;
1056 1057 mi->mi_call_type = call_type_v3;
1057 1058 mi->mi_ss_call_type = ss_call_type_v3;
1058 1059 mi->mi_timer_type = timer_type_v3;
1059 1060 mi->mi_aclnames = aclnames_v3;
1060 1061 mi->mi_aclreqs = nfsstatsp->nfs_stats_v3.aclreqcnt_ptr;
1061 1062 mi->mi_acl_call_type = acl_call_type_v3;
1062 1063 mi->mi_acl_ss_call_type = acl_ss_call_type_v3;
1063 1064 mi->mi_acl_timer_type = acl_timer_type_v3;
1064 1065 cv_init(&mi->mi_failover_cv, NULL, CV_DEFAULT, NULL);
1065 1066 mi->mi_servers = svp;
1066 1067 mi->mi_curr_serv = svp;
1067 1068 mi->mi_acregmin = SEC2HR(ACREGMIN);
1068 1069 mi->mi_acregmax = SEC2HR(ACREGMAX);
1069 1070 mi->mi_acdirmin = SEC2HR(ACDIRMIN);
1070 1071 mi->mi_acdirmax = SEC2HR(ACDIRMAX);
1071 1072
1072 1073 if (nfs3_dynamic)
1073 1074 mi->mi_flags |= MI_DYNAMIC;
1074 1075
1075 1076 if (flags & NFSMNT_DIRECTIO)
1076 1077 mi->mi_flags |= MI_DIRECTIO;
1077 1078
1078 1079 /*
1079 1080 * Make a vfs struct for nfs. We do this here instead of below
1080 1081 * because rtvp needs a vfs before we can do a getattr on it.
1081 1082 *
1082 1083 * Assign a unique device id to the mount
1083 1084 */
1084 1085 mutex_enter(&nfs_minor_lock);
1085 1086 do {
1086 1087 nfs_minor = (nfs_minor + 1) & MAXMIN32;
1087 1088 nfs_dev = makedevice(nfs_major, nfs_minor);
1088 1089 } while (vfs_devismounted(nfs_dev));
1089 1090 mutex_exit(&nfs_minor_lock);
1090 1091
1091 1092 vfsp->vfs_dev = nfs_dev;
1092 1093 vfs_make_fsid(&vfsp->vfs_fsid, nfs_dev, nfs3fstyp);
1093 1094 vfsp->vfs_data = (caddr_t)mi;
1094 1095 vfsp->vfs_fstype = nfsfstyp;
1095 1096
1096 1097 /*
1097 1098 * Verify that nfs3_bsize tuneable is set to an
1098 1099 * acceptable value. It be a multiple of PAGESIZE or
1099 1100 * file corruption can occur.
1100 1101 */
1101 1102 if (nfs3_bsize & PAGEOFFSET)
1102 1103 nfs3_bsize &= PAGEMASK;
1103 1104 if (nfs3_bsize < PAGESIZE)
1104 1105 nfs3_bsize = PAGESIZE;
1105 1106 vfsp->vfs_bsize = nfs3_bsize;
1106 1107
1107 1108 /*
1108 1109 * Initialize fields used to support async putpage operations.
1109 1110 */
1110 1111 for (i = 0; i < NFS_ASYNC_TYPES; i++)
1111 1112 mi->mi_async_clusters[i] = nfs3_async_clusters;
1112 1113 mi->mi_async_init_clusters = nfs3_async_clusters;
1113 1114 mi->mi_async_curr[NFS_ASYNC_QUEUE] =
1114 1115 mi->mi_async_curr[NFS_ASYNC_PGOPS_QUEUE] = &mi->mi_async_reqs[0];
1115 1116 mi->mi_max_threads = nfs3_max_threads;
1116 1117 mutex_init(&mi->mi_async_lock, NULL, MUTEX_DEFAULT, NULL);
1117 1118 cv_init(&mi->mi_async_reqs_cv, NULL, CV_DEFAULT, NULL);
1118 1119 cv_init(&mi->mi_async_work_cv[NFS_ASYNC_QUEUE], NULL, CV_DEFAULT, NULL);
1119 1120 cv_init(&mi->mi_async_work_cv[NFS_ASYNC_PGOPS_QUEUE], NULL,
1120 1121 CV_DEFAULT, NULL);
1121 1122 cv_init(&mi->mi_async_cv, NULL, CV_DEFAULT, NULL);
1122 1123
1123 1124 mi->mi_vfsp = vfsp;
1124 1125 mi->mi_zone = zone;
1125 1126 zone_init_ref(&mi->mi_zone_ref);
1126 1127 zone_hold_ref(zone, &mi->mi_zone_ref, ZONE_REF_NFS);
1127 1128 nfs_mi_zonelist_add(mi);
1128 1129
1129 1130 /*
1130 1131 * Make the root vnode, use it to get attributes,
1131 1132 * then remake it with the attributes.
1132 1133 */
1133 1134 rtvp = makenfs3node((nfs_fh3 *)&svp->sv_fhandle,
1134 1135 NULL, vfsp, gethrtime(), cr, NULL, NULL);
1135 1136
1136 1137 /*
1137 1138 * Make the FSINFO calls, primarily at this point to
1138 1139 * determine the transfer size. For client failover,
1139 1140 * we'll want this to be the minimum bid from any
1140 1141 * server, so that we don't overrun stated limits.
1141 1142 *
1142 1143 * While we're looping, we'll turn off AUTH_F_TRYNONE,
1143 1144 * which is only for the mount operation.
1144 1145 */
1145 1146
1146 1147 mi->mi_tsize = nfs3_tsize(svp->sv_knconf);
1147 1148 mi->mi_stsize = mi->mi_tsize;
1148 1149
1149 1150 mi->mi_curread = nfs3_bsize;
1150 1151 mi->mi_curwrite = mi->mi_curread;
1151 1152
1152 1153 /*
1153 1154 * If the uid is set then set the creds for secure mounts
1154 1155 * by proxy processes such as automountd.
1155 1156 */
1156 1157 if (svp->sv_secdata->uid != 0 &&
1157 1158 svp->sv_secdata->rpcflavor == RPCSEC_GSS) {
1158 1159 lcr = crdup(cr);
1159 1160 (void) crsetugid(lcr, svp->sv_secdata->uid, crgetgid(cr));
1160 1161 tcr = lcr;
1161 1162 }
1162 1163
1163 1164 for (svp = mi->mi_servers; svp != NULL; svp = svp->sv_next) {
1164 1165 douprintf = 1;
1165 1166 mi->mi_curr_serv = svp;
1166 1167 max_transfer_size = nfs3_tsize(svp->sv_knconf);
1167 1168 mi->mi_tsize = MIN(max_transfer_size, mi->mi_tsize);
1168 1169 mi->mi_stsize = MIN(max_transfer_size, mi->mi_stsize);
1169 1170 mi->mi_curread = MIN(max_transfer_size, mi->mi_curread);
1170 1171 mi->mi_curwrite = MIN(max_transfer_size, mi->mi_curwrite);
1171 1172 args.fsroot = *(nfs_fh3 *)&svp->sv_fhandle;
1172 1173
1173 1174 error = rfs3call(mi, NFSPROC3_FSINFO,
1174 1175 xdr_nfs_fh3, (caddr_t)&args,
1175 1176 xdr_FSINFO3res, (caddr_t)&res, tcr,
1176 1177 &douprintf, &res.status, 0, NULL);
1177 1178 if (error)
1178 1179 goto bad;
1179 1180 error = geterrno3(res.status);
1180 1181 if (error)
1181 1182 goto bad;
1182 1183
1183 1184 /* get type of root node */
1184 1185 if (res.resok.obj_attributes.attributes) {
1185 1186 if (res.resok.obj_attributes.attr.type < NF3REG ||
1186 1187 res.resok.obj_attributes.attr.type > NF3FIFO) {
1187 1188 #ifdef DEBUG
1188 1189 zcmn_err(getzoneid(), CE_WARN,
1189 1190 "NFS3 server %s returned a bad file type for root",
1190 1191 svp->sv_hostname);
1191 1192 #else
1192 1193 zcmn_err(getzoneid(), CE_WARN,
1193 1194 "NFS server %s returned a bad file type for root",
1194 1195 svp->sv_hostname);
1195 1196 #endif
1196 1197 error = EINVAL;
1197 1198 goto bad;
1198 1199 } else {
1199 1200 if (rtvp->v_type != VNON && rtvp->v_type !=
1200 1201 nf3_to_vt[res.resok.obj_attributes.attr.
1201 1202 type]) {
1202 1203 #ifdef DEBUG
1203 1204 zcmn_err(getzoneid(), CE_WARN,
1204 1205 "NFS3 server %s returned a different file type for root",
1205 1206 svp->sv_hostname);
1206 1207 #else
1207 1208 zcmn_err(getzoneid(), CE_WARN,
1208 1209 "NFS server %s returned a different file type for root",
1209 1210 svp->sv_hostname);
1210 1211 #endif
1211 1212 error = EINVAL;
1212 1213 goto bad;
1213 1214 }
1214 1215 rtvp->v_type =
1215 1216 nf3_to_vt[res.resok.obj_attributes.attr.
1216 1217 type];
1217 1218 }
1218 1219 }
1219 1220
1220 1221 if (res.resok.rtmax != 0) {
1221 1222 mi->mi_tsize = MIN(res.resok.rtmax, mi->mi_tsize);
1222 1223 if (res.resok.rtpref != 0) {
1223 1224 mi->mi_curread = MIN(res.resok.rtpref,
1224 1225 mi->mi_curread);
1225 1226 } else {
1226 1227 mi->mi_curread = MIN(res.resok.rtmax,
1227 1228 mi->mi_curread);
1228 1229 }
1229 1230 } else if (res.resok.rtpref != 0) {
1230 1231 mi->mi_tsize = MIN(res.resok.rtpref, mi->mi_tsize);
1231 1232 mi->mi_curread = MIN(res.resok.rtpref, mi->mi_curread);
1232 1233 } else {
1233 1234 #ifdef DEBUG
1234 1235 zcmn_err(getzoneid(), CE_WARN,
1235 1236 "NFS3 server %s returned 0 for read transfer sizes",
1236 1237 svp->sv_hostname);
1237 1238 #else
1238 1239 zcmn_err(getzoneid(), CE_WARN,
1239 1240 "NFS server %s returned 0 for read transfer sizes",
1240 1241 svp->sv_hostname);
1241 1242 #endif
1242 1243 error = EIO;
1243 1244 goto bad;
1244 1245 }
1245 1246 if (res.resok.wtmax != 0) {
1246 1247 mi->mi_stsize = MIN(res.resok.wtmax, mi->mi_stsize);
1247 1248 if (res.resok.wtpref != 0) {
1248 1249 mi->mi_curwrite = MIN(res.resok.wtpref,
1249 1250 mi->mi_curwrite);
1250 1251 } else {
1251 1252 mi->mi_curwrite = MIN(res.resok.wtmax,
1252 1253 mi->mi_curwrite);
1253 1254 }
1254 1255 } else if (res.resok.wtpref != 0) {
1255 1256 mi->mi_stsize = MIN(res.resok.wtpref, mi->mi_stsize);
1256 1257 mi->mi_curwrite = MIN(res.resok.wtpref,
1257 1258 mi->mi_curwrite);
1258 1259 } else {
1259 1260 #ifdef DEBUG
1260 1261 zcmn_err(getzoneid(), CE_WARN,
1261 1262 "NFS3 server %s returned 0 for write transfer sizes",
1262 1263 svp->sv_hostname);
1263 1264 #else
1264 1265 zcmn_err(getzoneid(), CE_WARN,
1265 1266 "NFS server %s returned 0 for write transfer sizes",
1266 1267 svp->sv_hostname);
1267 1268 #endif
1268 1269 error = EIO;
1269 1270 goto bad;
1270 1271 }
1271 1272
1272 1273 /*
1273 1274 * These signal the ability of the server to create
1274 1275 * hard links and symbolic links, so they really
1275 1276 * aren't relevant if there is more than one server.
1276 1277 * We'll set them here, though it probably looks odd.
1277 1278 */
1278 1279 if (res.resok.properties & FSF3_LINK)
1279 1280 mi->mi_flags |= MI_LINK;
1280 1281 if (res.resok.properties & FSF3_SYMLINK)
1281 1282 mi->mi_flags |= MI_SYMLINK;
1282 1283
1283 1284 /* Pick up smallest non-zero maxfilesize value */
1284 1285 if (res.resok.maxfilesize) {
1285 1286 if (mi->mi_maxfilesize) {
1286 1287 mi->mi_maxfilesize = MIN(mi->mi_maxfilesize,
1287 1288 res.resok.maxfilesize);
1288 1289 } else
1289 1290 mi->mi_maxfilesize = res.resok.maxfilesize;
1290 1291 }
1291 1292
1292 1293 /*
1293 1294 * AUTH_F_TRYNONE is only for the mount operation,
1294 1295 * so turn it back off.
1295 1296 */
1296 1297 svp->sv_secdata->flags &= ~AUTH_F_TRYNONE;
1297 1298 }
1298 1299 mi->mi_curr_serv = mi->mi_servers;
1299 1300
1300 1301 /*
1301 1302 * Start the thread responsible for handling async worker threads.
1302 1303 */
1303 1304 VFS_HOLD(vfsp); /* add reference for thread */
1304 1305 mi->mi_manager_thread = zthread_create(NULL, 0, nfs_async_manager,
1305 1306 vfsp, 0, minclsyspri);
1306 1307 ASSERT(mi->mi_manager_thread != NULL);
1307 1308
1308 1309 /*
1309 1310 * Initialize kstats
1310 1311 */
1311 1312 nfs_mnt_kstat_init(vfsp);
1312 1313
1313 1314 /* If we didn't get a type, get one now */
1314 1315 if (rtvp->v_type == VNON) {
1315 1316 va.va_mask = AT_ALL;
1316 1317
1317 1318 error = nfs3getattr(rtvp, &va, tcr);
1318 1319 if (error)
1319 1320 goto bad;
1320 1321 rtvp->v_type = va.va_type;
1321 1322 }
1322 1323
1323 1324 mi->mi_type = rtvp->v_type;
1324 1325
1325 1326 *rtvpp = rtvp;
1326 1327 if (lcr != NULL)
1327 1328 crfree(lcr);
1328 1329
1329 1330 return (0);
1330 1331 bad:
1331 1332 /*
1332 1333 * An error occurred somewhere, need to clean up...
1333 1334 * We need to release our reference to the root vnode and
1334 1335 * destroy the mntinfo struct that we just created.
1335 1336 */
1336 1337 if (lcr != NULL)
1337 1338 crfree(lcr);
1338 1339 rp = VTOR(rtvp);
1339 1340 if (rp->r_flags & RHASHED)
1340 1341 rp_rmhash(rp);
1341 1342 VN_RELE(rtvp);
1342 1343 nfs_async_stop(vfsp);
1343 1344 nfs_async_manager_stop(vfsp);
1344 1345 if (mi->mi_io_kstats) {
1345 1346 kstat_delete(mi->mi_io_kstats);
1346 1347 mi->mi_io_kstats = NULL;
1347 1348 }
1348 1349 if (mi->mi_ro_kstats) {
1349 1350 kstat_delete(mi->mi_ro_kstats);
1350 1351 mi->mi_ro_kstats = NULL;
1351 1352 }
1352 1353 nfs_free_mi(mi);
1353 1354 *rtvpp = NULL;
1354 1355 return (error);
1355 1356 }
1356 1357
1357 1358 /*
1358 1359 * vfs operations
1359 1360 */
1360 1361 static int
1361 1362 nfs3_unmount(vfs_t *vfsp, int flag, cred_t *cr)
1362 1363 {
1363 1364 mntinfo_t *mi;
1364 1365 ushort_t omax;
1365 1366
1366 1367 if (secpolicy_fs_unmount(cr, vfsp) != 0)
1367 1368 return (EPERM);
1368 1369
1369 1370 mi = VFTOMI(vfsp);
1370 1371 if (flag & MS_FORCE) {
1371 1372
1372 1373 vfsp->vfs_flag |= VFS_UNMOUNTED;
1373 1374
1374 1375 /*
1375 1376 * We are about to stop the async manager.
1376 1377 * Let every one know not to schedule any
1377 1378 * more async requests
1378 1379 */
1379 1380 mutex_enter(&mi->mi_async_lock);
1380 1381 mi->mi_max_threads = 0;
1381 1382 NFS_WAKEALL_ASYNC_WORKERS(mi->mi_async_work_cv);
1382 1383 mutex_exit(&mi->mi_async_lock);
1383 1384
1384 1385 /*
1385 1386 * We need to stop the manager thread explicitly; the worker
1386 1387 * threads can time out and exit on their own.
1387 1388 */
1388 1389 nfs_async_manager_stop(vfsp);
1389 1390 destroy_rtable(vfsp, cr);
1390 1391 if (mi->mi_io_kstats) {
1391 1392 kstat_delete(mi->mi_io_kstats);
1392 1393 mi->mi_io_kstats = NULL;
1393 1394 }
1394 1395 if (mi->mi_ro_kstats) {
1395 1396 kstat_delete(mi->mi_ro_kstats);
1396 1397 mi->mi_ro_kstats = NULL;
1397 1398 }
1398 1399 return (0);
1399 1400 }
1400 1401 /*
1401 1402 * Wait until all asynchronous putpage operations on
1402 1403 * this file system are complete before flushing rnodes
1403 1404 * from the cache.
1404 1405 */
1405 1406 omax = mi->mi_max_threads;
1406 1407 if (nfs_async_stop_sig(vfsp)) {
1407 1408 return (EINTR);
1408 1409 }
1409 1410 rflush(vfsp, cr);
1410 1411 /*
1411 1412 * If there are any active vnodes on this file system,
1412 1413 * then the file system is busy and can't be umounted.
1413 1414 */
1414 1415 if (check_rtable(vfsp)) {
1415 1416 mutex_enter(&mi->mi_async_lock);
1416 1417 mi->mi_max_threads = omax;
1417 1418 mutex_exit(&mi->mi_async_lock);
1418 1419 return (EBUSY);
1419 1420 }
1420 1421 /*
1421 1422 * The unmount can't fail from now on; stop the worker thread manager.
1422 1423 */
1423 1424 nfs_async_manager_stop(vfsp);
1424 1425 /*
1425 1426 * Destroy all rnodes belonging to this file system from the
1426 1427 * rnode hash queues and purge any resources allocated to
1427 1428 * them.
1428 1429 */
1429 1430 destroy_rtable(vfsp, cr);
1430 1431 if (mi->mi_io_kstats) {
1431 1432 kstat_delete(mi->mi_io_kstats);
1432 1433 mi->mi_io_kstats = NULL;
1433 1434 }
1434 1435 if (mi->mi_ro_kstats) {
1435 1436 kstat_delete(mi->mi_ro_kstats);
1436 1437 mi->mi_ro_kstats = NULL;
1437 1438 }
1438 1439 return (0);
1439 1440 }
1440 1441
1441 1442 /*
1442 1443 * find root of nfs
1443 1444 */
1444 1445 static int
1445 1446 nfs3_root(vfs_t *vfsp, vnode_t **vpp)
1446 1447 {
1447 1448 mntinfo_t *mi;
1448 1449 vnode_t *vp;
1449 1450 servinfo_t *svp;
1450 1451 rnode_t *rp;
1451 1452 int error = 0;
1452 1453
1453 1454 mi = VFTOMI(vfsp);
1454 1455
1455 1456 if (nfs_zone() != mi->mi_zone)
1456 1457 return (EPERM);
1457 1458
1458 1459 svp = mi->mi_curr_serv;
1459 1460 if (svp && (svp->sv_flags & SV_ROOT_STALE)) {
1460 1461 mutex_enter(&svp->sv_lock);
1461 1462 svp->sv_flags &= ~SV_ROOT_STALE;
1462 1463 mutex_exit(&svp->sv_lock);
1463 1464 error = ENOENT;
1464 1465 }
1465 1466
1466 1467 vp = makenfs3node((nfs_fh3 *)&mi->mi_curr_serv->sv_fhandle,
1467 1468 NULL, vfsp, gethrtime(), CRED(), NULL, NULL);
1468 1469
1469 1470 /*
1470 1471 * if the SV_ROOT_STALE flag was reset above, reset the
1471 1472 * RSTALE flag if needed and return an error
1472 1473 */
1473 1474 if (error == ENOENT) {
1474 1475 rp = VTOR(vp);
1475 1476 if (svp && rp->r_flags & RSTALE) {
1476 1477 mutex_enter(&rp->r_statelock);
1477 1478 rp->r_flags &= ~RSTALE;
1478 1479 mutex_exit(&rp->r_statelock);
1479 1480 }
1480 1481 VN_RELE(vp);
1481 1482 return (error);
1482 1483 }
1483 1484
1484 1485 ASSERT(vp->v_type == VNON || vp->v_type == mi->mi_type);
1485 1486
1486 1487 vp->v_type = mi->mi_type;
1487 1488
1488 1489 *vpp = vp;
1489 1490
1490 1491 return (0);
1491 1492 }
1492 1493
1493 1494 /*
1494 1495 * Get file system statistics.
1495 1496 */
1496 1497 static int
1497 1498 nfs3_statvfs(vfs_t *vfsp, struct statvfs64 *sbp)
1498 1499 {
1499 1500 int error;
1500 1501 struct mntinfo *mi;
1501 1502 struct FSSTAT3args args;
1502 1503 struct FSSTAT3res res;
1503 1504 int douprintf;
1504 1505 failinfo_t fi;
1505 1506 vnode_t *vp;
1506 1507 cred_t *cr;
1507 1508 hrtime_t t;
1508 1509
1509 1510 mi = VFTOMI(vfsp);
1510 1511 if (nfs_zone() != mi->mi_zone)
1511 1512 return (EPERM);
1512 1513 error = nfs3_root(vfsp, &vp);
1513 1514 if (error)
1514 1515 return (error);
1515 1516
1516 1517 cr = CRED();
1517 1518
1518 1519 args.fsroot = *VTOFH3(vp);
1519 1520 fi.vp = vp;
1520 1521 fi.fhp = (caddr_t)&args.fsroot;
1521 1522 fi.copyproc = nfs3copyfh;
1522 1523 fi.lookupproc = nfs3lookup;
1523 1524 fi.xattrdirproc = acl_getxattrdir3;
1524 1525
1525 1526 douprintf = 1;
1526 1527
1527 1528 t = gethrtime();
1528 1529
1529 1530 error = rfs3call(mi, NFSPROC3_FSSTAT,
1530 1531 xdr_nfs_fh3, (caddr_t)&args,
1531 1532 xdr_FSSTAT3res, (caddr_t)&res, cr,
1532 1533 &douprintf, &res.status, 0, &fi);
1533 1534
1534 1535 if (error) {
1535 1536 VN_RELE(vp);
1536 1537 return (error);
1537 1538 }
1538 1539
1539 1540 error = geterrno3(res.status);
1540 1541 if (!error) {
1541 1542 nfs3_cache_post_op_attr(vp, &res.resok.obj_attributes, t, cr);
1542 1543 sbp->f_bsize = MAXBSIZE;
1543 1544 sbp->f_frsize = DEV_BSIZE;
1544 1545 /*
1545 1546 * Allow -1 fields to pass through unconverted. These
1546 1547 * indicate "don't know" fields.
1547 1548 */
1548 1549 if (res.resok.tbytes == (size3)-1)
1549 1550 sbp->f_blocks = (fsblkcnt64_t)res.resok.tbytes;
1550 1551 else {
1551 1552 sbp->f_blocks = (fsblkcnt64_t)
1552 1553 (res.resok.tbytes / DEV_BSIZE);
1553 1554 }
1554 1555 if (res.resok.fbytes == (size3)-1)
1555 1556 sbp->f_bfree = (fsblkcnt64_t)res.resok.fbytes;
1556 1557 else {
1557 1558 sbp->f_bfree = (fsblkcnt64_t)
1558 1559 (res.resok.fbytes / DEV_BSIZE);
1559 1560 }
1560 1561 if (res.resok.abytes == (size3)-1)
1561 1562 sbp->f_bavail = (fsblkcnt64_t)res.resok.abytes;
1562 1563 else {
1563 1564 sbp->f_bavail = (fsblkcnt64_t)
1564 1565 (res.resok.abytes / DEV_BSIZE);
1565 1566 }
1566 1567 sbp->f_files = (fsfilcnt64_t)res.resok.tfiles;
1567 1568 sbp->f_ffree = (fsfilcnt64_t)res.resok.ffiles;
1568 1569 sbp->f_favail = (fsfilcnt64_t)res.resok.afiles;
1569 1570 sbp->f_fsid = (unsigned long)vfsp->vfs_fsid.val[0];
1570 1571 (void) strncpy(sbp->f_basetype,
1571 1572 vfssw[vfsp->vfs_fstype].vsw_name, FSTYPSZ);
1572 1573 sbp->f_flag = vf_to_stf(vfsp->vfs_flag);
1573 1574 sbp->f_namemax = (ulong_t)-1;
1574 1575 } else {
1575 1576 nfs3_cache_post_op_attr(vp, &res.resfail.obj_attributes, t, cr);
1576 1577 PURGE_STALE_FH(error, vp, cr);
1577 1578 }
1578 1579
1579 1580 VN_RELE(vp);
1580 1581
1581 1582 return (error);
1582 1583 }
1583 1584
1584 1585 static kmutex_t nfs3_syncbusy;
1585 1586
1586 1587 /*
1587 1588 * Flush dirty nfs files for file system vfsp.
1588 1589 * If vfsp == NULL, all nfs files are flushed.
1589 1590 */
1590 1591 /* ARGSUSED */
1591 1592 static int
1592 1593 nfs3_sync(vfs_t *vfsp, short flag, cred_t *cr)
1593 1594 {
1594 1595 /*
1595 1596 * Cross-zone calls are OK here, since this translates to a
1596 1597 * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone.
1597 1598 */
1598 1599 if (!(flag & SYNC_ATTR) && mutex_tryenter(&nfs3_syncbusy) != 0) {
1599 1600 rflush(vfsp, cr);
1600 1601 mutex_exit(&nfs3_syncbusy);
1601 1602 }
1602 1603 return (0);
1603 1604 }
1604 1605
1605 1606 /* ARGSUSED */
1606 1607 static int
1607 1608 nfs3_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
1608 1609 {
1609 1610 int error;
1610 1611 nfs_fh3 fh;
1611 1612 vnode_t *vp;
1612 1613 struct vattr va;
1613 1614
1614 1615 if (fidp->fid_len > NFS3_FHSIZE) {
1615 1616 *vpp = NULL;
1616 1617 return (ESTALE);
1617 1618 }
1618 1619
1619 1620 if (nfs_zone() != VFTOMI(vfsp)->mi_zone)
1620 1621 return (EPERM);
1621 1622 fh.fh3_length = fidp->fid_len;
1622 1623 bcopy(fidp->fid_data, fh.fh3_u.data, fh.fh3_length);
1623 1624
1624 1625 vp = makenfs3node(&fh, NULL, vfsp, gethrtime(), CRED(), NULL, NULL);
1625 1626
1626 1627 if (VTOR(vp)->r_flags & RSTALE) {
1627 1628 VN_RELE(vp);
1628 1629 *vpp = NULL;
1629 1630 return (ENOENT);
1630 1631 }
1631 1632
1632 1633 if (vp->v_type == VNON) {
1633 1634 va.va_mask = AT_ALL;
1634 1635 error = nfs3getattr(vp, &va, CRED());
1635 1636 if (error) {
1636 1637 VN_RELE(vp);
1637 1638 *vpp = NULL;
1638 1639 return (error);
1639 1640 }
1640 1641 vp->v_type = va.va_type;
1641 1642 }
1642 1643
1643 1644 *vpp = vp;
1644 1645
1645 1646 return (0);
1646 1647 }
1647 1648
1648 1649 /* ARGSUSED */
1649 1650 static int
1650 1651 nfs3_mountroot(vfs_t *vfsp, whymountroot_t why)
1651 1652 {
1652 1653 vnode_t *rtvp;
1653 1654 char root_hostname[SYS_NMLN+1];
1654 1655 struct servinfo *svp;
1655 1656 int error;
1656 1657 int vfsflags;
1657 1658 size_t size;
1658 1659 char *root_path;
1659 1660 struct pathname pn;
1660 1661 char *name;
1661 1662 cred_t *cr;
1662 1663 struct nfs_args args; /* nfs mount arguments */
1663 1664 static char token[10];
1664 1665
1665 1666 bzero(&args, sizeof (args));
1666 1667
1667 1668 /* do this BEFORE getfile which causes xid stamps to be initialized */
1668 1669 clkset(-1L); /* hack for now - until we get time svc? */
1669 1670
1670 1671 if (why == ROOT_REMOUNT) {
1671 1672 /*
1672 1673 * Shouldn't happen.
1673 1674 */
1674 1675 panic("nfs3_mountroot: why == ROOT_REMOUNT");
1675 1676 }
1676 1677
1677 1678 if (why == ROOT_UNMOUNT) {
1678 1679 /*
1679 1680 * Nothing to do for NFS.
1680 1681 */
1681 1682 return (0);
1682 1683 }
1683 1684
1684 1685 /*
1685 1686 * why == ROOT_INIT
1686 1687 */
1687 1688
1688 1689 name = token;
1689 1690 *name = 0;
1690 1691 getfsname("root", name, sizeof (token));
1691 1692
1692 1693 pn_alloc(&pn);
1693 1694 root_path = pn.pn_path;
1694 1695
1695 1696 svp = kmem_zalloc(sizeof (*svp), KM_SLEEP);
1696 1697 svp->sv_knconf = kmem_zalloc(sizeof (*svp->sv_knconf), KM_SLEEP);
1697 1698 svp->sv_knconf->knc_protofmly = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
1698 1699 svp->sv_knconf->knc_proto = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
1699 1700
1700 1701 /*
1701 1702 * Get server address
1702 1703 * Get the root fhandle
1703 1704 * Get server's transport
1704 1705 * Get server's hostname
1705 1706 * Get options
1706 1707 */
1707 1708 args.addr = &svp->sv_addr;
1708 1709 args.fh = (char *)&svp->sv_fhandle;
1709 1710 args.knconf = svp->sv_knconf;
1710 1711 args.hostname = root_hostname;
1711 1712 vfsflags = 0;
1712 1713 if (error = mount_root(*name ? name : "root", root_path, NFS_V3,
1713 1714 &args, &vfsflags)) {
1714 1715 if (error == EPROTONOSUPPORT)
1715 1716 nfs_cmn_err(error, CE_WARN, "nfs3_mountroot: "
1716 1717 "mount_root failed: server doesn't support NFS V3");
1717 1718 else
1718 1719 nfs_cmn_err(error, CE_WARN,
1719 1720 "nfs3_mountroot: mount_root failed: %m");
1720 1721 sv_free(svp);
1721 1722 pn_free(&pn);
1722 1723 return (error);
1723 1724 }
1724 1725 svp->sv_hostnamelen = (int)(strlen(root_hostname) + 1);
1725 1726 svp->sv_hostname = kmem_alloc(svp->sv_hostnamelen, KM_SLEEP);
1726 1727 (void) strcpy(svp->sv_hostname, root_hostname);
1727 1728
1728 1729 /*
1729 1730 * Force root partition to always be mounted with AUTH_UNIX for now
1730 1731 */
1731 1732 svp->sv_secdata = kmem_alloc(sizeof (*svp->sv_secdata), KM_SLEEP);
1732 1733 svp->sv_secdata->secmod = AUTH_UNIX;
1733 1734 svp->sv_secdata->rpcflavor = AUTH_UNIX;
1734 1735 svp->sv_secdata->data = NULL;
1735 1736
1736 1737 cr = crgetcred();
1737 1738 rtvp = NULL;
1738 1739
1739 1740 error = nfs3rootvp(&rtvp, vfsp, svp, args.flags, cr, global_zone);
1740 1741
1741 1742 crfree(cr);
1742 1743
1743 1744 if (error) {
1744 1745 pn_free(&pn);
1745 1746 sv_free(svp);
1746 1747 return (error);
1747 1748 }
1748 1749
1749 1750 error = nfs_setopts(rtvp, DATAMODEL_NATIVE, &args);
1750 1751 if (error) {
1751 1752 nfs_cmn_err(error, CE_WARN,
1752 1753 "nfs3_mountroot: invalid root mount options");
1753 1754 pn_free(&pn);
1754 1755 goto errout;
1755 1756 }
1756 1757
1757 1758 (void) vfs_lock_wait(vfsp);
1758 1759 vfs_add(NULL, vfsp, vfsflags);
1759 1760 vfs_unlock(vfsp);
1760 1761
1761 1762 size = strlen(svp->sv_hostname);
1762 1763 (void) strcpy(rootfs.bo_name, svp->sv_hostname);
1763 1764 rootfs.bo_name[size] = ':';
1764 1765 (void) strcpy(&rootfs.bo_name[size + 1], root_path);
1765 1766
1766 1767 pn_free(&pn);
1767 1768
1768 1769 errout:
1769 1770 if (error) {
1770 1771 sv_free(svp);
1771 1772 nfs_async_stop(vfsp);
1772 1773 nfs_async_manager_stop(vfsp);
1773 1774 }
1774 1775
1775 1776 if (rtvp != NULL)
1776 1777 VN_RELE(rtvp);
1777 1778
1778 1779 return (error);
1779 1780 }
1780 1781
1781 1782 /*
1782 1783 * Initialization routine for VFS routines. Should only be called once
1783 1784 */
1784 1785 int
1785 1786 nfs3_vfsinit(void)
1786 1787 {
1787 1788 mutex_init(&nfs3_syncbusy, NULL, MUTEX_DEFAULT, NULL);
1788 1789 return (0);
1789 1790 }
1790 1791
1791 1792 void
1792 1793 nfs3_vfsfini(void)
1793 1794 {
1794 1795 mutex_destroy(&nfs3_syncbusy);
1795 1796 }
1796 1797
1797 1798 void
1798 1799 nfs3_freevfs(vfs_t *vfsp)
1799 1800 {
1800 1801 mntinfo_t *mi;
1801 1802 servinfo_t *svp;
1802 1803
1803 1804 /* free up the resources */
1804 1805 mi = VFTOMI(vfsp);
1805 1806 svp = mi->mi_servers;
1806 1807 mi->mi_servers = mi->mi_curr_serv = NULL;
1807 1808 sv_free(svp);
1808 1809
1809 1810 /*
1810 1811 * By this time we should have already deleted the
1811 1812 * mi kstats in the unmount code. If they are still around
1812 1813 * somethings wrong
1813 1814 */
1814 1815 ASSERT(mi->mi_io_kstats == NULL);
1815 1816 nfs_free_mi(mi);
1816 1817 }
|
↓ open down ↓ |
799 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX