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