1 /* $NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $ */
4 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
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
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
34 * tmpfs vnode interface.
36 #include <sys/cdefs.h>
38 #include <sys/kernel.h>
39 #include <sys/kern_syscall.h>
40 #include <sys/param.h>
41 #include <sys/fcntl.h>
42 #include <sys/lockf.h>
45 #include <sys/resourcevar.h>
46 #include <sys/sched.h>
47 #include <sys/sfbuf.h>
49 #include <sys/systm.h>
50 #include <sys/unistd.h>
51 #include <sys/vfsops.h>
52 #include <sys/vnode.h>
54 #include <sys/mplock2.h>
57 #include <vm/vm_object.h>
58 #include <vm/vm_page.h>
59 #include <vm/vm_pager.h>
61 #include <vfs/fifofs/fifo.h>
62 #include <vfs/tmpfs/tmpfs_vnops.h>
63 #include <vfs/tmpfs/tmpfs.h>
65 MALLOC_DECLARE(M_TMPFS
);
67 /* --------------------------------------------------------------------- */
70 tmpfs_nresolve(struct vop_nresolve_args
*v
)
72 struct vnode
*dvp
= v
->a_dvp
;
73 struct vnode
*vp
= NULL
;
74 struct namecache
*ncp
= v
->a_nch
->ncp
;
75 struct tmpfs_node
*tnode
;
78 struct tmpfs_dirent
*de
;
79 struct tmpfs_node
*dnode
;
81 dnode
= VP_TO_TMPFS_DIR(dvp
);
83 de
= tmpfs_dir_lookup(dnode
, NULL
, ncp
);
88 * Allocate a vnode for the node we found.
91 error
= tmpfs_alloc_vp(dvp
->v_mount
, tnode
,
92 LK_EXCLUSIVE
| LK_RETRY
, &vp
);
100 * Store the result of this lookup in the cache. Avoid this if the
101 * request was for creation, as it does not improve timings on
106 cache_setvp(v
->a_nch
, vp
);
108 } else if (error
== ENOENT
) {
109 cache_setvp(v
->a_nch
, NULL
);
115 tmpfs_nlookupdotdot(struct vop_nlookupdotdot_args
*v
)
117 struct vnode
*dvp
= v
->a_dvp
;
118 struct vnode
**vpp
= v
->a_vpp
;
119 struct tmpfs_node
*dnode
= VP_TO_TMPFS_NODE(dvp
);
120 struct ucred
*cred
= v
->a_cred
;
124 /* Check accessibility of requested node as a first step. */
125 error
= VOP_ACCESS(dvp
, VEXEC
, cred
);
129 if (dnode
->tn_dir
.tn_parent
!= NULL
) {
130 /* Allocate a new vnode on the matching entry. */
131 error
= tmpfs_alloc_vp(dvp
->v_mount
, dnode
->tn_dir
.tn_parent
,
132 LK_EXCLUSIVE
| LK_RETRY
, vpp
);
138 return (*vpp
== NULL
) ? ENOENT
: 0;
141 /* --------------------------------------------------------------------- */
144 tmpfs_ncreate(struct vop_ncreate_args
*v
)
146 struct vnode
*dvp
= v
->a_dvp
;
147 struct vnode
**vpp
= v
->a_vpp
;
148 struct namecache
*ncp
= v
->a_nch
->ncp
;
149 struct vattr
*vap
= v
->a_vap
;
150 struct ucred
*cred
= v
->a_cred
;
153 KKASSERT(vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
);
155 error
= tmpfs_alloc_file(dvp
, vpp
, vap
, ncp
, cred
, NULL
);
157 cache_setunresolved(v
->a_nch
);
158 cache_setvp(v
->a_nch
, *vpp
);
163 /* --------------------------------------------------------------------- */
166 tmpfs_nmknod(struct vop_nmknod_args
*v
)
168 struct vnode
*dvp
= v
->a_dvp
;
169 struct vnode
**vpp
= v
->a_vpp
;
170 struct namecache
*ncp
= v
->a_nch
->ncp
;
171 struct vattr
*vap
= v
->a_vap
;
172 struct ucred
*cred
= v
->a_cred
;
175 if (vap
->va_type
!= VBLK
&& vap
->va_type
!= VCHR
&&
176 vap
->va_type
!= VFIFO
)
179 error
= tmpfs_alloc_file(dvp
, vpp
, vap
, ncp
, cred
, NULL
);
181 cache_setunresolved(v
->a_nch
);
182 cache_setvp(v
->a_nch
, *vpp
);
188 /* --------------------------------------------------------------------- */
191 tmpfs_open(struct vop_open_args
*v
)
193 struct vnode
*vp
= v
->a_vp
;
194 int mode
= v
->a_mode
;
197 struct tmpfs_node
*node
;
199 node
= VP_TO_TMPFS_NODE(vp
);
201 /* The file is still active but all its names have been removed
202 * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as
203 * it is about to die. */
204 if (node
->tn_links
< 1)
207 /* If the file is marked append-only, deny write requests. */
208 if ((node
->tn_flags
& APPEND
) &&
209 (mode
& (FWRITE
| O_APPEND
)) == FWRITE
) {
212 return (vop_stdopen(v
));
217 /* --------------------------------------------------------------------- */
220 tmpfs_close(struct vop_close_args
*v
)
222 struct vnode
*vp
= v
->a_vp
;
223 struct tmpfs_node
*node
;
225 node
= VP_TO_TMPFS_NODE(vp
);
227 if (node
->tn_links
> 0) {
228 /* Update node times. No need to do it if the node has
229 * been deleted, because it will vanish after we return. */
233 return vop_stdclose(v
);
236 /* --------------------------------------------------------------------- */
239 tmpfs_access(struct vop_access_args
*v
)
241 struct vnode
*vp
= v
->a_vp
;
243 struct tmpfs_node
*node
;
245 node
= VP_TO_TMPFS_NODE(vp
);
247 switch (vp
->v_type
) {
253 if (VWRITE
&& vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
273 if (VWRITE
&& node
->tn_flags
& IMMUTABLE
) {
278 error
= vop_helper_access(v
, node
->tn_uid
, node
->tn_gid
, node
->tn_mode
, 0);
285 /* --------------------------------------------------------------------- */
288 tmpfs_getattr(struct vop_getattr_args
*v
)
290 struct vnode
*vp
= v
->a_vp
;
291 struct vattr
*vap
= v
->a_vap
;
292 struct tmpfs_node
*node
;
294 node
= VP_TO_TMPFS_NODE(vp
);
298 vap
->va_type
= vp
->v_type
;
299 vap
->va_mode
= node
->tn_mode
;
300 vap
->va_nlink
= node
->tn_links
;
301 vap
->va_uid
= node
->tn_uid
;
302 vap
->va_gid
= node
->tn_gid
;
303 vap
->va_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
304 vap
->va_fileid
= node
->tn_id
;
305 vap
->va_size
= node
->tn_size
;
306 vap
->va_blocksize
= PAGE_SIZE
;
307 vap
->va_atime
.tv_sec
= node
->tn_atime
;
308 vap
->va_atime
.tv_nsec
= node
->tn_atimensec
;
309 vap
->va_mtime
.tv_sec
= node
->tn_mtime
;
310 vap
->va_mtime
.tv_nsec
= node
->tn_mtimensec
;
311 vap
->va_ctime
.tv_sec
= node
->tn_ctime
;
312 vap
->va_ctime
.tv_nsec
= node
->tn_ctimensec
;
313 vap
->va_gen
= node
->tn_gen
;
314 vap
->va_flags
= node
->tn_flags
;
315 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
317 vap
->va_rmajor
= umajor(node
->tn_rdev
);
318 vap
->va_rminor
= uminor(node
->tn_rdev
);
320 vap
->va_bytes
= round_page(node
->tn_size
);
326 /* --------------------------------------------------------------------- */
329 tmpfs_setattr(struct vop_setattr_args
*v
)
331 struct vnode
*vp
= v
->a_vp
;
332 struct vattr
*vap
= v
->a_vap
;
333 struct ucred
*cred
= v
->a_cred
;
336 if (error
== 0 && (vap
->va_flags
!= VNOVAL
))
337 error
= tmpfs_chflags(vp
, vap
->va_flags
, cred
);
339 if (error
== 0 && (vap
->va_size
!= VNOVAL
))
340 error
= tmpfs_chsize(vp
, vap
->va_size
, cred
);
342 if (error
== 0 && (vap
->va_uid
!= (uid_t
)VNOVAL
||
343 vap
->va_gid
!= (gid_t
)VNOVAL
)) {
344 error
= tmpfs_chown(vp
, vap
->va_uid
, vap
->va_gid
, cred
);
347 if (error
== 0 && (vap
->va_mode
!= (mode_t
)VNOVAL
))
348 error
= tmpfs_chmod(vp
, vap
->va_mode
, cred
);
350 if (error
== 0 && ((vap
->va_atime
.tv_sec
!= VNOVAL
&&
351 vap
->va_atime
.tv_nsec
!= VNOVAL
) ||
352 (vap
->va_mtime
.tv_sec
!= VNOVAL
&&
353 vap
->va_mtime
.tv_nsec
!= VNOVAL
) )) {
354 error
= tmpfs_chtimes(vp
, &vap
->va_atime
, &vap
->va_mtime
,
355 vap
->va_vaflags
, cred
);
358 /* Update the node times. We give preference to the error codes
359 * generated by this function rather than the ones that may arise
360 * from tmpfs_update. */
366 /* --------------------------------------------------------------------- */
369 * fsync is usually a NOP, but we must take action when unmounting or
373 tmpfs_fsync(struct vop_fsync_args
*v
)
375 struct tmpfs_mount
*tmp
;
376 struct tmpfs_node
*node
;
377 struct vnode
*vp
= v
->a_vp
;
379 tmp
= VFS_TO_TMPFS(vp
->v_mount
);
380 node
= VP_TO_TMPFS_NODE(vp
);
383 if (vp
->v_type
== VREG
) {
384 if (vp
->v_flag
& VRECLAIMED
) {
385 if (node
->tn_links
== 0)
386 tmpfs_truncate(vp
, 0);
388 vfsync(v
->a_vp
, v
->a_waitfor
, 1, NULL
, NULL
);
394 /* --------------------------------------------------------------------- */
397 tmpfs_read (struct vop_read_args
*ap
)
400 struct vnode
*vp
= ap
->a_vp
;
401 struct uio
*uio
= ap
->a_uio
;
402 struct tmpfs_node
*node
;
410 if (uio
->uio_resid
== 0) {
414 node
= VP_TO_TMPFS_NODE(vp
);
416 if (uio
->uio_offset
< 0)
418 if (vp
->v_type
!= VREG
)
422 if(curthread
->td_mpcount
)
430 while (uio
->uio_resid
> 0 && uio
->uio_offset
< node
->tn_size
) {
432 * Use buffer cache I/O (via tmpfs_strategy)
434 offset
= (size_t)uio
->uio_offset
& BMASK
;
435 base_offset
= (off_t
)uio
->uio_offset
- offset
;
436 bp
= getcacheblk(vp
, base_offset
);
439 if (got_mplock
== 0) {
444 error
= bread(vp
, base_offset
, BSIZE
, &bp
);
447 kprintf("tmpfs_read bread error %d\n", error
);
452 if (got_mplock
== 0) {
458 * Figure out how many bytes we can actually copy this loop.
460 len
= BSIZE
- offset
;
461 if (len
> uio
->uio_resid
)
462 len
= uio
->uio_resid
;
463 if (len
> node
->tn_size
- uio
->uio_offset
)
464 len
= (size_t)(node
->tn_size
- uio
->uio_offset
);
466 error
= uiomove((char *)bp
->b_data
+ offset
, len
, uio
);
469 kprintf("tmpfs_read uiomove error %d\n", error
);
477 TMPFS_NODE_LOCK(node
);
478 node
->tn_status
|= TMPFS_NODE_ACCESSED
;
479 TMPFS_NODE_UNLOCK(node
);
485 tmpfs_write (struct vop_write_args
*ap
)
488 struct vnode
*vp
= ap
->a_vp
;
489 struct uio
*uio
= ap
->a_uio
;
490 struct thread
*td
= uio
->uio_td
;
491 struct tmpfs_node
*node
;
503 if (uio
->uio_resid
== 0) {
507 node
= VP_TO_TMPFS_NODE(vp
);
509 if (vp
->v_type
!= VREG
)
512 oldsize
= node
->tn_size
;
513 if (ap
->a_ioflag
& IO_APPEND
)
514 uio
->uio_offset
= node
->tn_size
;
517 * Check for illegal write offsets.
519 if (uio
->uio_offset
+ uio
->uio_resid
>
520 VFS_TO_TMPFS(vp
->v_mount
)->tm_maxfilesize
)
523 if (vp
->v_type
== VREG
&& td
!= NULL
) {
524 error
= kern_getrlimit(RLIMIT_FSIZE
, &limit
);
527 if (uio
->uio_offset
+ uio
->uio_resid
> limit
.rlim_cur
) {
528 ksignal(td
->td_proc
, SIGXFSZ
);
535 * Extend the file's size if necessary
537 extended
= ((uio
->uio_offset
+ uio
->uio_resid
) > node
->tn_size
);
540 if (curthread
->td_mpcount
) {
549 while (uio
->uio_resid
> 0) {
551 * Use buffer cache I/O (via tmpfs_strategy)
553 offset
= (size_t)uio
->uio_offset
& BMASK
;
554 base_offset
= (off_t
)uio
->uio_offset
- offset
;
555 len
= BSIZE
- offset
;
556 if (len
> uio
->uio_resid
)
557 len
= uio
->uio_resid
;
559 if ((uio
->uio_offset
+ len
) > node
->tn_size
) {
560 trivial
= (uio
->uio_offset
<= node
->tn_size
);
561 error
= tmpfs_reg_resize(vp
, uio
->uio_offset
+ len
, trivial
);
567 * Read to fill in any gaps. Theoretically we could
568 * optimize this if the write covers the entire buffer
569 * and is not a UIO_NOCOPY write, however this can lead
570 * to a security violation exposing random kernel memory
571 * (whatever junk was in the backing VM pages before).
573 * So just use bread() to do the right thing.
575 error
= bread(vp
, base_offset
, BSIZE
, &bp
);
576 error
= uiomove((char *)bp
->b_data
+ offset
, len
, uio
);
578 kprintf("tmpfs_write uiomove error %d\n", error
);
583 if (uio
->uio_offset
> node
->tn_size
)
584 node
->tn_size
= uio
->uio_offset
;
587 * The data has been loaded into the buffer, write it out.
589 * We want tmpfs to be able to use all available ram, not
590 * just the buffer cache, so if not explicitly paging we
591 * use buwrite() to leave the buffer clean but mark all the
592 * VM pages valid+dirty.
594 * When the kernel is paging, either via normal pageout
595 * operation or when cleaning the object during a recycle,
596 * the underlying VM pages are going to get thrown away
597 * so we MUST write them to swap.
599 * XXX unfortunately this catches msync() system calls too
602 if (ap
->a_ioflag
& IO_SYNC
) {
604 } else if ((ap
->a_ioflag
& IO_ASYNC
) ||
605 (uio
->uio_segflg
== UIO_NOCOPY
)) {
612 kprintf("tmpfs_write bwrite error %d\n", error
);
622 (void)tmpfs_reg_resize(vp
, oldsize
, trivial
);
626 TMPFS_NODE_LOCK(node
);
627 node
->tn_status
|= TMPFS_NODE_ACCESSED
| TMPFS_NODE_MODIFIED
|
628 (extended
? TMPFS_NODE_CHANGED
: 0);
630 if (node
->tn_mode
& (S_ISUID
| S_ISGID
)) {
631 if (priv_check_cred(ap
->a_cred
, PRIV_VFS_RETAINSUGID
, 0))
632 node
->tn_mode
&= ~(S_ISUID
| S_ISGID
);
634 TMPFS_NODE_UNLOCK(node
);
640 tmpfs_advlock (struct vop_advlock_args
*ap
)
642 struct tmpfs_node
*node
;
643 struct vnode
*vp
= ap
->a_vp
;
645 node
= VP_TO_TMPFS_NODE(vp
);
647 return (lf_advlock(ap
, &node
->tn_advlock
, node
->tn_size
));
652 tmpfs_strategy(struct vop_strategy_args
*ap
)
654 struct bio
*bio
= ap
->a_bio
;
655 struct buf
*bp
= bio
->bio_buf
;
656 struct vnode
*vp
= ap
->a_vp
;
657 struct tmpfs_node
*node
;
660 if (vp
->v_type
!= VREG
) {
661 bp
->b_resid
= bp
->b_bcount
;
662 bp
->b_flags
|= B_ERROR
| B_INVAL
;
663 bp
->b_error
= EINVAL
;
668 node
= VP_TO_TMPFS_NODE(vp
);
670 uobj
= node
->tn_reg
.tn_aobj
;
673 * Call swap_pager_strategy to read or write between the VM
674 * object and the buffer cache.
676 swap_pager_strategy(uobj
, bio
);
682 tmpfs_bmap(struct vop_bmap_args
*ap
)
684 if (ap
->a_doffsetp
!= NULL
)
685 *ap
->a_doffsetp
= ap
->a_loffset
;
686 if (ap
->a_runp
!= NULL
)
688 if (ap
->a_runb
!= NULL
)
694 /* --------------------------------------------------------------------- */
697 tmpfs_nremove(struct vop_nremove_args
*v
)
699 struct vnode
*dvp
= v
->a_dvp
;
700 struct namecache
*ncp
= v
->a_nch
->ncp
;
703 struct tmpfs_dirent
*de
;
704 struct tmpfs_mount
*tmp
;
705 struct tmpfs_node
*dnode
;
706 struct tmpfs_node
*node
;
709 * We have to acquire the vp from v->a_nch because
710 * we will likely unresolve the namecache entry, and
711 * a vrele is needed to trigger the tmpfs_inactive/tmpfs_reclaim
712 * sequence to recover space from the file.
714 error
= cache_vref(v
->a_nch
, v
->a_cred
, &vp
);
715 KKASSERT(error
== 0);
717 if (vp
->v_type
== VDIR
) {
722 dnode
= VP_TO_TMPFS_DIR(dvp
);
723 node
= VP_TO_TMPFS_NODE(vp
);
724 tmp
= VFS_TO_TMPFS(vp
->v_mount
);
725 de
= tmpfs_dir_lookup(dnode
, node
, ncp
);
731 /* Files marked as immutable or append-only cannot be deleted. */
732 if ((node
->tn_flags
& (IMMUTABLE
| APPEND
| NOUNLINK
)) ||
733 (dnode
->tn_flags
& APPEND
)) {
738 /* Remove the entry from the directory; as it is a file, we do not
739 * have to change the number of hard links of the directory. */
740 tmpfs_dir_detach(dnode
, de
);
742 /* Free the directory entry we just deleted. Note that the node
743 * referred by it will not be removed until the vnode is really
745 tmpfs_free_dirent(tmp
, de
);
747 if (node
->tn_links
> 0) {
748 TMPFS_NODE_LOCK(node
);
749 node
->tn_status
|= TMPFS_NODE_ACCESSED
| TMPFS_NODE_CHANGED
| \
751 TMPFS_NODE_UNLOCK(node
);
754 cache_setunresolved(v
->a_nch
);
755 cache_setvp(v
->a_nch
, NULL
);
756 /*cache_inval_vp(vp, CINV_DESTROY);*/
765 /* --------------------------------------------------------------------- */
768 tmpfs_nlink(struct vop_nlink_args
*v
)
770 struct vnode
*dvp
= v
->a_dvp
;
771 struct vnode
*vp
= v
->a_vp
;
772 struct namecache
*ncp
= v
->a_nch
->ncp
;
773 struct tmpfs_dirent
*de
;
774 struct tmpfs_node
*node
;
775 struct tmpfs_node
*dnode
;
778 KKASSERT(dvp
!= vp
); /* XXX When can this be false? */
780 node
= VP_TO_TMPFS_NODE(vp
);
781 dnode
= VP_TO_TMPFS_NODE(dvp
);
783 /* XXX: Why aren't the following two tests done by the caller? */
785 /* Hard links of directories are forbidden. */
786 if (vp
->v_type
== VDIR
) {
791 /* Cannot create cross-device links. */
792 if (dvp
->v_mount
!= vp
->v_mount
) {
797 /* Ensure that we do not overflow the maximum number of links imposed
799 KKASSERT(node
->tn_links
<= LINK_MAX
);
800 if (node
->tn_links
== LINK_MAX
) {
805 /* We cannot create links of files marked immutable or append-only. */
806 if (node
->tn_flags
& (IMMUTABLE
| APPEND
)) {
811 /* Allocate a new directory entry to represent the node. */
812 error
= tmpfs_alloc_dirent(VFS_TO_TMPFS(vp
->v_mount
), node
,
813 ncp
->nc_name
, ncp
->nc_nlen
, &de
);
817 /* Insert the new directory entry into the appropriate directory. */
818 tmpfs_dir_attach(dnode
, de
);
820 /* vp link count has changed, so update node times. */
822 TMPFS_NODE_LOCK(node
);
823 node
->tn_status
|= TMPFS_NODE_CHANGED
;
824 TMPFS_NODE_UNLOCK(node
);
827 cache_setunresolved(v
->a_nch
);
828 cache_setvp(v
->a_nch
, vp
);
835 /* --------------------------------------------------------------------- */
838 tmpfs_nrename(struct vop_nrename_args
*v
)
840 struct vnode
*fdvp
= v
->a_fdvp
;
841 struct namecache
*fncp
= v
->a_fnch
->ncp
;
842 struct vnode
*fvp
= fncp
->nc_vp
;
843 struct vnode
*tdvp
= v
->a_tdvp
;
844 struct namecache
*tncp
= v
->a_tnch
->ncp
;
845 struct vnode
*tvp
= tncp
->nc_vp
;
846 struct tmpfs_dirent
*de
;
847 struct tmpfs_mount
*tmp
;
848 struct tmpfs_node
*fdnode
;
849 struct tmpfs_node
*fnode
;
850 struct tmpfs_node
*tnode
;
851 struct tmpfs_node
*tdnode
;
856 tnode
= (tvp
== NULL
) ? NULL
: VP_TO_TMPFS_NODE(tvp
);
858 /* Disallow cross-device renames.
859 * XXX Why isn't this done by the caller? */
860 if (fvp
->v_mount
!= tdvp
->v_mount
||
861 (tvp
!= NULL
&& fvp
->v_mount
!= tvp
->v_mount
)) {
866 tmp
= VFS_TO_TMPFS(tdvp
->v_mount
);
867 tdnode
= VP_TO_TMPFS_DIR(tdvp
);
869 /* If source and target are the same file, there is nothing to do. */
875 fdnode
= VP_TO_TMPFS_DIR(fdvp
);
876 fnode
= VP_TO_TMPFS_NODE(fvp
);
877 de
= tmpfs_dir_lookup(fdnode
, fnode
, fncp
);
879 /* Avoid manipulating '.' and '..' entries. */
884 KKASSERT(de
->td_node
== fnode
);
887 * If replacing an entry in the target directory and that entry
888 * is a directory, it must be empty.
890 * Kern_rename gurantees the destination to be a directory
891 * if the source is one (it does?).
894 KKASSERT(tnode
!= NULL
);
896 if ((tnode
->tn_flags
& (NOUNLINK
| IMMUTABLE
| APPEND
)) ||
897 (tdnode
->tn_flags
& (APPEND
| IMMUTABLE
))) {
902 if (fnode
->tn_type
== VDIR
&& tnode
->tn_type
== VDIR
) {
903 if (tnode
->tn_size
> 0) {
907 } else if (fnode
->tn_type
== VDIR
&& tnode
->tn_type
!= VDIR
) {
910 } else if (fnode
->tn_type
!= VDIR
&& tnode
->tn_type
== VDIR
) {
914 KKASSERT(fnode
->tn_type
!= VDIR
&&
915 tnode
->tn_type
!= VDIR
);
919 if ((fnode
->tn_flags
& (NOUNLINK
| IMMUTABLE
| APPEND
)) ||
920 (fdnode
->tn_flags
& (APPEND
| IMMUTABLE
))) {
926 * Ensure that we have enough memory to hold the new name, if it
929 if (fncp
->nc_nlen
!= tncp
->nc_nlen
||
930 bcmp(fncp
->nc_name
, tncp
->nc_name
, fncp
->nc_nlen
) != 0) {
931 newname
= kmalloc(tncp
->nc_nlen
+ 1, M_TMPFSNAME
, M_WAITOK
);
932 bcopy(tncp
->nc_name
, newname
, tncp
->nc_nlen
);
933 newname
[tncp
->nc_nlen
] = '\0';
939 * Unlink entry from source directory. Note that the kernel has
940 * already checked for illegal recursion cases (renaming a directory
941 * into a subdirectory of itself).
943 if (fdnode
!= tdnode
)
944 tmpfs_dir_detach(fdnode
, de
);
947 * Handle any name change. Swap with newname, we will
948 * deallocate it at the end.
950 if (newname
!= NULL
) {
952 TMPFS_NODE_LOCK(fnode
);
953 fnode
->tn_status
|= TMPFS_NODE_CHANGED
;
954 TMPFS_NODE_UNLOCK(fnode
);
956 oldname
= de
->td_name
;
957 de
->td_name
= newname
;
958 de
->td_namelen
= (uint16_t)tncp
->nc_nlen
;
963 * Link entry to target directory. If the entry
964 * represents a directory move the parent linkage
967 if (fdnode
!= tdnode
) {
968 if (de
->td_node
->tn_type
== VDIR
) {
969 TMPFS_VALIDATE_DIR(fnode
);
971 TMPFS_NODE_LOCK(tdnode
);
973 tdnode
->tn_status
|= TMPFS_NODE_MODIFIED
;
974 TMPFS_NODE_UNLOCK(tdnode
);
976 TMPFS_NODE_LOCK(fnode
);
977 fnode
->tn_dir
.tn_parent
= tdnode
;
978 fnode
->tn_status
|= TMPFS_NODE_CHANGED
;
979 TMPFS_NODE_UNLOCK(fnode
);
981 TMPFS_NODE_LOCK(fdnode
);
983 fdnode
->tn_status
|= TMPFS_NODE_MODIFIED
;
984 TMPFS_NODE_UNLOCK(fdnode
);
986 tmpfs_dir_attach(tdnode
, de
);
988 TMPFS_NODE_LOCK(tdnode
);
989 tdnode
->tn_status
|= TMPFS_NODE_MODIFIED
;
990 TMPFS_NODE_UNLOCK(tdnode
);
994 * If we are overwriting an entry, we have to remove the old one
995 * from the target directory.
998 /* Remove the old entry from the target directory. */
999 de
= tmpfs_dir_lookup(tdnode
, tnode
, tncp
);
1000 tmpfs_dir_detach(tdnode
, de
);
1003 * Free the directory entry we just deleted. Note that the
1004 * node referred by it will not be removed until the vnode is
1007 tmpfs_free_dirent(VFS_TO_TMPFS(tvp
->v_mount
), de
);
1008 /*cache_inval_vp(tvp, CINV_DESTROY);*/
1015 kfree(newname
, M_TMPFSNAME
);
1018 cache_rename(v
->a_fnch
, v
->a_tnch
);
1025 /* Release target nodes. */
1026 /* XXX: I don't understand when tdvp can be the same as tvp, but
1027 * other code takes care of this... */
1034 /* --------------------------------------------------------------------- */
1037 tmpfs_nmkdir(struct vop_nmkdir_args
*v
)
1039 struct vnode
*dvp
= v
->a_dvp
;
1040 struct vnode
**vpp
= v
->a_vpp
;
1041 struct namecache
*ncp
= v
->a_nch
->ncp
;
1042 struct vattr
*vap
= v
->a_vap
;
1043 struct ucred
*cred
= v
->a_cred
;
1046 KKASSERT(vap
->va_type
== VDIR
);
1048 error
= tmpfs_alloc_file(dvp
, vpp
, vap
, ncp
, cred
, NULL
);
1050 cache_setunresolved(v
->a_nch
);
1051 cache_setvp(v
->a_nch
, *vpp
);
1057 /* --------------------------------------------------------------------- */
1060 tmpfs_nrmdir(struct vop_nrmdir_args
*v
)
1062 struct vnode
*dvp
= v
->a_dvp
;
1063 struct namecache
*ncp
= v
->a_nch
->ncp
;
1065 struct tmpfs_dirent
*de
;
1066 struct tmpfs_mount
*tmp
;
1067 struct tmpfs_node
*dnode
;
1068 struct tmpfs_node
*node
;
1072 * Prevalidate so we don't hit an assertion later
1074 if (vp
->v_type
!= VDIR
)
1078 * We have to acquire the vp from v->a_nch because
1079 * we will likely unresolve the namecache entry, and
1080 * a vrele is needed to trigger the tmpfs_inactive/tmpfs_reclaim
1083 error
= cache_vref(v
->a_nch
, v
->a_cred
, &vp
);
1084 KKASSERT(error
== 0);
1086 tmp
= VFS_TO_TMPFS(dvp
->v_mount
);
1087 dnode
= VP_TO_TMPFS_DIR(dvp
);
1088 node
= VP_TO_TMPFS_DIR(vp
);
1090 /* Directories with more than two entries ('.' and '..') cannot be
1092 if (node
->tn_size
> 0) {
1097 if ((dnode
->tn_flags
& APPEND
)
1098 || (node
->tn_flags
& (NOUNLINK
| IMMUTABLE
| APPEND
))) {
1103 /* This invariant holds only if we are not trying to remove "..".
1104 * We checked for that above so this is safe now. */
1105 KKASSERT(node
->tn_dir
.tn_parent
== dnode
);
1107 /* Get the directory entry associated with node (vp). This was
1108 * filled by tmpfs_lookup while looking up the entry. */
1109 de
= tmpfs_dir_lookup(dnode
, node
, ncp
);
1110 KKASSERT(TMPFS_DIRENT_MATCHES(de
,
1114 /* Check flags to see if we are allowed to remove the directory. */
1115 if ((dnode
->tn_flags
& APPEND
) ||
1116 node
->tn_flags
& (NOUNLINK
| IMMUTABLE
| APPEND
)) {
1122 /* Detach the directory entry from the directory (dnode). */
1123 tmpfs_dir_detach(dnode
, de
);
1125 /* No vnode should be allocated for this entry from this point */
1126 TMPFS_NODE_LOCK(node
);
1127 TMPFS_ASSERT_ELOCKED(node
);
1128 TMPFS_NODE_LOCK(dnode
);
1129 TMPFS_ASSERT_ELOCKED(dnode
);
1132 /* handled by tmpfs_free_node */
1133 KKASSERT(node
->tn_links
> 0);
1135 node
->tn_dir
.tn_parent
= NULL
;
1137 node
->tn_status
|= TMPFS_NODE_ACCESSED
| TMPFS_NODE_CHANGED
| \
1138 TMPFS_NODE_MODIFIED
;
1141 /* handled by tmpfs_free_node */
1142 KKASSERT(dnode
->tn_links
> 0);
1145 dnode
->tn_status
|= TMPFS_NODE_ACCESSED
| \
1146 TMPFS_NODE_CHANGED
| TMPFS_NODE_MODIFIED
;
1148 TMPFS_NODE_UNLOCK(dnode
);
1149 TMPFS_NODE_UNLOCK(node
);
1151 /* Free the directory entry we just deleted. Note that the node
1152 * referred by it will not be removed until the vnode is really
1154 tmpfs_free_dirent(tmp
, de
);
1156 /* Release the deleted vnode (will destroy the node, notify
1157 * interested parties and clean it from the cache). */
1159 TMPFS_NODE_LOCK(dnode
);
1160 dnode
->tn_status
|= TMPFS_NODE_CHANGED
;
1161 TMPFS_NODE_UNLOCK(dnode
);
1164 cache_setunresolved(v
->a_nch
);
1165 cache_setvp(v
->a_nch
, NULL
);
1166 /*cache_inval_vp(vp, CINV_DESTROY);*/
1175 /* --------------------------------------------------------------------- */
1178 tmpfs_nsymlink(struct vop_nsymlink_args
*v
)
1180 struct vnode
*dvp
= v
->a_dvp
;
1181 struct vnode
**vpp
= v
->a_vpp
;
1182 struct namecache
*ncp
= v
->a_nch
->ncp
;
1183 struct vattr
*vap
= v
->a_vap
;
1184 struct ucred
*cred
= v
->a_cred
;
1185 char *target
= v
->a_target
;
1188 vap
->va_type
= VLNK
;
1189 error
= tmpfs_alloc_file(dvp
, vpp
, vap
, ncp
, cred
, target
);
1191 cache_setunresolved(v
->a_nch
);
1192 cache_setvp(v
->a_nch
, *vpp
);
1198 /* --------------------------------------------------------------------- */
1201 tmpfs_readdir(struct vop_readdir_args
*v
)
1203 struct vnode
*vp
= v
->a_vp
;
1204 struct uio
*uio
= v
->a_uio
;
1205 int *eofflag
= v
->a_eofflag
;
1206 off_t
**cookies
= v
->a_cookies
;
1207 int *ncookies
= v
->a_ncookies
;
1208 struct tmpfs_mount
*tmp
;
1212 struct tmpfs_node
*node
;
1214 /* This operation only makes sense on directory nodes. */
1215 if (vp
->v_type
!= VDIR
)
1218 tmp
= VFS_TO_TMPFS(vp
->v_mount
);
1219 node
= VP_TO_TMPFS_DIR(vp
);
1220 startoff
= uio
->uio_offset
;
1222 if (uio
->uio_offset
== TMPFS_DIRCOOKIE_DOT
) {
1223 error
= tmpfs_dir_getdotdent(node
, uio
);
1229 if (uio
->uio_offset
== TMPFS_DIRCOOKIE_DOTDOT
) {
1230 error
= tmpfs_dir_getdotdotdent(tmp
, node
, uio
);
1236 error
= tmpfs_dir_getdents(node
, uio
, &cnt
);
1239 KKASSERT(error
>= -1);
1244 if (eofflag
!= NULL
)
1246 (error
== 0 && uio
->uio_offset
== TMPFS_DIRCOOKIE_EOF
);
1248 /* Update NFS-related variables. */
1249 if (error
== 0 && cookies
!= NULL
&& ncookies
!= NULL
) {
1251 off_t off
= startoff
;
1252 struct tmpfs_dirent
*de
= NULL
;
1255 *cookies
= kmalloc(cnt
* sizeof(off_t
), M_TEMP
, M_WAITOK
);
1257 for (i
= 0; i
< cnt
; i
++) {
1258 KKASSERT(off
!= TMPFS_DIRCOOKIE_EOF
);
1259 if (off
== TMPFS_DIRCOOKIE_DOT
) {
1260 off
= TMPFS_DIRCOOKIE_DOTDOT
;
1262 if (off
== TMPFS_DIRCOOKIE_DOTDOT
) {
1263 de
= TAILQ_FIRST(&node
->tn_dir
.tn_dirhead
);
1264 } else if (de
!= NULL
) {
1265 de
= TAILQ_NEXT(de
, td_entries
);
1267 de
= tmpfs_dir_lookupbycookie(node
,
1269 KKASSERT(de
!= NULL
);
1270 de
= TAILQ_NEXT(de
, td_entries
);
1273 off
= TMPFS_DIRCOOKIE_EOF
;
1275 off
= tmpfs_dircookie(de
);
1278 (*cookies
)[i
] = off
;
1280 KKASSERT(uio
->uio_offset
== off
);
1286 /* --------------------------------------------------------------------- */
1289 tmpfs_readlink(struct vop_readlink_args
*v
)
1291 struct vnode
*vp
= v
->a_vp
;
1292 struct uio
*uio
= v
->a_uio
;
1295 struct tmpfs_node
*node
;
1297 KKASSERT(uio
->uio_offset
== 0);
1298 KKASSERT(vp
->v_type
== VLNK
);
1300 node
= VP_TO_TMPFS_NODE(vp
);
1302 error
= uiomove(node
->tn_link
, MIN(node
->tn_size
, uio
->uio_resid
),
1304 TMPFS_NODE_LOCK(node
);
1305 node
->tn_status
|= TMPFS_NODE_ACCESSED
;
1306 TMPFS_NODE_UNLOCK(node
);
1311 /* --------------------------------------------------------------------- */
1314 tmpfs_inactive(struct vop_inactive_args
*v
)
1316 struct vnode
*vp
= v
->a_vp
;
1318 struct tmpfs_node
*node
;
1320 node
= VP_TO_TMPFS_NODE(vp
);
1323 * Get rid of unreferenced deleted vnodes sooner rather than
1324 * later so the data memory can be recovered immediately.
1326 * We must truncate the vnode to prevent the normal reclamation
1327 * path from flushing the data for the removed file to disk.
1329 TMPFS_NODE_LOCK(node
);
1330 if ((node
->tn_vpstate
& TMPFS_VNODE_ALLOCATING
) == 0 &&
1331 (node
->tn_links
== 0 ||
1332 (node
->tn_links
== 1 && node
->tn_type
== VDIR
&&
1333 node
->tn_dir
.tn_parent
)))
1335 node
->tn_vpstate
= TMPFS_VNODE_DOOMED
;
1336 TMPFS_NODE_UNLOCK(node
);
1337 if (node
->tn_type
== VREG
)
1338 tmpfs_truncate(vp
, 0);
1341 TMPFS_NODE_UNLOCK(node
);
1347 /* --------------------------------------------------------------------- */
1350 tmpfs_reclaim(struct vop_reclaim_args
*v
)
1352 struct vnode
*vp
= v
->a_vp
;
1353 struct tmpfs_mount
*tmp
;
1354 struct tmpfs_node
*node
;
1356 node
= VP_TO_TMPFS_NODE(vp
);
1357 tmp
= VFS_TO_TMPFS(vp
->v_mount
);
1362 * If the node referenced by this vnode was deleted by the
1363 * user, we must free its associated data structures now that
1364 * the vnode is being reclaimed.
1366 * Directories have an extra link ref.
1368 TMPFS_NODE_LOCK(node
);
1369 if ((node
->tn_vpstate
& TMPFS_VNODE_ALLOCATING
) == 0 &&
1370 (node
->tn_links
== 0 ||
1371 (node
->tn_links
== 1 && node
->tn_type
== VDIR
&&
1372 node
->tn_dir
.tn_parent
)))
1374 node
->tn_vpstate
= TMPFS_VNODE_DOOMED
;
1375 tmpfs_free_node(tmp
, node
);
1378 TMPFS_NODE_UNLOCK(node
);
1381 KKASSERT(vp
->v_data
== NULL
);
1385 /* --------------------------------------------------------------------- */
1388 tmpfs_print(struct vop_print_args
*v
)
1390 struct vnode
*vp
= v
->a_vp
;
1392 struct tmpfs_node
*node
;
1394 node
= VP_TO_TMPFS_NODE(vp
);
1396 kprintf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n",
1397 node
, node
->tn_flags
, node
->tn_links
);
1398 kprintf("\tmode 0%o, owner %d, group %d, size %ju, status 0x%x\n",
1399 node
->tn_mode
, node
->tn_uid
, node
->tn_gid
,
1400 (uintmax_t)node
->tn_size
, node
->tn_status
);
1402 if (vp
->v_type
== VFIFO
)
1410 /* --------------------------------------------------------------------- */
1413 tmpfs_pathconf(struct vop_pathconf_args
*v
)
1415 int name
= v
->a_name
;
1416 register_t
*retval
= v
->a_retval
;
1439 case _PC_CHOWN_RESTRICTED
:
1451 case _PC_FILESIZEBITS
:
1452 *retval
= 0; /* XXX Don't know which value should I return. */
1462 /* --------------------------------------------------------------------- */
1465 * vnode operations vector used for files stored in a tmpfs file system.
1467 struct vop_ops tmpfs_vnode_vops
= {
1468 .vop_default
= vop_defaultop
,
1469 .vop_getpages
= vop_stdgetpages
,
1470 .vop_putpages
= vop_stdputpages
,
1471 .vop_ncreate
= tmpfs_ncreate
,
1472 .vop_nresolve
= tmpfs_nresolve
,
1473 .vop_nlookupdotdot
= tmpfs_nlookupdotdot
,
1474 .vop_nmknod
= tmpfs_nmknod
,
1475 .vop_open
= tmpfs_open
,
1476 .vop_close
= tmpfs_close
,
1477 .vop_access
= tmpfs_access
,
1478 .vop_getattr
= tmpfs_getattr
,
1479 .vop_setattr
= tmpfs_setattr
,
1480 .vop_read
= tmpfs_read
,
1481 .vop_write
= tmpfs_write
,
1482 .vop_fsync
= tmpfs_fsync
,
1483 .vop_nremove
= tmpfs_nremove
,
1484 .vop_nlink
= tmpfs_nlink
,
1485 .vop_nrename
= tmpfs_nrename
,
1486 .vop_nmkdir
= tmpfs_nmkdir
,
1487 .vop_nrmdir
= tmpfs_nrmdir
,
1488 .vop_nsymlink
= tmpfs_nsymlink
,
1489 .vop_readdir
= tmpfs_readdir
,
1490 .vop_readlink
= tmpfs_readlink
,
1491 .vop_inactive
= tmpfs_inactive
,
1492 .vop_reclaim
= tmpfs_reclaim
,
1493 .vop_print
= tmpfs_print
,
1494 .vop_pathconf
= tmpfs_pathconf
,
1495 .vop_bmap
= tmpfs_bmap
,
1496 .vop_bmap
= (void *)vop_eopnotsupp
,
1497 .vop_strategy
= tmpfs_strategy
,
1498 .vop_advlock
= tmpfs_advlock
,