kernel - Implement KVABIO API in TMPFS
[dragonfly.git] / sys / vfs / tmpfs / tmpfs_vnops.c
CommitLineData
7a2de9a4
MD
1/*-
2 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
7 * 2005 program.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
80ae59d7
MD
29 *
30 * $NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $
7a2de9a4
MD
31 */
32
33/*
34 * tmpfs vnode interface.
35 */
7a2de9a4
MD
36
37#include <sys/kernel.h>
38#include <sys/kern_syscall.h>
39#include <sys/param.h>
40#include <sys/fcntl.h>
41#include <sys/lockf.h>
42#include <sys/priv.h>
43#include <sys/proc.h>
44#include <sys/resourcevar.h>
45#include <sys/sched.h>
7a2de9a4
MD
46#include <sys/stat.h>
47#include <sys/systm.h>
48#include <sys/unistd.h>
49#include <sys/vfsops.h>
50#include <sys/vnode.h>
66fa44e7 51#include <sys/mountctl.h>
7a2de9a4 52
7a2de9a4 53#include <vm/vm.h>
cad75e56 54#include <vm/vm_extern.h>
7a2de9a4
MD
55#include <vm/vm_object.h>
56#include <vm/vm_page.h>
03697313 57#include <vm/vm_pageout.h>
7a2de9a4 58#include <vm/vm_pager.h>
b7545cb3 59#include <vm/swap_pager.h>
7a2de9a4 60
54341a3b 61#include <sys/buf2.h>
3c54bb74 62#include <vm/vm_page2.h>
54341a3b 63
7a2de9a4
MD
64#include <vfs/fifofs/fifo.h>
65#include <vfs/tmpfs/tmpfs_vnops.h>
aa1adbf0 66#include "tmpfs.h"
7a2de9a4 67
8f9ba07b
MD
68static void tmpfs_strategy_done(struct bio *bio);
69
80ae59d7
MD
70static __inline
71void
72tmpfs_knote(struct vnode *vp, int flags)
73{
74 if (flags)
75 KNOTE(&vp->v_pollinfo.vpi_kqinfo.ki_note, flags);
76}
77
78
7a2de9a4
MD
79/* --------------------------------------------------------------------- */
80
81static int
ba25006a 82tmpfs_nresolve(struct vop_nresolve_args *ap)
7a2de9a4 83{
ba25006a 84 struct vnode *dvp = ap->a_dvp;
7a2de9a4 85 struct vnode *vp = NULL;
ba25006a 86 struct namecache *ncp = ap->a_nch->ncp;
d89ce96a 87 struct tmpfs_node *tnode;
7a2de9a4
MD
88 struct tmpfs_dirent *de;
89 struct tmpfs_node *dnode;
ff837cd5 90 int error;
7a2de9a4
MD
91
92 dnode = VP_TO_TMPFS_DIR(dvp);
93
ff837cd5 94 TMPFS_NODE_LOCK_SH(dnode);
7a2de9a4
MD
95 de = tmpfs_dir_lookup(dnode, NULL, ncp);
96 if (de == NULL) {
d89ce96a 97 error = ENOENT;
7a2de9a4 98 } else {
d89ce96a
MD
99 /*
100 * Allocate a vnode for the node we found.
101 */
7a2de9a4 102 tnode = de->td_node;
7a2de9a4 103 error = tmpfs_alloc_vp(dvp->v_mount, tnode,
d89ce96a 104 LK_EXCLUSIVE | LK_RETRY, &vp);
974226b4
TK
105 if (error)
106 goto out;
107 KKASSERT(vp);
7a2de9a4 108 }
974226b4
TK
109
110out:
81aadc82 111 TMPFS_NODE_UNLOCK(dnode);
ff837cd5 112
bed3b851
TK
113 if ((dnode->tn_status & TMPFS_NODE_ACCESSED) == 0) {
114 TMPFS_NODE_LOCK(dnode);
115 dnode->tn_status |= TMPFS_NODE_ACCESSED;
116 TMPFS_NODE_UNLOCK(dnode);
117 }
ff837cd5 118
d89ce96a
MD
119 /*
120 * Store the result of this lookup in the cache. Avoid this if the
7a2de9a4 121 * request was for creation, as it does not improve timings on
d89ce96a
MD
122 * emprical tests.
123 */
7a2de9a4
MD
124 if (vp) {
125 vn_unlock(vp);
ba25006a 126 cache_setvp(ap->a_nch, vp);
7a2de9a4 127 vrele(vp);
d89ce96a 128 } else if (error == ENOENT) {
ba25006a 129 cache_setvp(ap->a_nch, NULL);
7a2de9a4 130 }
aa1adbf0 131 return (error);
7a2de9a4
MD
132}
133
134static int
ba25006a 135tmpfs_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
7a2de9a4 136{
ba25006a
SW
137 struct vnode *dvp = ap->a_dvp;
138 struct vnode **vpp = ap->a_vpp;
7a2de9a4 139 struct tmpfs_node *dnode = VP_TO_TMPFS_NODE(dvp);
ba25006a 140 struct ucred *cred = ap->a_cred;
7a2de9a4
MD
141 int error;
142
143 *vpp = NULL;
aa1adbf0 144
7a2de9a4
MD
145 /* Check accessibility of requested node as a first step. */
146 error = VOP_ACCESS(dvp, VEXEC, cred);
ff837cd5 147 if (error != 0)
7a2de9a4
MD
148 return error;
149
150 if (dnode->tn_dir.tn_parent != NULL) {
151 /* Allocate a new vnode on the matching entry. */
152 error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent,
aa1adbf0 153 LK_EXCLUSIVE | LK_RETRY, vpp);
7a2de9a4
MD
154
155 if (*vpp)
156 vn_unlock(*vpp);
157 }
7a2de9a4
MD
158 return (*vpp == NULL) ? ENOENT : 0;
159}
160
161/* --------------------------------------------------------------------- */
162
163static int
ba25006a 164tmpfs_ncreate(struct vop_ncreate_args *ap)
7a2de9a4 165{
ba25006a
SW
166 struct vnode *dvp = ap->a_dvp;
167 struct vnode **vpp = ap->a_vpp;
168 struct namecache *ncp = ap->a_nch->ncp;
169 struct vattr *vap = ap->a_vap;
170 struct ucred *cred = ap->a_cred;
7a2de9a4
MD
171 int error;
172
173 KKASSERT(vap->va_type == VREG || vap->va_type == VSOCK);
174
7a2de9a4
MD
175 error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
176 if (error == 0) {
ba25006a
SW
177 cache_setunresolved(ap->a_nch);
178 cache_setvp(ap->a_nch, *vpp);
80ae59d7 179 tmpfs_knote(dvp, NOTE_WRITE);
7a2de9a4 180 }
aa1adbf0 181 return (error);
7a2de9a4
MD
182}
183/* --------------------------------------------------------------------- */
184
185static int
ba25006a 186tmpfs_nmknod(struct vop_nmknod_args *ap)
7a2de9a4 187{
ba25006a
SW
188 struct vnode *dvp = ap->a_dvp;
189 struct vnode **vpp = ap->a_vpp;
190 struct namecache *ncp = ap->a_nch->ncp;
191 struct vattr *vap = ap->a_vap;
192 struct ucred *cred = ap->a_cred;
7a2de9a4
MD
193 int error;
194
195 if (vap->va_type != VBLK && vap->va_type != VCHR &&
aa1adbf0 196 vap->va_type != VFIFO) {
aa1adbf0
MD
197 return (EINVAL);
198 }
7a2de9a4 199
7a2de9a4
MD
200 error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
201 if (error == 0) {
ba25006a
SW
202 cache_setunresolved(ap->a_nch);
203 cache_setvp(ap->a_nch, *vpp);
80ae59d7 204 tmpfs_knote(dvp, NOTE_WRITE);
7a2de9a4 205 }
7a2de9a4
MD
206 return error;
207}
208
209/* --------------------------------------------------------------------- */
210
211static int
ba25006a 212tmpfs_open(struct vop_open_args *ap)
7a2de9a4 213{
ba25006a
SW
214 struct vnode *vp = ap->a_vp;
215 int mode = ap->a_mode;
7a2de9a4 216 struct tmpfs_node *node;
aa1adbf0 217 int error;
7a2de9a4 218
7a2de9a4
MD
219 node = VP_TO_TMPFS_NODE(vp);
220
6e0c5aab 221#if 0
7a2de9a4
MD
222 /* The file is still active but all its names have been removed
223 * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as
224 * it is about to die. */
225 if (node->tn_links < 1)
226 return (ENOENT);
6e0c5aab 227#endif
7a2de9a4
MD
228
229 /* If the file is marked append-only, deny write requests. */
630e3a33
MD
230 if ((node->tn_flags & APPEND) &&
231 (mode & (FWRITE | O_APPEND)) == FWRITE) {
7a2de9a4 232 error = EPERM;
630e3a33 233 } else {
ba25006a 234 error = (vop_stdopen(ap));
7a2de9a4 235 }
aa1adbf0 236
aa1adbf0 237 return (error);
7a2de9a4
MD
238}
239
240/* --------------------------------------------------------------------- */
241
242static int
ba25006a 243tmpfs_close(struct vop_close_args *ap)
7a2de9a4 244{
ba25006a 245 struct vnode *vp = ap->a_vp;
7a2de9a4 246 struct tmpfs_node *node;
aa1adbf0 247 int error;
7a2de9a4
MD
248
249 node = VP_TO_TMPFS_NODE(vp);
250
251 if (node->tn_links > 0) {
6e0c5aab
MD
252 /*
253 * Update node times. No need to do it if the node has
254 * been deleted, because it will vanish after we return.
255 */
7a2de9a4
MD
256 tmpfs_update(vp);
257 }
258
ba25006a 259 error = vop_stdclose(ap);
aa1adbf0 260
aa1adbf0 261 return (error);
7a2de9a4
MD
262}
263
264/* --------------------------------------------------------------------- */
265
266int
ba25006a 267tmpfs_access(struct vop_access_args *ap)
7a2de9a4 268{
ba25006a 269 struct vnode *vp = ap->a_vp;
7a2de9a4
MD
270 int error;
271 struct tmpfs_node *node;
272
7a2de9a4
MD
273 node = VP_TO_TMPFS_NODE(vp);
274
275 switch (vp->v_type) {
276 case VDIR:
277 /* FALLTHROUGH */
278 case VLNK:
279 /* FALLTHROUGH */
280 case VREG:
ba25006a 281 if ((ap->a_mode & VWRITE) &&
aa1adbf0 282 (vp->v_mount->mnt_flag & MNT_RDONLY)) {
7a2de9a4
MD
283 error = EROFS;
284 goto out;
285 }
286 break;
287
288 case VBLK:
289 /* FALLTHROUGH */
290 case VCHR:
291 /* FALLTHROUGH */
292 case VSOCK:
293 /* FALLTHROUGH */
294 case VFIFO:
295 break;
296
297 default:
298 error = EINVAL;
299 goto out;
300 }
301
ba25006a 302 if ((ap->a_mode & VWRITE) && (node->tn_flags & IMMUTABLE)) {
7a2de9a4
MD
303 error = EPERM;
304 goto out;
305 }
306
ba25006a 307 error = vop_helper_access(ap, node->tn_uid, node->tn_gid,
aa1adbf0 308 node->tn_mode, 0);
7a2de9a4 309out:
7a2de9a4
MD
310 return error;
311}
312
313/* --------------------------------------------------------------------- */
314
315int
ba25006a 316tmpfs_getattr(struct vop_getattr_args *ap)
7a2de9a4 317{
ba25006a
SW
318 struct vnode *vp = ap->a_vp;
319 struct vattr *vap = ap->a_vap;
7a2de9a4 320 struct tmpfs_node *node;
7a2de9a4
MD
321
322 node = VP_TO_TMPFS_NODE(vp);
323
324 tmpfs_update(vp);
325
ff837cd5 326 TMPFS_NODE_LOCK_SH(node);
7a2de9a4
MD
327 vap->va_type = vp->v_type;
328 vap->va_mode = node->tn_mode;
329 vap->va_nlink = node->tn_links;
330 vap->va_uid = node->tn_uid;
331 vap->va_gid = node->tn_gid;
332 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
333 vap->va_fileid = node->tn_id;
334 vap->va_size = node->tn_size;
335 vap->va_blocksize = PAGE_SIZE;
336 vap->va_atime.tv_sec = node->tn_atime;
337 vap->va_atime.tv_nsec = node->tn_atimensec;
338 vap->va_mtime.tv_sec = node->tn_mtime;
339 vap->va_mtime.tv_nsec = node->tn_mtimensec;
340 vap->va_ctime.tv_sec = node->tn_ctime;
341 vap->va_ctime.tv_nsec = node->tn_ctimensec;
342 vap->va_gen = node->tn_gen;
343 vap->va_flags = node->tn_flags;
ff837cd5 344 if (vp->v_type == VBLK || vp->v_type == VCHR) {
7a2de9a4
MD
345 vap->va_rmajor = umajor(node->tn_rdev);
346 vap->va_rminor = uminor(node->tn_rdev);
347 }
348 vap->va_bytes = round_page(node->tn_size);
349 vap->va_filerev = 0;
ff837cd5 350 TMPFS_NODE_UNLOCK(node);
e575e508 351
7a2de9a4
MD
352 return 0;
353}
354
355/* --------------------------------------------------------------------- */
356
357int
ba25006a 358tmpfs_setattr(struct vop_setattr_args *ap)
7a2de9a4 359{
ba25006a
SW
360 struct vnode *vp = ap->a_vp;
361 struct vattr *vap = ap->a_vap;
362 struct ucred *cred = ap->a_cred;
80ae59d7 363 struct tmpfs_node *node = VP_TO_TMPFS_NODE(vp);
7a2de9a4 364 int error = 0;
80ae59d7 365 int kflags = 0;
7a2de9a4 366
ff837cd5 367 TMPFS_NODE_LOCK(node);
80ae59d7 368 if (error == 0 && (vap->va_flags != VNOVAL)) {
7a2de9a4 369 error = tmpfs_chflags(vp, vap->va_flags, cred);
80ae59d7
MD
370 kflags |= NOTE_ATTRIB;
371 }
7a2de9a4 372
80ae59d7
MD
373 if (error == 0 && (vap->va_size != VNOVAL)) {
374 if (vap->va_size > node->tn_size)
375 kflags |= NOTE_WRITE | NOTE_EXTEND;
376 else
377 kflags |= NOTE_WRITE;
7a2de9a4 378 error = tmpfs_chsize(vp, vap->va_size, cred);
80ae59d7 379 }
7a2de9a4 380
d89ce96a
MD
381 if (error == 0 && (vap->va_uid != (uid_t)VNOVAL ||
382 vap->va_gid != (gid_t)VNOVAL)) {
7a2de9a4 383 error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred);
80ae59d7 384 kflags |= NOTE_ATTRIB;
d89ce96a 385 }
7a2de9a4 386
80ae59d7 387 if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) {
7a2de9a4 388 error = tmpfs_chmod(vp, vap->va_mode, cred);
80ae59d7
MD
389 kflags |= NOTE_ATTRIB;
390 }
7a2de9a4
MD
391
392 if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
393 vap->va_atime.tv_nsec != VNOVAL) ||
394 (vap->va_mtime.tv_sec != VNOVAL &&
d89ce96a 395 vap->va_mtime.tv_nsec != VNOVAL) )) {
7a2de9a4 396 error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
d89ce96a 397 vap->va_vaflags, cred);
80ae59d7 398 kflags |= NOTE_ATTRIB;
d89ce96a 399 }
7a2de9a4 400
ff837cd5
MD
401 /*
402 * Update the node times. We give preference to the error codes
7a2de9a4 403 * generated by this function rather than the ones that may arise
ff837cd5
MD
404 * from tmpfs_update.
405 */
7a2de9a4 406 tmpfs_update(vp);
ff837cd5 407 TMPFS_NODE_UNLOCK(node);
80ae59d7 408 tmpfs_knote(vp, kflags);
7a2de9a4 409
aa1adbf0 410 return (error);
7a2de9a4
MD
411}
412
413/* --------------------------------------------------------------------- */
414
9fc94b5f 415/*
630e3a33
MD
416 * fsync is usually a NOP, but we must take action when unmounting or
417 * when recycling.
9fc94b5f 418 */
7a2de9a4 419static int
ba25006a 420tmpfs_fsync(struct vop_fsync_args *ap)
7a2de9a4 421{
630e3a33 422 struct tmpfs_node *node;
ba25006a 423 struct vnode *vp = ap->a_vp;
7a2de9a4 424
630e3a33
MD
425 node = VP_TO_TMPFS_NODE(vp);
426
427 tmpfs_update(vp);
428 if (vp->v_type == VREG) {
d4623db3 429 if (vp->v_flag & VRECLAIMED) {
630e3a33
MD
430 if (node->tn_links == 0)
431 tmpfs_truncate(vp, 0);
432 else
ba25006a 433 vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL);
630e3a33 434 }
9fc94b5f 435 }
7a2de9a4
MD
436 return 0;
437}
438
439/* --------------------------------------------------------------------- */
440
441static int
ba25006a 442tmpfs_read(struct vop_read_args *ap)
7a2de9a4
MD
443{
444 struct buf *bp;
445 struct vnode *vp = ap->a_vp;
446 struct uio *uio = ap->a_uio;
447 struct tmpfs_node *node;
7a2de9a4 448 off_t base_offset;
9fc94b5f 449 size_t offset;
7a2de9a4 450 size_t len;
2446b819 451 size_t resid;
9fc94b5f 452 int error;
7a2de9a4 453
2446b819
MD
454 /*
455 * Check the basics
456 */
7a2de9a4
MD
457 if (uio->uio_offset < 0)
458 return (EINVAL);
459 if (vp->v_type != VREG)
460 return (EINVAL);
461
2446b819
MD
462 /*
463 * Extract node, try to shortcut the operation through
464 * the VM page cache, allowing us to avoid buffer cache
465 * overheads.
466 */
467 node = VP_TO_TMPFS_NODE(vp);
468 resid = uio->uio_resid;
469 error = vop_helper_read_shortcut(ap);
470 if (error)
471 return error;
472 if (uio->uio_resid == 0) {
473 if (resid)
474 goto finished;
475 return error;
476 }
477
478 /*
479 * Fall-through to our normal read code.
480 */
7a2de9a4
MD
481 while (uio->uio_resid > 0 && uio->uio_offset < node->tn_size) {
482 /*
483 * Use buffer cache I/O (via tmpfs_strategy)
484 */
3c54bb74 485 offset = (size_t)uio->uio_offset & TMPFS_BLKMASK64;
7a2de9a4 486 base_offset = (off_t)uio->uio_offset - offset;
48db4e20 487 bp = getcacheblk(vp, base_offset, TMPFS_BLKSIZE, GETBLK_KVABIO);
9de13b88 488 if (bp == NULL) {
48db4e20
MD
489 error = bread_kvabio(vp, base_offset,
490 TMPFS_BLKSIZE, &bp);
7a2de9a4
MD
491 if (error) {
492 brelse(bp);
493 kprintf("tmpfs_read bread error %d\n", error);
494 break;
495 }
527cd77d
MD
496
497 /*
498 * tmpfs pretty much fiddles directly with the VM
499 * system, don't let it exhaust it or we won't play
500 * nice with other processes.
501 *
502 * Only do this if the VOP is coming from a normal
503 * read/write. The VM system handles the case for
504 * UIO_NOCOPY.
505 */
506 if (uio->uio_segflg != UIO_NOCOPY)
507 vm_wait_nominal();
7a2de9a4 508 }
3c54bb74 509 bp->b_flags |= B_CLUSTEROK;
7a2de9a4 510
7a2de9a4
MD
511 /*
512 * Figure out how many bytes we can actually copy this loop.
513 */
3c54bb74 514 len = TMPFS_BLKSIZE - offset;
7a2de9a4
MD
515 if (len > uio->uio_resid)
516 len = uio->uio_resid;
517 if (len > node->tn_size - uio->uio_offset)
518 len = (size_t)(node->tn_size - uio->uio_offset);
519
44480e31 520 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
7a2de9a4
MD
521 bqrelse(bp);
522 if (error) {
523 kprintf("tmpfs_read uiomove error %d\n", error);
524 break;
525 }
526 }
527
2446b819 528finished:
bed3b851
TK
529 if ((node->tn_status & TMPFS_NODE_ACCESSED) == 0) {
530 TMPFS_NODE_LOCK(node);
531 node->tn_status |= TMPFS_NODE_ACCESSED;
532 TMPFS_NODE_UNLOCK(node);
533 }
aa1adbf0 534 return (error);
7a2de9a4
MD
535}
536
537static int
ba25006a 538tmpfs_write(struct vop_write_args *ap)
7a2de9a4
MD
539{
540 struct buf *bp;
541 struct vnode *vp = ap->a_vp;
542 struct uio *uio = ap->a_uio;
543 struct thread *td = uio->uio_td;
544 struct tmpfs_node *node;
545 boolean_t extended;
546 off_t oldsize;
547 int error;
7a2de9a4 548 off_t base_offset;
9fc94b5f 549 size_t offset;
7a2de9a4
MD
550 size_t len;
551 struct rlimit limit;
7a2de9a4 552 int trivial = 0;
80ae59d7 553 int kflags = 0;
3c54bb74 554 int seqcount;
7a2de9a4
MD
555
556 error = 0;
557 if (uio->uio_resid == 0) {
558 return error;
559 }
560
561 node = VP_TO_TMPFS_NODE(vp);
562
563 if (vp->v_type != VREG)
564 return (EINVAL);
3c54bb74 565 seqcount = ap->a_ioflag >> 16;
7a2de9a4 566
b37a7c00
MD
567 TMPFS_NODE_LOCK(node);
568
7a2de9a4
MD
569 oldsize = node->tn_size;
570 if (ap->a_ioflag & IO_APPEND)
571 uio->uio_offset = node->tn_size;
572
573 /*
574 * Check for illegal write offsets.
575 */
576 if (uio->uio_offset + uio->uio_resid >
1be4932c 577 VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize) {
b37a7c00
MD
578 error = EFBIG;
579 goto done;
1be4932c 580 }
7a2de9a4 581
4c5cdd6b
MD
582 /*
583 * NOTE: Ignore if UIO does not come from a user thread (e.g. VN).
584 */
585 if (vp->v_type == VREG && td != NULL && td->td_lwp != NULL) {
7a2de9a4 586 error = kern_getrlimit(RLIMIT_FSIZE, &limit);
b37a7c00
MD
587 if (error)
588 goto done;
7a2de9a4
MD
589 if (uio->uio_offset + uio->uio_resid > limit.rlim_cur) {
590 ksignal(td->td_proc, SIGXFSZ);
b37a7c00
MD
591 error = EFBIG;
592 goto done;
7a2de9a4
MD
593 }
594 }
595
7a2de9a4
MD
596 /*
597 * Extend the file's size if necessary
598 */
9fc94b5f 599 extended = ((uio->uio_offset + uio->uio_resid) > node->tn_size);
7a2de9a4 600
7a2de9a4 601 while (uio->uio_resid > 0) {
3c54bb74
MD
602 /*
603 * Don't completely blow out running buffer I/O
604 * when being hit from the pageout daemon.
605 */
606 if (uio->uio_segflg == UIO_NOCOPY &&
607 (ap->a_ioflag & IO_RECURSE) == 0) {
608 bwillwrite(TMPFS_BLKSIZE);
609 }
610
7a2de9a4
MD
611 /*
612 * Use buffer cache I/O (via tmpfs_strategy)
613 */
3c54bb74 614 offset = (size_t)uio->uio_offset & TMPFS_BLKMASK64;
7a2de9a4 615 base_offset = (off_t)uio->uio_offset - offset;
3c54bb74 616 len = TMPFS_BLKSIZE - offset;
7a2de9a4
MD
617 if (len > uio->uio_resid)
618 len = uio->uio_resid;
619
620 if ((uio->uio_offset + len) > node->tn_size) {
9fc94b5f 621 trivial = (uio->uio_offset <= node->tn_size);
b37a7c00
MD
622 error = tmpfs_reg_resize(vp, uio->uio_offset + len,
623 trivial);
7a2de9a4
MD
624 if (error)
625 break;
626 }
627
9fc94b5f
MD
628 /*
629 * Read to fill in any gaps. Theoretically we could
630 * optimize this if the write covers the entire buffer
631 * and is not a UIO_NOCOPY write, however this can lead
632 * to a security violation exposing random kernel memory
633 * (whatever junk was in the backing VM pages before).
634 *
635 * So just use bread() to do the right thing.
636 */
48db4e20 637 error = bread_kvabio(vp, base_offset, TMPFS_BLKSIZE, &bp);
44480e31 638 error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
7a2de9a4
MD
639 if (error) {
640 kprintf("tmpfs_write uiomove error %d\n", error);
641 brelse(bp);
642 break;
643 }
644
80ae59d7 645 if (uio->uio_offset > node->tn_size) {
7a2de9a4 646 node->tn_size = uio->uio_offset;
80ae59d7
MD
647 kflags |= NOTE_EXTEND;
648 }
649 kflags |= NOTE_WRITE;
7a2de9a4
MD
650
651 /*
d86d27a8
MD
652 * Always try to flush the page in the UIO_NOCOPY case. This
653 * can come from the pageout daemon or during vnode eviction.
654 * It is not necessarily going to be marked IO_ASYNC/IO_SYNC.
7a2de9a4 655 *
d86d27a8
MD
656 * For the normal case we buwrite(), dirtying the underlying
657 * VM pages instead of dirtying the buffer and releasing the
658 * buffer as a clean buffer. This allows tmpfs to use
659 * essentially all available memory to cache file data.
660 * If we used bdwrite() the buffer cache would wind up
661 * flushing the data to swap too quickly.
527cd77d 662 *
3c54bb74
MD
663 * But because tmpfs can seriously load the VM system we
664 * fall-back to using bdwrite() when free memory starts
665 * to get low. This shifts the load away from the VM system
666 * and makes tmpfs act more like a normal filesystem with
667 * regards to disk activity.
668 *
527cd77d
MD
669 * tmpfs pretty much fiddles directly with the VM
670 * system, don't let it exhaust it or we won't play
671 * nice with other processes. Only do this if the
672 * VOP is coming from a normal read/write. The VM system
673 * handles the case for UIO_NOCOPY.
7a2de9a4 674 */
3c54bb74 675 bp->b_flags |= B_CLUSTEROK;
d86d27a8 676 if (uio->uio_segflg == UIO_NOCOPY) {
6ff1f162
MD
677 /*
678 * Flush from the pageout daemon, deal with
679 * potentially very heavy tmpfs write activity
680 * causing long stalls in the pageout daemon
681 * before pages get to free/cache.
682 *
683 * (a) Under severe pressure setting B_DIRECT will
684 * cause a buffer release to try to free the
685 * underlying pages.
686 *
687 * (b) Under modest memory pressure the B_RELBUF
688 * alone is sufficient to get the pages moved
689 * to the cache. We could also force this by
690 * setting B_NOTMETA but that might have other
691 * unintended side-effects (e.g. setting
692 * PG_NOTMETA on the VM page).
693 *
694 * Hopefully this will unblock the VM system more
695 * quickly under extreme tmpfs write load.
696 */
77d1fb91 697 if (vm_page_count_min(vm_page_free_hysteresis))
6ff1f162 698 bp->b_flags |= B_DIRECT;
3c54bb74
MD
699 bp->b_flags |= B_AGE | B_RELBUF;
700 bp->b_act_count = 0; /* buffer->deactivate pgs */
701 cluster_awrite(bp);
702 } else if (vm_page_count_target()) {
6ff1f162
MD
703 /*
704 * Normal (userland) write but we are low on memory,
705 * run the buffer the buffer cache.
706 */
3c54bb74
MD
707 bp->b_act_count = 0; /* buffer->deactivate pgs */
708 bdwrite(bp);
b7545cb3 709 } else {
6ff1f162
MD
710 /*
711 * Otherwise run the buffer directly through to the
712 * backing VM store.
713 */
fc1a9118 714 buwrite(bp);
3c54bb74 715 /*vm_wait_nominal();*/
d89ce96a 716 }
9fc94b5f 717
7a2de9a4 718 if (bp->b_error) {
2cd8c774 719 kprintf("tmpfs_write bwrite error %d\n", bp->b_error);
7a2de9a4
MD
720 break;
721 }
722 }
7a2de9a4 723
7a2de9a4 724 if (error) {
80ae59d7 725 if (extended) {
7a2de9a4 726 (void)tmpfs_reg_resize(vp, oldsize, trivial);
80ae59d7
MD
727 kflags &= ~NOTE_EXTEND;
728 }
729 goto done;
7a2de9a4
MD
730 }
731
fc1a9118
MD
732 /*
733 * Currently we don't set the mtime on files modified via mmap()
734 * because we can't tell the difference between those modifications
735 * and an attempt by the pageout daemon to flush tmpfs pages to
736 * swap.
737 *
738 * This is because in order to defer flushes as long as possible
739 * buwrite() works by marking the underlying VM pages dirty in
740 * order to be able to dispose of the buffer cache buffer without
741 * flushing it.
742 */
fc1a9118
MD
743 if (uio->uio_segflg != UIO_NOCOPY)
744 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED;
745 if (extended)
746 node->tn_status |= TMPFS_NODE_CHANGED;
7a2de9a4
MD
747
748 if (node->tn_mode & (S_ISUID | S_ISGID)) {
749 if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID, 0))
750 node->tn_mode &= ~(S_ISUID | S_ISGID);
751 }
80ae59d7 752done:
b37a7c00
MD
753 TMPFS_NODE_UNLOCK(node);
754 if (kflags)
755 tmpfs_knote(vp, kflags);
1be4932c 756
7a2de9a4
MD
757 return(error);
758}
759
760static int
ba25006a 761tmpfs_advlock(struct vop_advlock_args *ap)
7a2de9a4
MD
762{
763 struct tmpfs_node *node;
764 struct vnode *vp = ap->a_vp;
aa1adbf0 765 int error;
7a2de9a4
MD
766
767 node = VP_TO_TMPFS_NODE(vp);
aa1adbf0 768 error = (lf_advlock(ap, &node->tn_advlock, node->tn_size));
aa1adbf0
MD
769
770 return (error);
7a2de9a4
MD
771}
772
fc1a9118
MD
773/*
774 * The strategy function is typically only called when memory pressure
775 * forces the system to attempt to pageout pages. It can also be called
776 * by [n]vtruncbuf() when a truncation cuts a page in half. Normal write
777 * operations
48db4e20
MD
778 *
779 * We set VKVABIO for VREG files so bp->b_data may not be synchronized to
780 * our cpu. swap_pager_strategy() is all we really use, and it directly
781 * supports this.
fc1a9118 782 */
7a2de9a4
MD
783static int
784tmpfs_strategy(struct vop_strategy_args *ap)
785{
786 struct bio *bio = ap->a_bio;
8f9ba07b 787 struct bio *nbio;
9fc94b5f 788 struct buf *bp = bio->bio_buf;
7a2de9a4
MD
789 struct vnode *vp = ap->a_vp;
790 struct tmpfs_node *node;
791 vm_object_t uobj;
8f9ba07b
MD
792 vm_page_t m;
793 int i;
7a2de9a4 794
9fc94b5f
MD
795 if (vp->v_type != VREG) {
796 bp->b_resid = bp->b_bcount;
797 bp->b_flags |= B_ERROR | B_INVAL;
798 bp->b_error = EINVAL;
799 biodone(bio);
800 return(0);
801 }
7a2de9a4
MD
802
803 node = VP_TO_TMPFS_NODE(vp);
804
805 uobj = node->tn_reg.tn_aobj;
9fc94b5f 806
7a2de9a4 807 /*
fc1a9118
MD
808 * Don't bother flushing to swap if there is no swap, just
809 * ensure that the pages are marked as needing a commit (still).
7a2de9a4 810 */
8f9ba07b
MD
811 if (bp->b_cmd == BUF_CMD_WRITE && vm_swap_size == 0) {
812 for (i = 0; i < bp->b_xio.xio_npages; ++i) {
813 m = bp->b_xio.xio_pages[i];
fc1a9118 814 vm_page_need_commit(m);
8f9ba07b
MD
815 }
816 bp->b_resid = 0;
817 bp->b_error = 0;
818 biodone(bio);
819 } else {
820 nbio = push_bio(bio);
821 nbio->bio_done = tmpfs_strategy_done;
822 nbio->bio_offset = bio->bio_offset;
823 swap_pager_strategy(uobj, nbio);
824 }
7a2de9a4
MD
825 return 0;
826}
827
8f9ba07b 828/*
fc1a9118
MD
829 * If we were unable to commit the pages to swap make sure they are marked
830 * as needing a commit (again). If we were, clear the flag to allow the
831 * pages to be freed.
8f9ba07b
MD
832 */
833static void
834tmpfs_strategy_done(struct bio *bio)
835{
836 struct buf *bp;
837 vm_page_t m;
838 int i;
839
840 bp = bio->bio_buf;
841
fc1a9118 842 if (bp->b_flags & B_ERROR) {
8f9ba07b
MD
843 bp->b_flags &= ~B_ERROR;
844 bp->b_error = 0;
845 bp->b_resid = 0;
846 for (i = 0; i < bp->b_xio.xio_npages; ++i) {
847 m = bp->b_xio.xio_pages[i];
fc1a9118
MD
848 vm_page_need_commit(m);
849 }
850 } else {
851 for (i = 0; i < bp->b_xio.xio_npages; ++i) {
852 m = bp->b_xio.xio_pages[i];
853 vm_page_clear_commit(m);
8f9ba07b
MD
854 }
855 }
856 bio = pop_bio(bio);
857 biodone(bio);
858}
859
7a2de9a4
MD
860static int
861tmpfs_bmap(struct vop_bmap_args *ap)
862{
863 if (ap->a_doffsetp != NULL)
864 *ap->a_doffsetp = ap->a_loffset;
865 if (ap->a_runp != NULL)
866 *ap->a_runp = 0;
867 if (ap->a_runb != NULL)
868 *ap->a_runb = 0;
869
870 return 0;
871}
9fc94b5f 872
7a2de9a4
MD
873/* --------------------------------------------------------------------- */
874
875static int
ba25006a 876tmpfs_nremove(struct vop_nremove_args *ap)
7a2de9a4 877{
ba25006a
SW
878 struct vnode *dvp = ap->a_dvp;
879 struct namecache *ncp = ap->a_nch->ncp;
9fc94b5f 880 struct vnode *vp;
7a2de9a4
MD
881 int error;
882 struct tmpfs_dirent *de;
883 struct tmpfs_mount *tmp;
884 struct tmpfs_node *dnode;
885 struct tmpfs_node *node;
aa1adbf0 886
9fc94b5f 887 /*
ba25006a 888 * We have to acquire the vp from ap->a_nch because we will likely
a1fa5d8d
MD
889 * unresolve the namecache entry, and a vrele/vput is needed to
890 * trigger the tmpfs_inactive/tmpfs_reclaim sequence.
891 *
892 * We have to use vget to clear any inactive state on the vnode,
893 * otherwise the vnode may remain inactive and thus tmpfs_inactive
894 * will not get called when we release it.
9fc94b5f 895 */
ba25006a 896 error = cache_vget(ap->a_nch, ap->a_cred, LK_SHARED, &vp);
aa1adbf0 897 KKASSERT(vp->v_mount == dvp->v_mount);
9fc94b5f 898 KKASSERT(error == 0);
a1fa5d8d 899 vn_unlock(vp);
7a2de9a4
MD
900
901 if (vp->v_type == VDIR) {
902 error = EISDIR;
ff837cd5 903 goto out2;
7a2de9a4
MD
904 }
905
906 dnode = VP_TO_TMPFS_DIR(dvp);
907 node = VP_TO_TMPFS_NODE(vp);
908 tmp = VFS_TO_TMPFS(vp->v_mount);
ff837cd5
MD
909
910 TMPFS_NODE_LOCK(dnode);
7a2de9a4
MD
911 de = tmpfs_dir_lookup(dnode, node, ncp);
912 if (de == NULL) {
913 error = ENOENT;
914 goto out;
915 }
916
917 /* Files marked as immutable or append-only cannot be deleted. */
918 if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
919 (dnode->tn_flags & APPEND)) {
920 error = EPERM;
921 goto out;
922 }
923
924 /* Remove the entry from the directory; as it is a file, we do not
925 * have to change the number of hard links of the directory. */
22d3b394 926 tmpfs_dir_detach(dnode, de);
7a2de9a4
MD
927
928 /* Free the directory entry we just deleted. Note that the node
929 * referred by it will not be removed until the vnode is really
930 * reclaimed. */
0786baf1 931 tmpfs_free_dirent(tmp, de);
7a2de9a4
MD
932
933 if (node->tn_links > 0) {
934 TMPFS_NODE_LOCK(node);
935 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
936 TMPFS_NODE_MODIFIED;
937 TMPFS_NODE_UNLOCK(node);
938 }
939
ba25006a 940 cache_unlink(ap->a_nch);
80ae59d7 941 tmpfs_knote(vp, NOTE_DELETE);
7a2de9a4
MD
942 error = 0;
943
7a2de9a4 944out:
ff837cd5
MD
945 TMPFS_NODE_UNLOCK(dnode);
946 if (error == 0)
947 tmpfs_knote(dvp, NOTE_WRITE);
948out2:
9fc94b5f 949 vrele(vp);
7a2de9a4
MD
950
951 return error;
952}
953
954/* --------------------------------------------------------------------- */
955
956static int
ba25006a 957tmpfs_nlink(struct vop_nlink_args *ap)
7a2de9a4 958{
ba25006a
SW
959 struct vnode *dvp = ap->a_dvp;
960 struct vnode *vp = ap->a_vp;
961 struct namecache *ncp = ap->a_nch->ncp;
7a2de9a4
MD
962 struct tmpfs_dirent *de;
963 struct tmpfs_node *node;
22d3b394
MD
964 struct tmpfs_node *dnode;
965 int error;
7a2de9a4 966
7a2de9a4
MD
967 KKASSERT(dvp != vp); /* XXX When can this be false? */
968
969 node = VP_TO_TMPFS_NODE(vp);
22d3b394 970 dnode = VP_TO_TMPFS_NODE(dvp);
ff837cd5 971 TMPFS_NODE_LOCK(dnode);
7a2de9a4
MD
972
973 /* XXX: Why aren't the following two tests done by the caller? */
974
975 /* Hard links of directories are forbidden. */
976 if (vp->v_type == VDIR) {
977 error = EPERM;
978 goto out;
979 }
980
981 /* Cannot create cross-device links. */
982 if (dvp->v_mount != vp->v_mount) {
983 error = EXDEV;
984 goto out;
985 }
986
987 /* Ensure that we do not overflow the maximum number of links imposed
988 * by the system. */
989 KKASSERT(node->tn_links <= LINK_MAX);
ff837cd5 990 if (node->tn_links >= LINK_MAX) {
7a2de9a4
MD
991 error = EMLINK;
992 goto out;
993 }
994
995 /* We cannot create links of files marked immutable or append-only. */
996 if (node->tn_flags & (IMMUTABLE | APPEND)) {
997 error = EPERM;
998 goto out;
999 }
1000
1001 /* Allocate a new directory entry to represent the node. */
1002 error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
aa1adbf0 1003 ncp->nc_name, ncp->nc_nlen, &de);
7a2de9a4
MD
1004 if (error != 0)
1005 goto out;
1006
1007 /* Insert the new directory entry into the appropriate directory. */
22d3b394 1008 tmpfs_dir_attach(dnode, de);
7a2de9a4
MD
1009
1010 /* vp link count has changed, so update node times. */
1011
1012 TMPFS_NODE_LOCK(node);
1013 node->tn_status |= TMPFS_NODE_CHANGED;
1014 TMPFS_NODE_UNLOCK(node);
1015 tmpfs_update(vp);
1016
80ae59d7 1017 tmpfs_knote(vp, NOTE_LINK);
ba25006a
SW
1018 cache_setunresolved(ap->a_nch);
1019 cache_setvp(ap->a_nch, vp);
7a2de9a4
MD
1020 error = 0;
1021
1022out:
ff837cd5
MD
1023 TMPFS_NODE_UNLOCK(dnode);
1024 if (error == 0)
1025 tmpfs_knote(dvp, NOTE_WRITE);
7a2de9a4
MD
1026 return error;
1027}
1028
1029/* --------------------------------------------------------------------- */
1030
1031static int
ba25006a 1032tmpfs_nrename(struct vop_nrename_args *ap)
7a2de9a4 1033{
ba25006a
SW
1034 struct vnode *fdvp = ap->a_fdvp;
1035 struct namecache *fncp = ap->a_fnch->ncp;
7a2de9a4 1036 struct vnode *fvp = fncp->nc_vp;
ba25006a
SW
1037 struct vnode *tdvp = ap->a_tdvp;
1038 struct namecache *tncp = ap->a_tnch->ncp;
a1fa5d8d 1039 struct vnode *tvp;
29ca4fd6 1040 struct tmpfs_dirent *de, *tde;
7a2de9a4
MD
1041 struct tmpfs_mount *tmp;
1042 struct tmpfs_node *fdnode;
1043 struct tmpfs_node *fnode;
1044 struct tmpfs_node *tnode;
1045 struct tmpfs_node *tdnode;
22d3b394 1046 char *newname;
dca262fb 1047 char *oldname;
22d3b394 1048 int error;
7a2de9a4 1049
aa1adbf0
MD
1050 KKASSERT(fdvp->v_mount == fvp->v_mount);
1051
a1fa5d8d
MD
1052 /*
1053 * Because tvp can get overwritten we have to vget it instead of
1054 * just vref or use it, otherwise it's VINACTIVE flag may not get
1055 * cleared and the node won't get destroyed.
1056 */
ba25006a 1057 error = cache_vget(ap->a_tnch, ap->a_cred, LK_SHARED, &tvp);
a1fa5d8d
MD
1058 if (error == 0) {
1059 tnode = VP_TO_TMPFS_NODE(tvp);
1060 vn_unlock(tvp);
1061 } else {
1062 tnode = NULL;
1063 }
7a2de9a4
MD
1064
1065 /* Disallow cross-device renames.
1066 * XXX Why isn't this done by the caller? */
1067 if (fvp->v_mount != tdvp->v_mount ||
1068 (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
1069 error = EXDEV;
1070 goto out;
1071 }
1072
1073 tmp = VFS_TO_TMPFS(tdvp->v_mount);
1074 tdnode = VP_TO_TMPFS_DIR(tdvp);
1075
1076 /* If source and target are the same file, there is nothing to do. */
1077 if (fvp == tvp) {
1078 error = 0;
1079 goto out;
1080 }
1081
7a2de9a4
MD
1082 fdnode = VP_TO_TMPFS_DIR(fdvp);
1083 fnode = VP_TO_TMPFS_NODE(fvp);
ff837cd5 1084 TMPFS_NODE_LOCK(fdnode);
7a2de9a4 1085 de = tmpfs_dir_lookup(fdnode, fnode, fncp);
ff837cd5 1086 TMPFS_NODE_UNLOCK(fdnode); /* XXX depend on namecache lock */
7a2de9a4
MD
1087
1088 /* Avoid manipulating '.' and '..' entries. */
1089 if (de == NULL) {
1090 error = ENOENT;
1091 goto out_locked;
1092 }
1093 KKASSERT(de->td_node == fnode);
1094
dca262fb
MD
1095 /*
1096 * If replacing an entry in the target directory and that entry
1097 * is a directory, it must be empty.
1098 *
7a2de9a4 1099 * Kern_rename gurantees the destination to be a directory
dca262fb
MD
1100 * if the source is one (it does?).
1101 */
7a2de9a4
MD
1102 if (tvp != NULL) {
1103 KKASSERT(tnode != NULL);
1104
1105 if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
1106 (tdnode->tn_flags & (APPEND | IMMUTABLE))) {
1107 error = EPERM;
1108 goto out_locked;
1109 }
1110
1111 if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
1112 if (tnode->tn_size > 0) {
1113 error = ENOTEMPTY;
1114 goto out_locked;
1115 }
1116 } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
1117 error = ENOTDIR;
1118 goto out_locked;
1119 } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
1120 error = EISDIR;
1121 goto out_locked;
1122 } else {
1123 KKASSERT(fnode->tn_type != VDIR &&
1124 tnode->tn_type != VDIR);
1125 }
1126 }
1127
dca262fb
MD
1128 if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
1129 (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
7a2de9a4
MD
1130 error = EPERM;
1131 goto out_locked;
1132 }
1133
dca262fb
MD
1134 /*
1135 * Ensure that we have enough memory to hold the new name, if it
1136 * has to be changed.
1137 */
7a2de9a4
MD
1138 if (fncp->nc_nlen != tncp->nc_nlen ||
1139 bcmp(fncp->nc_name, tncp->nc_name, fncp->nc_nlen) != 0) {
d00cd01c 1140 newname = kmalloc(tncp->nc_nlen + 1, tmp->tm_name_zone,
42f6f6b1
VS
1141 M_WAITOK | M_NULLOK);
1142 if (newname == NULL) {
1143 error = ENOSPC;
1144 goto out_locked;
1145 }
dca262fb
MD
1146 bcopy(tncp->nc_name, newname, tncp->nc_nlen);
1147 newname[tncp->nc_nlen] = '\0';
1148 } else {
7a2de9a4 1149 newname = NULL;
dca262fb 1150 }
7a2de9a4 1151
dca262fb
MD
1152 /*
1153 * Unlink entry from source directory. Note that the kernel has
1154 * already checked for illegal recursion cases (renaming a directory
1155 * into a subdirectory of itself).
1156 */
6e0c5aab 1157 if (fdnode != tdnode) {
dca262fb 1158 tmpfs_dir_detach(fdnode, de);
6e0c5aab 1159 } else {
e195a8fe
MD
1160 /* XXX depend on namecache lock */
1161 TMPFS_NODE_LOCK(fdnode);
1162 KKASSERT(de == tmpfs_dir_lookup(fdnode, fnode, fncp));
29ca4fd6 1163 RB_REMOVE(tmpfs_dirtree, &fdnode->tn_dir.tn_dirtree, de);
f5f22af6
MD
1164 RB_REMOVE(tmpfs_dirtree_cookie,
1165 &fdnode->tn_dir.tn_cookietree, de);
e195a8fe 1166 TMPFS_NODE_UNLOCK(fdnode);
29ca4fd6 1167 }
dca262fb
MD
1168
1169 /*
1170 * Handle any name change. Swap with newname, we will
1171 * deallocate it at the end.
1172 */
1173 if (newname != NULL) {
1174#if 0
1175 TMPFS_NODE_LOCK(fnode);
1176 fnode->tn_status |= TMPFS_NODE_CHANGED;
1177 TMPFS_NODE_UNLOCK(fnode);
1178#endif
1179 oldname = de->td_name;
1180 de->td_name = newname;
1181 de->td_namelen = (uint16_t)tncp->nc_nlen;
1182 newname = oldname;
1183 }
1184
29ca4fd6
JH
1185 /*
1186 * If we are overwriting an entry, we have to remove the old one
1187 * from the target directory.
1188 */
1189 if (tvp != NULL) {
1190 /* Remove the old entry from the target directory. */
ff837cd5 1191 TMPFS_NODE_LOCK(tdnode);
29ca4fd6
JH
1192 tde = tmpfs_dir_lookup(tdnode, tnode, tncp);
1193 tmpfs_dir_detach(tdnode, tde);
ff837cd5 1194 TMPFS_NODE_UNLOCK(tdnode);
29ca4fd6
JH
1195 tmpfs_knote(tdnode->tn_vnode, NOTE_DELETE);
1196
1197 /*
1198 * Free the directory entry we just deleted. Note that the
1199 * node referred by it will not be removed until the vnode is
1200 * really reclaimed.
1201 */
1202 tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), tde);
1203 /*cache_inval_vp(tvp, CINV_DESTROY);*/
1204 }
1205
dca262fb
MD
1206 /*
1207 * Link entry to target directory. If the entry
1208 * represents a directory move the parent linkage
1209 * as well.
1210 */
7a2de9a4 1211 if (fdnode != tdnode) {
7a2de9a4 1212 if (de->td_node->tn_type == VDIR) {
7a2de9a4 1213 TMPFS_VALIDATE_DIR(fnode);
7a2de9a4 1214 }
22d3b394 1215 tmpfs_dir_attach(tdnode, de);
dca262fb 1216 } else {
7a2de9a4 1217 TMPFS_NODE_LOCK(tdnode);
7a2de9a4 1218 tdnode->tn_status |= TMPFS_NODE_MODIFIED;
29ca4fd6 1219 RB_INSERT(tmpfs_dirtree, &tdnode->tn_dir.tn_dirtree, de);
f5f22af6
MD
1220 RB_INSERT(tmpfs_dirtree_cookie,
1221 &tdnode->tn_dir.tn_cookietree, de);
7a2de9a4
MD
1222 TMPFS_NODE_UNLOCK(tdnode);
1223 }
1224
dca262fb
MD
1225 /*
1226 * Finish up
1227 */
1228 if (newname) {
d00cd01c 1229 kfree(newname, tmp->tm_name_zone);
dca262fb
MD
1230 newname = NULL;
1231 }
ba25006a
SW
1232 cache_rename(ap->a_fnch, ap->a_tnch);
1233 tmpfs_knote(ap->a_fdvp, NOTE_WRITE);
1234 tmpfs_knote(ap->a_tdvp, NOTE_WRITE);
80ae59d7
MD
1235 if (fnode->tn_vnode)
1236 tmpfs_knote(fnode->tn_vnode, NOTE_RENAME);
7a2de9a4
MD
1237 error = 0;
1238
1239out_locked:
630e3a33 1240 ;
7a2de9a4 1241out:
a1fa5d8d
MD
1242 if (tvp)
1243 vrele(tvp);
7a2de9a4
MD
1244 return error;
1245}
1246
1247/* --------------------------------------------------------------------- */
1248
1249static int
ba25006a 1250tmpfs_nmkdir(struct vop_nmkdir_args *ap)
7a2de9a4 1251{
ba25006a
SW
1252 struct vnode *dvp = ap->a_dvp;
1253 struct vnode **vpp = ap->a_vpp;
1254 struct namecache *ncp = ap->a_nch->ncp;
1255 struct vattr *vap = ap->a_vap;
1256 struct ucred *cred = ap->a_cred;
7a2de9a4
MD
1257 int error;
1258
1259 KKASSERT(vap->va_type == VDIR);
1260
7a2de9a4
MD
1261 error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
1262 if (error == 0) {
ba25006a
SW
1263 cache_setunresolved(ap->a_nch);
1264 cache_setvp(ap->a_nch, *vpp);
80ae59d7 1265 tmpfs_knote(dvp, NOTE_WRITE | NOTE_LINK);
7a2de9a4 1266 }
7a2de9a4
MD
1267 return error;
1268}
1269
1270/* --------------------------------------------------------------------- */
1271
1272static int
ba25006a 1273tmpfs_nrmdir(struct vop_nrmdir_args *ap)
7a2de9a4 1274{
ba25006a
SW
1275 struct vnode *dvp = ap->a_dvp;
1276 struct namecache *ncp = ap->a_nch->ncp;
9fc94b5f 1277 struct vnode *vp;
7a2de9a4
MD
1278 struct tmpfs_dirent *de;
1279 struct tmpfs_mount *tmp;
1280 struct tmpfs_node *dnode;
1281 struct tmpfs_node *node;
38e5e604
MD
1282 int error;
1283
9fc94b5f 1284 /*
ba25006a 1285 * We have to acquire the vp from ap->a_nch because we will likely
a1fa5d8d
MD
1286 * unresolve the namecache entry, and a vrele/vput is needed to
1287 * trigger the tmpfs_inactive/tmpfs_reclaim sequence.
1288 *
1289 * We have to use vget to clear any inactive state on the vnode,
1290 * otherwise the vnode may remain inactive and thus tmpfs_inactive
1291 * will not get called when we release it.
9fc94b5f 1292 */
ba25006a 1293 error = cache_vget(ap->a_nch, ap->a_cred, LK_SHARED, &vp);
9fc94b5f 1294 KKASSERT(error == 0);
a1fa5d8d 1295 vn_unlock(vp);
7a2de9a4 1296
e527fb6b
MD
1297 /*
1298 * Prevalidate so we don't hit an assertion later
1299 */
1300 if (vp->v_type != VDIR) {
1301 error = ENOTDIR;
1302 goto out;
1303 }
1304
7a2de9a4
MD
1305 tmp = VFS_TO_TMPFS(dvp->v_mount);
1306 dnode = VP_TO_TMPFS_DIR(dvp);
1307 node = VP_TO_TMPFS_DIR(vp);
1308
ff837cd5
MD
1309 /*
1310 * Directories with more than two entries ('.' and '..') cannot
1311 * be removed.
1312 */
1313 if (node->tn_size > 0) {
1314 error = ENOTEMPTY;
1315 goto out;
1316 }
7a2de9a4
MD
1317
1318 if ((dnode->tn_flags & APPEND)
1319 || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1320 error = EPERM;
1321 goto out;
1322 }
1323
ff837cd5
MD
1324 /*
1325 * This invariant holds only if we are not trying to
1326 * remove "..". We checked for that above so this is safe now.
1327 */
7a2de9a4
MD
1328 KKASSERT(node->tn_dir.tn_parent == dnode);
1329
ff837cd5
MD
1330 /*
1331 * Get the directory entry associated with node (vp). This
1332 * was filled by tmpfs_lookup while looking up the entry.
1333 */
1334 TMPFS_NODE_LOCK(dnode);
7a2de9a4 1335 de = tmpfs_dir_lookup(dnode, node, ncp);
ff837cd5 1336 KKASSERT(TMPFS_DIRENT_MATCHES(de, ncp->nc_name, ncp->nc_nlen));
7a2de9a4
MD
1337
1338 /* Check flags to see if we are allowed to remove the directory. */
b7fe63af
MD
1339 if ((dnode->tn_flags & APPEND) ||
1340 node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) {
7a2de9a4 1341 error = EPERM;
ff837cd5 1342 TMPFS_NODE_UNLOCK(dnode);
7a2de9a4
MD
1343 goto out;
1344 }
1345
7a2de9a4 1346 /* Detach the directory entry from the directory (dnode). */
22d3b394 1347 tmpfs_dir_detach(dnode, de);
ff837cd5 1348 TMPFS_NODE_UNLOCK(dnode);
7a2de9a4
MD
1349
1350 /* No vnode should be allocated for this entry from this point */
7a2de9a4
MD
1351 TMPFS_NODE_LOCK(dnode);
1352 TMPFS_ASSERT_ELOCKED(dnode);
76683624
TK
1353 TMPFS_NODE_LOCK(node);
1354 TMPFS_ASSERT_ELOCKED(node);
7a2de9a4 1355
6e0c5aab
MD
1356 /*
1357 * Must set parent linkage to NULL (tested by ncreate to disallow
1358 * the creation of new files/dirs in a deleted directory)
1359 */
ff837cd5
MD
1360 node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
1361 TMPFS_NODE_MODIFIED;
7a2de9a4 1362
ff837cd5
MD
1363 dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
1364 TMPFS_NODE_MODIFIED;
7a2de9a4 1365
7a2de9a4 1366 TMPFS_NODE_UNLOCK(node);
76683624 1367 TMPFS_NODE_UNLOCK(dnode);
7a2de9a4
MD
1368
1369 /* Free the directory entry we just deleted. Note that the node
1370 * referred by it will not be removed until the vnode is really
1371 * reclaimed. */
0786baf1 1372 tmpfs_free_dirent(tmp, de);
7a2de9a4
MD
1373
1374 /* Release the deleted vnode (will destroy the node, notify
1375 * interested parties and clean it from the cache). */
1376
1377 TMPFS_NODE_LOCK(dnode);
1378 dnode->tn_status |= TMPFS_NODE_CHANGED;
1379 TMPFS_NODE_UNLOCK(dnode);
1380 tmpfs_update(dvp);
1381
ba25006a 1382 cache_unlink(ap->a_nch);
80ae59d7 1383 tmpfs_knote(dvp, NOTE_WRITE | NOTE_LINK);
7a2de9a4
MD
1384 error = 0;
1385
1386out:
9fc94b5f 1387 vrele(vp);
7a2de9a4
MD
1388
1389 return error;
1390}
1391
1392/* --------------------------------------------------------------------- */
1393
1394static int
ba25006a 1395tmpfs_nsymlink(struct vop_nsymlink_args *ap)
7a2de9a4 1396{
ba25006a
SW
1397 struct vnode *dvp = ap->a_dvp;
1398 struct vnode **vpp = ap->a_vpp;
1399 struct namecache *ncp = ap->a_nch->ncp;
1400 struct vattr *vap = ap->a_vap;
1401 struct ucred *cred = ap->a_cred;
1402 char *target = ap->a_target;
7a2de9a4
MD
1403 int error;
1404
7a2de9a4
MD
1405 vap->va_type = VLNK;
1406 error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, target);
1407 if (error == 0) {
80ae59d7 1408 tmpfs_knote(*vpp, NOTE_WRITE);
ba25006a
SW
1409 cache_setunresolved(ap->a_nch);
1410 cache_setvp(ap->a_nch, *vpp);
7a2de9a4 1411 }
7a2de9a4
MD
1412 return error;
1413}
1414
1415/* --------------------------------------------------------------------- */
1416
1417static int
ba25006a 1418tmpfs_readdir(struct vop_readdir_args *ap)
7a2de9a4 1419{
ba25006a
SW
1420 struct vnode *vp = ap->a_vp;
1421 struct uio *uio = ap->a_uio;
1422 int *eofflag = ap->a_eofflag;
1423 off_t **cookies = ap->a_cookies;
1424 int *ncookies = ap->a_ncookies;
22d3b394 1425 struct tmpfs_mount *tmp;
7a2de9a4
MD
1426 int error;
1427 off_t startoff;
1428 off_t cnt = 0;
1429 struct tmpfs_node *node;
1430
1431 /* This operation only makes sense on directory nodes. */
aa1adbf0 1432 if (vp->v_type != VDIR) {
7a2de9a4 1433 return ENOTDIR;
aa1adbf0 1434 }
7a2de9a4 1435
22d3b394 1436 tmp = VFS_TO_TMPFS(vp->v_mount);
7a2de9a4
MD
1437 node = VP_TO_TMPFS_DIR(vp);
1438 startoff = uio->uio_offset;
1439
1440 if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
1441 error = tmpfs_dir_getdotdent(node, uio);
ff837cd5
MD
1442 if (error != 0) {
1443 TMPFS_NODE_LOCK_SH(node);
7a2de9a4 1444 goto outok;
ff837cd5 1445 }
7a2de9a4
MD
1446 cnt++;
1447 }
1448
1449 if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
ff837cd5 1450 /* may lock parent, cannot hold node lock */
22d3b394 1451 error = tmpfs_dir_getdotdotdent(tmp, node, uio);
ff837cd5
MD
1452 if (error != 0) {
1453 TMPFS_NODE_LOCK_SH(node);
7a2de9a4 1454 goto outok;
ff837cd5 1455 }
7a2de9a4
MD
1456 cnt++;
1457 }
1458
ff837cd5 1459 TMPFS_NODE_LOCK_SH(node);
7a2de9a4
MD
1460 error = tmpfs_dir_getdents(node, uio, &cnt);
1461
1462outok:
1463 KKASSERT(error >= -1);
1464
1465 if (error == -1)
1466 error = 0;
1467
1468 if (eofflag != NULL)
1469 *eofflag =
1470 (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
1471
1472 /* Update NFS-related variables. */
1473 if (error == 0 && cookies != NULL && ncookies != NULL) {
1474 off_t i;
1475 off_t off = startoff;
1476 struct tmpfs_dirent *de = NULL;
1477
1478 *ncookies = cnt;
1479 *cookies = kmalloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);
1480
1481 for (i = 0; i < cnt; i++) {
1482 KKASSERT(off != TMPFS_DIRCOOKIE_EOF);
1483 if (off == TMPFS_DIRCOOKIE_DOT) {
1484 off = TMPFS_DIRCOOKIE_DOTDOT;
1485 } else {
1486 if (off == TMPFS_DIRCOOKIE_DOTDOT) {
f5f22af6
MD
1487 de = RB_MIN(tmpfs_dirtree_cookie,
1488 &node->tn_dir.tn_cookietree);
7a2de9a4 1489 } else if (de != NULL) {
f5f22af6
MD
1490 de = RB_NEXT(tmpfs_dirtree_cookie,
1491 &node->tn_dir.tn_cookietree, de);
7a2de9a4
MD
1492 } else {
1493 de = tmpfs_dir_lookupbycookie(node,
f5f22af6 1494 off);
7a2de9a4 1495 KKASSERT(de != NULL);
f5f22af6
MD
1496 de = RB_NEXT(tmpfs_dirtree_cookie,
1497 &node->tn_dir.tn_cookietree, de);
7a2de9a4
MD
1498 }
1499 if (de == NULL)
1500 off = TMPFS_DIRCOOKIE_EOF;
1501 else
1502 off = tmpfs_dircookie(de);
1503 }
7a2de9a4
MD
1504 (*cookies)[i] = off;
1505 }
1506 KKASSERT(uio->uio_offset == off);
1507 }
81aadc82 1508 TMPFS_NODE_UNLOCK(node);
7a2de9a4 1509
bed3b851
TK
1510 if ((node->tn_status & TMPFS_NODE_ACCESSED) == 0) {
1511 TMPFS_NODE_LOCK(node);
1512 node->tn_status |= TMPFS_NODE_ACCESSED;
1513 TMPFS_NODE_UNLOCK(node);
1514 }
7a2de9a4
MD
1515 return error;
1516}
1517
1518/* --------------------------------------------------------------------- */
1519
1520static int
ba25006a 1521tmpfs_readlink(struct vop_readlink_args *ap)
7a2de9a4 1522{
ba25006a
SW
1523 struct vnode *vp = ap->a_vp;
1524 struct uio *uio = ap->a_uio;
7a2de9a4
MD
1525 int error;
1526 struct tmpfs_node *node;
1527
1528 KKASSERT(uio->uio_offset == 0);
1529 KKASSERT(vp->v_type == VLNK);
1530
1531 node = VP_TO_TMPFS_NODE(vp);
ff837cd5
MD
1532 TMPFS_NODE_LOCK_SH(node);
1533 error = uiomove(node->tn_link,
1534 MIN(node->tn_size, uio->uio_resid), uio);
81aadc82 1535 TMPFS_NODE_UNLOCK(node);
bed3b851
TK
1536 if ((node->tn_status & TMPFS_NODE_ACCESSED) == 0) {
1537 TMPFS_NODE_LOCK(node);
1538 node->tn_status |= TMPFS_NODE_ACCESSED;
1539 TMPFS_NODE_UNLOCK(node);
1540 }
7a2de9a4
MD
1541 return error;
1542}
1543
1544/* --------------------------------------------------------------------- */
1545
1546static int
ba25006a 1547tmpfs_inactive(struct vop_inactive_args *ap)
7a2de9a4 1548{
ba25006a 1549 struct vnode *vp = ap->a_vp;
7a2de9a4 1550 struct tmpfs_node *node;
aa1adbf0 1551 struct mount *mp;
7a2de9a4 1552
aa1adbf0
MD
1553 mp = vp->v_mount;
1554 lwkt_gettoken(&mp->mnt_token);
7a2de9a4
MD
1555 node = VP_TO_TMPFS_NODE(vp);
1556
a1fa5d8d
MD
1557 /*
1558 * Degenerate case
1559 */
1560 if (node == NULL) {
1561 vrecycle(vp);
aa1adbf0 1562 lwkt_reltoken(&mp->mnt_token);
a1fa5d8d
MD
1563 return(0);
1564 }
1565
9fc94b5f
MD
1566 /*
1567 * Get rid of unreferenced deleted vnodes sooner rather than
1568 * later so the data memory can be recovered immediately.
f96f2f39
MD
1569 *
1570 * We must truncate the vnode to prevent the normal reclamation
1571 * path from flushing the data for the removed file to disk.
9fc94b5f 1572 */
7a2de9a4 1573 TMPFS_NODE_LOCK(node);
b7fe63af 1574 if ((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0 &&
6e0c5aab 1575 node->tn_links == 0)
b7fe63af 1576 {
9fc94b5f 1577 node->tn_vpstate = TMPFS_VNODE_DOOMED;
7a2de9a4 1578 TMPFS_NODE_UNLOCK(node);
f96f2f39
MD
1579 if (node->tn_type == VREG)
1580 tmpfs_truncate(vp, 0);
7a2de9a4 1581 vrecycle(vp);
9fc94b5f 1582 } else {
7a2de9a4 1583 TMPFS_NODE_UNLOCK(node);
9fc94b5f 1584 }
aa1adbf0 1585 lwkt_reltoken(&mp->mnt_token);
7a2de9a4
MD
1586
1587 return 0;
1588}
1589
1590/* --------------------------------------------------------------------- */
1591
1592int
ba25006a 1593tmpfs_reclaim(struct vop_reclaim_args *ap)
7a2de9a4 1594{
ba25006a 1595 struct vnode *vp = ap->a_vp;
7a2de9a4
MD
1596 struct tmpfs_mount *tmp;
1597 struct tmpfs_node *node;
aa1adbf0
MD
1598 struct mount *mp;
1599
1600 mp = vp->v_mount;
1601 lwkt_gettoken(&mp->mnt_token);
7a2de9a4
MD
1602
1603 node = VP_TO_TMPFS_NODE(vp);
1604 tmp = VFS_TO_TMPFS(vp->v_mount);
aa1adbf0 1605 KKASSERT(mp == tmp->tm_mount);
7a2de9a4 1606
7a2de9a4
MD
1607 tmpfs_free_vp(vp);
1608
b7fe63af
MD
1609 /*
1610 * If the node referenced by this vnode was deleted by the
1611 * user, we must free its associated data structures now that
1612 * the vnode is being reclaimed.
1613 *
1614 * Directories have an extra link ref.
1615 */
7a2de9a4 1616 TMPFS_NODE_LOCK(node);
b7fe63af 1617 if ((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0 &&
6e0c5aab 1618 node->tn_links == 0) {
7a2de9a4 1619 node->tn_vpstate = TMPFS_VNODE_DOOMED;
7a2de9a4 1620 tmpfs_free_node(tmp, node);
0786baf1 1621 /* eats the lock */
9fc94b5f 1622 } else {
7a2de9a4 1623 TMPFS_NODE_UNLOCK(node);
9fc94b5f 1624 }
aa1adbf0 1625 lwkt_reltoken(&mp->mnt_token);
7a2de9a4
MD
1626
1627 KKASSERT(vp->v_data == NULL);
1628 return 0;
1629}
1630
4dd27cb8 1631/* --------------------------------------------------------------------- */
66fa44e7 1632
4dd27cb8
TK
1633static int
1634tmpfs_mountctl(struct vop_mountctl_args *ap)
1635{
1636 struct tmpfs_mount *tmp;
1637 struct mount *mp;
1638 int rc;
66fa44e7 1639
aa1adbf0
MD
1640 mp = ap->a_head.a_ops->head.vv_mount;
1641 lwkt_gettoken(&mp->mnt_token);
1642
4dd27cb8
TK
1643 switch (ap->a_op) {
1644 case (MOUNTCTL_SET_EXPORT):
1645 tmp = (struct tmpfs_mount *) mp->mnt_data;
1646
1647 if (ap->a_ctllen != sizeof(struct export_args))
1648 rc = (EINVAL);
1649 else
1650 rc = vfs_export(mp, &tmp->tm_export,
1651 (const struct export_args *) ap->a_ctl);
1652 break;
1653 default:
1654 rc = vop_stdmountctl(ap);
1655 break;
1656 }
aa1adbf0
MD
1657
1658 lwkt_reltoken(&mp->mnt_token);
4dd27cb8
TK
1659 return (rc);
1660}
66fa44e7 1661
7a2de9a4
MD
1662/* --------------------------------------------------------------------- */
1663
1664static int
ba25006a 1665tmpfs_print(struct vop_print_args *ap)
7a2de9a4 1666{
ba25006a 1667 struct vnode *vp = ap->a_vp;
7a2de9a4
MD
1668
1669 struct tmpfs_node *node;
1670
1671 node = VP_TO_TMPFS_NODE(vp);
1672
1673 kprintf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n",
1674 node, node->tn_flags, node->tn_links);
1675 kprintf("\tmode 0%o, owner %d, group %d, size %ju, status 0x%x\n",
1676 node->tn_mode, node->tn_uid, node->tn_gid,
1677 (uintmax_t)node->tn_size, node->tn_status);
1678
1679 if (vp->v_type == VFIFO)
1680 fifo_printinfo(vp);
1681
1682 kprintf("\n");
1683
1684 return 0;
1685}
1686
1687/* --------------------------------------------------------------------- */
1688
1689static int
ba25006a 1690tmpfs_pathconf(struct vop_pathconf_args *ap)
7a2de9a4 1691{
ba25006a
SW
1692 struct vnode *vp = ap->a_vp;
1693 int name = ap->a_name;
1694 register_t *retval = ap->a_retval;
36799b8e 1695 struct tmpfs_mount *tmp;
7a2de9a4
MD
1696 int error;
1697
1698 error = 0;
1699
1700 switch (name) {
b3b8fc63
SW
1701 case _PC_CHOWN_RESTRICTED:
1702 *retval = 1;
1703 break;
1704
1705 case _PC_FILESIZEBITS:
36799b8e
SW
1706 tmp = VFS_TO_TMPFS(vp->v_mount);
1707 *retval = max(32, flsll(tmp->tm_pages_max * PAGE_SIZE) + 1);
b3b8fc63
SW
1708 break;
1709
7a2de9a4
MD
1710 case _PC_LINK_MAX:
1711 *retval = LINK_MAX;
1712 break;
1713
1714 case _PC_NAME_MAX:
1715 *retval = NAME_MAX;
1716 break;
1717
b3b8fc63
SW
1718 case _PC_NO_TRUNC:
1719 *retval = 1;
1720 break;
1721
7a2de9a4
MD
1722 case _PC_PATH_MAX:
1723 *retval = PATH_MAX;
1724 break;
1725
1726 case _PC_PIPE_BUF:
1727 *retval = PIPE_BUF;
1728 break;
1729
7a2de9a4
MD
1730 case _PC_SYNC_IO:
1731 *retval = 1;
1732 break;
1733
09789cfd
SW
1734 case _PC_2_SYMLINKS:
1735 *retval = 1;
1736 break;
1737
7a2de9a4
MD
1738 default:
1739 error = EINVAL;
1740 }
1741
1742 return error;
1743}
1744
80ae59d7
MD
1745/************************************************************************
1746 * KQFILTER OPS *
1747 ************************************************************************/
1748
1749static void filt_tmpfsdetach(struct knote *kn);
1750static int filt_tmpfsread(struct knote *kn, long hint);
1751static int filt_tmpfswrite(struct knote *kn, long hint);
1752static int filt_tmpfsvnode(struct knote *kn, long hint);
1753
1754static struct filterops tmpfsread_filtops =
ff837cd5
MD
1755 { FILTEROP_ISFD | FILTEROP_MPSAFE,
1756 NULL, filt_tmpfsdetach, filt_tmpfsread };
80ae59d7 1757static struct filterops tmpfswrite_filtops =
ff837cd5
MD
1758 { FILTEROP_ISFD | FILTEROP_MPSAFE,
1759 NULL, filt_tmpfsdetach, filt_tmpfswrite };
80ae59d7 1760static struct filterops tmpfsvnode_filtops =
ff837cd5
MD
1761 { FILTEROP_ISFD | FILTEROP_MPSAFE,
1762 NULL, filt_tmpfsdetach, filt_tmpfsvnode };
80ae59d7
MD
1763
1764static int
1765tmpfs_kqfilter (struct vop_kqfilter_args *ap)
1766{
1767 struct vnode *vp = ap->a_vp;
1768 struct knote *kn = ap->a_kn;
1769
1770 switch (kn->kn_filter) {
1771 case EVFILT_READ:
1772 kn->kn_fop = &tmpfsread_filtops;
1773 break;
1774 case EVFILT_WRITE:
1775 kn->kn_fop = &tmpfswrite_filtops;
1776 break;
1777 case EVFILT_VNODE:
1778 kn->kn_fop = &tmpfsvnode_filtops;
1779 break;
1780 default:
1781 return (EOPNOTSUPP);
1782 }
1783
1784 kn->kn_hook = (caddr_t)vp;
1785
1786 knote_insert(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
1787
1788 return(0);
1789}
1790
1791static void
1792filt_tmpfsdetach(struct knote *kn)
1793{
1794 struct vnode *vp = (void *)kn->kn_hook;
1795
1796 knote_remove(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
1797}
1798
1799static int
1800filt_tmpfsread(struct knote *kn, long hint)
1801{
1802 struct vnode *vp = (void *)kn->kn_hook;
1803 struct tmpfs_node *node = VP_TO_TMPFS_NODE(vp);
1804 off_t off;
1805
1806 if (hint == NOTE_REVOKE) {
3bcb6e5e 1807 kn->kn_flags |= (EV_EOF | EV_NODATA | EV_ONESHOT);
80ae59d7
MD
1808 return(1);
1809 }
f79d9cc9
MD
1810
1811 /*
1812 * Interlock against MP races when performing this function.
1813 */
ff837cd5 1814 TMPFS_NODE_LOCK_SH(node);
80ae59d7
MD
1815 off = node->tn_size - kn->kn_fp->f_offset;
1816 kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
f79d9cc9 1817 if (kn->kn_sfflags & NOTE_OLDAPI) {
ff837cd5 1818 TMPFS_NODE_UNLOCK(node);
80ae59d7 1819 return(1);
f79d9cc9 1820 }
80ae59d7 1821 if (kn->kn_data == 0) {
80ae59d7 1822 kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
80ae59d7 1823 }
ff837cd5 1824 TMPFS_NODE_UNLOCK(node);
80ae59d7
MD
1825 return (kn->kn_data != 0);
1826}
1827
1828static int
1829filt_tmpfswrite(struct knote *kn, long hint)
1830{
1831 if (hint == NOTE_REVOKE)
3bcb6e5e 1832 kn->kn_flags |= (EV_EOF | EV_NODATA | EV_ONESHOT);
80ae59d7
MD
1833 kn->kn_data = 0;
1834 return (1);
1835}
1836
1837static int
1838filt_tmpfsvnode(struct knote *kn, long hint)
1839{
1840 if (kn->kn_sfflags & hint)
1841 kn->kn_fflags |= hint;
1842 if (hint == NOTE_REVOKE) {
3bcb6e5e 1843 kn->kn_flags |= (EV_EOF | EV_NODATA);
80ae59d7
MD
1844 return (1);
1845 }
1846 return (kn->kn_fflags != 0);
1847}
1848
1849
7a2de9a4
MD
1850/* --------------------------------------------------------------------- */
1851
1852/*
1853 * vnode operations vector used for files stored in a tmpfs file system.
1854 */
1855struct vop_ops tmpfs_vnode_vops = {
1856 .vop_default = vop_defaultop,
1857 .vop_getpages = vop_stdgetpages,
1858 .vop_putpages = vop_stdputpages,
1859 .vop_ncreate = tmpfs_ncreate,
1860 .vop_nresolve = tmpfs_nresolve,
1861 .vop_nlookupdotdot = tmpfs_nlookupdotdot,
1862 .vop_nmknod = tmpfs_nmknod,
1863 .vop_open = tmpfs_open,
1864 .vop_close = tmpfs_close,
1865 .vop_access = tmpfs_access,
1866 .vop_getattr = tmpfs_getattr,
1867 .vop_setattr = tmpfs_setattr,
1868 .vop_read = tmpfs_read,
1869 .vop_write = tmpfs_write,
1870 .vop_fsync = tmpfs_fsync,
66fa44e7 1871 .vop_mountctl = tmpfs_mountctl,
7a2de9a4
MD
1872 .vop_nremove = tmpfs_nremove,
1873 .vop_nlink = tmpfs_nlink,
1874 .vop_nrename = tmpfs_nrename,
1875 .vop_nmkdir = tmpfs_nmkdir,
1876 .vop_nrmdir = tmpfs_nrmdir,
1877 .vop_nsymlink = tmpfs_nsymlink,
1878 .vop_readdir = tmpfs_readdir,
1879 .vop_readlink = tmpfs_readlink,
1880 .vop_inactive = tmpfs_inactive,
1881 .vop_reclaim = tmpfs_reclaim,
1882 .vop_print = tmpfs_print,
1883 .vop_pathconf = tmpfs_pathconf,
9fc94b5f 1884 .vop_bmap = tmpfs_bmap,
7a2de9a4
MD
1885 .vop_strategy = tmpfs_strategy,
1886 .vop_advlock = tmpfs_advlock,
80ae59d7 1887 .vop_kqfilter = tmpfs_kqfilter
7a2de9a4 1888};