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