Print this page
OS-1571 Placate gcc -Wparentheses
Reviewed by: Robert Mustacchi <rm@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/hyprlofs/hyprlofs_vnops.c
+++ new/usr/src/uts/common/fs/hyprlofs/hyprlofs_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 /*
23 23 * Copyright 2012 Joyent, Inc. All rights reserved.
24 24 */
25 25
26 26 #include <sys/types.h>
27 27 #include <sys/param.h>
28 28 #include <sys/t_lock.h>
29 29 #include <sys/systm.h>
30 30 #include <sys/sysmacros.h>
31 31 #include <sys/user.h>
32 32 #include <sys/time.h>
33 33 #include <sys/vfs.h>
34 34 #include <sys/vfs_opreg.h>
35 35 #include <sys/vnode.h>
36 36 #include <sys/file.h>
37 37 #include <sys/fcntl.h>
38 38 #include <sys/flock.h>
39 39 #include <sys/kmem.h>
40 40 #include <sys/errno.h>
41 41 #include <sys/stat.h>
42 42 #include <sys/cred.h>
43 43 #include <sys/dirent.h>
44 44 #include <sys/pathname.h>
45 45 #include <sys/fs/hyprlofs.h>
46 46 #include <sys/fs/hyprlofs_info.h>
47 47 #include <sys/mman.h>
48 48 #include <vm/pvn.h>
49 49 #include <sys/cmn_err.h>
50 50 #include <sys/buf.h>
51 51 #include <sys/policy.h>
52 52 #include <fs/fs_subr.h>
53 53 #include <sys/ddi.h>
54 54 #include <sys/sunddi.h>
55 55
56 56 static int hyprlofs_add_entry(vnode_t *, char *, char *, cred_t *,
57 57 caller_context_t *);
58 58 static int hyprlofs_rm_entry(vnode_t *, char *, cred_t *, caller_context_t *,
59 59 int);
60 60 static int hyprlofs_rm_all(vnode_t *, cred_t *, caller_context_t *, int);
61 61 static int hyprlofs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
62 62 int);
63 63 static int hyprlofs_get_all(vnode_t *, intptr_t, cred_t *, caller_context_t *,
64 64 int);
65 65
66 66 /*
67 67 * This is a somewhat arbitrary upper limit on the number of entries we can
68 68 * pass in on a single add/rm ioctl call. This is only used to validate that
69 69 * the input list looks sane.
70 70 */
71 71 #define MAX_IOCTL_PARAMS 100000
72 72
73 73 static int
74 74 hyprlofs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
75 75 {
76 76 vnode_t *rvp;
77 77 int error;
78 78
79 79 rvp = REALVP(*vpp);
80 80
81 81 if (VTOHLN(*vpp)->hln_looped == 0)
82 82 return (0);
83 83
84 84 /*
85 85 * looped back, pass through to real vnode. Need to hold new reference
86 86 * to vp since VOP_OPEN() may decide to release it.
87 87 */
88 88 VN_HOLD(rvp);
89 89 error = VOP_OPEN(&rvp, flag, cr, ct);
90 90 ASSERT(rvp->v_count > 1);
91 91 VN_RELE(rvp);
92 92
93 93 return (error);
94 94 }
95 95
96 96 static int
97 97 hyprlofs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
98 98 caller_context_t *ct)
99 99 {
100 100 if (VTOHLN(vp)->hln_looped == 0) {
101 101 cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
102 102 cleanshares(vp, ttoproc(curthread)->p_pid);
103 103 return (0);
104 104 }
105 105
106 106 return (VOP_CLOSE(REALVP(vp), flag, count, offset, cr, ct));
107 107 }
108 108
109 109 static int
110 110 hyprlofs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
111 111 caller_context_t *ct)
112 112 {
113 113 return (VOP_READ(REALVP(vp), uiop, ioflag, cr, ct));
114 114 }
115 115
116 116 static int
117 117 hyprlofs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
118 118 caller_context_t *ct)
119 119 {
120 120 /* We don't support writing to non-regular files */
121 121 if (vp->v_type != VREG)
122 122 return (EINVAL);
123 123
124 124 if (vn_is_readonly(vp))
125 125 return (EROFS);
126 126
127 127 return (VOP_WRITE(REALVP(vp), uiop, ioflag, cr, ct));
128 128 }
129 129
130 130 /* ARGSUSED */
131 131 static int
132 132 hyprlofs_ioctl(vnode_t *vp, int cmd, intptr_t data, int flag,
133 133 cred_t *cr, int *rvalp, caller_context_t *ct)
134 134 {
135 135 int len, cnt, error;
136 136 int i;
137 137 model_t model;
138 138 char path[MAXPATHLEN];
139 139 char nm[MAXPATHLEN];
140 140
141 141 /* We only support the hyprlofs ioctls on the root vnode */
142 142 if (!(vp->v_flag & VROOT))
143 143 return (ENOTTY);
144 144
145 145 /*
146 146 * Check if managing hyprlofs is allowed.
147 147 */
148 148 if (secpolicy_hyprlofs_control(cr) != 0)
149 149 return (EPERM);
150 150
151 151 if (cmd == HYPRLOFS_ADD_ENTRIES || cmd == HYPRLOFS_RM_ENTRIES) {
152 152 model = get_udatamodel();
153 153
154 154 if (model == DATAMODEL_NATIVE) {
155 155 hyprlofs_entries_t ebuf;
156 156 hyprlofs_entry_t *e;
157 157
158 158 if (copyin((void *)data, &ebuf, sizeof (ebuf)))
159 159 return (EFAULT);
160 160 cnt = ebuf.hle_len;
161 161 if (cnt > MAX_IOCTL_PARAMS)
162 162 return (EINVAL);
163 163 len = sizeof (hyprlofs_entry_t) * cnt;
164 164
165 165 e = kmem_alloc(len, KM_SLEEP);
166 166 if (copyin((void *)(ebuf.hle_entries), e, len)) {
167 167 kmem_free(e, len);
168 168 return (EFAULT);
169 169 }
170 170
171 171 for (i = 0; i < cnt; i++) {
172 172 if (e[i].hle_nlen == 0 ||
173 173 e[i].hle_nlen > MAXPATHLEN)
174 174 return (EINVAL);
175 175
176 176 if (copyin(e[i].hle_name, nm, e[i].hle_nlen)
177 177 != 0) {
178 178 kmem_free(e, len);
179 179 return (EFAULT);
180 180 }
181 181 nm[e[i].hle_nlen] = '\0';
182 182
183 183 if (cmd == HYPRLOFS_ADD_ENTRIES) {
184 184 if (e[i].hle_plen == 0 ||
185 185 e[i].hle_plen > MAXPATHLEN)
186 186 return (EINVAL);
187 187
188 188 if (copyin(e[i].hle_path, path,
189 189 e[i].hle_plen) != 0) {
190 190 kmem_free(e, len);
191 191 return (EFAULT);
192 192 }
193 193 path[e[i].hle_plen] = '\0';
194 194
195 195 if ((error = hyprlofs_add_entry(vp,
196 196 path, nm, cr, ct)) != 0) {
197 197 kmem_free(e, len);
198 198 return (error);
199 199 }
200 200 } else {
201 201 if ((error = hyprlofs_rm_entry(vp, nm,
202 202 cr, ct, flag)) != 0) {
203 203 kmem_free(e, len);
204 204 return (error);
205 205 }
206 206 }
207 207 }
208 208
209 209 kmem_free(e, len);
210 210 return (0);
211 211
212 212 } else {
213 213 hyprlofs_entries32_t ebuf32;
214 214 hyprlofs_entry32_t *e32;
215 215
216 216 if (copyin((void *)data, &ebuf32, sizeof (ebuf32)))
217 217 return (EFAULT);
218 218
219 219 cnt = ebuf32.hle_len;
220 220 if (cnt > MAX_IOCTL_PARAMS)
221 221 return (EINVAL);
222 222 len = sizeof (hyprlofs_entry32_t) * cnt;
223 223
224 224 e32 = kmem_alloc(len, KM_SLEEP);
225 225 if (copyin((void *)(unsigned long)(ebuf32.hle_entries),
226 226 e32, len)) {
227 227 kmem_free(e32, len);
228 228 return (EFAULT);
229 229 }
230 230
231 231 for (i = 0; i < cnt; i++) {
232 232 if (e32[i].hle_nlen == 0 ||
233 233 e32[i].hle_nlen > MAXPATHLEN)
234 234 return (EINVAL);
235 235
236 236 if (copyin((void *)(unsigned long)
237 237 e32[i].hle_name, nm,
238 238 e32[i].hle_nlen) != 0) {
239 239 kmem_free(e32, len);
240 240 return (EFAULT);
241 241 }
242 242 nm[e32[i].hle_nlen] = '\0';
243 243
244 244 if (cmd == HYPRLOFS_ADD_ENTRIES) {
245 245 if (e32[i].hle_plen == 0 ||
246 246 e32[i].hle_plen > MAXPATHLEN)
247 247 return (EINVAL);
248 248
249 249 if (copyin((void *)(unsigned long)
250 250 e32[i].hle_path, path,
251 251 e32[i].hle_plen) != 0) {
252 252 kmem_free(e32, len);
253 253 return (EFAULT);
254 254 }
255 255 path[e32[i].hle_plen] = '\0';
256 256
257 257 if ((error = hyprlofs_add_entry(vp,
258 258 path, nm, cr, ct)) != 0) {
259 259 kmem_free(e32, len);
260 260 return (error);
261 261 }
262 262 } else {
263 263 if ((error = hyprlofs_rm_entry(vp, nm,
264 264 cr, ct, flag)) != 0) {
265 265 kmem_free(e32, len);
266 266 return (error);
267 267 }
268 268 }
269 269 }
270 270
271 271 kmem_free(e32, len);
272 272 return (0);
273 273 }
274 274 }
275 275
276 276 if (cmd == HYPRLOFS_RM_ALL) {
277 277 return (hyprlofs_rm_all(vp, cr, ct, flag));
278 278 }
279 279
280 280 if (cmd == HYPRLOFS_GET_ENTRIES) {
281 281 return (hyprlofs_get_all(vp, data, cr, ct, flag));
282 282 }
283 283
284 284 return (ENOTTY);
285 285 }
286 286
287 287 /*ARGSUSED2*/
288 288 static int
289 289 hyprlofs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
290 290 caller_context_t *ct)
291 291 {
292 292 hlnode_t *tp = (hlnode_t *)VTOHLN(vp);
293 293
294 294 mutex_enter(&tp->hln_tlock);
295 295 vap->va_type = vp->v_type;
296 296 vap->va_mode = tp->hln_mode & MODEMASK;
297 297 vap->va_uid = tp->hln_uid;
298 298 vap->va_gid = tp->hln_gid;
299 299 vap->va_fsid = tp->hln_fsid;
300 300 vap->va_nodeid = (ino64_t)tp->hln_nodeid;
301 301 vap->va_nlink = tp->hln_nlink;
302 302 vap->va_size = (u_offset_t)tp->hln_size;
303 303 vap->va_atime = tp->hln_atime;
304 304 vap->va_mtime = tp->hln_mtime;
305 305 vap->va_ctime = tp->hln_ctime;
306 306 vap->va_blksize = PAGESIZE;
307 307 vap->va_rdev = tp->hln_rdev;
308 308 vap->va_seq = tp->hln_seq;
309 309
310 310 vap->va_nblocks = (fsblkcnt64_t)btodb(ptob(btopr(vap->va_size)));
311 311 mutex_exit(&tp->hln_tlock);
312 312 return (0);
313 313 }
314 314
315 315 /*ARGSUSED4*/
316 316 static int
317 317 hyprlofs_setattr(vnode_t *vp, vattr_t *vap, int flags,
318 318 cred_t *cr, caller_context_t *ct)
319 319 {
320 320 hlnode_t *tp = (hlnode_t *)VTOHLN(vp);
321 321 int error = 0;
322 322 vattr_t *get;
323 323 long mask;
324 324
325 325 /*
326 326 * Cannot set these attributes
327 327 */
328 328 if ((vap->va_mask & AT_NOSET) || (vap->va_mask & AT_XVATTR))
329 329 return (EINVAL);
330 330
331 331 mutex_enter(&tp->hln_tlock);
332 332
333 333 get = &tp->hln_attr;
334 334 /*
335 335 * Change file access modes. Must be owner or have sufficient
336 336 * privileges.
337 337 */
338 338 error = secpolicy_vnode_setattr(cr, vp, vap, get, flags,
339 339 hyprlofs_taccess, tp);
340 340
341 341 if (error)
342 342 goto out;
343 343
344 344 mask = vap->va_mask;
345 345
346 346 if (mask & AT_MODE) {
347 347 get->va_mode &= S_IFMT;
348 348 get->va_mode |= vap->va_mode & ~S_IFMT;
349 349 }
350 350
351 351 if (mask & AT_UID)
352 352 get->va_uid = vap->va_uid;
353 353 if (mask & AT_GID)
354 354 get->va_gid = vap->va_gid;
355 355 if (mask & AT_ATIME)
356 356 get->va_atime = vap->va_atime;
357 357 if (mask & AT_MTIME)
358 358 get->va_mtime = vap->va_mtime;
359 359
360 360 if (mask & (AT_UID | AT_GID | AT_MODE | AT_MTIME))
361 361 gethrestime(&tp->hln_ctime);
362 362
363 363 out:
364 364 mutex_exit(&tp->hln_tlock);
365 365 return (error);
366 366 }
367 367
368 368 static int
369 369 hyprlofs_access(vnode_t *vp, int mode, int flags, cred_t *cr,
370 370 caller_context_t *ct)
371 371 {
372 372 hlnode_t *tp = (hlnode_t *)VTOHLN(vp);
373 373 int error;
374 374
375 375 if (mode & VWRITE) {
376 376 if (vp->v_type == VREG && vn_is_readonly(vp))
377 377 return (EROFS);
378 378 }
379 379 if (VTOHLN(vp)->hln_looped == 1)
380 380 return (VOP_ACCESS(REALVP(vp), mode, flags, cr, ct));
381 381
382 382 mutex_enter(&tp->hln_tlock);
383 383 error = hyprlofs_taccess(tp, mode, cr);
384 384 mutex_exit(&tp->hln_tlock);
385 385 return (error);
386 386 }
387 387
388 388 /* ARGSUSED3 */
389 389 static int
390 390 hyprlofs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
391 391 int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
392 392 int *direntflags, pathname_t *realpnp)
393 393 {
394 394 hlnode_t *tp = (hlnode_t *)VTOHLN(dvp);
395 395 hlnode_t *ntp = NULL;
396 396 int error;
397 397
398 398 if (VTOHLN(dvp)->hln_looped == 1)
399 399 return (VOP_LOOKUP(REALVP(dvp), nm, vpp, pnp, flags, rdir,
400 400 cr, ct, direntflags, realpnp));
401 401
402 402 if (flags & LOOKUP_XATTR)
403 403 return (EINVAL);
404 404
405 405 /* Null component name is a synonym for directory being searched. */
406 406 if (*nm == '\0') {
407 407 VN_HOLD(dvp);
408 408 *vpp = dvp;
409 409 return (0);
410 410 }
411 411 ASSERT(tp);
412 412
413 413 if ((error = hyprlofs_dirlookup(tp, nm, &ntp, cr)) == 0) {
414 414 ASSERT(ntp);
415 415 *vpp = HLNTOV(ntp);
416 416 }
417 417 return (error);
418 418 }
419 419
420 420 /*
421 421 * Create the loopback from the hyprlofs vnode to the real vnode.
422 422 */
423 423 static int
424 424 hyprlofs_loopback(vnode_t *dvp, vnode_t *rvp, char *nm, vattr_t *vap,
425 425 int mode, cred_t *cr, caller_context_t *ct)
426 426 {
427 427 hlnode_t *parent;
428 428 hlfsmount_t *tm;
429 429 int error;
430 430 hlnode_t *oldtp;
431 431 vnode_t *vp;
432 432
433 433 parent = (hlnode_t *)VTOHLN(dvp);
434 434 tm = (hlfsmount_t *)VTOHLM(dvp);
435 435 error = 0;
436 436 oldtp = NULL;
437 437
438 438 if (vap->va_type == VREG && (vap->va_mode & VSVTX)) {
439 439 /* we don't support the sticky bit */
440 440 vap->va_mode &= ~VSVTX;
441 441 } else if (vap->va_type == VNON) {
442 442 return (EINVAL);
443 443 }
444 444
445 445 /* Null component name is a synonym for directory being searched. */
446 446 if (*nm == '\0') {
447 447 VN_HOLD(dvp);
448 448 oldtp = parent;
449 449 } else {
450 450 error = hyprlofs_dirlookup(parent, nm, &oldtp, cr);
451 451 }
452 452
453 453 if (error == 0) { /* name found */
454 454 ASSERT(oldtp);
455 455
456 456 rw_enter(&oldtp->hln_rwlock, RW_WRITER);
457 457
458 458 /*
459 459 * if create/read-only an existing directory, allow it
460 460 */
461 461 if ((oldtp->hln_type == VDIR) && (mode & VWRITE))
462 462 error = EISDIR;
463 463 else {
464 464 error = hyprlofs_taccess(oldtp, mode, cr);
465 465 }
466 466
467 467 if (error) {
468 468 rw_exit(&oldtp->hln_rwlock);
469 469 hlnode_rele(oldtp);
470 470 return (error);
471 471 }
472 472
473 473 vp = HLNTOV(oldtp);
474 474 rw_exit(&oldtp->hln_rwlock);
475 475
476 476 if (vp->v_type == VREG) {
477 477 hlnode_rele(oldtp);
478 478 return (EEXIST);
479 479 }
480 480
481 481 vnevent_create(vp, ct);
482 482 return (0);
483 483 }
484 484
485 485 if (error != ENOENT)
486 486 return (error);
487 487
488 488 rw_enter(&parent->hln_rwlock, RW_WRITER);
489 489 error = hyprlofs_direnter(tm, parent, nm, DE_CREATE, rvp, vap, NULL,
490 490 cr);
491 491 rw_exit(&parent->hln_rwlock);
492 492
493 493 return (error);
494 494 }
495 495
496 496 /*
497 497 * Create an in-memory directory based on the add-entry ioctl name.
498 498 * If the dir exists, return EEXIST but still also return node in vpp.
499 499 */
500 500 static int
501 501 hyprlofs_mkdir(vnode_t *dvp, char *nm, vattr_t *va, vnode_t **vpp, cred_t *cr)
502 502 {
503 503 hlnode_t *parent = (hlnode_t *)VTOHLN(dvp);
504 504 hlnode_t *self = NULL;
505 505 hlfsmount_t *tm = (hlfsmount_t *)VTOHLM(dvp);
506 506 int error;
507 507
508 508 /*
509 509 * Might be dangling directory. Catch it here, because a ENOENT return
510 510 * from hyprlofs_dirlookup() is a valid return.
511 511 */
512 512 if (parent->hln_nlink == 0)
513 513 return (ENOENT);
514 514
515 515 error = hyprlofs_dirlookup(parent, nm, &self, cr);
516 516 if (error == 0) {
517 517 ASSERT(self);
518 518 hlnode_rele(self);
519 519 /* We can't loop in under a looped in directory */
520 520 if (self->hln_looped)
521 521 return (EACCES);
522 522 *vpp = HLNTOV(self);
523 523 return (EEXIST);
524 524 }
525 525 if (error != ENOENT)
526 526 return (error);
527 527
528 528 rw_enter(&parent->hln_rwlock, RW_WRITER);
529 529 error = hyprlofs_direnter(tm, parent, nm, DE_MKDIR, (vnode_t *)NULL,
530 530 va, &self, cr);
531 531 rw_exit(&parent->hln_rwlock);
532 532
533 533 if (error == 0 || error == EEXIST) {
534 534 hlnode_rele(self);
535 535 *vpp = HLNTOV(self);
536 536 }
537 537
538 538 return (error);
539 539 }
540 540
541 541 /*
542 542 * Loop in a file or directory into the namespace.
543 543 */
544 544 static int
545 545 hyprlofs_add_entry(vnode_t *vp, char *fspath, char *fsname,
546 546 cred_t *cr, caller_context_t *ct)
↓ open down ↓ |
546 lines elided |
↑ open up ↑ |
547 547 {
548 548 int error;
549 549 char *p, *pnm;
550 550 vnode_t *realvp, *dvp;
551 551 vattr_t va;
552 552
553 553 /*
554 554 * Get vnode for the real file/dir. We'll have a hold on realvp which
555 555 * we won't vn_rele until hyprlofs_inactive.
556 556 */
557 - if (error = lookupname(fspath, UIO_SYSSPACE, FOLLOW, NULLVPP, &realvp))
557 + if ((error = lookupname(fspath, UIO_SYSSPACE, FOLLOW, NULLVPP,
558 + &realvp)) != 0)
558 559 return (error);
559 560
560 561 /* no devices allowed */
561 562 if (IS_DEVVP(realvp)) {
562 563 VN_RELE(realvp);
563 564 return (ENODEV);
564 565 }
565 566
566 567 /*
567 568 * realvp may be an AUTOFS node, in which case we perform a VOP_ACCESS
568 569 * to trigger the mount of the intended filesystem. This causes a
569 570 * loopback mount of the intended filesystem instead of the AUTOFS
570 571 * filesystem.
571 572 */
572 573 if ((error = VOP_ACCESS(realvp, 0, 0, cr, NULL)) != 0) {
573 574 VN_RELE(realvp);
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
574 575 return (error);
575 576 }
576 577
577 578 /*
578 579 * We're interested in the top most filesystem. This is specially
579 580 * important when fspath is a trigger AUTOFS node, since we're really
580 581 * interested in mounting the filesystem AUTOFS mounted as result of
581 582 * the VOP_ACCESS() call not the AUTOFS node itself.
582 583 */
583 584 if (vn_mountedvfs(realvp) != NULL) {
584 - if (error = traverse(&realvp)) {
585 + if ((error = traverse(&realvp)) != 0) {
585 586 VN_RELE(realvp);
586 587 return (error);
587 588 }
588 589 }
589 590
590 591 va.va_type = VNON;
591 592 /*
592 593 * If the target name is a path, make sure we have all of the
593 594 * intermediate directories, creating them if necessary.
594 595 */
595 596 dvp = vp;
596 597 pnm = p = fsname;
597 598
598 599 /* path cannot be absolute */
599 600 if (*p == '/') {
600 601 VN_RELE(realvp);
601 602 return (EINVAL);
602 603 }
603 604
604 605 for (p = strchr(pnm, '/'); p != NULL; p = strchr(pnm, '/')) {
605 606 if (va.va_type == VNON)
606 607 /* use the top-level dir as the template va for mkdir */
607 608 if ((error = VOP_GETATTR(vp, &va, 0, cr, NULL)) != 0) {
608 609 VN_RELE(realvp);
609 610 return (error);
610 611 }
611 612
612 613 *p = '\0';
613 614
614 615 /* Path component cannot be empty or relative */
615 616 if (pnm[0] == '\0' || (pnm[0] == '.' && pnm[1] == '.')) {
616 617 VN_RELE(realvp);
617 618 return (EINVAL);
618 619 }
619 620
620 621 if ((error = hyprlofs_mkdir(dvp, pnm, &va, &dvp, cr)) != 0 &&
621 622 error != EEXIST) {
622 623 VN_RELE(realvp);
623 624 return (error);
624 625 }
625 626
626 627 *p = '/';
627 628 pnm = p + 1;
628 629 }
629 630
630 631 /* The file name is required */
631 632 if (pnm[0] == '\0') {
632 633 VN_RELE(realvp);
633 634 return (EINVAL);
634 635 }
635 636
636 637 /* Now use the real file's va as the template va */
637 638 if ((error = VOP_GETATTR(realvp, &va, 0, cr, NULL)) != 0) {
638 639 VN_RELE(realvp);
639 640 return (error);
640 641 }
641 642
642 643 /* Make the vnode */
643 644 error = hyprlofs_loopback(dvp, realvp, pnm, &va, va.va_mode, cr, ct);
644 645 if (error != 0)
645 646 VN_RELE(realvp);
646 647 return (error);
647 648 }
648 649
649 650 /*
650 651 * Remove a looped in file from the namespace.
651 652 */
652 653 static int
653 654 hyprlofs_rm_entry(vnode_t *dvp, char *fsname, cred_t *cr, caller_context_t *ct,
654 655 int flags)
655 656 {
656 657 int error;
657 658 char *p, *pnm;
658 659 hlnode_t *parent;
659 660 hlnode_t *fndtp;
660 661
661 662 pnm = p = fsname;
662 663
663 664 /* path cannot be absolute */
664 665 if (*p == '/')
665 666 return (EINVAL);
666 667
667 668 /*
668 669 * If the target name is a path, get the containing dir and simple
669 670 * file name.
670 671 */
671 672 parent = (hlnode_t *)VTOHLN(dvp);
672 673 for (p = strchr(pnm, '/'); p != NULL; p = strchr(pnm, '/')) {
673 674 *p = '\0';
674 675
675 676 /* Path component cannot be empty or relative */
676 677 if (pnm[0] == '\0' || (pnm[0] == '.' && pnm[1] == '.'))
677 678 return (EINVAL);
678 679
679 680 if ((error = hyprlofs_dirlookup(parent, pnm, &fndtp, cr)) != 0)
680 681 return (error);
681 682
682 683 dvp = HLNTOV(fndtp);
683 684 parent = fndtp;
684 685 pnm = p + 1;
685 686 }
686 687
687 688 /* The file name is required */
688 689 if (pnm[0] == '\0')
689 690 return (EINVAL);
690 691
691 692 /* Remove the entry from the parent dir */
692 693 return (hyprlofs_remove(dvp, pnm, cr, ct, flags));
693 694 }
694 695
695 696 /*
696 697 * Remove all looped in files from the namespace.
697 698 */
698 699 static int
699 700 hyprlofs_rm_all(vnode_t *dvp, cred_t *cr, caller_context_t *ct,
700 701 int flags)
701 702 {
702 703 int error = 0;
703 704 hlnode_t *hp = (hlnode_t *)VTOHLN(dvp);
704 705 hldirent_t *hdp;
705 706
706 707 hlnode_hold(hp);
707 708
708 709 /*
709 710 * There's a window here where someone could have removed
710 711 * all the entries in the directory after we put a hold on the
711 712 * vnode but before we grabbed the rwlock. Just return.
712 713 */
713 714 if (hp->hln_dir == NULL) {
714 715 if (hp->hln_nlink) {
715 716 panic("empty directory 0x%p", (void *)hp);
716 717 /*NOTREACHED*/
717 718 }
718 719 goto done;
719 720 }
720 721
721 722 hdp = hp->hln_dir;
722 723 while (hdp) {
723 724 hlnode_t *fndhp;
724 725
725 726 if (strcmp(hdp->hld_name, ".") == 0 ||
726 727 strcmp(hdp->hld_name, "..") == 0) {
727 728 hdp = hdp->hld_next;
728 729 continue;
729 730 }
730 731
731 732 /* This holds the fndhp vnode */
732 733 error = hyprlofs_dirlookup(hp, hdp->hld_name, &fndhp, cr);
733 734 if (error != 0)
734 735 goto done;
735 736 hlnode_rele(fndhp);
736 737
737 738 if (fndhp->hln_looped == 0) {
738 739 /* recursively remove contents of this subdir */
739 740 if (fndhp->hln_type == VDIR) {
740 741 vnode_t *tvp = HLNTOV(fndhp);
741 742
742 743 error = hyprlofs_rm_all(tvp, cr, ct, flags);
743 744 if (error != 0)
744 745 goto done;
745 746 }
746 747 }
747 748
748 749 /* remove the entry */
749 750 error = hyprlofs_remove(dvp, hdp->hld_name, cr, ct, flags);
750 751 if (error != 0)
751 752 goto done;
752 753
753 754 hdp = hp->hln_dir;
754 755 }
755 756
756 757 done:
757 758 hlnode_rele(hp);
758 759 return (error);
759 760 }
760 761
761 762 /*
762 763 * Get a list of all looped in files in the namespace.
763 764 */
764 765 static int
765 766 hyprlofs_get_all_entries(vnode_t *dvp, hyprlofs_curr_entry_t *hcp,
766 767 char *prefix, int *pcnt, int n_max,
767 768 cred_t *cr, caller_context_t *ct, int flags)
768 769 {
769 770 int error = 0;
770 771 int too_big = 0;
771 772 int cnt;
772 773 int len;
773 774 hlnode_t *hp = (hlnode_t *)VTOHLN(dvp);
774 775 hldirent_t *hdp;
775 776 char *path;
776 777
777 778 cnt = *pcnt;
778 779 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
779 780
780 781 hlnode_hold(hp);
781 782
782 783 /*
783 784 * There's a window here where someone could have removed
784 785 * all the entries in the directory after we put a hold on the
785 786 * vnode but before we grabbed the rwlock. Just return.
786 787 */
787 788 if (hp->hln_dir == NULL) {
788 789 if (hp->hln_nlink) {
789 790 panic("empty directory 0x%p", (void *)hp);
790 791 /*NOTREACHED*/
791 792 }
792 793 goto done;
793 794 }
794 795
795 796 hdp = hp->hln_dir;
796 797 while (hdp) {
797 798 hlnode_t *fndhp;
798 799 vnode_t *tvp;
799 800
800 801 if (strcmp(hdp->hld_name, ".") == 0 ||
801 802 strcmp(hdp->hld_name, "..") == 0) {
802 803 hdp = hdp->hld_next;
803 804 continue;
804 805 }
805 806
806 807 /* This holds the fndhp vnode */
807 808 error = hyprlofs_dirlookup(hp, hdp->hld_name, &fndhp, cr);
808 809 if (error != 0)
809 810 goto done;
810 811 hlnode_rele(fndhp);
811 812
812 813 if (fndhp->hln_looped == 0) {
813 814 /* recursively get contents of this subdir */
814 815 VERIFY(fndhp->hln_type == VDIR);
815 816 tvp = HLNTOV(fndhp);
816 817
817 818 if (*prefix == '\0')
818 819 (void) strlcpy(path, hdp->hld_name, MAXPATHLEN);
819 820 else
820 821 (void) snprintf(path, MAXPATHLEN, "%s/%s",
821 822 prefix, hdp->hld_name);
822 823
823 824 error = hyprlofs_get_all_entries(tvp, hcp, path,
824 825 &cnt, n_max, cr, ct, flags);
825 826
826 827 if (error == E2BIG) {
827 828 too_big = 1;
828 829 error = 0;
829 830 }
830 831 if (error != 0)
831 832 goto done;
832 833 } else {
833 834 if (cnt < n_max) {
834 835 char *p;
835 836
836 837 if (*prefix == '\0')
837 838 (void) strlcpy(path, hdp->hld_name,
838 839 MAXPATHLEN);
839 840 else
840 841 (void) snprintf(path, MAXPATHLEN,
841 842 "%s/%s", prefix, hdp->hld_name);
842 843
843 844 len = strlen(path);
844 845 ASSERT(len <= MAXPATHLEN);
845 846 if (copyout(path, (void *)(hcp[cnt].hce_name),
846 847 len)) {
847 848 error = EFAULT;
848 849 goto done;
849 850 }
850 851
851 852 tvp = REALVP(HLNTOV(fndhp));
852 853 if (tvp->v_path == NULL) {
853 854 p = "<unknown>";
854 855 } else {
855 856 p = tvp->v_path;
856 857 }
857 858 len = strlen(p);
858 859 ASSERT(len <= MAXPATHLEN);
859 860 if (copyout(p, (void *)(hcp[cnt].hce_path),
860 861 len)) {
861 862 error = EFAULT;
862 863 goto done;
863 864 }
864 865 }
865 866
866 867 cnt++;
867 868 if (cnt > n_max)
868 869 too_big = 1;
869 870 }
870 871
871 872 hdp = hdp->hld_next;
872 873 }
873 874
874 875 done:
875 876 hlnode_rele(hp);
876 877 kmem_free(path, MAXPATHLEN);
877 878
878 879 *pcnt = cnt;
879 880 if (error == 0 && too_big == 1)
880 881 error = E2BIG;
881 882
882 883 return (error);
883 884 }
884 885
885 886 /*
886 887 * Return a list of all looped in files in the namespace.
887 888 */
888 889 static int
889 890 hyprlofs_get_all(vnode_t *dvp, intptr_t data, cred_t *cr, caller_context_t *ct,
890 891 int flags)
891 892 {
892 893 int limit, cnt, error;
893 894 model_t model;
894 895 hyprlofs_curr_entry_t *e;
895 896
896 897 model = get_udatamodel();
897 898
898 899 if (model == DATAMODEL_NATIVE) {
899 900 hyprlofs_curr_entries_t ebuf;
900 901
901 902 if (copyin((void *)data, &ebuf, sizeof (ebuf)))
902 903 return (EFAULT);
903 904 limit = ebuf.hce_cnt;
904 905 e = ebuf.hce_entries;
905 906 if (limit > MAX_IOCTL_PARAMS)
906 907 return (EINVAL);
907 908
908 909 } else {
909 910 hyprlofs_curr_entries32_t ebuf32;
910 911
911 912 if (copyin((void *)data, &ebuf32, sizeof (ebuf32)))
912 913 return (EFAULT);
913 914
914 915 limit = ebuf32.hce_cnt;
915 916 e = (hyprlofs_curr_entry_t *)(unsigned long)
916 917 (ebuf32.hce_entries);
917 918 if (limit > MAX_IOCTL_PARAMS)
918 919 return (EINVAL);
919 920 }
920 921
921 922 cnt = 0;
922 923 error = hyprlofs_get_all_entries(dvp, e, "", &cnt, limit, cr, ct,
923 924 flags);
924 925
925 926 if (error == 0 || error == E2BIG) {
926 927 if (model == DATAMODEL_NATIVE) {
927 928 hyprlofs_curr_entries_t ebuf;
928 929
929 930 ebuf.hce_cnt = cnt;
930 931 if (copyout(&ebuf, (void *)data, sizeof (ebuf)))
931 932 return (EFAULT);
932 933
933 934 } else {
934 935 hyprlofs_curr_entries32_t ebuf32;
935 936
936 937 ebuf32.hce_cnt = cnt;
937 938 if (copyout(&ebuf32, (void *)data, sizeof (ebuf32)))
938 939 return (EFAULT);
939 940 }
940 941 }
941 942
942 943 return (error);
943 944 }
944 945
945 946 /* ARGSUSED3 */
946 947 static int
947 948 hyprlofs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
948 949 int flags)
949 950 {
950 951 hlnode_t *parent = (hlnode_t *)VTOHLN(dvp);
951 952 int error;
952 953 hlnode_t *hp = NULL;
953 954
954 955 /* This holds the hp vnode */
955 956 error = hyprlofs_dirlookup(parent, nm, &hp, cr);
956 957 if (error)
957 958 return (error);
958 959
959 960 ASSERT(hp);
960 961 rw_enter(&parent->hln_rwlock, RW_WRITER);
961 962 rw_enter(&hp->hln_rwlock, RW_WRITER);
962 963
963 964 error = hyprlofs_dirdelete(parent, hp, nm, DR_REMOVE, cr);
964 965
965 966 rw_exit(&hp->hln_rwlock);
966 967 rw_exit(&parent->hln_rwlock);
967 968 vnevent_remove(HLNTOV(hp), dvp, nm, ct);
968 969
969 970 /*
970 971 * We've now dropped the dir link so by rele-ing our vnode we should
971 972 * clean up in hyprlofs_inactive.
972 973 */
973 974 hlnode_rele(hp);
974 975
975 976 return (error);
976 977 }
977 978
978 979 /* ARGSUSED4 */
979 980 static int
980 981 hyprlofs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
981 982 caller_context_t *ct, int flags)
982 983 {
983 984 hlnode_t *parent = (hlnode_t *)VTOHLN(dvp);
984 985 hlnode_t *self = NULL;
985 986 vnode_t *vp;
986 987 int error = 0;
987 988
988 989 /* Return error if removing . or .. */
989 990 if (strcmp(nm, ".") == 0)
990 991 return (EINVAL);
991 992 if (strcmp(nm, "..") == 0)
992 993 return (EEXIST); /* Should be ENOTEMPTY */
993 994 error = hyprlofs_dirlookup(parent, nm, &self, cr);
994 995 if (error)
995 996 return (error);
996 997
997 998 rw_enter(&parent->hln_rwlock, RW_WRITER);
998 999 rw_enter(&self->hln_rwlock, RW_WRITER);
999 1000
1000 1001 vp = HLNTOV(self);
1001 1002 if (vp == dvp || vp == cdir) {
1002 1003 error = EINVAL;
1003 1004 goto done1;
1004 1005 }
1005 1006 if (self->hln_type != VDIR) {
1006 1007 error = ENOTDIR;
1007 1008 goto done1;
1008 1009 }
1009 1010
1010 1011 /*
1011 1012 * When a dir is looped in, we only remove the in-memory dir, not the
1012 1013 * backing dir.
1013 1014 */
1014 1015 if (self->hln_looped == 0) {
1015 1016 mutex_enter(&self->hln_tlock);
1016 1017 if (self->hln_nlink > 2) {
1017 1018 mutex_exit(&self->hln_tlock);
1018 1019 error = EEXIST;
1019 1020 goto done1;
1020 1021 }
1021 1022 mutex_exit(&self->hln_tlock);
1022 1023
1023 1024 if (vn_vfswlock(vp)) {
1024 1025 error = EBUSY;
1025 1026 goto done1;
1026 1027 }
1027 1028 if (vn_mountedvfs(vp) != NULL) {
1028 1029 error = EBUSY;
1029 1030 goto done;
1030 1031 }
1031 1032
1032 1033 /*
1033 1034 * Check for an empty directory, i.e. only includes entries for
1034 1035 * "." and ".."
1035 1036 */
1036 1037 if (self->hln_dirents > 2) {
1037 1038 error = EEXIST; /* SIGH should be ENOTEMPTY */
1038 1039 /*
1039 1040 * Update atime because checking hln_dirents is
1040 1041 * equivalent to reading the directory
1041 1042 */
1042 1043 gethrestime(&self->hln_atime);
1043 1044 goto done;
1044 1045 }
1045 1046
1046 1047 error = hyprlofs_dirdelete(parent, self, nm, DR_RMDIR, cr);
1047 1048 } else {
1048 1049 error = hyprlofs_dirdelete(parent, self, nm, DR_REMOVE, cr);
1049 1050 }
1050 1051
1051 1052 done:
1052 1053 if (self->hln_looped == 0)
1053 1054 vn_vfsunlock(vp);
1054 1055 done1:
1055 1056 rw_exit(&self->hln_rwlock);
1056 1057 rw_exit(&parent->hln_rwlock);
1057 1058 vnevent_rmdir(HLNTOV(self), dvp, nm, ct);
1058 1059
1059 1060 /*
1060 1061 * We've now dropped the dir link so by rele-ing our vnode we should
1061 1062 * clean up in hyprlofs_inactive.
1062 1063 */
1063 1064 hlnode_rele(self);
1064 1065
1065 1066 return (error);
1066 1067 }
1067 1068
1068 1069 static int
1069 1070 hyprlofs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
1070 1071 caller_context_t *ct, int flags)
1071 1072 {
1072 1073 hlnode_t *hp = (hlnode_t *)VTOHLN(vp);
1073 1074 hldirent_t *hdp;
1074 1075 int error = 0;
1075 1076 size_t namelen;
1076 1077 struct dirent64 *dp;
1077 1078 ulong_t offset;
1078 1079 ulong_t total_bytes_wanted;
1079 1080 long outcount = 0;
1080 1081 long bufsize;
1081 1082 int reclen;
1082 1083 caddr_t outbuf;
1083 1084
1084 1085 if (VTOHLN(vp)->hln_looped == 1)
1085 1086 return (VOP_READDIR(REALVP(vp), uiop, cr, eofp, ct, flags));
1086 1087
1087 1088 if (uiop->uio_loffset >= MAXOFF_T) {
1088 1089 if (eofp)
1089 1090 *eofp = 1;
1090 1091 return (0);
1091 1092 }
1092 1093 /* assuming syscall has already called hln_rwlock */
1093 1094 ASSERT(RW_READ_HELD(&hp->hln_rwlock));
1094 1095
1095 1096 if (uiop->uio_iovcnt != 1)
1096 1097 return (EINVAL);
1097 1098
1098 1099 if (vp->v_type != VDIR)
1099 1100 return (ENOTDIR);
1100 1101
1101 1102 /*
1102 1103 * There's a window here where someone could have removed
1103 1104 * all the entries in the directory after we put a hold on the
1104 1105 * vnode but before we grabbed the rwlock. Just return.
1105 1106 */
1106 1107 if (hp->hln_dir == NULL) {
1107 1108 if (hp->hln_nlink) {
1108 1109 panic("empty directory 0x%p", (void *)hp);
1109 1110 /*NOTREACHED*/
1110 1111 }
1111 1112 return (0);
1112 1113 }
1113 1114
1114 1115 /* Get space for multiple dir entries */
1115 1116 total_bytes_wanted = uiop->uio_iov->iov_len;
1116 1117 bufsize = total_bytes_wanted + sizeof (struct dirent64);
1117 1118 outbuf = kmem_alloc(bufsize, KM_SLEEP);
1118 1119
1119 1120 dp = (struct dirent64 *)((uintptr_t)outbuf);
1120 1121
1121 1122 offset = 0;
1122 1123 hdp = hp->hln_dir;
1123 1124 while (hdp) {
1124 1125 namelen = strlen(hdp->hld_name); /* no +1 needed */
1125 1126 offset = hdp->hld_offset;
1126 1127 if (offset >= uiop->uio_offset) {
1127 1128 reclen = (int)DIRENT64_RECLEN(namelen);
1128 1129 if (outcount + reclen > total_bytes_wanted) {
1129 1130 if (!outcount)
1130 1131 /* Buffer too small for any entries. */
1131 1132 error = EINVAL;
1132 1133 break;
1133 1134 }
1134 1135 ASSERT(hdp->hld_hlnode != NULL);
1135 1136
1136 1137 /* zero out uninitialized bytes */
1137 1138 (void) strncpy(dp->d_name, hdp->hld_name,
1138 1139 DIRENT64_NAMELEN(reclen));
1139 1140 dp->d_reclen = (ushort_t)reclen;
1140 1141 dp->d_ino = (ino64_t)hdp->hld_hlnode->hln_nodeid;
1141 1142 dp->d_off = (offset_t)hdp->hld_offset + 1;
1142 1143 dp = (struct dirent64 *)
1143 1144 ((uintptr_t)dp + dp->d_reclen);
1144 1145 outcount += reclen;
1145 1146 ASSERT(outcount <= bufsize);
1146 1147 }
1147 1148 hdp = hdp->hld_next;
1148 1149 }
1149 1150
1150 1151 if (!error)
1151 1152 error = uiomove(outbuf, outcount, UIO_READ, uiop);
1152 1153
1153 1154 if (!error) {
1154 1155 /*
1155 1156 * If we reached the end of the list our offset should now be
1156 1157 * just past the end.
1157 1158 */
1158 1159 if (!hdp) {
1159 1160 offset += 1;
1160 1161 if (eofp)
1161 1162 *eofp = 1;
1162 1163 } else if (eofp)
1163 1164 *eofp = 0;
1164 1165 uiop->uio_offset = offset;
1165 1166 }
1166 1167 gethrestime(&hp->hln_atime);
1167 1168 kmem_free(outbuf, bufsize);
1168 1169 return (error);
1169 1170 }
1170 1171
1171 1172 static int
1172 1173 hyprlofs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1173 1174 {
1174 1175 if (VTOHLN(vp)->hln_looped == 1)
1175 1176 return (VOP_FSYNC(REALVP(vp), syncflag, cr, ct));
1176 1177 return (0);
1177 1178 }
1178 1179
1179 1180 /* ARGSUSED */
1180 1181 static void
1181 1182 hyprlofs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1182 1183 {
1183 1184 hlnode_t *hp = (hlnode_t *)VTOHLN(vp);
1184 1185 hlfsmount_t *hm = (hlfsmount_t *)VFSTOHLM(vp->v_vfsp);
1185 1186
1186 1187 rw_enter(&hp->hln_rwlock, RW_WRITER);
1187 1188
1188 1189 mutex_enter(&hp->hln_tlock);
1189 1190 mutex_enter(&vp->v_lock);
1190 1191 ASSERT(vp->v_count >= 1);
1191 1192
1192 1193 /*
1193 1194 * If we don't have the last hold or the link count is non-zero,
1194 1195 * there's nothing to do except drop our hold.
1195 1196 */
1196 1197 if (vp->v_count > 1 || hp->hln_nlink != 0) {
1197 1198 vp->v_count--;
1198 1199 mutex_exit(&vp->v_lock);
1199 1200 mutex_exit(&hp->hln_tlock);
1200 1201 rw_exit(&hp->hln_rwlock);
1201 1202 return;
1202 1203 }
1203 1204
1204 1205 mutex_exit(&vp->v_lock);
1205 1206 mutex_exit(&hp->hln_tlock);
1206 1207
1207 1208 /* release hold on the real vnode now */
1208 1209 if (hp->hln_looped == 1 && hp->hln_realvp != NULL)
1209 1210 VN_RELE(hp->hln_realvp);
1210 1211
1211 1212 /* Here's our chance to send invalid event while we're between locks */
1212 1213 vn_invalid(HLNTOV(hp));
1213 1214
1214 1215 mutex_enter(&hm->hlm_contents);
1215 1216 if (hp->hln_forw == NULL)
1216 1217 hm->hlm_rootnode->hln_back = hp->hln_back;
1217 1218 else
1218 1219 hp->hln_forw->hln_back = hp->hln_back;
1219 1220 hp->hln_back->hln_forw = hp->hln_forw;
1220 1221 mutex_exit(&hm->hlm_contents);
1221 1222 rw_exit(&hp->hln_rwlock);
1222 1223 rw_destroy(&hp->hln_rwlock);
1223 1224 mutex_destroy(&hp->hln_tlock);
1224 1225 vn_free(HLNTOV(hp));
1225 1226 hyprlofs_memfree(hp, sizeof (hlnode_t));
1226 1227 }
1227 1228
1228 1229 static int
1229 1230 hyprlofs_fid(vnode_t *vp, struct fid *fidp, caller_context_t *ct)
1230 1231 {
1231 1232 hlnode_t *hp = (hlnode_t *)VTOHLN(vp);
1232 1233 hlfid_t *hfid;
1233 1234
1234 1235 if (VTOHLN(vp)->hln_looped == 1)
1235 1236 return (VOP_FID(REALVP(vp), fidp, ct));
1236 1237
1237 1238 if (fidp->fid_len < (sizeof (hlfid_t) - sizeof (ushort_t))) {
1238 1239 fidp->fid_len = sizeof (hlfid_t) - sizeof (ushort_t);
1239 1240 return (ENOSPC);
1240 1241 }
1241 1242
1242 1243 hfid = (hlfid_t *)fidp;
1243 1244 bzero(hfid, sizeof (hlfid_t));
1244 1245 hfid->hlfid_len = (int)sizeof (hlfid_t) - sizeof (ushort_t);
1245 1246
1246 1247 hfid->hlfid_ino = hp->hln_nodeid;
1247 1248 hfid->hlfid_gen = hp->hln_gen;
1248 1249
1249 1250 return (0);
1250 1251 }
1251 1252
1252 1253 static int
1253 1254 hyprlofs_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
1254 1255 page_t *pl[], size_t plsz, struct seg *seg, caddr_t addr, enum seg_rw rw,
1255 1256 cred_t *cr, caller_context_t *ct)
1256 1257 {
1257 1258 ASSERT(VTOHLN(vp)->hln_looped == 1);
1258 1259 return (VOP_GETPAGE(REALVP(vp), off, len, protp, pl, plsz, seg, addr,
1259 1260 rw, cr, ct));
1260 1261 }
1261 1262
1262 1263 int
1263 1264 hyprlofs_putpage(vnode_t *vp, offset_t off, size_t len, int flags,
1264 1265 cred_t *cr, caller_context_t *ct)
1265 1266 {
1266 1267 ASSERT(VTOHLN(vp)->hln_looped == 1);
1267 1268 return (VOP_PUTPAGE(REALVP(vp), off, len, flags, cr, ct));
1268 1269 }
1269 1270
1270 1271 static int
1271 1272 hyprlofs_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
1272 1273 size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
1273 1274 caller_context_t *ct)
1274 1275 {
1275 1276 ASSERT(VTOHLN(vp)->hln_looped == 1);
1276 1277 return (VOP_MAP(REALVP(vp), off, as, addrp, len, prot, maxprot, flags,
1277 1278 cr, ct));
1278 1279 }
1279 1280
1280 1281 static int
1281 1282 hyprlofs_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
1282 1283 size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, cred_t *cr,
1283 1284 caller_context_t *ct)
1284 1285 {
1285 1286 ASSERT(VTOHLN(vp)->hln_looped == 1);
1286 1287 return (VOP_ADDMAP(REALVP(vp), off, as, addr, len, prot, maxprot,
1287 1288 flags, cr, ct));
1288 1289 }
1289 1290
1290 1291 static int
1291 1292 hyprlofs_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
1292 1293 size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
1293 1294 caller_context_t *ct)
1294 1295 {
1295 1296 ASSERT(VTOHLN(vp)->hln_looped == 1);
1296 1297 return (VOP_DELMAP(REALVP(vp), off, as, addr, len, prot, maxprot,
1297 1298 flags, cr, ct));
1298 1299 }
1299 1300
1300 1301 static int
1301 1302 hyprlofs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
1302 1303 offset_t offset, cred_t *cr, caller_context_t *ct)
1303 1304 {
1304 1305 ASSERT(VTOHLN(vp)->hln_looped == 1);
1305 1306 return (VOP_SPACE(REALVP(vp), cmd, bfp, flag, offset, cr, ct));
1306 1307 }
1307 1308
1308 1309 static int
1309 1310 hyprlofs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp,
1310 1311 caller_context_t *ct)
1311 1312 {
1312 1313 if (VTOHLN(vp)->hln_looped == 0)
1313 1314 return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
1314 1315
1315 1316 return (VOP_SEEK(REALVP(vp), ooff, noffp, ct));
1316 1317 }
1317 1318
1318 1319 static int
1319 1320 hyprlofs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1320 1321 {
1321 1322 hlnode_t *hp = VTOHLN(vp);
1322 1323
1323 1324 if (hp->hln_looped == 1)
1324 1325 return (VOP_RWLOCK(REALVP(vp), write_lock, ct));
1325 1326
1326 1327 if (write_lock) {
1327 1328 rw_enter(&hp->hln_rwlock, RW_WRITER);
1328 1329 } else {
1329 1330 rw_enter(&hp->hln_rwlock, RW_READER);
1330 1331 }
1331 1332 return (write_lock);
1332 1333 }
1333 1334
1334 1335 static void
1335 1336 hyprlofs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
1336 1337 {
1337 1338 hlnode_t *hp = VTOHLN(vp);
1338 1339
1339 1340 if (hp->hln_looped == 1) {
1340 1341 VOP_RWUNLOCK(REALVP(vp), write_lock, ct);
1341 1342 return;
1342 1343 }
1343 1344
1344 1345 rw_exit(&hp->hln_rwlock);
1345 1346 }
1346 1347
1347 1348 static int
1348 1349 hyprlofs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
1349 1350 caller_context_t *ct)
1350 1351 {
1351 1352 int error;
1352 1353
1353 1354 if (VTOHLN(vp)->hln_looped == 1)
1354 1355 return (VOP_PATHCONF(REALVP(vp), cmd, valp, cr, ct));
1355 1356
1356 1357 switch (cmd) {
1357 1358 case _PC_XATTR_ENABLED:
1358 1359 case _PC_XATTR_EXISTS:
1359 1360 case _PC_SATTR_ENABLED:
1360 1361 case _PC_SATTR_EXISTS:
1361 1362 error = EINVAL;
1362 1363 break;
1363 1364 case _PC_TIMESTAMP_RESOLUTION:
1364 1365 /* nanosecond timestamp resolution */
1365 1366 *valp = 1L;
1366 1367 error = 0;
1367 1368 break;
1368 1369 default:
1369 1370 error = fs_pathconf(vp, cmd, valp, cr, ct);
1370 1371 }
1371 1372 return (error);
1372 1373 }
1373 1374
1374 1375
1375 1376 struct vnodeops *hyprlofs_vnodeops;
1376 1377
1377 1378 const fs_operation_def_t hyprlofs_vnodeops_template[] = {
1378 1379 VOPNAME_OPEN, { .vop_open = hyprlofs_open },
1379 1380 VOPNAME_CLOSE, { .vop_close = hyprlofs_close },
1380 1381 VOPNAME_READ, { .vop_read = hyprlofs_read },
1381 1382 VOPNAME_WRITE, { .vop_write = hyprlofs_write },
1382 1383 VOPNAME_IOCTL, { .vop_ioctl = hyprlofs_ioctl },
1383 1384 VOPNAME_GETATTR, { .vop_getattr = hyprlofs_getattr },
1384 1385 VOPNAME_SETATTR, { .vop_setattr = hyprlofs_setattr },
1385 1386 VOPNAME_ACCESS, { .vop_access = hyprlofs_access },
1386 1387 VOPNAME_LOOKUP, { .vop_lookup = hyprlofs_lookup },
1387 1388 VOPNAME_CREATE, { .error = fs_error },
1388 1389 VOPNAME_REMOVE, { .vop_remove = hyprlofs_remove },
1389 1390 VOPNAME_LINK, { .error = fs_error },
1390 1391 VOPNAME_RENAME, { .error = fs_error },
1391 1392 VOPNAME_MKDIR, { .error = fs_error },
1392 1393 VOPNAME_RMDIR, { .vop_rmdir = hyprlofs_rmdir },
1393 1394 VOPNAME_READDIR, { .vop_readdir = hyprlofs_readdir },
1394 1395 VOPNAME_SYMLINK, { .error = fs_error },
1395 1396 VOPNAME_READLINK, { .error = fs_error },
1396 1397 VOPNAME_FSYNC, { .vop_fsync = hyprlofs_fsync },
1397 1398 VOPNAME_INACTIVE, { .vop_inactive = hyprlofs_inactive },
1398 1399 VOPNAME_FID, { .vop_fid = hyprlofs_fid },
1399 1400 VOPNAME_RWLOCK, { .vop_rwlock = hyprlofs_rwlock },
1400 1401 VOPNAME_RWUNLOCK, { .vop_rwunlock = hyprlofs_rwunlock },
1401 1402 VOPNAME_SEEK, { .vop_seek = hyprlofs_seek },
1402 1403 VOPNAME_SPACE, { .vop_space = hyprlofs_space },
1403 1404 VOPNAME_GETPAGE, { .vop_getpage = hyprlofs_getpage },
1404 1405 VOPNAME_PUTPAGE, { .vop_putpage = hyprlofs_putpage },
1405 1406 VOPNAME_MAP, { .vop_map = hyprlofs_map },
1406 1407 VOPNAME_ADDMAP, { .vop_addmap = hyprlofs_addmap },
1407 1408 VOPNAME_DELMAP, { .vop_delmap = hyprlofs_delmap },
1408 1409 VOPNAME_PATHCONF, { .vop_pathconf = hyprlofs_pathconf },
1409 1410 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
1410 1411 NULL, NULL
1411 1412 };
↓ open down ↓ |
817 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX