]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/fs/tmpfs/tmpfs_vnops.c
MFC r228796:
[FreeBSD/stable/8.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  * 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/namei.h>
43 #include <sys/priv.h>
44 #include <sys/proc.h>
45 #include <sys/sched.h>
46 #include <sys/sf_buf.h>
47 #include <sys/stat.h>
48 #include <sys/systm.h>
49 #include <sys/unistd.h>
50 #include <sys/vnode.h>
51
52 #include <vm/vm.h>
53 #include <vm/vm_object.h>
54 #include <vm/vm_page.h>
55 #include <vm/vm_pager.h>
56
57 #include <machine/_inttypes.h>
58
59 #include <fs/fifofs/fifo.h>
60 #include <fs/tmpfs/tmpfs_vnops.h>
61 #include <fs/tmpfs/tmpfs.h>
62
63 /* --------------------------------------------------------------------- */
64
65 static int
66 tmpfs_lookup(struct vop_cachedlookup_args *v)
67 {
68         struct vnode *dvp = v->a_dvp;
69         struct vnode **vpp = v->a_vpp;
70         struct componentname *cnp = v->a_cnp;
71
72         int error;
73         struct tmpfs_dirent *de;
74         struct tmpfs_node *dnode;
75
76         dnode = VP_TO_TMPFS_DIR(dvp);
77         *vpp = NULLVP;
78
79         /* Check accessibility of requested node as a first step. */
80         error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_thread);
81         if (error != 0)
82                 goto out;
83
84         /* We cannot be requesting the parent directory of the root node. */
85         MPASS(IMPLIES(dnode->tn_type == VDIR &&
86             dnode->tn_dir.tn_parent == dnode,
87             !(cnp->cn_flags & ISDOTDOT)));
88
89         if (cnp->cn_flags & ISDOTDOT) {
90                 int ltype = 0;
91
92                 ltype = VOP_ISLOCKED(dvp);
93                 vhold(dvp);
94                 VOP_UNLOCK(dvp, 0);
95                 /* Allocate a new vnode on the matching entry. */
96                 error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent,
97                     cnp->cn_lkflags, vpp);
98
99                 vn_lock(dvp, ltype | LK_RETRY);
100                 vdrop(dvp);
101         } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
102                 VREF(dvp);
103                 *vpp = dvp;
104                 error = 0;
105         } else {
106                 de = tmpfs_dir_lookup(dnode, NULL, cnp);
107                 if (de != NULL && de->td_node == NULL)
108                         cnp->cn_flags |= ISWHITEOUT;
109                 if (de == NULL || de->td_node == NULL) {
110                         /* The entry was not found in the directory.
111                          * This is OK if we are creating or renaming an
112                          * entry and are working on the last component of
113                          * the path name. */
114                         if ((cnp->cn_flags & ISLASTCN) &&
115                             (cnp->cn_nameiop == CREATE || \
116                             cnp->cn_nameiop == RENAME ||
117                             (cnp->cn_nameiop == DELETE &&
118                             cnp->cn_flags & DOWHITEOUT &&
119                             cnp->cn_flags & ISWHITEOUT))) {
120                                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
121                                     cnp->cn_thread);
122                                 if (error != 0)
123                                         goto out;
124
125                                 /* Keep the component name in the buffer for
126                                  * future uses. */
127                                 cnp->cn_flags |= SAVENAME;
128
129                                 error = EJUSTRETURN;
130                         } else
131                                 error = ENOENT;
132                 } else {
133                         struct tmpfs_node *tnode;
134
135                         /* The entry was found, so get its associated
136                          * tmpfs_node. */
137                         tnode = de->td_node;
138
139                         /* If we are not at the last path component and
140                          * found a non-directory or non-link entry (which
141                          * may itself be pointing to a directory), raise
142                          * an error. */
143                         if ((tnode->tn_type != VDIR &&
144                             tnode->tn_type != VLNK) &&
145                             !(cnp->cn_flags & ISLASTCN)) {
146                                 error = ENOTDIR;
147                                 goto out;
148                         }
149
150                         /* If we are deleting or renaming the entry, keep
151                          * track of its tmpfs_dirent so that it can be
152                          * easily deleted later. */
153                         if ((cnp->cn_flags & ISLASTCN) &&
154                             (cnp->cn_nameiop == DELETE ||
155                             cnp->cn_nameiop == RENAME)) {
156                                 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
157                                     cnp->cn_thread);
158                                 if (error != 0)
159                                         goto out;
160
161                                 /* Allocate a new vnode on the matching entry. */
162                                 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
163                                                 cnp->cn_lkflags, vpp);
164                                 if (error != 0)
165                                         goto out;
166
167                                 if ((dnode->tn_mode & S_ISTXT) &&
168                                   VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, cnp->cn_thread) &&
169                                   VOP_ACCESS(*vpp, VADMIN, cnp->cn_cred, cnp->cn_thread)) {
170                                         error = EPERM;
171                                         vput(*vpp);
172                                         *vpp = NULL;
173                                         goto out;
174                                 }
175                                 cnp->cn_flags |= SAVENAME;
176                         } else {
177                                 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
178                                                 cnp->cn_lkflags, vpp);
179                         }
180                 }
181         }
182
183         /* Store the result of this lookup in the cache.  Avoid this if the
184          * request was for creation, as it does not improve timings on
185          * emprical tests. */
186         if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE)
187                 cache_enter(dvp, *vpp, cnp);
188
189 out:
190         /* If there were no errors, *vpp cannot be null and it must be
191          * locked. */
192         MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp)));
193
194         return error;
195 }
196
197 /* --------------------------------------------------------------------- */
198
199 static int
200 tmpfs_create(struct vop_create_args *v)
201 {
202         struct vnode *dvp = v->a_dvp;
203         struct vnode **vpp = v->a_vpp;
204         struct componentname *cnp = v->a_cnp;
205         struct vattr *vap = v->a_vap;
206
207         MPASS(vap->va_type == VREG || vap->va_type == VSOCK);
208
209         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
210 }
211 /* --------------------------------------------------------------------- */
212
213 static int
214 tmpfs_mknod(struct vop_mknod_args *v)
215 {
216         struct vnode *dvp = v->a_dvp;
217         struct vnode **vpp = v->a_vpp;
218         struct componentname *cnp = v->a_cnp;
219         struct vattr *vap = v->a_vap;
220
221         if (vap->va_type != VBLK && vap->va_type != VCHR &&
222             vap->va_type != VFIFO)
223                 return EINVAL;
224
225         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
226 }
227
228 /* --------------------------------------------------------------------- */
229
230 static int
231 tmpfs_open(struct vop_open_args *v)
232 {
233         struct vnode *vp = v->a_vp;
234         int mode = v->a_mode;
235
236         int error;
237         struct tmpfs_node *node;
238
239         MPASS(VOP_ISLOCKED(vp));
240
241         node = VP_TO_TMPFS_NODE(vp);
242
243         /* The file is still active but all its names have been removed
244          * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
245          * it is about to die. */
246         if (node->tn_links < 1)
247                 return (ENOENT);
248
249         /* If the file is marked append-only, deny write requests. */
250         if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
251                 error = EPERM;
252         else {
253                 error = 0;
254                 vnode_create_vobject(vp, node->tn_size, v->a_td);
255         }
256
257         MPASS(VOP_ISLOCKED(vp));
258         return error;
259 }
260
261 /* --------------------------------------------------------------------- */
262
263 static int
264 tmpfs_close(struct vop_close_args *v)
265 {
266         struct vnode *vp = v->a_vp;
267
268         struct tmpfs_node *node;
269
270         MPASS(VOP_ISLOCKED(vp));
271
272         node = VP_TO_TMPFS_NODE(vp);
273
274         if (node->tn_links > 0) {
275                 /* Update node times.  No need to do it if the node has
276                  * been deleted, because it will vanish after we return. */
277                 tmpfs_update(vp);
278         }
279
280         return 0;
281 }
282
283 /* --------------------------------------------------------------------- */
284
285 int
286 tmpfs_access(struct vop_access_args *v)
287 {
288         struct vnode *vp = v->a_vp;
289         accmode_t accmode = v->a_accmode;
290         struct ucred *cred = v->a_cred;
291
292         int error;
293         struct tmpfs_node *node;
294
295         MPASS(VOP_ISLOCKED(vp));
296
297         node = VP_TO_TMPFS_NODE(vp);
298
299         switch (vp->v_type) {
300         case VDIR:
301                 /* FALLTHROUGH */
302         case VLNK:
303                 /* FALLTHROUGH */
304         case VREG:
305                 if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
306                         error = EROFS;
307                         goto out;
308                 }
309                 break;
310
311         case VBLK:
312                 /* FALLTHROUGH */
313         case VCHR:
314                 /* FALLTHROUGH */
315         case VSOCK:
316                 /* FALLTHROUGH */
317         case VFIFO:
318                 break;
319
320         default:
321                 error = EINVAL;
322                 goto out;
323         }
324
325         if (accmode & VWRITE && node->tn_flags & IMMUTABLE) {
326                 error = EPERM;
327                 goto out;
328         }
329
330         error = vaccess(vp->v_type, node->tn_mode, node->tn_uid,
331             node->tn_gid, accmode, cred, NULL);
332
333 out:
334         MPASS(VOP_ISLOCKED(vp));
335
336         return error;
337 }
338
339 /* --------------------------------------------------------------------- */
340
341 int
342 tmpfs_getattr(struct vop_getattr_args *v)
343 {
344         struct vnode *vp = v->a_vp;
345         struct vattr *vap = v->a_vap;
346
347         struct tmpfs_node *node;
348
349         node = VP_TO_TMPFS_NODE(vp);
350
351         tmpfs_update(vp);
352
353         vap->va_type = vp->v_type;
354         vap->va_mode = node->tn_mode;
355         vap->va_nlink = node->tn_links;
356         vap->va_uid = node->tn_uid;
357         vap->va_gid = node->tn_gid;
358         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
359         vap->va_fileid = node->tn_id;
360         vap->va_size = node->tn_size;
361         vap->va_blocksize = PAGE_SIZE;
362         vap->va_atime = node->tn_atime;
363         vap->va_mtime = node->tn_mtime;
364         vap->va_ctime = node->tn_ctime;
365         vap->va_birthtime = node->tn_birthtime;
366         vap->va_gen = node->tn_gen;
367         vap->va_flags = node->tn_flags;
368         vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
369                 node->tn_rdev : NODEV;
370         vap->va_bytes = round_page(node->tn_size);
371         vap->va_filerev = 0;
372
373         return 0;
374 }
375
376 /* --------------------------------------------------------------------- */
377
378 /* XXX Should this operation be atomic?  I think it should, but code in
379  * XXX other places (e.g., ufs) doesn't seem to be... */
380 int
381 tmpfs_setattr(struct vop_setattr_args *v)
382 {
383         struct vnode *vp = v->a_vp;
384         struct vattr *vap = v->a_vap;
385         struct ucred *cred = v->a_cred;
386         struct thread *td = curthread;
387
388         int error;
389
390         MPASS(VOP_ISLOCKED(vp));
391
392         error = 0;
393
394         /* Abort if any unsettable attribute is given. */
395         if (vap->va_type != VNON ||
396             vap->va_nlink != VNOVAL ||
397             vap->va_fsid != VNOVAL ||
398             vap->va_fileid != VNOVAL ||
399             vap->va_blocksize != VNOVAL ||
400             vap->va_gen != VNOVAL ||
401             vap->va_rdev != VNOVAL ||
402             vap->va_bytes != VNOVAL)
403                 error = EINVAL;
404
405         if (error == 0 && (vap->va_flags != VNOVAL))
406                 error = tmpfs_chflags(vp, vap->va_flags, cred, td);
407
408         if (error == 0 && (vap->va_size != VNOVAL))
409                 error = tmpfs_chsize(vp, vap->va_size, cred, td);
410
411         if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
412                 error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td);
413
414         if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
415                 error = tmpfs_chmod(vp, vap->va_mode, cred, td);
416
417         if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
418             vap->va_atime.tv_nsec != VNOVAL) ||
419             (vap->va_mtime.tv_sec != VNOVAL &&
420             vap->va_mtime.tv_nsec != VNOVAL) ||
421             (vap->va_birthtime.tv_sec != VNOVAL &&
422             vap->va_birthtime.tv_nsec != VNOVAL)))
423                 error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
424                         &vap->va_birthtime, vap->va_vaflags, cred, td);
425
426         /* Update the node times.  We give preference to the error codes
427          * generated by this function rather than the ones that may arise
428          * from tmpfs_update. */
429         tmpfs_update(vp);
430
431         MPASS(VOP_ISLOCKED(vp));
432
433         return error;
434 }
435
436 /* --------------------------------------------------------------------- */
437 static int
438 tmpfs_nocacheread(vm_object_t tobj, vm_pindex_t idx,
439     vm_offset_t offset, size_t tlen, struct uio *uio)
440 {
441         vm_page_t       m;
442         int             error;
443
444         VM_OBJECT_LOCK(tobj);
445         vm_object_pip_add(tobj, 1);
446         m = vm_page_grab(tobj, idx, VM_ALLOC_WIRED |
447             VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
448         if (m->valid != VM_PAGE_BITS_ALL) {
449                 if (vm_pager_has_page(tobj, idx, NULL, NULL)) {
450                         error = vm_pager_get_pages(tobj, &m, 1, 0);
451                         if (error != 0) {
452                                 printf("tmpfs get pages from pager error [read]\n");
453                                 goto out;
454                         }
455                 } else
456                         vm_page_zero_invalid(m, TRUE);
457         }
458         VM_OBJECT_UNLOCK(tobj);
459         error = uiomove_fromphys(&m, offset, tlen, uio);
460         VM_OBJECT_LOCK(tobj);
461 out:
462         vm_page_lock_queues();
463         vm_page_unwire(m, TRUE);
464         vm_page_unlock_queues();
465         vm_page_wakeup(m);
466         vm_object_pip_subtract(tobj, 1);
467         VM_OBJECT_UNLOCK(tobj);
468
469         return (error);
470 }
471
472 static __inline int
473 tmpfs_nocacheread_buf(vm_object_t tobj, vm_pindex_t idx,
474     vm_offset_t offset, size_t tlen, void *buf)
475 {
476         struct uio uio;
477         struct iovec iov;
478
479         uio.uio_iovcnt = 1;
480         uio.uio_iov = &iov;
481         iov.iov_base = buf;
482         iov.iov_len = tlen;
483
484         uio.uio_offset = 0;
485         uio.uio_resid = tlen;
486         uio.uio_rw = UIO_READ;
487         uio.uio_segflg = UIO_SYSSPACE;
488         uio.uio_td = curthread;
489
490         return (tmpfs_nocacheread(tobj, idx, offset, tlen, &uio));
491 }
492
493 static int
494 tmpfs_mappedread(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio)
495 {
496         struct sf_buf   *sf;
497         vm_pindex_t     idx;
498         vm_page_t       m;
499         vm_offset_t     offset;
500         off_t           addr;
501         size_t          tlen;
502         char            *ma;
503         int             error;
504
505         addr = uio->uio_offset;
506         idx = OFF_TO_IDX(addr);
507         offset = addr & PAGE_MASK;
508         tlen = MIN(PAGE_SIZE - offset, len);
509
510         if ((vobj == NULL) || (vobj->resident_page_count == 0))
511                 goto nocache;
512
513         VM_OBJECT_LOCK(vobj);
514 lookupvpg:
515         if (((m = vm_page_lookup(vobj, idx)) != NULL) &&
516             vm_page_is_valid(m, offset, tlen)) {
517                 if (vm_page_sleep_if_busy(m, FALSE, "tmfsmr"))
518                         goto lookupvpg;
519                 vm_page_busy(m);
520                 VM_OBJECT_UNLOCK(vobj);
521                 error = uiomove_fromphys(&m, offset, tlen, uio);
522                 VM_OBJECT_LOCK(vobj);
523                 vm_page_wakeup(m);
524                 VM_OBJECT_UNLOCK(vobj);
525                 return  (error);
526         } else if (m != NULL && uio->uio_segflg == UIO_NOCOPY) {
527                 KASSERT(offset == 0,
528                     ("unexpected offset in tmpfs_mappedread for sendfile"));
529                 if (vm_page_sleep_if_busy(m, FALSE, "tmfsmr"))
530                         goto lookupvpg;
531                 vm_page_busy(m);
532                 VM_OBJECT_UNLOCK(vobj);
533                 sched_pin();
534                 sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
535                 ma = (char *)sf_buf_kva(sf);
536                 error = tmpfs_nocacheread_buf(tobj, idx, 0, tlen, ma);
537                 if (error == 0) {
538                         if (tlen != PAGE_SIZE)
539                                 bzero(ma + tlen, PAGE_SIZE - tlen);
540                         uio->uio_offset += tlen;
541                         uio->uio_resid -= tlen;
542                 }
543                 sf_buf_free(sf);
544                 sched_unpin();
545                 VM_OBJECT_LOCK(vobj);
546                 if (error == 0)
547                         m->valid = VM_PAGE_BITS_ALL;
548                 vm_page_wakeup(m);
549                 VM_OBJECT_UNLOCK(vobj);
550                 return  (error);
551         }
552         VM_OBJECT_UNLOCK(vobj);
553 nocache:
554         error = tmpfs_nocacheread(tobj, idx, offset, tlen, uio);
555
556         return  (error);
557 }
558
559 static int
560 tmpfs_read(struct vop_read_args *v)
561 {
562         struct vnode *vp = v->a_vp;
563         struct uio *uio = v->a_uio;
564
565         struct tmpfs_node *node;
566         vm_object_t uobj;
567         size_t len;
568         int resid;
569
570         int error = 0;
571
572         node = VP_TO_TMPFS_NODE(vp);
573
574         if (vp->v_type != VREG) {
575                 error = EISDIR;
576                 goto out;
577         }
578
579         if (uio->uio_offset < 0) {
580                 error = EINVAL;
581                 goto out;
582         }
583
584         node->tn_status |= TMPFS_NODE_ACCESSED;
585
586         uobj = node->tn_reg.tn_aobj;
587         while ((resid = uio->uio_resid) > 0) {
588                 error = 0;
589                 if (node->tn_size <= uio->uio_offset)
590                         break;
591                 len = MIN(node->tn_size - uio->uio_offset, resid);
592                 if (len == 0)
593                         break;
594                 error = tmpfs_mappedread(vp->v_object, uobj, len, uio);
595                 if ((error != 0) || (resid == uio->uio_resid))
596                         break;
597         }
598
599 out:
600
601         return error;
602 }
603
604 /* --------------------------------------------------------------------- */
605
606 static int
607 tmpfs_mappedwrite(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio)
608 {
609         vm_pindex_t     idx;
610         vm_page_t       vpg, tpg;
611         vm_offset_t     offset;
612         off_t           addr;
613         size_t          tlen;
614         int             error;
615
616         error = 0;
617         
618         addr = uio->uio_offset;
619         idx = OFF_TO_IDX(addr);
620         offset = addr & PAGE_MASK;
621         tlen = MIN(PAGE_SIZE - offset, len);
622
623         if ((vobj == NULL) || (vobj->resident_page_count == 0)) {
624                 vpg = NULL;
625                 goto nocache;
626         }
627
628         VM_OBJECT_LOCK(vobj);
629 lookupvpg:
630         if (((vpg = vm_page_lookup(vobj, idx)) != NULL) &&
631             vm_page_is_valid(vpg, offset, tlen)) {
632                 if (vm_page_sleep_if_busy(vpg, FALSE, "tmfsmw"))
633                         goto lookupvpg;
634                 vm_page_busy(vpg);
635                 vm_page_lock_queues();
636                 vm_page_undirty(vpg);
637                 vm_page_unlock_queues();
638                 VM_OBJECT_UNLOCK(vobj);
639                 error = uiomove_fromphys(&vpg, offset, tlen, uio);
640         } else {
641                 VM_OBJECT_UNLOCK(vobj);
642                 vpg = NULL;
643         }
644 nocache:
645         VM_OBJECT_LOCK(tobj);
646         vm_object_pip_add(tobj, 1);
647         tpg = vm_page_grab(tobj, idx, VM_ALLOC_WIRED |
648             VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
649         if (tpg->valid != VM_PAGE_BITS_ALL) {
650                 if (vm_pager_has_page(tobj, idx, NULL, NULL)) {
651                         error = vm_pager_get_pages(tobj, &tpg, 1, 0);
652                         if (error != 0) {
653                                 printf("tmpfs get pages from pager error [write]\n");
654                                 goto out;
655                         }
656                 } else
657                         vm_page_zero_invalid(tpg, TRUE);
658         }
659         VM_OBJECT_UNLOCK(tobj);
660         if (vpg == NULL)
661                 error = uiomove_fromphys(&tpg, offset, tlen, uio);
662         else {
663                 KASSERT(vpg->valid == VM_PAGE_BITS_ALL, ("parts of vpg invalid"));
664                 pmap_copy_page(vpg, tpg);
665         }
666         VM_OBJECT_LOCK(tobj);
667 out:
668         if (vobj != NULL)
669                 VM_OBJECT_LOCK(vobj);
670         vm_page_lock_queues();
671         if (error == 0) {
672                 KASSERT(tpg->valid == VM_PAGE_BITS_ALL,
673                     ("parts of tpg invalid"));
674                 vm_page_dirty(tpg);
675         }
676         vm_page_unwire(tpg, TRUE);
677         vm_page_unlock_queues();
678         vm_page_wakeup(tpg);
679         if (vpg != NULL)
680                 vm_page_wakeup(vpg);
681         if (vobj != NULL)
682                 VM_OBJECT_UNLOCK(vobj);
683         vm_object_pip_subtract(tobj, 1);
684         VM_OBJECT_UNLOCK(tobj);
685
686         return  (error);
687 }
688
689 static int
690 tmpfs_write(struct vop_write_args *v)
691 {
692         struct vnode *vp = v->a_vp;
693         struct uio *uio = v->a_uio;
694         int ioflag = v->a_ioflag;
695         struct thread *td = uio->uio_td;
696
697         boolean_t extended;
698         int error = 0;
699         off_t oldsize;
700         struct tmpfs_node *node;
701         vm_object_t uobj;
702         size_t len;
703         int resid;
704
705         node = VP_TO_TMPFS_NODE(vp);
706         oldsize = node->tn_size;
707
708         if (uio->uio_offset < 0 || vp->v_type != VREG) {
709                 error = EINVAL;
710                 goto out;
711         }
712
713         if (uio->uio_resid == 0) {
714                 error = 0;
715                 goto out;
716         }
717
718         if (ioflag & IO_APPEND)
719                 uio->uio_offset = node->tn_size;
720
721         if (uio->uio_offset + uio->uio_resid >
722           VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
723                 return (EFBIG);
724
725         if (vn_rlimit_fsize(vp, uio, td))
726                 return (EFBIG);
727
728         extended = uio->uio_offset + uio->uio_resid > node->tn_size;
729         if (extended) {
730                 error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid);
731                 if (error != 0)
732                         goto out;
733         }
734
735         uobj = node->tn_reg.tn_aobj;
736         while ((resid = uio->uio_resid) > 0) {
737                 if (node->tn_size <= uio->uio_offset)
738                         break;
739                 len = MIN(node->tn_size - uio->uio_offset, resid);
740                 if (len == 0)
741                         break;
742                 error = tmpfs_mappedwrite(vp->v_object, uobj, len, uio);
743                 if ((error != 0) || (resid == uio->uio_resid))
744                         break;
745         }
746
747         node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
748             (extended ? TMPFS_NODE_CHANGED : 0);
749
750         if (node->tn_mode & (S_ISUID | S_ISGID)) {
751                 if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0))
752                         node->tn_mode &= ~(S_ISUID | S_ISGID);
753         }
754
755         if (error != 0)
756                 (void)tmpfs_reg_resize(vp, oldsize);
757
758 out:
759         MPASS(IMPLIES(error == 0, uio->uio_resid == 0));
760         MPASS(IMPLIES(error != 0, oldsize == node->tn_size));
761
762         return error;
763 }
764
765 /* --------------------------------------------------------------------- */
766
767 static int
768 tmpfs_fsync(struct vop_fsync_args *v)
769 {
770         struct vnode *vp = v->a_vp;
771
772         MPASS(VOP_ISLOCKED(vp));
773
774         tmpfs_update(vp);
775
776         return 0;
777 }
778
779 /* --------------------------------------------------------------------- */
780
781 static int
782 tmpfs_remove(struct vop_remove_args *v)
783 {
784         struct vnode *dvp = v->a_dvp;
785         struct vnode *vp = v->a_vp;
786
787         int error;
788         struct tmpfs_dirent *de;
789         struct tmpfs_mount *tmp;
790         struct tmpfs_node *dnode;
791         struct tmpfs_node *node;
792
793         MPASS(VOP_ISLOCKED(dvp));
794         MPASS(VOP_ISLOCKED(vp));
795
796         if (vp->v_type == VDIR) {
797                 error = EISDIR;
798                 goto out;
799         }
800
801         dnode = VP_TO_TMPFS_DIR(dvp);
802         node = VP_TO_TMPFS_NODE(vp);
803         tmp = VFS_TO_TMPFS(vp->v_mount);
804         de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
805         MPASS(de != NULL);
806
807         /* Files marked as immutable or append-only cannot be deleted. */
808         if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
809             (dnode->tn_flags & APPEND)) {
810                 error = EPERM;
811                 goto out;
812         }
813
814         /* Remove the entry from the directory; as it is a file, we do not
815          * have to change the number of hard links of the directory. */
816         tmpfs_dir_detach(dvp, de);
817         if (v->a_cnp->cn_flags & DOWHITEOUT)
818                 tmpfs_dir_whiteout_add(dvp, v->a_cnp);
819
820         /* Free the directory entry we just deleted.  Note that the node
821          * referred by it will not be removed until the vnode is really
822          * reclaimed. */
823         tmpfs_free_dirent(tmp, de, TRUE);
824
825         if (node->tn_links > 0)
826                 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED;
827         error = 0;
828
829 out:
830
831         return error;
832 }
833
834 /* --------------------------------------------------------------------- */
835
836 static int
837 tmpfs_link(struct vop_link_args *v)
838 {
839         struct vnode *dvp = v->a_tdvp;
840         struct vnode *vp = v->a_vp;
841         struct componentname *cnp = v->a_cnp;
842
843         int error;
844         struct tmpfs_dirent *de;
845         struct tmpfs_node *node;
846
847         MPASS(VOP_ISLOCKED(dvp));
848         MPASS(cnp->cn_flags & HASBUF);
849         MPASS(dvp != vp); /* XXX When can this be false? */
850
851         node = VP_TO_TMPFS_NODE(vp);
852
853         /* XXX: Why aren't the following two tests done by the caller? */
854
855         /* Hard links of directories are forbidden. */
856         if (vp->v_type == VDIR) {
857                 error = EPERM;
858                 goto out;
859         }
860
861         /* Cannot create cross-device links. */
862         if (dvp->v_mount != vp->v_mount) {
863                 error = EXDEV;
864                 goto out;
865         }
866
867         /* Ensure that we do not overflow the maximum number of links imposed
868          * by the system. */
869         MPASS(node->tn_links <= LINK_MAX);
870         if (node->tn_links == LINK_MAX) {
871                 error = EMLINK;
872                 goto out;
873         }
874
875         /* We cannot create links of files marked immutable or append-only. */
876         if (node->tn_flags & (IMMUTABLE | APPEND)) {
877                 error = EPERM;
878                 goto out;
879         }
880
881         /* Allocate a new directory entry to represent the node. */
882         error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
883             cnp->cn_nameptr, cnp->cn_namelen, &de);
884         if (error != 0)
885                 goto out;
886
887         /* Insert the new directory entry into the appropriate directory. */
888         if (cnp->cn_flags & ISWHITEOUT)
889                 tmpfs_dir_whiteout_remove(dvp, cnp);
890         tmpfs_dir_attach(dvp, de);
891
892         /* vp link count has changed, so update node times. */
893         node->tn_status |= TMPFS_NODE_CHANGED;
894         tmpfs_update(vp);
895
896         error = 0;
897
898 out:
899         return error;
900 }
901
902 /* --------------------------------------------------------------------- */
903
904 static int
905 tmpfs_rename(struct vop_rename_args *v)
906 {
907         struct vnode *fdvp = v->a_fdvp;
908         struct vnode *fvp = v->a_fvp;
909         struct componentname *fcnp = v->a_fcnp;
910         struct vnode *tdvp = v->a_tdvp;
911         struct vnode *tvp = v->a_tvp;
912         struct componentname *tcnp = v->a_tcnp;
913
914         char *newname;
915         int error;
916         struct tmpfs_dirent *de;
917         struct tmpfs_node *fdnode;
918         struct tmpfs_node *fnode;
919         struct tmpfs_node *tnode;
920         struct tmpfs_node *tdnode;
921
922         MPASS(VOP_ISLOCKED(tdvp));
923         MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp)));
924         MPASS(fcnp->cn_flags & HASBUF);
925         MPASS(tcnp->cn_flags & HASBUF);
926
927         tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
928
929         /* Disallow cross-device renames.
930          * XXX Why isn't this done by the caller? */
931         if (fvp->v_mount != tdvp->v_mount ||
932             (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
933                 error = EXDEV;
934                 goto out;
935         }
936
937         tdnode = VP_TO_TMPFS_DIR(tdvp);
938
939         /* If source and target are the same file, there is nothing to do. */
940         if (fvp == tvp) {
941                 error = 0;
942                 goto out;
943         }
944
945         /* If we need to move the directory between entries, lock the
946          * source so that we can safely operate on it. */
947         if (tdvp != fdvp) {
948                 error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
949                 if (error != 0)
950                         goto out;
951         }
952         fdnode = VP_TO_TMPFS_DIR(fdvp);
953         fnode = VP_TO_TMPFS_NODE(fvp);
954         de = tmpfs_dir_lookup(fdnode, fnode, fcnp);
955
956         /* Entry can disappear before we lock fdvp,
957          * also avoid manipulating '.' and '..' entries. */
958         if (de == NULL) {
959                 if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
960                     (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
961                         error = EINVAL;
962                 else
963                         error = ENOENT;
964                 goto out_locked;
965         }
966         MPASS(de->td_node == fnode);
967
968         /* If re-naming a directory to another preexisting directory
969          * ensure that the target directory is empty so that its
970          * removal causes no side effects.
971          * Kern_rename gurantees the destination to be a directory
972          * if the source is one. */
973         if (tvp != NULL) {
974                 MPASS(tnode != NULL);
975
976                 if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
977                     (tdnode->tn_flags & (APPEND | IMMUTABLE))) {
978                         error = EPERM;
979                         goto out_locked;
980                 }
981
982                 if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
983                         if (tnode->tn_size > 0) {
984                                 error = ENOTEMPTY;
985                                 goto out_locked;
986                         }
987                 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
988                         error = ENOTDIR;
989                         goto out_locked;
990                 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
991                         error = EISDIR;
992                         goto out_locked;
993                 } else {
994                         MPASS(fnode->tn_type != VDIR &&
995                                 tnode->tn_type != VDIR);
996                 }
997         }
998
999         if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))
1000             || (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
1001                 error = EPERM;
1002                 goto out_locked;
1003         }
1004
1005         /* Ensure that we have enough memory to hold the new name, if it
1006          * has to be changed. */
1007         if (fcnp->cn_namelen != tcnp->cn_namelen ||
1008             bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
1009                 newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK);
1010         } else
1011                 newname = NULL;
1012
1013         /* If the node is being moved to another directory, we have to do
1014          * the move. */
1015         if (fdnode != tdnode) {
1016                 /* In case we are moving a directory, we have to adjust its
1017                  * parent to point to the new parent. */
1018                 if (de->td_node->tn_type == VDIR) {
1019                         struct tmpfs_node *n;
1020
1021                         /* Ensure the target directory is not a child of the
1022                          * directory being moved.  Otherwise, we'd end up
1023                          * with stale nodes. */
1024                         n = tdnode;
1025                         while (n != n->tn_dir.tn_parent) {
1026                                 if (n == fnode) {
1027                                         error = EINVAL;
1028                                         if (newname != NULL)
1029                                                     free(newname, M_TMPFSNAME);
1030                                         goto out_locked;
1031                                 }
1032                                 n = n->tn_dir.tn_parent;
1033                         }
1034
1035                         /* Adjust the parent pointer. */
1036                         TMPFS_VALIDATE_DIR(fnode);
1037                         de->td_node->tn_dir.tn_parent = tdnode;
1038
1039                         /* As a result of changing the target of the '..'
1040                          * entry, the link count of the source and target
1041                          * directories has to be adjusted. */
1042                         fdnode->tn_links--;
1043                         tdnode->tn_links++;
1044                 }
1045
1046                 /* Do the move: just remove the entry from the source directory
1047                  * and insert it into the target one. */
1048                 tmpfs_dir_detach(fdvp, de);
1049                 if (fcnp->cn_flags & DOWHITEOUT)
1050                         tmpfs_dir_whiteout_add(fdvp, fcnp);
1051                 if (tcnp->cn_flags & ISWHITEOUT)
1052                         tmpfs_dir_whiteout_remove(tdvp, tcnp);
1053                 tmpfs_dir_attach(tdvp, de);
1054         }
1055
1056         /* If the name has changed, we need to make it effective by changing
1057          * it in the directory entry. */
1058         if (newname != NULL) {
1059                 MPASS(tcnp->cn_namelen <= MAXNAMLEN);
1060
1061                 free(de->td_name, M_TMPFSNAME);
1062                 de->td_namelen = (uint16_t)tcnp->cn_namelen;
1063                 memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen);
1064                 de->td_name = newname;
1065
1066                 fnode->tn_status |= TMPFS_NODE_CHANGED;
1067                 tdnode->tn_status |= TMPFS_NODE_MODIFIED;
1068         }
1069
1070         /* If we are overwriting an entry, we have to remove the old one
1071          * from the target directory. */
1072         if (tvp != NULL) {
1073                 /* Remove the old entry from the target directory. */
1074                 de = tmpfs_dir_lookup(tdnode, tnode, tcnp);
1075                 tmpfs_dir_detach(tdvp, de);
1076
1077                 /* Free the directory entry we just deleted.  Note that the
1078                  * node referred by it will not be removed until the vnode is
1079                  * really reclaimed. */
1080                 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE);
1081         }
1082         cache_purge(fvp);
1083
1084         error = 0;
1085
1086 out_locked:
1087         if (fdnode != tdnode)
1088                 VOP_UNLOCK(fdvp, 0);
1089
1090 out:
1091         /* Release target nodes. */
1092         /* XXX: I don't understand when tdvp can be the same as tvp, but
1093          * other code takes care of this... */
1094         if (tdvp == tvp)
1095                 vrele(tdvp);
1096         else
1097                 vput(tdvp);
1098         if (tvp != NULL)
1099                 vput(tvp);
1100
1101         /* Release source nodes. */
1102         vrele(fdvp);
1103         vrele(fvp);
1104
1105         return error;
1106 }
1107
1108 /* --------------------------------------------------------------------- */
1109
1110 static int
1111 tmpfs_mkdir(struct vop_mkdir_args *v)
1112 {
1113         struct vnode *dvp = v->a_dvp;
1114         struct vnode **vpp = v->a_vpp;
1115         struct componentname *cnp = v->a_cnp;
1116         struct vattr *vap = v->a_vap;
1117
1118         MPASS(vap->va_type == VDIR);
1119
1120         return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
1121 }
1122
1123 /* --------------------------------------------------------------------- */
1124
1125 static int
1126 tmpfs_rmdir(struct vop_rmdir_args *v)
1127 {
1128         struct vnode *dvp = v->a_dvp;
1129         struct vnode *vp = v->a_vp;
1130
1131         int error;
1132         struct tmpfs_dirent *de;
1133         struct tmpfs_mount *tmp;
1134         struct tmpfs_node *dnode;
1135         struct tmpfs_node *node;
1136
1137         MPASS(VOP_ISLOCKED(dvp));
1138         MPASS(VOP_ISLOCKED(vp));
1139
1140         tmp = VFS_TO_TMPFS(dvp->v_mount);
1141         dnode = VP_TO_TMPFS_DIR(dvp);
1142         node = VP_TO_TMPFS_DIR(vp);
1143
1144         /* Directories with more than two entries ('.' and '..') cannot be
1145          * removed. */
1146          if (node->tn_size > 0) {
1147                  error = ENOTEMPTY;
1148                  goto out;
1149          }
1150
1151         if ((dnode->tn_flags & APPEND)
1152             || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1153                 error = EPERM;
1154                 goto out;
1155         }
1156
1157         /* This invariant holds only if we are not trying to remove "..".
1158           * We checked for that above so this is safe now. */
1159         MPASS(node->tn_dir.tn_parent == dnode);
1160
1161         /* Get the directory entry associated with node (vp).  This was
1162          * filled by tmpfs_lookup while looking up the entry. */
1163         de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
1164         MPASS(TMPFS_DIRENT_MATCHES(de,
1165             v->a_cnp->cn_nameptr,
1166             v->a_cnp->cn_namelen));
1167
1168         /* Check flags to see if we are allowed to remove the directory. */
1169         if (dnode->tn_flags & APPEND
1170                 || node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) {
1171                 error = EPERM;
1172                 goto out;
1173         }
1174
1175         /* Detach the directory entry from the directory (dnode). */
1176         tmpfs_dir_detach(dvp, de);
1177         if (v->a_cnp->cn_flags & DOWHITEOUT)
1178                 tmpfs_dir_whiteout_add(dvp, v->a_cnp);
1179
1180         node->tn_links--;
1181         node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
1182             TMPFS_NODE_MODIFIED;
1183         node->tn_dir.tn_parent->tn_links--;
1184         node->tn_dir.tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \
1185             TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
1186
1187         cache_purge(dvp);
1188         cache_purge(vp);
1189
1190         /* Free the directory entry we just deleted.  Note that the node
1191          * referred by it will not be removed until the vnode is really
1192          * reclaimed. */
1193         tmpfs_free_dirent(tmp, de, TRUE);
1194
1195         /* Release the deleted vnode (will destroy the node, notify
1196          * interested parties and clean it from the cache). */
1197
1198         dnode->tn_status |= TMPFS_NODE_CHANGED;
1199         tmpfs_update(dvp);
1200
1201         error = 0;
1202
1203 out:
1204         return error;
1205 }
1206
1207 /* --------------------------------------------------------------------- */
1208
1209 static int
1210 tmpfs_symlink(struct vop_symlink_args *v)
1211 {
1212         struct vnode *dvp = v->a_dvp;
1213         struct vnode **vpp = v->a_vpp;
1214         struct componentname *cnp = v->a_cnp;
1215         struct vattr *vap = v->a_vap;
1216         char *target = v->a_target;
1217
1218 #ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */
1219         MPASS(vap->va_type == VLNK);
1220 #else
1221         vap->va_type = VLNK;
1222 #endif
1223
1224         return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
1225 }
1226
1227 /* --------------------------------------------------------------------- */
1228
1229 static int
1230 tmpfs_readdir(struct vop_readdir_args *v)
1231 {
1232         struct vnode *vp = v->a_vp;
1233         struct uio *uio = v->a_uio;
1234         int *eofflag = v->a_eofflag;
1235         u_long **cookies = v->a_cookies;
1236         int *ncookies = v->a_ncookies;
1237
1238         int error;
1239         off_t startoff;
1240         off_t cnt = 0;
1241         struct tmpfs_node *node;
1242
1243         /* This operation only makes sense on directory nodes. */
1244         if (vp->v_type != VDIR)
1245                 return ENOTDIR;
1246
1247         node = VP_TO_TMPFS_DIR(vp);
1248
1249         startoff = uio->uio_offset;
1250
1251         if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
1252                 error = tmpfs_dir_getdotdent(node, uio);
1253                 if (error != 0)
1254                         goto outok;
1255                 cnt++;
1256         }
1257
1258         if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
1259                 error = tmpfs_dir_getdotdotdent(node, uio);
1260                 if (error != 0)
1261                         goto outok;
1262                 cnt++;
1263         }
1264
1265         error = tmpfs_dir_getdents(node, uio, &cnt);
1266
1267 outok:
1268         MPASS(error >= -1);
1269
1270         if (error == -1)
1271                 error = (cnt != 0) ? 0 : EINVAL;
1272
1273         if (eofflag != NULL)
1274                 *eofflag =
1275                     (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
1276
1277         /* Update NFS-related variables. */
1278         if (error == 0 && cookies != NULL && ncookies != NULL) {
1279                 off_t i;
1280                 off_t off = startoff;
1281                 struct tmpfs_dirent *de = NULL;
1282
1283                 *ncookies = cnt;
1284                 *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);
1285
1286                 for (i = 0; i < cnt; i++) {
1287                         MPASS(off != TMPFS_DIRCOOKIE_EOF);
1288                         if (off == TMPFS_DIRCOOKIE_DOT) {
1289                                 off = TMPFS_DIRCOOKIE_DOTDOT;
1290                         } else {
1291                                 if (off == TMPFS_DIRCOOKIE_DOTDOT) {
1292                                         de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
1293                                 } else if (de != NULL) {
1294                                         de = TAILQ_NEXT(de, td_entries);
1295                                 } else {
1296                                         de = tmpfs_dir_lookupbycookie(node,
1297                                             off);
1298                                         MPASS(de != NULL);
1299                                         de = TAILQ_NEXT(de, td_entries);
1300                                 }
1301                                 if (de == NULL)
1302                                         off = TMPFS_DIRCOOKIE_EOF;
1303                                 else
1304                                         off = tmpfs_dircookie(de);
1305                         }
1306
1307                         (*cookies)[i] = off;
1308                 }
1309                 MPASS(uio->uio_offset == off);
1310         }
1311
1312         return error;
1313 }
1314
1315 /* --------------------------------------------------------------------- */
1316
1317 static int
1318 tmpfs_readlink(struct vop_readlink_args *v)
1319 {
1320         struct vnode *vp = v->a_vp;
1321         struct uio *uio = v->a_uio;
1322
1323         int error;
1324         struct tmpfs_node *node;
1325
1326         MPASS(uio->uio_offset == 0);
1327         MPASS(vp->v_type == VLNK);
1328
1329         node = VP_TO_TMPFS_NODE(vp);
1330
1331         error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
1332             uio);
1333         node->tn_status |= TMPFS_NODE_ACCESSED;
1334
1335         return error;
1336 }
1337
1338 /* --------------------------------------------------------------------- */
1339
1340 static int
1341 tmpfs_inactive(struct vop_inactive_args *v)
1342 {
1343         struct vnode *vp = v->a_vp;
1344         struct thread *l = v->a_td;
1345
1346         struct tmpfs_node *node;
1347
1348         MPASS(VOP_ISLOCKED(vp));
1349
1350         node = VP_TO_TMPFS_NODE(vp);
1351
1352         if (node->tn_links == 0)
1353                 vrecycle(vp, l);
1354
1355         return 0;
1356 }
1357
1358 /* --------------------------------------------------------------------- */
1359
1360 int
1361 tmpfs_reclaim(struct vop_reclaim_args *v)
1362 {
1363         struct vnode *vp = v->a_vp;
1364
1365         struct tmpfs_mount *tmp;
1366         struct tmpfs_node *node;
1367
1368         node = VP_TO_TMPFS_NODE(vp);
1369         tmp = VFS_TO_TMPFS(vp->v_mount);
1370
1371         vnode_destroy_vobject(vp);
1372         cache_purge(vp);
1373         tmpfs_free_vp(vp);
1374
1375         /* If the node referenced by this vnode was deleted by the user,
1376          * we must free its associated data structures (now that the vnode
1377          * is being reclaimed). */
1378         if (node->tn_links == 0)
1379                 tmpfs_free_node(tmp, node);
1380
1381         MPASS(vp->v_data == NULL);
1382         return 0;
1383 }
1384
1385 /* --------------------------------------------------------------------- */
1386
1387 static int
1388 tmpfs_print(struct vop_print_args *v)
1389 {
1390         struct vnode *vp = v->a_vp;
1391
1392         struct tmpfs_node *node;
1393
1394         node = VP_TO_TMPFS_NODE(vp);
1395
1396         printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n",
1397             node, node->tn_flags, node->tn_links);
1398         printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX
1399             ", status 0x%x\n",
1400             node->tn_mode, node->tn_uid, node->tn_gid,
1401             (uintmax_t)node->tn_size, node->tn_status);
1402
1403         if (vp->v_type == VFIFO)
1404                 fifo_printinfo(vp);
1405
1406         printf("\n");
1407
1408         return 0;
1409 }
1410
1411 /* --------------------------------------------------------------------- */
1412
1413 static int
1414 tmpfs_pathconf(struct vop_pathconf_args *v)
1415 {
1416         int name = v->a_name;
1417         register_t *retval = v->a_retval;
1418
1419         int error;
1420
1421         error = 0;
1422
1423         switch (name) {
1424         case _PC_LINK_MAX:
1425                 *retval = LINK_MAX;
1426                 break;
1427
1428         case _PC_NAME_MAX:
1429                 *retval = NAME_MAX;
1430                 break;
1431
1432         case _PC_PATH_MAX:
1433                 *retval = PATH_MAX;
1434                 break;
1435
1436         case _PC_PIPE_BUF:
1437                 *retval = PIPE_BUF;
1438                 break;
1439
1440         case _PC_CHOWN_RESTRICTED:
1441                 *retval = 1;
1442                 break;
1443
1444         case _PC_NO_TRUNC:
1445                 *retval = 1;
1446                 break;
1447
1448         case _PC_SYNC_IO:
1449                 *retval = 1;
1450                 break;
1451
1452         case _PC_FILESIZEBITS:
1453                 *retval = 0; /* XXX Don't know which value should I return. */
1454                 break;
1455
1456         default:
1457                 error = EINVAL;
1458         }
1459
1460         return error;
1461 }
1462
1463 static int
1464 tmpfs_vptofh(struct vop_vptofh_args *ap)
1465 {
1466         struct tmpfs_fid *tfhp;
1467         struct tmpfs_node *node;
1468
1469         tfhp = (struct tmpfs_fid *)ap->a_fhp;
1470         node = VP_TO_TMPFS_NODE(ap->a_vp);
1471
1472         tfhp->tf_len = sizeof(struct tmpfs_fid);
1473         tfhp->tf_id = node->tn_id;
1474         tfhp->tf_gen = node->tn_gen;
1475
1476         return (0);
1477 }
1478
1479 static int
1480 tmpfs_whiteout(struct vop_whiteout_args *ap)
1481 {
1482         struct vnode *dvp = ap->a_dvp;
1483         struct componentname *cnp = ap->a_cnp;
1484         struct tmpfs_dirent *de;
1485
1486         switch (ap->a_flags) {
1487         case LOOKUP:
1488                 return (0);
1489         case CREATE:
1490                 de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp);
1491                 if (de != NULL)
1492                         return (de->td_node == NULL ? 0 : EEXIST);
1493                 return (tmpfs_dir_whiteout_add(dvp, cnp));
1494         case DELETE:
1495                 tmpfs_dir_whiteout_remove(dvp, cnp);
1496                 return (0);
1497         default:
1498                 panic("tmpfs_whiteout: unknown op");
1499         }
1500 }
1501
1502 /* --------------------------------------------------------------------- */
1503
1504 /*
1505  * vnode operations vector used for files stored in a tmpfs file system.
1506  */
1507 struct vop_vector tmpfs_vnodeop_entries = {
1508         .vop_default =                  &default_vnodeops,
1509         .vop_lookup =                   vfs_cache_lookup,
1510         .vop_cachedlookup =             tmpfs_lookup,
1511         .vop_create =                   tmpfs_create,
1512         .vop_mknod =                    tmpfs_mknod,
1513         .vop_open =                     tmpfs_open,
1514         .vop_close =                    tmpfs_close,
1515         .vop_access =                   tmpfs_access,
1516         .vop_getattr =                  tmpfs_getattr,
1517         .vop_setattr =                  tmpfs_setattr,
1518         .vop_read =                     tmpfs_read,
1519         .vop_write =                    tmpfs_write,
1520         .vop_fsync =                    tmpfs_fsync,
1521         .vop_remove =                   tmpfs_remove,
1522         .vop_link =                     tmpfs_link,
1523         .vop_rename =                   tmpfs_rename,
1524         .vop_mkdir =                    tmpfs_mkdir,
1525         .vop_rmdir =                    tmpfs_rmdir,
1526         .vop_symlink =                  tmpfs_symlink,
1527         .vop_readdir =                  tmpfs_readdir,
1528         .vop_readlink =                 tmpfs_readlink,
1529         .vop_inactive =                 tmpfs_inactive,
1530         .vop_reclaim =                  tmpfs_reclaim,
1531         .vop_print =                    tmpfs_print,
1532         .vop_pathconf =                 tmpfs_pathconf,
1533         .vop_vptofh =                   tmpfs_vptofh,
1534         .vop_whiteout =                 tmpfs_whiteout,
1535         .vop_bmap =                     VOP_EOPNOTSUPP,
1536 };
1537