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