1 /* $NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $ */
2
3 /*-
4 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 * 2005 program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * tmpfs vnode interface.
35 */
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/fcntl.h>
41 #include <sys/lockf.h>
42 #include <sys/lock.h>
43 #include <sys/namei.h>
44 #include <sys/priv.h>
45 #include <sys/proc.h>
46 #include <sys/rwlock.h>
47 #include <sys/sched.h>
48 #include <sys/stat.h>
49 #include <sys/sysctl.h>
50 #include <sys/unistd.h>
51 #include <sys/vnode.h>
52
53 #include <vm/vm.h>
54 #include <vm/vm_param.h>
55 #include <vm/vm_object.h>
56
57 #include <fs/tmpfs/tmpfs_vnops.h>
58 #include <fs/tmpfs/tmpfs.h>
59
60 SYSCTL_DECL(_vfs_tmpfs);
61
62 static volatile int tmpfs_rename_restarts;
63 SYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD,
64 __DEVOLATILE(int *, &tmpfs_rename_restarts), 0,
65 "Times rename had to restart due to lock contention");
66
67 static int
68 tmpfs_vn_get_ino_alloc(struct mount *mp, void *arg, int lkflags,
69 struct vnode **rvp)
70 {
71
72 return (tmpfs_alloc_vp(mp, arg, lkflags, rvp));
73 }
74
75 static int
76 tmpfs_lookup1(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp)
77 {
78 struct tmpfs_dirent *de;
79 struct tmpfs_node *dnode, *pnode;
80 struct tmpfs_mount *tm;
81 int error;
82
83 dnode = VP_TO_TMPFS_DIR(dvp);
84 *vpp = NULLVP;
85
86 /* Check accessibility of requested node as a first step. */
87 error = vn_dir_check_exec(dvp, cnp);
88 if (error != 0)
89 goto out;
90
91 /* We cannot be requesting the parent directory of the root node. */
92 MPASS(IMPLIES(dnode->tn_type == VDIR &&
93 dnode->tn_dir.tn_parent == dnode,
94 !(cnp->cn_flags & ISDOTDOT)));
95
96 TMPFS_ASSERT_LOCKED(dnode);
97 if (dnode->tn_dir.tn_parent == NULL) {
98 error = ENOENT;
99 goto out;
100 }
101 if (cnp->cn_flags & ISDOTDOT) {
102 tm = VFS_TO_TMPFS(dvp->v_mount);
103 pnode = dnode->tn_dir.tn_parent;
104 tmpfs_ref_node(pnode);
105 error = vn_vget_ino_gen(dvp, tmpfs_vn_get_ino_alloc,
106 pnode, cnp->cn_lkflags, vpp);
107 tmpfs_free_node(tm, pnode);
108 if (error != 0)
109 goto out;
110 } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
111 VREF(dvp);
112 *vpp = dvp;
113 error = 0;
114 } else {
115 de = tmpfs_dir_lookup(dnode, NULL, cnp);
116 if (de != NULL && de->td_node == NULL)
117 cnp->cn_flags |= ISWHITEOUT;
118 if (de == NULL || de->td_node == NULL) {
119 /*
120 * The entry was not found in the directory.
121 * This is OK if we are creating or renaming an
122 * entry and are working on the last component of
123 * the path name.
124 */
125 if ((cnp->cn_flags & ISLASTCN) &&
126 (cnp->cn_nameiop == CREATE || \
127 cnp->cn_nameiop == RENAME ||
128 (cnp->cn_nameiop == DELETE &&
129 cnp->cn_flags & DOWHITEOUT &&
130 cnp->cn_flags & ISWHITEOUT))) {
131 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
132 cnp->cn_thread);
133 if (error != 0)
134 goto out;
135
136 /*
137 * Keep the component name in the buffer for
138 * future uses.
139 */
140 cnp->cn_flags |= SAVENAME;
141
142 error = EJUSTRETURN;
143 } else
144 error = ENOENT;
145 } else {
146 struct tmpfs_node *tnode;
147
148 /*
149 * The entry was found, so get its associated
150 * tmpfs_node.
151 */
152 tnode = de->td_node;
153
154 /*
155 * If we are not at the last path component and
156 * found a non-directory or non-link entry (which
157 * may itself be pointing to a directory), raise
158 * an error.
159 */
160 if ((tnode->tn_type != VDIR &&
161 tnode->tn_type != VLNK) &&
162 !(cnp->cn_flags & ISLASTCN)) {
163 error = ENOTDIR;
164 goto out;
165 }
166
167 /*
168 * If we are deleting or renaming the entry, keep
169 * track of its tmpfs_dirent so that it can be
170 * easily deleted later.
171 */
172 if ((cnp->cn_flags & ISLASTCN) &&
173 (cnp->cn_nameiop == DELETE ||
174 cnp->cn_nameiop == RENAME)) {
175 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
176 cnp->cn_thread);
177 if (error != 0)
178 goto out;
179
180 /* Allocate a new vnode on the matching entry. */
181 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
182 cnp->cn_lkflags, vpp);
183 if (error != 0)
184 goto out;
185
186 if ((dnode->tn_mode & S_ISTXT) &&
187 VOP_ACCESS(dvp, VADMIN, cnp->cn_cred,
188 cnp->cn_thread) && VOP_ACCESS(*vpp, VADMIN,
189 cnp->cn_cred, cnp->cn_thread)) {
190 error = EPERM;
191 vput(*vpp);
192 *vpp = NULL;
193 goto out;
194 }
195 cnp->cn_flags |= SAVENAME;
196 } else {
197 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
198 cnp->cn_lkflags, vpp);
199 if (error != 0)
200 goto out;
201 }
202 }
203 }
204
205 /*
206 * Store the result of this lookup in the cache. Avoid this if the
207 * request was for creation, as it does not improve timings on
208 * emprical tests.
209 */
210 if ((cnp->cn_flags & MAKEENTRY) != 0 && tmpfs_use_nc(dvp))
211 cache_enter(dvp, *vpp, cnp);
212
213 out:
214 /*
215 * If there were no errors, *vpp cannot be null and it must be
216 * locked.
217 */
218 MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp)));
219
220 return (error);
221 }
222
223 static int
224 tmpfs_cached_lookup(struct vop_cachedlookup_args *v)
225 {
226
227 return (tmpfs_lookup1(v->a_dvp, v->a_vpp, v->a_cnp));
228 }
229
230 static int
231 tmpfs_lookup(struct vop_lookup_args *v)
232 {
233
234 return (tmpfs_lookup1(v->a_dvp, v->a_vpp, v->a_cnp));
235 }
236
237 static int
238 tmpfs_create(struct vop_create_args *v)
239 {
240 struct vnode *dvp = v->a_dvp;
241 struct vnode **vpp = v->a_vpp;
242 struct componentname *cnp = v->a_cnp;
243 struct vattr *vap = v->a_vap;
244 int error;
245
246 MPASS(vap->va_type == VREG || vap->va_type == VSOCK);
247
248 error = tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
249 if (error == 0 && (cnp->cn_flags & MAKEENTRY) != 0 && tmpfs_use_nc(dvp))
250 cache_enter(dvp, *vpp, cnp);
251 return (error);
252 }
253
254 static int
255 tmpfs_mknod(struct vop_mknod_args *v)
256 {
257 struct vnode *dvp = v->a_dvp;
258 struct vnode **vpp = v->a_vpp;
259 struct componentname *cnp = v->a_cnp;
260 struct vattr *vap = v->a_vap;
261
262 if (vap->va_type != VBLK && vap->va_type != VCHR &&
263 vap->va_type != VFIFO)
264 return EINVAL;
265
266 return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
267 }
268
269 static int
270 tmpfs_open(struct vop_open_args *v)
271 {
272 struct vnode *vp = v->a_vp;
273 int mode = v->a_mode;
274
275 int error;
276 struct tmpfs_node *node;
277
278 MPASS(VOP_ISLOCKED(vp));
279
280 node = VP_TO_TMPFS_NODE(vp);
281
282 /* The file is still active but all its names have been removed
283 * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as
284 * it is about to die. */
285 if (node->tn_links < 1)
286 return (ENOENT);
287
288 /* If the file is marked append-only, deny write requests. */
289 if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
290 error = EPERM;
291 else {
292 error = 0;
293 /* For regular files, the call below is nop. */
294 KASSERT(vp->v_type != VREG || (node->tn_reg.tn_aobj->flags &
295 OBJ_DEAD) == 0, ("dead object"));
296 vnode_create_vobject(vp, node->tn_size, v->a_td);
297 }
298
299 MPASS(VOP_ISLOCKED(vp));
300 return error;
301 }
302
303 static int
304 tmpfs_close(struct vop_close_args *v)
305 {
306 struct vnode *vp = v->a_vp;
307
308 /* Update node times. */
309 tmpfs_update(vp);
310
311 return (0);
312 }
313
314 int
315 tmpfs_access(struct vop_access_args *v)
316 {
317 struct vnode *vp = v->a_vp;
318 accmode_t accmode = v->a_accmode;
319 struct ucred *cred = v->a_cred;
320
321 int error;
322 struct tmpfs_node *node;
323
324 MPASS(VOP_ISLOCKED(vp));
325
326 node = VP_TO_TMPFS_NODE(vp);
327
328 switch (vp->v_type) {
329 case VDIR:
330 /* FALLTHROUGH */
331 case VLNK:
332 /* FALLTHROUGH */
333 case VREG:
334 if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
335 error = EROFS;
336 goto out;
337 }
338 break;
339
340 case VBLK:
341 /* FALLTHROUGH */
342 case VCHR:
343 /* FALLTHROUGH */
344 case VSOCK:
345 /* FALLTHROUGH */
346 case VFIFO:
347 break;
348
349 default:
350 error = EINVAL;
351 goto out;
352 }
353
354 if (accmode & VWRITE && node->tn_flags & IMMUTABLE) {
355 error = EPERM;
356 goto out;
357 }
358
359 error = vaccess(vp->v_type, node->tn_mode, node->tn_uid,
360 node->tn_gid, accmode, cred, NULL);
361
362 out:
363 MPASS(VOP_ISLOCKED(vp));
364
365 return error;
366 }
367
368 int
369 tmpfs_getattr(struct vop_getattr_args *v)
370 {
371 struct vnode *vp = v->a_vp;
372 struct vattr *vap = v->a_vap;
373 vm_object_t obj;
374 struct tmpfs_node *node;
375
376 node = VP_TO_TMPFS_NODE(vp);
377
378 tmpfs_update(vp);
379
380 vap->va_type = vp->v_type;
381 vap->va_mode = node->tn_mode;
382 vap->va_nlink = node->tn_links;
383 vap->va_uid = node->tn_uid;
384 vap->va_gid = node->tn_gid;
385 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
386 vap->va_fileid = node->tn_id;
387 vap->va_size = node->tn_size;
388 vap->va_blocksize = PAGE_SIZE;
389 vap->va_atime = node->tn_atime;
390 vap->va_mtime = node->tn_mtime;
391 vap->va_ctime = node->tn_ctime;
392 vap->va_birthtime = node->tn_birthtime;
393 vap->va_gen = node->tn_gen;
394 vap->va_flags = node->tn_flags;
395 vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
396 node->tn_rdev : NODEV;
397 if (vp->v_type == VREG) {
398 obj = node->tn_reg.tn_aobj;
399 vap->va_bytes = (u_quad_t)obj->resident_page_count * PAGE_SIZE;
400 } else
401 vap->va_bytes = node->tn_size;
402 vap->va_filerev = 0;
403
404 return 0;
405 }
406
407 int
408 tmpfs_setattr(struct vop_setattr_args *v)
409 {
410 struct vnode *vp = v->a_vp;
411 struct vattr *vap = v->a_vap;
412 struct ucred *cred = v->a_cred;
413 struct thread *td = curthread;
414
415 int error;
416
417 MPASS(VOP_ISLOCKED(vp));
418
419 error = 0;
420
421 /* Abort if any unsettable attribute is given. */
422 if (vap->va_type != VNON ||
423 vap->va_nlink != VNOVAL ||
424 vap->va_fsid != VNOVAL ||
425 vap->va_fileid != VNOVAL ||
426 vap->va_blocksize != VNOVAL ||
427 vap->va_gen != VNOVAL ||
428 vap->va_rdev != VNOVAL ||
429 vap->va_bytes != VNOVAL)
430 error = EINVAL;
431
432 if (error == 0 && (vap->va_flags != VNOVAL))
433 error = tmpfs_chflags(vp, vap->va_flags, cred, td);
434
435 if (error == 0 && (vap->va_size != VNOVAL))
436 error = tmpfs_chsize(vp, vap->va_size, cred, td);
437
438 if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
439 error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td);
440
441 if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
442 error = tmpfs_chmod(vp, vap->va_mode, cred, td);
443
444 if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
445 vap->va_atime.tv_nsec != VNOVAL) ||
446 (vap->va_mtime.tv_sec != VNOVAL &&
447 vap->va_mtime.tv_nsec != VNOVAL) ||
448 (vap->va_birthtime.tv_sec != VNOVAL &&
449 vap->va_birthtime.tv_nsec != VNOVAL)))
450 error = tmpfs_chtimes(vp, vap, cred, td);
451
452 /* Update the node times. We give preference to the error codes
453 * generated by this function rather than the ones that may arise
454 * from tmpfs_update. */
455 tmpfs_update(vp);
456
457 MPASS(VOP_ISLOCKED(vp));
458
459 return error;
460 }
461
462 static int
463 tmpfs_read(struct vop_read_args *v)
464 {
465 struct vnode *vp;
466 struct uio *uio;
467 struct tmpfs_node *node;
468
469 vp = v->a_vp;
470 if (vp->v_type != VREG)
471 return (EISDIR);
472 uio = v->a_uio;
473 if (uio->uio_offset < 0)
474 return (EINVAL);
475 node = VP_TO_TMPFS_NODE(vp);
476 tmpfs_set_status(VFS_TO_TMPFS(vp->v_mount), node, TMPFS_NODE_ACCESSED);
477 return (uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio));
478 }
479
480 static int
481 tmpfs_write(struct vop_write_args *v)
482 {
483 struct vnode *vp;
484 struct uio *uio;
485 struct tmpfs_node *node;
486 off_t oldsize;
487 int error, ioflag;
488
489 vp = v->a_vp;
490 uio = v->a_uio;
491 ioflag = v->a_ioflag;
492 error = 0;
493 node = VP_TO_TMPFS_NODE(vp);
494 oldsize = node->tn_size;
495
496 if (uio->uio_offset < 0 || vp->v_type != VREG)
497 return (EINVAL);
498 if (uio->uio_resid == 0)
499 return (0);
500 if (ioflag & IO_APPEND)
501 uio->uio_offset = node->tn_size;
502 if (uio->uio_offset + uio->uio_resid >
503 VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
504 return (EFBIG);
505 if (vn_rlimit_fsize(vp, uio, uio->uio_td))
506 return (EFBIG);
507 if (uio->uio_offset + uio->uio_resid > node->tn_size) {
508 error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid,
509 FALSE);
510 if (error != 0)
511 goto out;
512 }
513
514 error = uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio);
515 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
516 TMPFS_NODE_CHANGED;
517 if (node->tn_mode & (S_ISUID | S_ISGID)) {
518 if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0))
519 node->tn_mode &= ~(S_ISUID | S_ISGID);
520 }
521 if (error != 0)
522 (void)tmpfs_reg_resize(vp, oldsize, TRUE);
523
524 out:
525 MPASS(IMPLIES(error == 0, uio->uio_resid == 0));
526 MPASS(IMPLIES(error != 0, oldsize == node->tn_size));
527
528 return (error);
529 }
530
531 static int
532 tmpfs_fsync(struct vop_fsync_args *v)
533 {
534 struct vnode *vp = v->a_vp;
535
536 MPASS(VOP_ISLOCKED(vp));
537
538 tmpfs_check_mtime(vp);
539 tmpfs_update(vp);
540
541 return 0;
542 }
543
544 static int
545 tmpfs_remove(struct vop_remove_args *v)
546 {
547 struct vnode *dvp = v->a_dvp;
548 struct vnode *vp = v->a_vp;
549
550 int error;
551 struct tmpfs_dirent *de;
552 struct tmpfs_mount *tmp;
553 struct tmpfs_node *dnode;
554 struct tmpfs_node *node;
555
556 MPASS(VOP_ISLOCKED(dvp));
557 MPASS(VOP_ISLOCKED(vp));
558
559 if (vp->v_type == VDIR) {
560 error = EISDIR;
561 goto out;
562 }
563
564 dnode = VP_TO_TMPFS_DIR(dvp);
565 node = VP_TO_TMPFS_NODE(vp);
566 tmp = VFS_TO_TMPFS(vp->v_mount);
567 de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
568 MPASS(de != NULL);
569
570 /* Files marked as immutable or append-only cannot be deleted. */
571 if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
572 (dnode->tn_flags & APPEND)) {
573 error = EPERM;
574 goto out;
575 }
576
577 /* Remove the entry from the directory; as it is a file, we do not
578 * have to change the number of hard links of the directory. */
579 tmpfs_dir_detach(dvp, de);
580 if (v->a_cnp->cn_flags & DOWHITEOUT)
581 tmpfs_dir_whiteout_add(dvp, v->a_cnp);
582
583 /* Free the directory entry we just deleted. Note that the node
584 * referred by it will not be removed until the vnode is really
585 * reclaimed. */
586 tmpfs_free_dirent(tmp, de);
587
588 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED;
589 error = 0;
590
591 out:
592
593 return error;
594 }
595
596 static int
597 tmpfs_link(struct vop_link_args *v)
598 {
599 struct vnode *dvp = v->a_tdvp;
600 struct vnode *vp = v->a_vp;
601 struct componentname *cnp = v->a_cnp;
602
603 int error;
604 struct tmpfs_dirent *de;
605 struct tmpfs_node *node;
606
607 MPASS(VOP_ISLOCKED(dvp));
608 MPASS(cnp->cn_flags & HASBUF);
609 MPASS(dvp != vp); /* XXX When can this be false? */
610 node = VP_TO_TMPFS_NODE(vp);
611
612 /* Ensure that we do not overflow the maximum number of links imposed
613 * by the system. */
614 MPASS(node->tn_links <= LINK_MAX);
615 if (node->tn_links == LINK_MAX) {
616 error = EMLINK;
617 goto out;
618 }
619
620 /* We cannot create links of files marked immutable or append-only. */
621 if (node->tn_flags & (IMMUTABLE | APPEND)) {
622 error = EPERM;
623 goto out;
624 }
625
626 /* Allocate a new directory entry to represent the node. */
627 error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
628 cnp->cn_nameptr, cnp->cn_namelen, &de);
629 if (error != 0)
630 goto out;
631
632 /* Insert the new directory entry into the appropriate directory. */
633 if (cnp->cn_flags & ISWHITEOUT)
634 tmpfs_dir_whiteout_remove(dvp, cnp);
635 tmpfs_dir_attach(dvp, de);
636
637 /* vp link count has changed, so update node times. */
638 node->tn_status |= TMPFS_NODE_CHANGED;
639 tmpfs_update(vp);
640
641 error = 0;
642
643 out:
644 return error;
645 }
646
647 /*
648 * We acquire all but fdvp locks using non-blocking acquisitions. If we
649 * fail to acquire any lock in the path we will drop all held locks,
650 * acquire the new lock in a blocking fashion, and then release it and
651 * restart the rename. This acquire/release step ensures that we do not
652 * spin on a lock waiting for release. On error release all vnode locks
653 * and decrement references the way tmpfs_rename() would do.
654 */
655 static int
656 tmpfs_rename_relock(struct vnode *fdvp, struct vnode **fvpp,
657 struct vnode *tdvp, struct vnode **tvpp,
658 struct componentname *fcnp, struct componentname *tcnp)
659 {
660 struct vnode *nvp;
661 struct mount *mp;
662 struct tmpfs_dirent *de;
663 int error, restarts = 0;
664
665 VOP_UNLOCK(tdvp, 0);
666 if (*tvpp != NULL && *tvpp != tdvp)
667 VOP_UNLOCK(*tvpp, 0);
668 mp = fdvp->v_mount;
669
670 relock:
671 restarts += 1;
672 error = vn_lock(fdvp, LK_EXCLUSIVE);
673 if (error)
674 goto releout;
675 if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
676 VOP_UNLOCK(fdvp, 0);
677 error = vn_lock(tdvp, LK_EXCLUSIVE);
678 if (error)
679 goto releout;
680 VOP_UNLOCK(tdvp, 0);
681 goto relock;
682 }
683 /*
684 * Re-resolve fvp to be certain it still exists and fetch the
685 * correct vnode.
686 */
687 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(fdvp), NULL, fcnp);
688 if (de == NULL) {
689 VOP_UNLOCK(fdvp, 0);
690 VOP_UNLOCK(tdvp, 0);
691 if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
692 (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
693 error = EINVAL;
694 else
695 error = ENOENT;
696 goto releout;
697 }
698 error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE | LK_NOWAIT, &nvp);
699 if (error != 0) {
700 VOP_UNLOCK(fdvp, 0);
701 VOP_UNLOCK(tdvp, 0);
702 if (error != EBUSY)
703 goto releout;
704 error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, &nvp);
705 if (error != 0)
706 goto releout;
707 VOP_UNLOCK(nvp, 0);
708 /*
709 * Concurrent rename race.
710 */
711 if (nvp == tdvp) {
712 vrele(nvp);
713 error = EINVAL;
714 goto releout;
715 }
716 vrele(*fvpp);
717 *fvpp = nvp;
718 goto relock;
719 }
720 vrele(*fvpp);
721 *fvpp = nvp;
722 VOP_UNLOCK(*fvpp, 0);
723 /*
724 * Re-resolve tvp and acquire the vnode lock if present.
725 */
726 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(tdvp), NULL, tcnp);
727 /*
728 * If tvp disappeared we just carry on.
729 */
730 if (de == NULL && *tvpp != NULL) {
731 vrele(*tvpp);
732 *tvpp = NULL;
733 }
734 /*
735 * Get the tvp ino if the lookup succeeded. We may have to restart
736 * if the non-blocking acquire fails.
737 */
738 if (de != NULL) {
739 nvp = NULL;
740 error = tmpfs_alloc_vp(mp, de->td_node,
741 LK_EXCLUSIVE | LK_NOWAIT, &nvp);
742 if (*tvpp != NULL)
743 vrele(*tvpp);
744 *tvpp = nvp;
745 if (error != 0) {
746 VOP_UNLOCK(fdvp, 0);
747 VOP_UNLOCK(tdvp, 0);
748 if (error != EBUSY)
749 goto releout;
750 error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE,
751 &nvp);
752 if (error != 0)
753 goto releout;
754 VOP_UNLOCK(nvp, 0);
755 /*
756 * fdvp contains fvp, thus tvp (=fdvp) is not empty.
757 */
758 if (nvp == fdvp) {
759 error = ENOTEMPTY;
760 goto releout;
761 }
762 goto relock;
763 }
764 }
765 tmpfs_rename_restarts += restarts;
766
767 return (0);
768
769 releout:
770 vrele(fdvp);
771 vrele(*fvpp);
772 vrele(tdvp);
773 if (*tvpp != NULL)
774 vrele(*tvpp);
775 tmpfs_rename_restarts += restarts;
776
777 return (error);
778 }
779
780 static int
781 tmpfs_rename(struct vop_rename_args *v)
782 {
783 struct vnode *fdvp = v->a_fdvp;
784 struct vnode *fvp = v->a_fvp;
785 struct componentname *fcnp = v->a_fcnp;
786 struct vnode *tdvp = v->a_tdvp;
787 struct vnode *tvp = v->a_tvp;
788 struct componentname *tcnp = v->a_tcnp;
789 char *newname;
790 struct tmpfs_dirent *de;
791 struct tmpfs_mount *tmp;
792 struct tmpfs_node *fdnode;
793 struct tmpfs_node *fnode;
794 struct tmpfs_node *tnode;
795 struct tmpfs_node *tdnode;
796 int error;
797
798 MPASS(VOP_ISLOCKED(tdvp));
799 MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp)));
800 MPASS(fcnp->cn_flags & HASBUF);
801 MPASS(tcnp->cn_flags & HASBUF);
802
803 /*
804 * Disallow cross-device renames.
805 * XXX Why isn't this done by the caller?
806 */
807 if (fvp->v_mount != tdvp->v_mount ||
808 (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
809 error = EXDEV;
810 goto out;
811 }
812
813 /* If source and target are the same file, there is nothing to do. */
814 if (fvp == tvp) {
815 error = 0;
816 goto out;
817 }
818
819 /*
820 * If we need to move the directory between entries, lock the
821 * source so that we can safely operate on it.
822 */
823 if (fdvp != tdvp && fdvp != tvp) {
824 if (vn_lock(fdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
825 error = tmpfs_rename_relock(fdvp, &fvp, tdvp, &tvp,
826 fcnp, tcnp);
827 if (error != 0)
828 return (error);
829 ASSERT_VOP_ELOCKED(fdvp,
830 "tmpfs_rename: fdvp not locked");
831 ASSERT_VOP_ELOCKED(tdvp,
832 "tmpfs_rename: tdvp not locked");
833 if (tvp != NULL)
834 ASSERT_VOP_ELOCKED(tvp,
835 "tmpfs_rename: tvp not locked");
836 if (fvp == tvp) {
837 error = 0;
838 goto out_locked;
839 }
840 }
841 }
842
843 tmp = VFS_TO_TMPFS(tdvp->v_mount);
844 tdnode = VP_TO_TMPFS_DIR(tdvp);
845 tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
846 fdnode = VP_TO_TMPFS_DIR(fdvp);
847 fnode = VP_TO_TMPFS_NODE(fvp);
848 de = tmpfs_dir_lookup(fdnode, fnode, fcnp);
849
850 /*
851 * Entry can disappear before we lock fdvp,
852 * also avoid manipulating '.' and '..' entries.
853 */
854 if (de == NULL) {
855 if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
856 (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
857 error = EINVAL;
858 else
859 error = ENOENT;
860 goto out_locked;
861 }
862 MPASS(de->td_node == fnode);
863
864 /*
865 * If re-naming a directory to another preexisting directory
866 * ensure that the target directory is empty so that its
867 * removal causes no side effects.
868 * Kern_rename guarantees the destination to be a directory
869 * if the source is one.
870 */
871 if (tvp != NULL) {
872 MPASS(tnode != NULL);
873
874 if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
875 (tdnode->tn_flags & (APPEND | IMMUTABLE))) {
876 error = EPERM;
877 goto out_locked;
878 }
879
880 if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
881 if (tnode->tn_size > 0) {
882 error = ENOTEMPTY;
883 goto out_locked;
884 }
885 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
886 error = ENOTDIR;
887 goto out_locked;
888 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
889 error = EISDIR;
890 goto out_locked;
891 } else {
892 MPASS(fnode->tn_type != VDIR &&
893 tnode->tn_type != VDIR);
894 }
895 }
896
897 if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))
898 || (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
899 error = EPERM;
900 goto out_locked;
901 }
902
903 /*
904 * Ensure that we have enough memory to hold the new name, if it
905 * has to be changed.
906 */
907 if (fcnp->cn_namelen != tcnp->cn_namelen ||
908 bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
909 newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK);
910 } else
911 newname = NULL;
912
913 /*
914 * If the node is being moved to another directory, we have to do
915 * the move.
916 */
917 if (fdnode != tdnode) {
918 /*
919 * In case we are moving a directory, we have to adjust its
920 * parent to point to the new parent.
921 */
922 if (de->td_node->tn_type == VDIR) {
923 struct tmpfs_node *n;
924
925 /*
926 * Ensure the target directory is not a child of the
927 * directory being moved. Otherwise, we'd end up
928 * with stale nodes.
929 */
930 n = tdnode;
931 /*
932 * TMPFS_LOCK guaranties that no nodes are freed while
933 * traversing the list. Nodes can only be marked as
934 * removed: tn_parent == NULL.
935 */
936 TMPFS_LOCK(tmp);
937 TMPFS_NODE_LOCK(n);
938 while (n != n->tn_dir.tn_parent) {
939 struct tmpfs_node *parent;
940
941 if (n == fnode) {
942 TMPFS_NODE_UNLOCK(n);
943 TMPFS_UNLOCK(tmp);
944 error = EINVAL;
945 if (newname != NULL)
946 free(newname, M_TMPFSNAME);
947 goto out_locked;
948 }
949 parent = n->tn_dir.tn_parent;
950 TMPFS_NODE_UNLOCK(n);
951 if (parent == NULL) {
952 n = NULL;
953 break;
954 }
955 TMPFS_NODE_LOCK(parent);
956 if (parent->tn_dir.tn_parent == NULL) {
957 TMPFS_NODE_UNLOCK(parent);
958 n = NULL;
959 break;
960 }
961 n = parent;
962 }
963 TMPFS_UNLOCK(tmp);
964 if (n == NULL) {
965 error = EINVAL;
966 if (newname != NULL)
967 free(newname, M_TMPFSNAME);
968 goto out_locked;
969 }
970 TMPFS_NODE_UNLOCK(n);
971
972 /* Adjust the parent pointer. */
973 TMPFS_VALIDATE_DIR(fnode);
974 TMPFS_NODE_LOCK(de->td_node);
975 de->td_node->tn_dir.tn_parent = tdnode;
976 TMPFS_NODE_UNLOCK(de->td_node);
977
978 /*
979 * As a result of changing the target of the '..'
980 * entry, the link count of the source and target
981 * directories has to be adjusted.
982 */
983 TMPFS_NODE_LOCK(tdnode);
984 TMPFS_ASSERT_LOCKED(tdnode);
985 tdnode->tn_links++;
986 TMPFS_NODE_UNLOCK(tdnode);
987
988 TMPFS_NODE_LOCK(fdnode);
989 TMPFS_ASSERT_LOCKED(fdnode);
990 fdnode->tn_links--;
991 TMPFS_NODE_UNLOCK(fdnode);
992 }
993 }
994
995 /*
996 * Do the move: just remove the entry from the source directory
997 * and insert it into the target one.
998 */
999 tmpfs_dir_detach(fdvp, de);
1000
1001 if (fcnp->cn_flags & DOWHITEOUT)
1002 tmpfs_dir_whiteout_add(fdvp, fcnp);
1003 if (tcnp->cn_flags & ISWHITEOUT)
1004 tmpfs_dir_whiteout_remove(tdvp, tcnp);
1005
1006 /*
1007 * If the name has changed, we need to make it effective by changing
1008 * it in the directory entry.
1009 */
1010 if (newname != NULL) {
1011 MPASS(tcnp->cn_namelen <= MAXNAMLEN);
1012
1013 free(de->ud.td_name, M_TMPFSNAME);
1014 de->ud.td_name = newname;
1015 tmpfs_dirent_init(de, tcnp->cn_nameptr, tcnp->cn_namelen);
1016
1017 fnode->tn_status |= TMPFS_NODE_CHANGED;
1018 tdnode->tn_status |= TMPFS_NODE_MODIFIED;
1019 }
1020
1021 /*
1022 * If we are overwriting an entry, we have to remove the old one
1023 * from the target directory.
1024 */
1025 if (tvp != NULL) {
1026 struct tmpfs_dirent *tde;
1027
1028 /* Remove the old entry from the target directory. */
1029 tde = tmpfs_dir_lookup(tdnode, tnode, tcnp);
1030 tmpfs_dir_detach(tdvp, tde);
1031
1032 /*
1033 * Free the directory entry we just deleted. Note that the
1034 * node referred by it will not be removed until the vnode is
1035 * really reclaimed.
1036 */
1037 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), tde);
1038 }
1039
1040 tmpfs_dir_attach(tdvp, de);
1041
1042 if (tmpfs_use_nc(fvp)) {
1043 cache_purge(fvp);
1044 if (tvp != NULL)
1045 cache_purge(tvp);
1046 cache_purge_negative(tdvp);
1047 }
1048
1049 error = 0;
1050
1051 out_locked:
1052 if (fdvp != tdvp && fdvp != tvp)
1053 VOP_UNLOCK(fdvp, 0);
1054
1055 out:
1056 /*
1057 * Release target nodes.
1058 * XXX: I don't understand when tdvp can be the same as tvp, but
1059 * other code takes care of this...
1060 */
1061 if (tdvp == tvp)
1062 vrele(tdvp);
1063 else
1064 vput(tdvp);
1065 if (tvp != NULL)
1066 vput(tvp);
1067
1068 /* Release source nodes. */
1069 vrele(fdvp);
1070 vrele(fvp);
1071
1072 return (error);
1073 }
1074
1075 static int
1076 tmpfs_mkdir(struct vop_mkdir_args *v)
1077 {
1078 struct vnode *dvp = v->a_dvp;
1079 struct vnode **vpp = v->a_vpp;
1080 struct componentname *cnp = v->a_cnp;
1081 struct vattr *vap = v->a_vap;
1082
1083 MPASS(vap->va_type == VDIR);
1084
1085 return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
1086 }
1087
1088 static int
1089 tmpfs_rmdir(struct vop_rmdir_args *v)
1090 {
1091 struct vnode *dvp = v->a_dvp;
1092 struct vnode *vp = v->a_vp;
1093
1094 int error;
1095 struct tmpfs_dirent *de;
1096 struct tmpfs_mount *tmp;
1097 struct tmpfs_node *dnode;
1098 struct tmpfs_node *node;
1099
1100 MPASS(VOP_ISLOCKED(dvp));
1101 MPASS(VOP_ISLOCKED(vp));
1102
1103 tmp = VFS_TO_TMPFS(dvp->v_mount);
1104 dnode = VP_TO_TMPFS_DIR(dvp);
1105 node = VP_TO_TMPFS_DIR(vp);
1106
1107 /* Directories with more than two entries ('.' and '..') cannot be
1108 * removed. */
1109 if (node->tn_size > 0) {
1110 error = ENOTEMPTY;
1111 goto out;
1112 }
1113
1114 if ((dnode->tn_flags & APPEND)
1115 || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1116 error = EPERM;
1117 goto out;
1118 }
1119
1120 /* This invariant holds only if we are not trying to remove "..".
1121 * We checked for that above so this is safe now. */
1122 MPASS(node->tn_dir.tn_parent == dnode);
1123
1124 /* Get the directory entry associated with node (vp). This was
1125 * filled by tmpfs_lookup while looking up the entry. */
1126 de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
1127 MPASS(TMPFS_DIRENT_MATCHES(de,
1128 v->a_cnp->cn_nameptr,
1129 v->a_cnp->cn_namelen));
1130
1131 /* Check flags to see if we are allowed to remove the directory. */
1132 if ((dnode->tn_flags & APPEND) != 0 ||
1133 (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) != 0) {
1134 error = EPERM;
1135 goto out;
1136 }
1137
1138
1139 /* Detach the directory entry from the directory (dnode). */
1140 tmpfs_dir_detach(dvp, de);
1141 if (v->a_cnp->cn_flags & DOWHITEOUT)
1142 tmpfs_dir_whiteout_add(dvp, v->a_cnp);
1143
1144 /* No vnode should be allocated for this entry from this point */
1145 TMPFS_NODE_LOCK(node);
1146 node->tn_links--;
1147 node->tn_dir.tn_parent = NULL;
1148 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
1149 TMPFS_NODE_MODIFIED;
1150
1151 TMPFS_NODE_UNLOCK(node);
1152
1153 TMPFS_NODE_LOCK(dnode);
1154 dnode->tn_links--;
1155 dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
1156 TMPFS_NODE_MODIFIED;
1157 TMPFS_NODE_UNLOCK(dnode);
1158
1159 if (tmpfs_use_nc(dvp)) {
1160 cache_purge(dvp);
1161 cache_purge(vp);
1162 }
1163
1164 /* Free the directory entry we just deleted. Note that the node
1165 * referred by it will not be removed until the vnode is really
1166 * reclaimed. */
1167 tmpfs_free_dirent(tmp, de);
1168
1169 /* Release the deleted vnode (will destroy the node, notify
1170 * interested parties and clean it from the cache). */
1171
1172 dnode->tn_status |= TMPFS_NODE_CHANGED;
1173 tmpfs_update(dvp);
1174
1175 error = 0;
1176
1177 out:
1178 return error;
1179 }
1180
1181 static int
1182 tmpfs_symlink(struct vop_symlink_args *v)
1183 {
1184 struct vnode *dvp = v->a_dvp;
1185 struct vnode **vpp = v->a_vpp;
1186 struct componentname *cnp = v->a_cnp;
1187 struct vattr *vap = v->a_vap;
1188 char *target = v->a_target;
1189
1190 #ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */
1191 MPASS(vap->va_type == VLNK);
1192 #else
1193 vap->va_type = VLNK;
1194 #endif
1195
1196 return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
1197 }
1198
1199 static int
1200 tmpfs_readdir(struct vop_readdir_args *va)
1201 {
1202 struct vnode *vp;
1203 struct uio *uio;
1204 struct tmpfs_mount *tm;
1205 struct tmpfs_node *node;
1206 u_long **cookies;
1207 int *eofflag, *ncookies;
1208 ssize_t startresid;
1209 int error, maxcookies;
1210
1211 vp = va->a_vp;
1212 uio = va->a_uio;
1213 eofflag = va->a_eofflag;
1214 cookies = va->a_cookies;
1215 ncookies = va->a_ncookies;
1216
1217 /* This operation only makes sense on directory nodes. */
1218 if (vp->v_type != VDIR)
1219 return ENOTDIR;
1220
1221 maxcookies = 0;
1222 node = VP_TO_TMPFS_DIR(vp);
1223 tm = VFS_TO_TMPFS(vp->v_mount);
1224
1225 startresid = uio->uio_resid;
1226
1227 /* Allocate cookies for NFS and compat modules. */
1228 if (cookies != NULL && ncookies != NULL) {
1229 maxcookies = howmany(node->tn_size,
1230 sizeof(struct tmpfs_dirent)) + 2;
1231 *cookies = malloc(maxcookies * sizeof(**cookies), M_TEMP,
1232 M_WAITOK);
1233 *ncookies = 0;
1234 }
1235
1236 if (cookies == NULL)
1237 error = tmpfs_dir_getdents(tm, node, uio, 0, NULL, NULL);
1238 else
1239 error = tmpfs_dir_getdents(tm, node, uio, maxcookies, *cookies,
1240 ncookies);
1241
1242 /* Buffer was filled without hitting EOF. */
1243 if (error == EJUSTRETURN)
1244 error = (uio->uio_resid != startresid) ? 0 : EINVAL;
1245
1246 if (error != 0 && cookies != NULL && ncookies != NULL) {
1247 free(*cookies, M_TEMP);
1248 *cookies = NULL;
1249 *ncookies = 0;
1250 }
1251
1252 if (eofflag != NULL)
1253 *eofflag =
1254 (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
1255
1256 return error;
1257 }
1258
1259 static int
1260 tmpfs_readlink(struct vop_readlink_args *v)
1261 {
1262 struct vnode *vp = v->a_vp;
1263 struct uio *uio = v->a_uio;
1264
1265 int error;
1266 struct tmpfs_node *node;
1267
1268 MPASS(uio->uio_offset == 0);
1269 MPASS(vp->v_type == VLNK);
1270
1271 node = VP_TO_TMPFS_NODE(vp);
1272
1273 error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
1274 uio);
1275 tmpfs_set_status(VFS_TO_TMPFS(vp->v_mount), node, TMPFS_NODE_ACCESSED);
1276
1277 return (error);
1278 }
1279
1280 static int
1281 tmpfs_inactive(struct vop_inactive_args *v)
1282 {
1283 struct vnode *vp;
1284 struct tmpfs_node *node;
1285
1286 vp = v->a_vp;
1287 node = VP_TO_TMPFS_NODE(vp);
1288 if (node->tn_links == 0)
1289 vrecycle(vp);
1290 else
1291 tmpfs_check_mtime(vp);
1292 return (0);
1293 }
1294
1295 int
1296 tmpfs_reclaim(struct vop_reclaim_args *v)
1297 {
1298 struct vnode *vp = v->a_vp;
1299
1300 struct tmpfs_mount *tmp;
1301 struct tmpfs_node *node;
1302
1303 node = VP_TO_TMPFS_NODE(vp);
1304 tmp = VFS_TO_TMPFS(vp->v_mount);
1305
1306 if (vp->v_type == VREG)
1307 tmpfs_destroy_vobject(vp, node->tn_reg.tn_aobj);
1308 else
1309 vnode_destroy_vobject(vp);
1310 vp->v_object = NULL;
1311 if (tmpfs_use_nc(vp))
1312 cache_purge(vp);
1313
1314 TMPFS_NODE_LOCK(node);
1315 tmpfs_free_vp(vp);
1316
1317 /* If the node referenced by this vnode was deleted by the user,
1318 * we must free its associated data structures (now that the vnode
1319 * is being reclaimed). */
1320 if (node->tn_links == 0 &&
1321 (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0) {
1322 node->tn_vpstate = TMPFS_VNODE_DOOMED;
1323 TMPFS_NODE_UNLOCK(node);
1324 tmpfs_free_node(tmp, node);
1325 } else
1326 TMPFS_NODE_UNLOCK(node);
1327
1328 MPASS(vp->v_data == NULL);
1329 return 0;
1330 }
1331
1332 int
1333 tmpfs_print(struct vop_print_args *v)
1334 {
1335 struct vnode *vp = v->a_vp;
1336
1337 struct tmpfs_node *node;
1338
1339 node = VP_TO_TMPFS_NODE(vp);
1340
1341 printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%lx, links %jd\n",
1342 node, node->tn_flags, (uintmax_t)node->tn_links);
1343 printf("\tmode 0%o, owner %d, group %d, size %jd, status 0x%x\n",
1344 node->tn_mode, node->tn_uid, node->tn_gid,
1345 (intmax_t)node->tn_size, node->tn_status);
1346
1347 if (vp->v_type == VFIFO)
1348 fifo_printinfo(vp);
1349
1350 printf("\n");
1351
1352 return 0;
1353 }
1354
1355 int
1356 tmpfs_pathconf(struct vop_pathconf_args *v)
1357 {
1358 struct vnode *vp = v->a_vp;
1359 int name = v->a_name;
1360 register_t *retval = v->a_retval;
1361
1362 int error;
1363
1364 error = 0;
1365
1366 switch (name) {
1367 case _PC_LINK_MAX:
1368 *retval = LINK_MAX;
1369 break;
1370
1371 case _PC_NAME_MAX:
1372 *retval = NAME_MAX;
1373 break;
1374
1375 case _PC_PIPE_BUF:
1376 if (vp->v_type == VDIR || vp->v_type == VFIFO)
1377 *retval = PIPE_BUF;
1378 else
1379 error = EINVAL;
1380 break;
1381
1382 case _PC_CHOWN_RESTRICTED:
1383 *retval = 1;
1384 break;
1385
1386 case _PC_NO_TRUNC:
1387 *retval = 1;
1388 break;
1389
1390 case _PC_SYNC_IO:
1391 *retval = 1;
1392 break;
1393
1394 case _PC_FILESIZEBITS:
1395 *retval = 64;
1396 break;
1397
1398 default:
1399 error = vop_stdpathconf(v);
1400 }
1401
1402 return error;
1403 }
1404
1405 static int
1406 tmpfs_vptofh(struct vop_vptofh_args *ap)
1407 {
1408 struct tmpfs_fid *tfhp;
1409 struct tmpfs_node *node;
1410
1411 tfhp = (struct tmpfs_fid *)ap->a_fhp;
1412 node = VP_TO_TMPFS_NODE(ap->a_vp);
1413
1414 tfhp->tf_len = sizeof(struct tmpfs_fid);
1415 tfhp->tf_id = node->tn_id;
1416 tfhp->tf_gen = node->tn_gen;
1417
1418 return (0);
1419 }
1420
1421 static int
1422 tmpfs_whiteout(struct vop_whiteout_args *ap)
1423 {
1424 struct vnode *dvp = ap->a_dvp;
1425 struct componentname *cnp = ap->a_cnp;
1426 struct tmpfs_dirent *de;
1427
1428 switch (ap->a_flags) {
1429 case LOOKUP:
1430 return (0);
1431 case CREATE:
1432 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp);
1433 if (de != NULL)
1434 return (de->td_node == NULL ? 0 : EEXIST);
1435 return (tmpfs_dir_whiteout_add(dvp, cnp));
1436 case DELETE:
1437 tmpfs_dir_whiteout_remove(dvp, cnp);
1438 return (0);
1439 default:
1440 panic("tmpfs_whiteout: unknown op");
1441 }
1442 }
1443
1444 static int
1445 tmpfs_vptocnp_dir(struct tmpfs_node *tn, struct tmpfs_node *tnp,
1446 struct tmpfs_dirent **pde)
1447 {
1448 struct tmpfs_dir_cursor dc;
1449 struct tmpfs_dirent *de;
1450
1451 for (de = tmpfs_dir_first(tnp, &dc); de != NULL;
1452 de = tmpfs_dir_next(tnp, &dc)) {
1453 if (de->td_node == tn) {
1454 *pde = de;
1455 return (0);
1456 }
1457 }
1458 return (ENOENT);
1459 }
1460
1461 static int
1462 tmpfs_vptocnp_fill(struct vnode *vp, struct tmpfs_node *tn,
1463 struct tmpfs_node *tnp, char *buf, int *buflen, struct vnode **dvp)
1464 {
1465 struct tmpfs_dirent *de;
1466 int error, i;
1467
1468 error = vn_vget_ino_gen(vp, tmpfs_vn_get_ino_alloc, tnp, LK_SHARED,
1469 dvp);
1470 if (error != 0)
1471 return (error);
1472 error = tmpfs_vptocnp_dir(tn, tnp, &de);
1473 if (error == 0) {
1474 i = *buflen;
1475 i -= de->td_namelen;
1476 if (i < 0) {
1477 error = ENOMEM;
1478 } else {
1479 bcopy(de->ud.td_name, buf + i, de->td_namelen);
1480 *buflen = i;
1481 }
1482 }
1483 if (error == 0) {
1484 if (vp != *dvp)
1485 VOP_UNLOCK(*dvp, 0);
1486 } else {
1487 if (vp != *dvp)
1488 vput(*dvp);
1489 else
1490 vrele(vp);
1491 }
1492 return (error);
1493 }
1494
1495 static int
1496 tmpfs_vptocnp(struct vop_vptocnp_args *ap)
1497 {
1498 struct vnode *vp, **dvp;
1499 struct tmpfs_node *tn, *tnp, *tnp1;
1500 struct tmpfs_dirent *de;
1501 struct tmpfs_mount *tm;
1502 char *buf;
1503 int *buflen;
1504 int error;
1505
1506 vp = ap->a_vp;
1507 dvp = ap->a_vpp;
1508 buf = ap->a_buf;
1509 buflen = ap->a_buflen;
1510
1511 tm = VFS_TO_TMPFS(vp->v_mount);
1512 tn = VP_TO_TMPFS_NODE(vp);
1513 if (tn->tn_type == VDIR) {
1514 tnp = tn->tn_dir.tn_parent;
1515 if (tnp == NULL)
1516 return (ENOENT);
1517 tmpfs_ref_node(tnp);
1518 error = tmpfs_vptocnp_fill(vp, tn, tn->tn_dir.tn_parent, buf,
1519 buflen, dvp);
1520 tmpfs_free_node(tm, tnp);
1521 return (error);
1522 }
1523 restart:
1524 TMPFS_LOCK(tm);
1525 LIST_FOREACH_SAFE(tnp, &tm->tm_nodes_used, tn_entries, tnp1) {
1526 if (tnp->tn_type != VDIR)
1527 continue;
1528 TMPFS_NODE_LOCK(tnp);
1529 tmpfs_ref_node_locked(tnp);
1530
1531 /*
1532 * tn_vnode cannot be instantiated while we hold the
1533 * node lock, so the directory cannot be changed while
1534 * we iterate over it. Do this to avoid instantiating
1535 * vnode for directories which cannot point to our
1536 * node.
1537 */
1538 error = tnp->tn_vnode == NULL ? tmpfs_vptocnp_dir(tn, tnp,
1539 &de) : 0;
1540
1541 if (error == 0) {
1542 TMPFS_NODE_UNLOCK(tnp);
1543 TMPFS_UNLOCK(tm);
1544 error = tmpfs_vptocnp_fill(vp, tn, tnp, buf, buflen,
1545 dvp);
1546 if (error == 0) {
1547 tmpfs_free_node(tm, tnp);
1548 return (0);
1549 }
1550 if ((vp->v_iflag & VI_DOOMED) != 0) {
1551 tmpfs_free_node(tm, tnp);
1552 return (ENOENT);
1553 }
1554 TMPFS_LOCK(tm);
1555 TMPFS_NODE_LOCK(tnp);
1556 }
1557 if (tmpfs_free_node_locked(tm, tnp, false)) {
1558 goto restart;
1559 } else {
1560 KASSERT(tnp->tn_refcount > 0,
1561 ("node %p refcount zero", tnp));
1562 tnp1 = LIST_NEXT(tnp, tn_entries);
1563 TMPFS_NODE_UNLOCK(tnp);
1564 }
1565 }
1566 TMPFS_UNLOCK(tm);
1567 return (ENOENT);
1568 }
1569
1570 /*
1571 * Vnode operations vector used for files stored in a tmpfs file system.
1572 */
1573 struct vop_vector tmpfs_vnodeop_entries = {
1574 .vop_default = &default_vnodeops,
1575 .vop_lookup = vfs_cache_lookup,
1576 .vop_cachedlookup = tmpfs_cached_lookup,
1577 .vop_create = tmpfs_create,
1578 .vop_mknod = tmpfs_mknod,
1579 .vop_open = tmpfs_open,
1580 .vop_close = tmpfs_close,
1581 .vop_access = tmpfs_access,
1582 .vop_getattr = tmpfs_getattr,
1583 .vop_setattr = tmpfs_setattr,
1584 .vop_read = tmpfs_read,
1585 .vop_write = tmpfs_write,
1586 .vop_fsync = tmpfs_fsync,
1587 .vop_remove = tmpfs_remove,
1588 .vop_link = tmpfs_link,
1589 .vop_rename = tmpfs_rename,
1590 .vop_mkdir = tmpfs_mkdir,
1591 .vop_rmdir = tmpfs_rmdir,
1592 .vop_symlink = tmpfs_symlink,
1593 .vop_readdir = tmpfs_readdir,
1594 .vop_readlink = tmpfs_readlink,
1595 .vop_inactive = tmpfs_inactive,
1596 .vop_reclaim = tmpfs_reclaim,
1597 .vop_print = tmpfs_print,
1598 .vop_pathconf = tmpfs_pathconf,
1599 .vop_vptofh = tmpfs_vptofh,
1600 .vop_whiteout = tmpfs_whiteout,
1601 .vop_bmap = VOP_EOPNOTSUPP,
1602 .vop_vptocnp = tmpfs_vptocnp,
1603 };
1604
1605 /*
1606 * Same vector for mounts which do not use namecache.
1607 */
1608 struct vop_vector tmpfs_vnodeop_nonc_entries = {
1609 .vop_default = &tmpfs_vnodeop_entries,
1610 .vop_lookup = tmpfs_lookup,
1611 };
Cache object: 65170cfe93989e17586b912b03c21c23
|