Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/autofs/auto_vnops.c
+++ new/usr/src/uts/common/fs/autofs/auto_vnops.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) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 #include <sys/param.h>
26 26 #include <sys/systm.h>
27 27 #include <sys/errno.h>
28 28 #include <sys/proc.h>
29 29 #include <sys/vnode.h>
30 30 #include <sys/vfs.h>
31 31 #include <sys/vfs_opreg.h>
32 32 #include <sys/uio.h>
33 33 #include <sys/cred.h>
34 34 #include <sys/pathname.h>
35 35 #include <sys/dirent.h>
36 36 #include <sys/debug.h>
37 37 #include <sys/sysmacros.h>
38 38 #include <sys/tiuser.h>
39 39 #include <sys/cmn_err.h>
40 40 #include <sys/stat.h>
41 41 #include <sys/mode.h>
42 42 #include <sys/policy.h>
43 43 #include <rpc/types.h>
44 44 #include <rpc/auth.h>
45 45 #include <rpc/clnt.h>
46 46 #include <sys/fs/autofs.h>
47 47 #include <rpcsvc/autofs_prot.h>
48 48 #include <fs/fs_subr.h>
49 49
50 50 /*
51 51 * Vnode ops for autofs
52 52 */
53 53 static int auto_open(vnode_t **, int, cred_t *, caller_context_t *);
54 54 static int auto_close(vnode_t *, int, int, offset_t, cred_t *,
55 55 caller_context_t *);
56 56 static int auto_getattr(vnode_t *, vattr_t *, int, cred_t *,
57 57 caller_context_t *);
58 58 static int auto_setattr(vnode_t *, vattr_t *, int, cred_t *,
59 59 caller_context_t *);
60 60 static int auto_access(vnode_t *, int, int, cred_t *, caller_context_t *);
61 61 static int auto_lookup(vnode_t *, char *, vnode_t **,
62 62 pathname_t *, int, vnode_t *, cred_t *, caller_context_t *, int *,
63 63 pathname_t *);
64 64 static int auto_create(vnode_t *, char *, vattr_t *, vcexcl_t,
65 65 int, vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *);
66 66 static int auto_remove(vnode_t *, char *, cred_t *, caller_context_t *, int);
67 67 static int auto_link(vnode_t *, vnode_t *, char *, cred_t *,
68 68 caller_context_t *, int);
69 69 static int auto_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
70 70 caller_context_t *, int);
71 71 static int auto_mkdir(vnode_t *, char *, vattr_t *, vnode_t **, cred_t *,
72 72 caller_context_t *, int, vsecattr_t *);
73 73 static int auto_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
74 74 caller_context_t *, int);
75 75 static int auto_readdir(vnode_t *, uio_t *, cred_t *, int *,
76 76 caller_context_t *, int);
77 77 static int auto_symlink(vnode_t *, char *, vattr_t *, char *, cred_t *,
78 78 caller_context_t *, int);
79 79 static int auto_readlink(vnode_t *, struct uio *, cred_t *,
80 80 caller_context_t *);
81 81 static int auto_fsync(vnode_t *, int, cred_t *, caller_context_t *);
↓ open down ↓ |
81 lines elided |
↑ open up ↑ |
82 82 static void auto_inactive(vnode_t *, cred_t *, caller_context_t *);
83 83 static int auto_rwlock(vnode_t *, int, caller_context_t *);
84 84 static void auto_rwunlock(vnode_t *vp, int, caller_context_t *);
85 85 static int auto_seek(vnode_t *vp, offset_t, offset_t *, caller_context_t *);
86 86
87 87 static int auto_trigger_mount(vnode_t *, cred_t *, vnode_t **);
88 88
89 89 vnodeops_t *auto_vnodeops;
90 90
91 91 const fs_operation_def_t auto_vnodeops_template[] = {
92 - VOPNAME_OPEN, { .vop_open = auto_open },
93 - VOPNAME_CLOSE, { .vop_close = auto_close },
94 - VOPNAME_GETATTR, { .vop_getattr = auto_getattr },
95 - VOPNAME_SETATTR, { .vop_setattr = auto_setattr },
96 - VOPNAME_ACCESS, { .vop_access = auto_access },
97 - VOPNAME_LOOKUP, { .vop_lookup = auto_lookup },
98 - VOPNAME_CREATE, { .vop_create = auto_create },
99 - VOPNAME_REMOVE, { .vop_remove = auto_remove },
100 - VOPNAME_LINK, { .vop_link = auto_link },
101 - VOPNAME_RENAME, { .vop_rename = auto_rename },
102 - VOPNAME_MKDIR, { .vop_mkdir = auto_mkdir },
103 - VOPNAME_RMDIR, { .vop_rmdir = auto_rmdir },
104 - VOPNAME_READDIR, { .vop_readdir = auto_readdir },
105 - VOPNAME_SYMLINK, { .vop_symlink = auto_symlink },
106 - VOPNAME_READLINK, { .vop_readlink = auto_readlink },
107 - VOPNAME_FSYNC, { .vop_fsync = auto_fsync },
108 - VOPNAME_INACTIVE, { .vop_inactive = auto_inactive },
109 - VOPNAME_RWLOCK, { .vop_rwlock = auto_rwlock },
110 - VOPNAME_RWUNLOCK, { .vop_rwunlock = auto_rwunlock },
111 - VOPNAME_SEEK, { .vop_seek = auto_seek },
112 - VOPNAME_FRLOCK, { .error = fs_error },
113 - VOPNAME_DISPOSE, { .error = fs_error },
114 - VOPNAME_SHRLOCK, { .error = fs_error },
115 - VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
116 - NULL, NULL
92 + { VOPNAME_OPEN, { .vop_open = auto_open } },
93 + { VOPNAME_CLOSE, { .vop_close = auto_close } },
94 + { VOPNAME_GETATTR, { .vop_getattr = auto_getattr } },
95 + { VOPNAME_SETATTR, { .vop_setattr = auto_setattr } },
96 + { VOPNAME_ACCESS, { .vop_access = auto_access } },
97 + { VOPNAME_LOOKUP, { .vop_lookup = auto_lookup } },
98 + { VOPNAME_CREATE, { .vop_create = auto_create } },
99 + { VOPNAME_REMOVE, { .vop_remove = auto_remove } },
100 + { VOPNAME_LINK, { .vop_link = auto_link } },
101 + { VOPNAME_RENAME, { .vop_rename = auto_rename } },
102 + { VOPNAME_MKDIR, { .vop_mkdir = auto_mkdir } },
103 + { VOPNAME_RMDIR, { .vop_rmdir = auto_rmdir } },
104 + { VOPNAME_READDIR, { .vop_readdir = auto_readdir } },
105 + { VOPNAME_SYMLINK, { .vop_symlink = auto_symlink } },
106 + { VOPNAME_READLINK, { .vop_readlink = auto_readlink } },
107 + { VOPNAME_FSYNC, { .vop_fsync = auto_fsync } },
108 + { VOPNAME_INACTIVE, { .vop_inactive = auto_inactive } },
109 + { VOPNAME_RWLOCK, { .vop_rwlock = auto_rwlock } },
110 + { VOPNAME_RWUNLOCK, { .vop_rwunlock = auto_rwunlock } },
111 + { VOPNAME_SEEK, { .vop_seek = auto_seek } },
112 + { VOPNAME_FRLOCK, { .error = fs_error } },
113 + { VOPNAME_DISPOSE, { .error = fs_error } },
114 + { VOPNAME_SHRLOCK, { .error = fs_error } },
115 + { VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support } },
116 + { NULL, { NULL } }
117 117 };
118 118
119 119
120 120
121 121 /* ARGSUSED */
122 122 static int
123 123 auto_open(vnode_t **vpp, int flag, cred_t *cred, caller_context_t *ct)
124 124 {
125 125 vnode_t *newvp;
126 126 int error;
127 127
128 128 AUTOFS_DPRINT((4, "auto_open: *vpp=%p\n", (void *)*vpp));
129 129
130 130 error = auto_trigger_mount(*vpp, cred, &newvp);
131 131 if (error)
132 132 goto done;
133 133
134 134 if (newvp != NULL) {
135 135 /*
136 136 * Node is now mounted on.
137 137 */
138 138 VN_RELE(*vpp);
139 139 *vpp = newvp;
140 140 error = VOP_ACCESS(*vpp, VREAD, 0, cred, ct);
141 141 if (!error)
142 142 error = VOP_OPEN(vpp, flag, cred, ct);
143 143 }
144 144
145 145 done:
146 146 AUTOFS_DPRINT((5, "auto_open: *vpp=%p error=%d\n", (void *)*vpp,
147 147 error));
148 148 return (error);
149 149 }
150 150
151 151 /* ARGSUSED */
152 152 static int
153 153 auto_close(
154 154 vnode_t *vp,
155 155 int flag,
156 156 int count,
157 157 offset_t offset,
158 158 cred_t *cred,
159 159 caller_context_t *ct)
160 160 {
161 161 return (0);
162 162 }
163 163
164 164 static int
165 165 auto_getattr(
166 166 vnode_t *vp,
167 167 vattr_t *vap,
168 168 int flags,
169 169 cred_t *cred,
170 170 caller_context_t *ct)
171 171 {
172 172 fnnode_t *fnp = vntofn(vp);
173 173 vnode_t *newvp;
174 174 vfs_t *vfsp;
175 175 int error;
176 176
177 177 AUTOFS_DPRINT((4, "auto_getattr vp %p\n", (void *)vp));
178 178
179 179 if (flags & ATTR_TRIGGER) {
180 180 /*
181 181 * Pre-trigger the mount
182 182 */
183 183 error = auto_trigger_mount(vp, cred, &newvp);
184 184 if (error)
185 185 return (error);
186 186
187 187 if (newvp == NULL)
188 188 goto defattr;
189 189
190 190 if (error = vn_vfsrlock_wait(vp)) {
191 191 VN_RELE(newvp);
192 192 return (error);
193 193 }
194 194
195 195 vfsp = newvp->v_vfsp;
196 196 VN_RELE(newvp);
197 197 } else {
198 198 /*
199 199 * Recursive auto_getattr/mount; go to the vfsp == NULL
200 200 * case.
201 201 */
202 202 if (vn_vfswlock_held(vp))
203 203 goto defattr;
204 204
205 205 if (error = vn_vfsrlock_wait(vp))
206 206 return (error);
207 207
208 208 vfsp = vn_mountedvfs(vp);
209 209 }
210 210
211 211 if (vfsp != NULL) {
212 212 /*
213 213 * Node is mounted on.
214 214 */
215 215 error = VFS_ROOT(vfsp, &newvp);
216 216 vn_vfsunlock(vp);
217 217 if (error)
218 218 return (error);
219 219 mutex_enter(&fnp->fn_lock);
220 220 if (fnp->fn_seen == newvp && fnp->fn_thread == curthread) {
221 221 /*
222 222 * Recursive auto_getattr(); just release newvp and drop
223 223 * into the vfsp == NULL case.
224 224 */
225 225 mutex_exit(&fnp->fn_lock);
226 226 VN_RELE(newvp);
227 227 } else {
228 228 while (fnp->fn_thread && fnp->fn_thread != curthread) {
229 229 fnp->fn_flags |= MF_ATTR_WAIT;
230 230 cv_wait(&fnp->fn_cv_mount, &fnp->fn_lock);
231 231 }
232 232 fnp->fn_thread = curthread;
233 233 fnp->fn_seen = newvp;
234 234 mutex_exit(&fnp->fn_lock);
235 235 error = VOP_GETATTR(newvp, vap, flags, cred, ct);
236 236 VN_RELE(newvp);
237 237 mutex_enter(&fnp->fn_lock);
238 238 fnp->fn_seen = 0;
239 239 fnp->fn_thread = 0;
240 240 if (fnp->fn_flags & MF_ATTR_WAIT) {
241 241 fnp->fn_flags &= ~MF_ATTR_WAIT;
242 242 cv_broadcast(&fnp->fn_cv_mount);
243 243 }
244 244 mutex_exit(&fnp->fn_lock);
245 245 return (error);
246 246 }
247 247 } else {
248 248 vn_vfsunlock(vp);
249 249 }
250 250
251 251 defattr:
252 252 ASSERT(vp->v_type == VDIR || vp->v_type == VLNK);
253 253 vap->va_uid = 0;
254 254 vap->va_gid = 0;
255 255 vap->va_nlink = fnp->fn_linkcnt;
256 256 vap->va_nodeid = (u_longlong_t)fnp->fn_nodeid;
257 257 vap->va_size = fnp->fn_size;
258 258 vap->va_atime = fnp->fn_atime;
259 259 vap->va_mtime = fnp->fn_mtime;
260 260 vap->va_ctime = fnp->fn_ctime;
261 261 vap->va_type = vp->v_type;
262 262 vap->va_mode = fnp->fn_mode;
263 263 vap->va_fsid = vp->v_vfsp->vfs_dev;
264 264 vap->va_rdev = 0;
265 265 vap->va_blksize = MAXBSIZE;
266 266 vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
267 267 vap->va_seq = 0;
268 268
269 269 return (0);
270 270 }
271 271
272 272 /*ARGSUSED4*/
273 273 static int
274 274 auto_setattr(
275 275 vnode_t *vp,
276 276 struct vattr *vap,
277 277 int flags,
278 278 cred_t *cred,
279 279 caller_context_t *ct)
280 280 {
281 281 vnode_t *newvp;
282 282 int error;
283 283
284 284 AUTOFS_DPRINT((4, "auto_setattr vp %p\n", (void *)vp));
285 285
286 286 if (error = auto_trigger_mount(vp, cred, &newvp))
287 287 goto done;
288 288
289 289 if (newvp != NULL) {
290 290 /*
291 291 * Node is mounted on.
292 292 */
293 293 if (vn_is_readonly(newvp))
294 294 error = EROFS;
295 295 else
296 296 error = VOP_SETATTR(newvp, vap, flags, cred, ct);
297 297 VN_RELE(newvp);
298 298 } else
299 299 error = ENOSYS;
300 300
301 301 done:
302 302 AUTOFS_DPRINT((5, "auto_setattr: error=%d\n", error));
303 303 return (error);
304 304 }
305 305
306 306 /* ARGSUSED */
307 307 static int
308 308 auto_access(
309 309 vnode_t *vp,
310 310 int mode,
311 311 int flags,
312 312 cred_t *cred,
313 313 caller_context_t *ct)
314 314 {
315 315 fnnode_t *fnp = vntofn(vp);
316 316 vnode_t *newvp;
317 317 int error;
318 318
319 319 AUTOFS_DPRINT((4, "auto_access: vp=%p\n", (void *)vp));
320 320
321 321 if (error = auto_trigger_mount(vp, cred, &newvp))
322 322 goto done;
323 323
324 324 if (newvp != NULL) {
325 325 /*
326 326 * Node is mounted on.
327 327 */
328 328 error = VOP_ACCESS(newvp, mode, 0, cred, ct);
329 329 VN_RELE(newvp);
330 330 } else {
331 331 int shift = 0;
332 332
333 333 /*
334 334 * really interested in the autofs node, check the
335 335 * access on it
336 336 */
337 337 ASSERT(error == 0);
338 338 if (crgetuid(cred) != fnp->fn_uid) {
339 339 shift += 3;
340 340 if (groupmember(fnp->fn_gid, cred) == 0)
341 341 shift += 3;
342 342 }
343 343 error = secpolicy_vnode_access2(cred, vp, fnp->fn_uid,
344 344 fnp->fn_mode << shift, mode);
345 345 }
346 346
347 347 done:
348 348 AUTOFS_DPRINT((5, "auto_access: error=%d\n", error));
349 349 return (error);
350 350 }
351 351
352 352 static int
353 353 auto_lookup(
354 354 vnode_t *dvp,
355 355 char *nm,
356 356 vnode_t **vpp,
357 357 pathname_t *pnp,
358 358 int flags,
359 359 vnode_t *rdir,
360 360 cred_t *cred,
361 361 caller_context_t *ct,
362 362 int *direntflags,
363 363 pathname_t *realpnp)
364 364 {
365 365 int error = 0;
366 366 vnode_t *newvp = NULL;
367 367 vfs_t *vfsp;
368 368 fninfo_t *dfnip;
369 369 fnnode_t *dfnp = NULL;
370 370 fnnode_t *fnp = NULL;
371 371 char *searchnm;
372 372 int operation; /* either AUTOFS_LOOKUP or AUTOFS_MOUNT */
373 373
374 374 dfnip = vfstofni(dvp->v_vfsp);
375 375 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p (%s) name=%s\n",
376 376 (void *)dvp, dfnip->fi_map, nm));
377 377
378 378 if (nm[0] == 0) {
379 379 VN_HOLD(dvp);
380 380 *vpp = dvp;
381 381 return (0);
382 382 }
383 383
384 384 if (error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct))
385 385 return (error);
386 386
387 387 if (nm[0] == '.' && nm[1] == 0) {
388 388 VN_HOLD(dvp);
389 389 *vpp = dvp;
390 390 return (0);
391 391 }
392 392
393 393 if (nm[0] == '.' && nm[1] == '.' && nm[2] == 0) {
394 394 fnnode_t *pdfnp;
395 395
396 396 pdfnp = (vntofn(dvp))->fn_parent;
397 397 ASSERT(pdfnp != NULL);
398 398
399 399 /*
400 400 * Since it is legitimate to have the VROOT flag set for the
401 401 * subdirectories of the indirect map in autofs filesystem,
402 402 * rootfnnodep is checked against fnnode of dvp instead of
403 403 * just checking whether VROOT flag is set in dvp
404 404 */
405 405
406 406 if (pdfnp == pdfnp->fn_globals->fng_rootfnnodep) {
407 407 vnode_t *vp;
408 408
409 409 vfs_rlock_wait(dvp->v_vfsp);
410 410 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
411 411 vfs_unlock(dvp->v_vfsp);
412 412 return (EIO);
413 413 }
414 414 vp = dvp->v_vfsp->vfs_vnodecovered;
415 415 VN_HOLD(vp);
416 416 vfs_unlock(dvp->v_vfsp);
417 417 error = VOP_LOOKUP(vp, nm, vpp, pnp, flags, rdir, cred,
418 418 ct, direntflags, realpnp);
419 419 VN_RELE(vp);
420 420 return (error);
421 421 } else {
422 422 *vpp = fntovn(pdfnp);
423 423 VN_HOLD(*vpp);
424 424 return (0);
425 425 }
426 426 }
427 427
428 428 top:
429 429 dfnp = vntofn(dvp);
430 430 searchnm = nm;
431 431 operation = 0;
432 432
433 433 ASSERT(vn_matchops(dvp, auto_vnodeops));
434 434
435 435 AUTOFS_DPRINT((3, "auto_lookup: dvp=%p dfnp=%p\n", (void *)dvp,
436 436 (void *)dfnp));
437 437
438 438 /*
439 439 * If a lookup or mount of this node is in progress, wait for it
440 440 * to finish, and return whatever result it got.
441 441 */
442 442 mutex_enter(&dfnp->fn_lock);
443 443 if (dfnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
444 444 mutex_exit(&dfnp->fn_lock);
445 445 error = auto_wait4mount(dfnp);
446 446 if (error == AUTOFS_SHUTDOWN)
447 447 error = ENOENT;
448 448 if (error == EAGAIN)
449 449 goto top;
450 450 if (error)
451 451 return (error);
452 452 } else
453 453 mutex_exit(&dfnp->fn_lock);
454 454
455 455
456 456 error = vn_vfsrlock_wait(dvp);
457 457 if (error)
458 458 return (error);
459 459 vfsp = vn_mountedvfs(dvp);
460 460 if (vfsp != NULL) {
461 461 error = VFS_ROOT(vfsp, &newvp);
462 462 vn_vfsunlock(dvp);
463 463 if (!error) {
464 464 error = VOP_LOOKUP(newvp, nm, vpp, pnp,
465 465 flags, rdir, cred, ct, direntflags, realpnp);
466 466 VN_RELE(newvp);
467 467 }
468 468 return (error);
469 469 }
470 470 vn_vfsunlock(dvp);
471 471
472 472 rw_enter(&dfnp->fn_rwlock, RW_READER);
473 473 error = auto_search(dfnp, nm, &fnp, cred);
474 474 if (error) {
475 475 if (dfnip->fi_flags & MF_DIRECT) {
476 476 /*
477 477 * direct map.
478 478 */
479 479 if (dfnp->fn_dirents) {
480 480 /*
481 481 * Mount previously triggered.
482 482 * 'nm' not found
483 483 */
484 484 error = ENOENT;
485 485 } else {
486 486 /*
487 487 * I need to contact the daemon to trigger
488 488 * the mount. 'dfnp' will be the mountpoint.
489 489 */
490 490 operation = AUTOFS_MOUNT;
491 491 VN_HOLD(fntovn(dfnp));
492 492 fnp = dfnp;
493 493 error = 0;
494 494 }
495 495 } else if (dvp == dfnip->fi_rootvp) {
496 496 /*
497 497 * 'dfnp' is the root of the indirect AUTOFS.
498 498 */
499 499 if (rw_tryupgrade(&dfnp->fn_rwlock) == 0) {
500 500 /*
501 501 * Could not acquire writer lock, release
502 502 * reader, and wait until available. We
503 503 * need to search for 'nm' again, since we
504 504 * had to release the lock before reacquiring
505 505 * it.
506 506 */
507 507 rw_exit(&dfnp->fn_rwlock);
508 508 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
509 509 error = auto_search(dfnp, nm, &fnp, cred);
510 510 }
511 511
512 512 ASSERT(RW_WRITE_HELD(&dfnp->fn_rwlock));
513 513 if (error) {
514 514 /*
515 515 * create node being looked-up and request
516 516 * mount on it.
517 517 */
518 518 error = auto_enter(dfnp, nm, &fnp, kcred);
519 519 if (!error)
520 520 operation = AUTOFS_LOOKUP;
521 521 }
522 522 } else if ((dfnp->fn_dirents == NULL) &&
523 523 ((dvp->v_flag & VROOT) == 0) &&
524 524 ((fntovn(dfnp->fn_parent))->v_flag & VROOT)) {
525 525 /*
526 526 * dfnp is the actual 'mountpoint' of indirect map,
527 527 * it is the equivalent of a direct mount,
528 528 * ie, /home/'user1'
529 529 */
530 530 operation = AUTOFS_MOUNT;
531 531 VN_HOLD(fntovn(dfnp));
532 532 fnp = dfnp;
533 533 error = 0;
534 534 searchnm = dfnp->fn_name;
535 535 }
536 536 }
537 537
538 538 if (error == EAGAIN) {
539 539 rw_exit(&dfnp->fn_rwlock);
540 540 goto top;
541 541 }
542 542 if (error) {
543 543 rw_exit(&dfnp->fn_rwlock);
544 544 return (error);
545 545 }
546 546
547 547 /*
548 548 * We now have the actual fnnode we're interested in.
549 549 * The 'MF_LOOKUP' indicates another thread is currently
550 550 * performing a daemon lookup of this node, therefore we
551 551 * wait for its completion.
552 552 * The 'MF_INPROG' indicates another thread is currently
553 553 * performing a daemon mount of this node, we wait for it
554 554 * to be done if we are performing a MOUNT. We don't
555 555 * wait for it if we are performing a LOOKUP.
556 556 * We can release the reader/writer lock as soon as we acquire
557 557 * the mutex, since the state of the lock can only change by
558 558 * first acquiring the mutex.
559 559 */
560 560 mutex_enter(&fnp->fn_lock);
561 561 rw_exit(&dfnp->fn_rwlock);
562 562 if ((fnp->fn_flags & MF_LOOKUP) ||
563 563 ((operation == AUTOFS_MOUNT) && (fnp->fn_flags & MF_INPROG))) {
564 564 mutex_exit(&fnp->fn_lock);
565 565 error = auto_wait4mount(fnp);
566 566 VN_RELE(fntovn(fnp));
567 567 if (error == AUTOFS_SHUTDOWN)
568 568 error = ENOENT;
569 569 if (error && error != EAGAIN)
570 570 return (error);
571 571 goto top;
572 572 }
573 573
574 574 if (operation == 0) {
575 575 /*
576 576 * got the fnnode, check for any errors
577 577 * on the previous operation on that node.
578 578 */
579 579 error = fnp->fn_error;
580 580 if ((error == EINTR) || (error == EAGAIN)) {
581 581 /*
582 582 * previous operation on this node was
583 583 * not completed, do a lookup now.
584 584 */
585 585 operation = AUTOFS_LOOKUP;
586 586 } else {
587 587 /*
588 588 * previous operation completed. Return
589 589 * a pointer to the node only if there was
590 590 * no error.
591 591 */
592 592 mutex_exit(&fnp->fn_lock);
593 593 if (!error)
594 594 *vpp = fntovn(fnp);
595 595 else
596 596 VN_RELE(fntovn(fnp));
597 597 return (error);
598 598 }
599 599 }
600 600
601 601 /*
602 602 * Since I got to this point, it means I'm the one
603 603 * responsible for triggering the mount/look-up of this node.
604 604 */
605 605 switch (operation) {
606 606 case AUTOFS_LOOKUP:
607 607 AUTOFS_BLOCK_OTHERS(fnp, MF_LOOKUP);
608 608 fnp->fn_error = 0;
609 609 mutex_exit(&fnp->fn_lock);
610 610 error = auto_lookup_aux(fnp, searchnm, cred);
611 611 if (!error) {
612 612 /*
613 613 * Return this vnode
614 614 */
615 615 *vpp = fntovn(fnp);
616 616 } else {
617 617 /*
618 618 * release our reference to this vnode
619 619 * and return error
620 620 */
621 621 VN_RELE(fntovn(fnp));
622 622 }
623 623 break;
624 624 case AUTOFS_MOUNT:
625 625 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
626 626 fnp->fn_error = 0;
627 627 mutex_exit(&fnp->fn_lock);
628 628 /*
629 629 * auto_new_mount_thread fires up a new thread which
630 630 * calls automountd finishing up the work
631 631 */
632 632 auto_new_mount_thread(fnp, searchnm, cred);
633 633
634 634 /*
635 635 * At this point, we are simply another thread
636 636 * waiting for the mount to complete
637 637 */
638 638 error = auto_wait4mount(fnp);
639 639 if (error == AUTOFS_SHUTDOWN)
640 640 error = ENOENT;
641 641
642 642 /*
643 643 * now release our reference to this vnode
644 644 */
645 645 VN_RELE(fntovn(fnp));
646 646 if (!error)
647 647 goto top;
648 648 break;
649 649 default:
650 650 auto_log(dfnp->fn_globals->fng_verbose,
651 651 dfnp->fn_globals->fng_zoneid, CE_WARN,
652 652 "auto_lookup: unknown operation %d",
653 653 operation);
654 654 }
655 655
656 656 AUTOFS_DPRINT((5, "auto_lookup: name=%s *vpp=%p return=%d\n",
657 657 nm, (void *)*vpp, error));
658 658
659 659 return (error);
660 660 }
661 661
662 662 static int
663 663 auto_create(
664 664 vnode_t *dvp,
665 665 char *nm,
666 666 vattr_t *va,
667 667 vcexcl_t excl,
668 668 int mode,
669 669 vnode_t **vpp,
670 670 cred_t *cred,
671 671 int flag,
672 672 caller_context_t *ct,
673 673 vsecattr_t *vsecp)
674 674 {
675 675 vnode_t *newvp;
676 676 int error;
677 677
678 678 AUTOFS_DPRINT((4, "auto_create dvp %p nm %s\n", (void *)dvp, nm));
679 679
680 680 if (error = auto_trigger_mount(dvp, cred, &newvp))
681 681 goto done;
682 682
683 683 if (newvp != NULL) {
684 684 /*
685 685 * Node is now mounted on.
686 686 */
687 687 if (vn_is_readonly(newvp))
688 688 error = EROFS;
689 689 else
690 690 error = VOP_CREATE(newvp, nm, va, excl,
691 691 mode, vpp, cred, flag, ct, vsecp);
692 692 VN_RELE(newvp);
693 693 } else
694 694 error = ENOSYS;
695 695
696 696 done:
697 697 AUTOFS_DPRINT((5, "auto_create: error=%d\n", error));
698 698 return (error);
699 699 }
700 700
701 701 static int
702 702 auto_remove(
703 703 vnode_t *dvp,
704 704 char *nm,
705 705 cred_t *cred,
706 706 caller_context_t *ct,
707 707 int flags)
708 708 {
709 709 vnode_t *newvp;
710 710 int error;
711 711
712 712 AUTOFS_DPRINT((4, "auto_remove dvp %p nm %s\n", (void *)dvp, nm));
713 713
714 714 if (error = auto_trigger_mount(dvp, cred, &newvp))
715 715 goto done;
716 716
717 717 if (newvp != NULL) {
718 718 /*
719 719 * Node is now mounted on.
720 720 */
721 721 if (vn_is_readonly(newvp))
722 722 error = EROFS;
723 723 else
724 724 error = VOP_REMOVE(newvp, nm, cred, ct, flags);
725 725 VN_RELE(newvp);
726 726 } else
727 727 error = ENOSYS;
728 728
729 729 done:
730 730 AUTOFS_DPRINT((5, "auto_remove: error=%d\n", error));
731 731 return (error);
732 732 }
733 733
734 734 static int
735 735 auto_link(
736 736 vnode_t *tdvp,
737 737 vnode_t *svp,
738 738 char *nm,
739 739 cred_t *cred,
740 740 caller_context_t *ct,
741 741 int flags)
742 742 {
743 743 vnode_t *newvp;
744 744 int error;
745 745
746 746 AUTOFS_DPRINT((4, "auto_link tdvp %p svp %p nm %s\n", (void *)tdvp,
747 747 (void *)svp, nm));
748 748
749 749 if (error = auto_trigger_mount(tdvp, cred, &newvp))
750 750 goto done;
751 751
752 752 if (newvp == NULL) {
753 753 /*
754 754 * an autonode can not be a link to another node
755 755 */
756 756 error = ENOSYS;
757 757 goto done;
758 758 }
759 759
760 760 if (vn_is_readonly(newvp)) {
761 761 error = EROFS;
762 762 VN_RELE(newvp);
763 763 goto done;
764 764 }
765 765
766 766 if (vn_matchops(svp, auto_vnodeops)) {
767 767 /*
768 768 * source vp can't be an autonode
769 769 */
770 770 error = ENOSYS;
771 771 VN_RELE(newvp);
772 772 goto done;
773 773 }
774 774
775 775 error = VOP_LINK(newvp, svp, nm, cred, ct, flags);
776 776 VN_RELE(newvp);
777 777
778 778 done:
779 779 AUTOFS_DPRINT((5, "auto_link error=%d\n", error));
780 780 return (error);
781 781 }
782 782
783 783 static int
784 784 auto_rename(
785 785 vnode_t *odvp,
786 786 char *onm,
787 787 vnode_t *ndvp,
788 788 char *nnm,
789 789 cred_t *cr,
790 790 caller_context_t *ct,
791 791 int flags)
792 792 {
793 793 vnode_t *o_newvp, *n_newvp;
794 794 int error;
795 795
796 796 AUTOFS_DPRINT((4, "auto_rename odvp %p onm %s to ndvp %p nnm %s\n",
797 797 (void *)odvp, onm, (void *)ndvp, nnm));
798 798
799 799 /*
800 800 * we know odvp is an autonode, otherwise this function
801 801 * could not have ever been called.
802 802 */
803 803 ASSERT(vn_matchops(odvp, auto_vnodeops));
804 804
805 805 if (error = auto_trigger_mount(odvp, cr, &o_newvp))
806 806 goto done;
807 807
808 808 if (o_newvp == NULL) {
809 809 /*
810 810 * can't rename an autonode
811 811 */
812 812 error = ENOSYS;
813 813 goto done;
814 814 }
815 815
816 816 if (vn_matchops(ndvp, auto_vnodeops)) {
817 817 /*
818 818 * directory is AUTOFS, need to trigger the
819 819 * mount of the real filesystem.
820 820 */
821 821 if (error = auto_trigger_mount(ndvp, cr, &n_newvp)) {
822 822 VN_RELE(o_newvp);
823 823 goto done;
824 824 }
825 825
826 826 if (n_newvp == NULL) {
827 827 /*
828 828 * target can't be an autonode
829 829 */
830 830 error = ENOSYS;
831 831 VN_RELE(o_newvp);
832 832 goto done;
833 833 }
834 834 } else {
835 835 /*
836 836 * destination directory mount had been
837 837 * triggered prior to the call to this function.
838 838 */
839 839 n_newvp = ndvp;
840 840 }
841 841
842 842 ASSERT(!vn_matchops(n_newvp, auto_vnodeops));
843 843
844 844 if (vn_is_readonly(n_newvp)) {
845 845 error = EROFS;
846 846 VN_RELE(o_newvp);
847 847 if (n_newvp != ndvp)
848 848 VN_RELE(n_newvp);
849 849 goto done;
850 850 }
851 851
852 852 error = VOP_RENAME(o_newvp, onm, n_newvp, nnm, cr, ct, flags);
853 853 VN_RELE(o_newvp);
854 854 if (n_newvp != ndvp)
855 855 VN_RELE(n_newvp);
856 856
857 857 done:
858 858 AUTOFS_DPRINT((5, "auto_rename error=%d\n", error));
859 859 return (error);
860 860 }
861 861
862 862 static int
863 863 auto_mkdir(
864 864 vnode_t *dvp,
865 865 char *nm,
866 866 vattr_t *va,
867 867 vnode_t **vpp,
868 868 cred_t *cred,
869 869 caller_context_t *ct,
870 870 int flags,
871 871 vsecattr_t *vsecp)
872 872 {
873 873 vnode_t *newvp;
874 874 int error;
875 875
876 876 AUTOFS_DPRINT((4, "auto_mkdir dvp %p nm %s\n", (void *)dvp, nm));
877 877
878 878 if (error = auto_trigger_mount(dvp, cred, &newvp))
879 879 goto done;
880 880
881 881 if (newvp != NULL) {
882 882 /*
883 883 * Node is now mounted on.
884 884 */
885 885 if (vn_is_readonly(newvp))
886 886 error = EROFS;
887 887 else
888 888 error = VOP_MKDIR(newvp, nm, va, vpp, cred, ct,
889 889 flags, vsecp);
890 890 VN_RELE(newvp);
891 891 } else
892 892 error = ENOSYS;
893 893
894 894 done:
895 895 AUTOFS_DPRINT((5, "auto_mkdir: error=%d\n", error));
896 896 return (error);
897 897 }
898 898
899 899 static int
900 900 auto_rmdir(
901 901 vnode_t *dvp,
902 902 char *nm,
903 903 vnode_t *cdir,
904 904 cred_t *cred,
905 905 caller_context_t *ct,
906 906 int flags)
907 907 {
908 908 vnode_t *newvp;
909 909 int error;
910 910
911 911 AUTOFS_DPRINT((4, "auto_rmdir: vp=%p nm=%s\n", (void *)dvp, nm));
912 912
913 913 if (error = auto_trigger_mount(dvp, cred, &newvp))
914 914 goto done;
915 915
916 916 if (newvp != NULL) {
917 917 /*
918 918 * Node is now mounted on.
919 919 */
920 920 if (vn_is_readonly(newvp))
921 921 error = EROFS;
922 922 else
923 923 error = VOP_RMDIR(newvp, nm, cdir, cred, ct, flags);
924 924 VN_RELE(newvp);
925 925 } else
926 926 error = ENOSYS;
927 927
928 928 done:
929 929 AUTOFS_DPRINT((5, "auto_rmdir: error=%d\n", error));
930 930 return (error);
931 931 }
932 932
933 933 static int autofs_nobrowse = 0;
934 934
935 935 #ifdef nextdp
936 936 #undef nextdp
937 937 #endif
938 938 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
939 939
940 940 /* ARGSUSED */
941 941 static int
942 942 auto_readdir(
943 943 vnode_t *vp,
944 944 uio_t *uiop,
945 945 cred_t *cred,
946 946 int *eofp,
947 947 caller_context_t *ct,
948 948 int flags)
949 949 {
950 950 struct autofs_rddirargs rda;
951 951 autofs_rddirres rd;
952 952 fnnode_t *fnp = vntofn(vp);
953 953 fnnode_t *cfnp, *nfnp;
954 954 dirent64_t *dp;
955 955 ulong_t offset;
956 956 ulong_t outcount = 0, count = 0;
957 957 size_t namelen;
958 958 ulong_t alloc_count;
959 959 void *outbuf = NULL;
960 960 fninfo_t *fnip = vfstofni(vp->v_vfsp);
961 961 struct iovec *iovp;
962 962 int error = 0;
963 963 int reached_max = 0;
964 964 int myeof = 0;
965 965 int this_reclen;
966 966 struct autofs_globals *fngp = vntofn(fnip->fi_rootvp)->fn_globals;
967 967
968 968 AUTOFS_DPRINT((4, "auto_readdir vp=%p offset=%lld\n",
969 969 (void *)vp, uiop->uio_loffset));
970 970
971 971 if (eofp != NULL)
972 972 *eofp = 0;
973 973
974 974 if (uiop->uio_iovcnt != 1)
975 975 return (EINVAL);
976 976
977 977 iovp = uiop->uio_iov;
978 978 alloc_count = iovp->iov_len;
979 979
980 980 gethrestime(&fnp->fn_atime);
981 981 fnp->fn_ref_time = fnp->fn_atime.tv_sec;
982 982
983 983 dp = outbuf = kmem_zalloc(alloc_count, KM_SLEEP);
984 984
985 985 /*
986 986 * Held when getdents calls VOP_RWLOCK....
987 987 */
988 988 ASSERT(RW_READ_HELD(&fnp->fn_rwlock));
989 989 if (uiop->uio_offset >= AUTOFS_DAEMONCOOKIE) {
990 990 again:
991 991 /*
992 992 * Do readdir of daemon contents only
993 993 * Drop readers lock and reacquire after reply.
994 994 */
995 995 rw_exit(&fnp->fn_rwlock);
996 996 bzero(&rd, sizeof (struct autofs_rddirres));
997 997 count = 0;
998 998 rda.rda_map = fnip->fi_map;
999 999 rda.rda_offset = (uint_t)uiop->uio_offset;
1000 1000 rd.rd_rddir.rddir_entries = dp;
1001 1001 rda.rda_count = rd.rd_rddir.rddir_size = (uint_t)alloc_count;
1002 1002 rda.uid = crgetuid(cred);
1003 1003
1004 1004 error = auto_calldaemon(fngp->fng_zoneid,
1005 1005 AUTOFS_READDIR,
1006 1006 xdr_autofs_rddirargs,
1007 1007 &rda,
1008 1008 xdr_autofs_rddirres,
1009 1009 (void *)&rd,
1010 1010 sizeof (autofs_rddirres),
1011 1011 TRUE);
1012 1012
1013 1013 /*
1014 1014 * reacquire previously dropped lock
1015 1015 */
1016 1016 rw_enter(&fnp->fn_rwlock, RW_READER);
1017 1017
1018 1018 if (!error) {
1019 1019 error = rd.rd_status;
1020 1020 dp = rd.rd_rddir.rddir_entries;
1021 1021 }
1022 1022
1023 1023 if (error) {
1024 1024 if (error == AUTOFS_SHUTDOWN) {
1025 1025 /*
1026 1026 * treat as empty directory
1027 1027 */
1028 1028 error = 0;
1029 1029 myeof = 1;
1030 1030 if (eofp)
1031 1031 *eofp = 1;
1032 1032 }
1033 1033 goto done;
1034 1034 }
1035 1035 if (rd.rd_rddir.rddir_size) {
1036 1036 dirent64_t *odp = dp; /* next in output buffer */
1037 1037 dirent64_t *cdp = dp; /* current examined entry */
1038 1038
1039 1039 /*
1040 1040 * Check for duplicates here
1041 1041 */
1042 1042 do {
1043 1043 this_reclen = cdp->d_reclen;
1044 1044 if (auto_search(fnp, cdp->d_name,
1045 1045 NULL, cred)) {
1046 1046 /*
1047 1047 * entry not found in kernel list,
1048 1048 * include it in readdir output.
1049 1049 *
1050 1050 * If we are skipping entries. then
1051 1051 * we need to copy this entry to the
1052 1052 * correct position in the buffer
1053 1053 * to be copied out.
1054 1054 */
1055 1055 if (cdp != odp)
1056 1056 bcopy(cdp, odp,
1057 1057 (size_t)this_reclen);
1058 1058 odp = nextdp(odp);
1059 1059 outcount += this_reclen;
1060 1060 } else {
1061 1061 /*
1062 1062 * Entry was found in the kernel
1063 1063 * list. If it is the first entry
1064 1064 * in this buffer, then just skip it
1065 1065 */
1066 1066 if (odp == dp) {
1067 1067 dp = nextdp(dp);
1068 1068 odp = dp;
1069 1069 }
1070 1070 }
1071 1071 count += this_reclen;
1072 1072 cdp = (struct dirent64 *)
1073 1073 ((char *)cdp + this_reclen);
1074 1074 } while (count < rd.rd_rddir.rddir_size);
1075 1075
1076 1076 if (outcount)
1077 1077 error = uiomove(dp, outcount, UIO_READ, uiop);
1078 1078 uiop->uio_offset = rd.rd_rddir.rddir_offset;
1079 1079 } else {
1080 1080 if (rd.rd_rddir.rddir_eof == 0) {
1081 1081 /*
1082 1082 * alloc_count not large enough for one
1083 1083 * directory entry
1084 1084 */
1085 1085 error = EINVAL;
1086 1086 }
1087 1087 }
1088 1088 if (rd.rd_rddir.rddir_eof && !error) {
1089 1089 myeof = 1;
1090 1090 if (eofp)
1091 1091 *eofp = 1;
1092 1092 }
1093 1093 if (!error && !myeof && outcount == 0) {
1094 1094 /*
1095 1095 * call daemon with new cookie, all previous
1096 1096 * elements happened to be duplicates
1097 1097 */
1098 1098 dp = outbuf;
1099 1099 goto again;
1100 1100 }
1101 1101 goto done;
1102 1102 }
1103 1103
1104 1104 if (uiop->uio_offset == 0) {
1105 1105 /*
1106 1106 * first time: so fudge the . and ..
1107 1107 */
1108 1108 this_reclen = DIRENT64_RECLEN(1);
1109 1109 if (alloc_count < this_reclen) {
1110 1110 error = EINVAL;
1111 1111 goto done;
1112 1112 }
1113 1113 dp->d_ino = (ino64_t)fnp->fn_nodeid;
1114 1114 dp->d_off = (off64_t)1;
1115 1115 dp->d_reclen = (ushort_t)this_reclen;
1116 1116
1117 1117 /* use strncpy(9f) to zero out uninitialized bytes */
1118 1118
1119 1119 (void) strncpy(dp->d_name, ".",
1120 1120 DIRENT64_NAMELEN(this_reclen));
1121 1121 outcount += dp->d_reclen;
1122 1122 dp = nextdp(dp);
1123 1123
1124 1124 this_reclen = DIRENT64_RECLEN(2);
1125 1125 if (alloc_count < outcount + this_reclen) {
1126 1126 error = EINVAL;
1127 1127 goto done;
1128 1128 }
1129 1129 dp->d_reclen = (ushort_t)this_reclen;
1130 1130 dp->d_ino = (ino64_t)fnp->fn_parent->fn_nodeid;
1131 1131 dp->d_off = (off64_t)2;
1132 1132
1133 1133 /* use strncpy(9f) to zero out uninitialized bytes */
1134 1134
1135 1135 (void) strncpy(dp->d_name, "..",
1136 1136 DIRENT64_NAMELEN(this_reclen));
1137 1137 outcount += dp->d_reclen;
1138 1138 dp = nextdp(dp);
1139 1139 }
1140 1140
1141 1141 offset = 2;
1142 1142 cfnp = fnp->fn_dirents;
1143 1143 while (cfnp != NULL) {
1144 1144 nfnp = cfnp->fn_next;
1145 1145 offset = cfnp->fn_offset;
1146 1146 if ((offset >= uiop->uio_offset) &&
1147 1147 (!(cfnp->fn_flags & MF_LOOKUP))) {
1148 1148 int reclen;
1149 1149
1150 1150 /*
1151 1151 * include node only if its offset is greater or
1152 1152 * equal to the one required and it is not in
1153 1153 * transient state (not being looked-up)
1154 1154 */
1155 1155 namelen = strlen(cfnp->fn_name);
1156 1156 reclen = (int)DIRENT64_RECLEN(namelen);
1157 1157 if (outcount + reclen > alloc_count) {
1158 1158 reached_max = 1;
1159 1159 break;
1160 1160 }
1161 1161 dp->d_reclen = (ushort_t)reclen;
1162 1162 dp->d_ino = (ino64_t)cfnp->fn_nodeid;
1163 1163 if (nfnp != NULL) {
1164 1164 /*
1165 1165 * get the offset of the next element
1166 1166 */
1167 1167 dp->d_off = (off64_t)nfnp->fn_offset;
1168 1168 } else {
1169 1169 /*
1170 1170 * This is the last element, make
1171 1171 * offset one plus the current
1172 1172 */
1173 1173 dp->d_off = (off64_t)cfnp->fn_offset + 1;
1174 1174 }
1175 1175
1176 1176 /* use strncpy(9f) to zero out uninitialized bytes */
1177 1177
1178 1178 (void) strncpy(dp->d_name, cfnp->fn_name,
1179 1179 DIRENT64_NAMELEN(reclen));
1180 1180 outcount += dp->d_reclen;
1181 1181 dp = nextdp(dp);
1182 1182 }
1183 1183 cfnp = nfnp;
1184 1184 }
1185 1185
1186 1186 if (outcount)
1187 1187 error = uiomove(outbuf, outcount, UIO_READ, uiop);
1188 1188
1189 1189 if (!error) {
1190 1190 if (reached_max) {
1191 1191 /*
1192 1192 * This entry did not get added to the buffer on this,
1193 1193 * call. We need to add it on the next call therefore
1194 1194 * set uio_offset to this entry's offset. If there
1195 1195 * wasn't enough space for one dirent, return EINVAL.
1196 1196 */
1197 1197 uiop->uio_offset = offset;
1198 1198 if (outcount == 0)
1199 1199 error = EINVAL;
1200 1200 } else if (autofs_nobrowse ||
1201 1201 auto_nobrowse_option(fnip->fi_opts) ||
1202 1202 (fnip->fi_flags & MF_DIRECT) ||
1203 1203 (fnp->fn_trigger != NULL) ||
1204 1204 (((vp->v_flag & VROOT) == 0) &&
1205 1205 ((fntovn(fnp->fn_parent))->v_flag & VROOT) &&
1206 1206 (fnp->fn_dirents == NULL))) {
1207 1207 /*
1208 1208 * done reading directory entries
1209 1209 */
1210 1210 uiop->uio_offset = offset + 1;
1211 1211 if (eofp)
1212 1212 *eofp = 1;
1213 1213 } else {
1214 1214 /*
1215 1215 * Need to get the rest of the entries from the daemon.
1216 1216 */
1217 1217 uiop->uio_offset = AUTOFS_DAEMONCOOKIE;
1218 1218 }
1219 1219 }
1220 1220
1221 1221 done:
1222 1222 kmem_free(outbuf, alloc_count);
1223 1223 AUTOFS_DPRINT((5, "auto_readdir vp=%p offset=%lld eof=%d\n",
1224 1224 (void *)vp, uiop->uio_loffset, myeof));
1225 1225 return (error);
1226 1226 }
1227 1227
1228 1228 static int
1229 1229 auto_symlink(
1230 1230 vnode_t *dvp,
1231 1231 char *lnknm, /* new entry */
1232 1232 vattr_t *tva,
1233 1233 char *tnm, /* existing entry */
1234 1234 cred_t *cred,
1235 1235 caller_context_t *ct,
1236 1236 int flags)
1237 1237 {
1238 1238 vnode_t *newvp;
1239 1239 int error;
1240 1240
1241 1241 AUTOFS_DPRINT((4, "auto_symlink: dvp=%p lnknm=%s tnm=%s\n",
1242 1242 (void *)dvp, lnknm, tnm));
1243 1243
1244 1244 if (error = auto_trigger_mount(dvp, cred, &newvp))
1245 1245 goto done;
1246 1246
1247 1247 if (newvp != NULL) {
1248 1248 /*
1249 1249 * Node is mounted on.
1250 1250 */
1251 1251 if (vn_is_readonly(newvp))
1252 1252 error = EROFS;
1253 1253 else
1254 1254 error = VOP_SYMLINK(newvp, lnknm, tva, tnm, cred,
1255 1255 ct, flags);
1256 1256 VN_RELE(newvp);
1257 1257 } else
1258 1258 error = ENOSYS;
1259 1259
1260 1260 done:
1261 1261 AUTOFS_DPRINT((5, "auto_symlink: error=%d\n", error));
1262 1262 return (error);
1263 1263 }
1264 1264
1265 1265 /* ARGSUSED */
1266 1266 static int
1267 1267 auto_readlink(vnode_t *vp, struct uio *uiop, cred_t *cr, caller_context_t *ct)
1268 1268 {
1269 1269 fnnode_t *fnp = vntofn(vp);
1270 1270 int error;
1271 1271 timestruc_t now;
1272 1272
1273 1273 AUTOFS_DPRINT((4, "auto_readlink: vp=%p\n", (void *)vp));
1274 1274
1275 1275 gethrestime(&now);
1276 1276 fnp->fn_ref_time = now.tv_sec;
1277 1277
1278 1278 if (vp->v_type != VLNK)
1279 1279 error = EINVAL;
1280 1280 else {
1281 1281 ASSERT(!(fnp->fn_flags & (MF_INPROG | MF_LOOKUP)));
1282 1282 fnp->fn_atime = now;
1283 1283 error = uiomove(fnp->fn_symlink, MIN(fnp->fn_symlinklen,
1284 1284 uiop->uio_resid), UIO_READ, uiop);
1285 1285 }
1286 1286
1287 1287 AUTOFS_DPRINT((5, "auto_readlink: error=%d\n", error));
1288 1288 return (error);
1289 1289 }
1290 1290
1291 1291 /* ARGSUSED */
1292 1292 static int
1293 1293 auto_fsync(vnode_t *cp, int syncflag, cred_t *cred, caller_context_t *ct)
1294 1294 {
1295 1295 return (0);
1296 1296 }
1297 1297
1298 1298 /* ARGSUSED */
1299 1299 static void
1300 1300 auto_inactive(vnode_t *vp, cred_t *cred, caller_context_t *ct)
1301 1301 {
1302 1302 fnnode_t *fnp = vntofn(vp);
1303 1303 fnnode_t *dfnp = fnp->fn_parent;
1304 1304 int count;
1305 1305
1306 1306 AUTOFS_DPRINT((4, "auto_inactive: vp=%p v_count=%u fn_link=%d\n",
1307 1307 (void *)vp, vp->v_count, fnp->fn_linkcnt));
1308 1308
1309 1309 /*
1310 1310 * The rwlock should not be already held by this thread.
1311 1311 * The assert relies on the fact that the owner field is cleared
1312 1312 * when the lock is released.
1313 1313 */
1314 1314 ASSERT(dfnp != NULL);
1315 1315 ASSERT(rw_owner(&dfnp->fn_rwlock) != curthread);
1316 1316 rw_enter(&dfnp->fn_rwlock, RW_WRITER);
1317 1317 mutex_enter(&vp->v_lock);
1318 1318 ASSERT(vp->v_count > 0);
1319 1319 count = --vp->v_count;
1320 1320 mutex_exit(&vp->v_lock);
1321 1321 if (count == 0) {
1322 1322 /*
1323 1323 * Free only if node has no subdirectories.
1324 1324 */
1325 1325 if (fnp->fn_linkcnt == 1) {
1326 1326 auto_disconnect(dfnp, fnp);
1327 1327 rw_exit(&dfnp->fn_rwlock);
1328 1328 auto_freefnnode(fnp);
1329 1329 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p freed\n",
1330 1330 (void *)vp));
1331 1331 return;
1332 1332 }
1333 1333 }
1334 1334 rw_exit(&dfnp->fn_rwlock);
1335 1335
1336 1336 AUTOFS_DPRINT((5, "auto_inactive: (exit) vp=%p v_count=%u fn_link=%d\n",
1337 1337 (void *)vp, vp->v_count, fnp->fn_linkcnt));
1338 1338 }
1339 1339
1340 1340 /* ARGSUSED2 */
1341 1341 static int
1342 1342 auto_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1343 1343 {
1344 1344 fnnode_t *fnp = vntofn(vp);
1345 1345 if (write_lock)
1346 1346 rw_enter(&fnp->fn_rwlock, RW_WRITER);
1347 1347 else
1348 1348 rw_enter(&fnp->fn_rwlock, RW_READER);
1349 1349 return (write_lock);
1350 1350 }
1351 1351
1352 1352 /* ARGSUSED */
1353 1353 static void
1354 1354 auto_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1355 1355 {
1356 1356 fnnode_t *fnp = vntofn(vp);
1357 1357 rw_exit(&fnp->fn_rwlock);
1358 1358 }
1359 1359
1360 1360
1361 1361 /* ARGSUSED */
1362 1362 static int
1363 1363 auto_seek(
1364 1364 struct vnode *vp,
1365 1365 offset_t ooff,
1366 1366 offset_t *noffp,
1367 1367 caller_context_t *ct)
1368 1368 {
1369 1369 /*
1370 1370 * Return 0 unconditionally, since we expect
1371 1371 * a VDIR all the time
1372 1372 */
1373 1373 return (0);
1374 1374 }
1375 1375
1376 1376 /*
1377 1377 * Triggers the mount if needed. If the mount has been triggered by
1378 1378 * another thread, it will wait for its return status, and return it.
1379 1379 * Whether the mount is triggered by this thread, another thread, or
1380 1380 * if the vnode was already covered, '*newvp' is a
1381 1381 * VN_HELD vnode pointing to the root of the filesystem covering 'vp'.
1382 1382 * If the node is not mounted on, and should not be mounted on, '*newvp'
1383 1383 * will be NULL.
1384 1384 * The calling routine may use '*newvp' to do the filesystem jump.
1385 1385 */
1386 1386 static int
1387 1387 auto_trigger_mount(vnode_t *vp, cred_t *cred, vnode_t **newvp)
1388 1388 {
1389 1389 fnnode_t *fnp = vntofn(vp);
1390 1390 fninfo_t *fnip = vfstofni(vp->v_vfsp);
1391 1391 vnode_t *dvp;
1392 1392 vfs_t *vfsp;
1393 1393 int delayed_ind;
1394 1394 char name[AUTOFS_MAXPATHLEN];
1395 1395 int error;
1396 1396
1397 1397 AUTOFS_DPRINT((4, "auto_trigger_mount: vp=%p\n", (void *)vp));
1398 1398
1399 1399 *newvp = NULL;
1400 1400
1401 1401 /*
1402 1402 * Cross-zone mount triggering is disallowed.
1403 1403 */
1404 1404 if (fnip->fi_zoneid != getzoneid())
1405 1405 return (EPERM); /* Not owner of mount */
1406 1406
1407 1407 retry:
1408 1408 error = 0;
1409 1409 delayed_ind = 0;
1410 1410 mutex_enter(&fnp->fn_lock);
1411 1411 while (fnp->fn_flags & (MF_LOOKUP | MF_INPROG)) {
1412 1412 /*
1413 1413 * Mount or lookup in progress,
1414 1414 * wait for it before proceeding.
1415 1415 */
1416 1416 mutex_exit(&fnp->fn_lock);
1417 1417 error = auto_wait4mount(fnp);
1418 1418 if (error == AUTOFS_SHUTDOWN) {
1419 1419 error = 0;
1420 1420 goto done;
1421 1421 }
1422 1422 if (error && error != EAGAIN)
1423 1423 goto done;
1424 1424 error = 0;
1425 1425 mutex_enter(&fnp->fn_lock);
1426 1426 }
1427 1427
1428 1428 /*
1429 1429 * If the vfslock can't be acquired for the first time.
1430 1430 * drop the fn_lock and retry next time in blocking mode.
1431 1431 */
1432 1432 if (vn_vfswlock(vp)) {
1433 1433 /*
1434 1434 * Lock held by another thread.
1435 1435 * Perform blocking by dropping the
1436 1436 * fn_lock.
1437 1437 */
1438 1438 mutex_exit(&fnp->fn_lock);
1439 1439 error = vn_vfswlock_wait(vp);
1440 1440 if (error)
1441 1441 goto done;
1442 1442 /*
1443 1443 * Because fn_lock wasn't held, the state
1444 1444 * of the trigger node might have changed.
1445 1445 * Need to run through the checks on trigger
1446 1446 * node again.
1447 1447 */
1448 1448 vn_vfsunlock(vp);
1449 1449 goto retry;
1450 1450 }
1451 1451
1452 1452 vfsp = vn_mountedvfs(vp);
1453 1453 if (vfsp != NULL) {
1454 1454 mutex_exit(&fnp->fn_lock);
1455 1455 error = VFS_ROOT(vfsp, newvp);
1456 1456 vn_vfsunlock(vp);
1457 1457 goto done;
1458 1458 } else {
1459 1459 vn_vfsunlock(vp);
1460 1460 if ((fnp->fn_flags & MF_MOUNTPOINT) &&
1461 1461 fnp->fn_trigger != NULL) {
1462 1462 ASSERT(fnp->fn_dirents == NULL);
1463 1463 mutex_exit(&fnp->fn_lock);
1464 1464 /*
1465 1465 * The filesystem that used to sit here has been
1466 1466 * forcibly unmounted. Do our best to recover.
1467 1467 * Try to unmount autofs subtree below this node
1468 1468 * and retry the action.
1469 1469 */
1470 1470 if (unmount_subtree(fnp, B_TRUE) != 0) {
1471 1471 error = EIO;
1472 1472 goto done;
1473 1473 }
1474 1474 goto retry;
1475 1475 }
1476 1476 }
1477 1477
1478 1478 ASSERT(vp->v_type == VDIR);
1479 1479 dvp = fntovn(fnp->fn_parent);
1480 1480
1481 1481 if ((fnp->fn_dirents == NULL) &&
1482 1482 ((fnip->fi_flags & MF_DIRECT) == 0) &&
1483 1483 ((vp->v_flag & VROOT) == 0) &&
1484 1484 (dvp->v_flag & VROOT)) {
1485 1485 /*
1486 1486 * If the parent of this node is the root of an indirect
1487 1487 * AUTOFS filesystem, this node is remountable.
1488 1488 */
1489 1489 delayed_ind = 1;
1490 1490 }
1491 1491
1492 1492 if (delayed_ind ||
1493 1493 ((fnip->fi_flags & MF_DIRECT) && (fnp->fn_dirents == NULL))) {
1494 1494 /*
1495 1495 * Trigger mount since:
1496 1496 * direct mountpoint with no subdirs or
1497 1497 * delayed indirect.
1498 1498 */
1499 1499 AUTOFS_BLOCK_OTHERS(fnp, MF_INPROG);
1500 1500 fnp->fn_error = 0;
1501 1501 mutex_exit(&fnp->fn_lock);
1502 1502 if (delayed_ind)
1503 1503 (void) strcpy(name, fnp->fn_name);
1504 1504 else
1505 1505 (void) strcpy(name, ".");
1506 1506 fnp->fn_ref_time = gethrestime_sec();
1507 1507 auto_new_mount_thread(fnp, name, cred);
1508 1508 /*
1509 1509 * At this point we're simply another thread waiting
1510 1510 * for the mount to finish.
1511 1511 */
1512 1512 error = auto_wait4mount(fnp);
1513 1513 if (error == EAGAIN)
1514 1514 goto retry;
1515 1515 if (error == AUTOFS_SHUTDOWN) {
1516 1516 error = 0;
1517 1517 goto done;
1518 1518 }
1519 1519 if (error == 0) {
1520 1520 if (error = vn_vfsrlock_wait(vp))
1521 1521 goto done;
1522 1522 /* Reacquire after dropping locks */
1523 1523 vfsp = vn_mountedvfs(vp);
1524 1524 if (vfsp != NULL) {
1525 1525 error = VFS_ROOT(vfsp, newvp);
1526 1526 vn_vfsunlock(vp);
1527 1527 } else {
1528 1528 vn_vfsunlock(vp);
1529 1529 goto retry;
1530 1530 }
1531 1531 }
1532 1532 } else
1533 1533 mutex_exit(&fnp->fn_lock);
1534 1534
1535 1535 done:
1536 1536 AUTOFS_DPRINT((5, "auto_trigger_mount: error=%d\n", error));
1537 1537 return (error);
1538 1538 }
↓ open down ↓ |
1412 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX