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