kernel - TMPFS - Initial port of NetBSD's tmpfs
[dragonfly.git] / sys / vfs / tmpfs / tmpfs_subr.c
1 /*      $NetBSD: tmpfs_subr.c,v 1.35 2007/07/09 21:10:50 ad Exp $       */
2
3 /*-
4  * Copyright (c) 2005 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  * Efficient memory file system supporting functions.
35  */
36 #include <sys/cdefs.h>
37
38 #include <sys/kernel.h>
39 #include <sys/param.h>
40 #include <sys/namei.h>
41 #include <sys/priv.h>
42 #include <sys/proc.h>
43 #include <sys/spinlock2.h>
44 #include <sys/stat.h>
45 #include <sys/systm.h>
46 #include <sys/vnode.h>
47 #include <sys/vmmeter.h>
48
49 #include <sys/mplock2.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 <vm/vm_extern.h>
56
57 #include <vfs/tmpfs/tmpfs.h>
58 #include <vfs/tmpfs/tmpfs_fifoops.h>
59 #include <vfs/tmpfs/tmpfs_vnops.h>
60
61 static ino_t t_ino = 2;
62 static struct spinlock  ino_lock;
63 static ino_t tmpfs_fetch_ino(void);
64
65 /* --------------------------------------------------------------------- */
66
67 /*
68  * Allocates a new node of type 'type' inside the 'tmp' mount point, with
69  * its owner set to 'uid', its group to 'gid' and its mode set to 'mode',
70  * using the credentials of the process 'p'.
71  *
72  * If the node type is set to 'VDIR', then the parent parameter must point
73  * to the parent directory of the node being created.  It may only be NULL
74  * while allocating the root node.
75  *
76  * If the node type is set to 'VBLK' or 'VCHR', then the rdev parameter
77  * specifies the device the node represents.
78  *
79  * If the node type is set to 'VLNK', then the parameter target specifies
80  * the file name of the target file for the symbolic link that is being
81  * created.
82  *
83  * Note that new nodes are retrieved from the available list if it has
84  * items or, if it is empty, from the node pool as long as there is enough
85  * space to create them.
86  *
87  * Returns zero on success or an appropriate error code on failure.
88  */
89 int
90 tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type,
91     uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *parent,
92     char *target, int rmajor, int rminor, struct tmpfs_node **node)
93 {
94         struct tmpfs_node *nnode;
95         struct timespec ts;
96         udev_t rdev;
97
98         /* If the root directory of the 'tmp' file system is not yet
99          * allocated, this must be the request to do it. */
100         KKASSERT(IMPLIES(tmp->tm_root == NULL, parent == NULL && type == VDIR));
101
102         KKASSERT(IFF(type == VLNK, target != NULL));
103         KKASSERT(IFF(type == VBLK || type == VCHR, rmajor != VNOVAL));
104
105         if (tmp->tm_nodes_inuse > tmp->tm_nodes_max)
106                 return (ENOSPC);
107
108         nnode = (struct tmpfs_node *)objcache_get(tmp->tm_node_pool, M_WAITOK);
109
110         /* Generic initialization. */
111         nnode->tn_type = type;
112         vfs_timestamp(&ts);
113         nnode->tn_ctime = nnode->tn_mtime = nnode->tn_atime
114                 = ts.tv_sec;
115         nnode->tn_ctimensec = nnode->tn_mtimensec = nnode->tn_atimensec
116                 = ts.tv_nsec;
117         nnode->tn_uid = uid;
118         nnode->tn_gid = gid;
119         nnode->tn_mode = mode;
120         nnode->tn_id = tmpfs_fetch_ino();
121
122         /* Type-specific initialization. */
123         switch (nnode->tn_type) {
124         case VBLK:
125         case VCHR:
126                 rdev = makeudev(rmajor, rminor);
127                 if (rdev == NOUDEV) {
128                         return(EINVAL);
129                 }
130                 nnode->tn_rdev = rdev;
131                 break;
132
133         case VDIR:
134                 TAILQ_INIT(&nnode->tn_dir.tn_dirhead);
135                 KKASSERT(parent != nnode);
136                 KKASSERT(IMPLIES(parent == NULL, tmp->tm_root == NULL));
137                 nnode->tn_dir.tn_parent = (parent == NULL) ? nnode : parent;
138                 nnode->tn_dir.tn_readdir_lastn = 0;
139                 nnode->tn_dir.tn_readdir_lastp = NULL;
140                 nnode->tn_links++;
141                 nnode->tn_size = 0;
142                 TMPFS_NODE_LOCK(nnode->tn_dir.tn_parent);
143                 nnode->tn_dir.tn_parent->tn_links++;
144                 TMPFS_NODE_UNLOCK(nnode->tn_dir.tn_parent);
145                 break;
146
147         case VFIFO:
148                 /* FALLTHROUGH */
149         case VSOCK:
150                 break;
151
152         case VLNK:
153                 KKASSERT((strlen(target) +1) < MAXPATHLEN);
154                 nnode->tn_size = strlen(target) +1;
155                 nnode->tn_link = kmalloc(nnode->tn_size, M_TMPFSNAME,
156                     M_WAITOK);
157                 bcopy(target, nnode->tn_link, nnode->tn_size);
158                 nnode->tn_link[nnode->tn_size] = '\0';
159                 break;
160
161         case VREG:
162                 nnode->tn_reg.tn_aobj =
163                     vm_pager_allocate(OBJT_SWAP, NULL, 0, VM_PROT_DEFAULT, 0);
164                 nnode->tn_reg.tn_aobj_pages = 0;
165                 nnode->tn_size = 0;
166                 break;
167
168         default:
169                 panic("tmpfs_alloc_node: type %p %d", nnode, (int)nnode->tn_type);
170         }
171
172         TMPFS_NODE_LOCK(nnode);
173         LIST_INSERT_HEAD(&tmp->tm_nodes_used, nnode, tn_entries);
174         TMPFS_LOCK(tmp);
175         tmp->tm_nodes_inuse++;
176         TMPFS_UNLOCK(tmp);
177         TMPFS_NODE_UNLOCK(nnode);
178
179         *node = nnode;
180         return 0;
181 }
182
183 /* --------------------------------------------------------------------- */
184
185 /*
186  * Destroys the node pointed to by node from the file system 'tmp'.
187  * If the node does not belong to the given mount point, the results are
188  * unpredicted.
189  *
190  * If the node references a directory; no entries are allowed because
191  * their removal could need a recursive algorithm, something forbidden in
192  * kernel space.  Furthermore, there is not need to provide such
193  * functionality (recursive removal) because the only primitives offered
194  * to the user are the removal of empty directories and the deletion of
195  * individual files.
196  *
197  * Note that nodes are not really deleted; in fact, when a node has been
198  * allocated, it cannot be deleted during the whole life of the file
199  * system.  Instead, they are moved to the available list and remain there
200  * until reused.
201  */
202 void
203 tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node)
204 {
205         size_t pages = 0;
206
207         TMPFS_NODE_LOCK(node);
208
209 #ifdef INVARIANTS
210         TMPFS_ASSERT_ELOCKED(node);
211         KKASSERT(node->tn_vnode == NULL);
212         KKASSERT((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0);
213 #endif
214
215         LIST_REMOVE(node, tn_entries);
216         TMPFS_LOCK(tmp);
217         tmp->tm_nodes_inuse--;
218         TMPFS_UNLOCK(tmp);
219
220         switch (node->tn_type) {
221         case VNON:
222                 /* Do not do anything.  VNON is provided to let the
223                  * allocation routine clean itself easily by avoiding
224                  * duplicating code in it. */
225                 /* FALLTHROUGH */
226         case VBLK:
227                 /* FALLTHROUGH */
228         case VCHR:
229                 /* FALLTHROUGH */
230                 break;
231         case VDIR:
232                 node->tn_links--;
233                 node->tn_size = 0;
234                 TMPFS_NODE_LOCK(node->tn_dir.tn_parent);
235                 node->tn_dir.tn_parent->tn_links--;
236                 TMPFS_NODE_UNLOCK(node->tn_dir.tn_parent);
237                 break;
238         case VFIFO:
239                 /* FALLTHROUGH */
240         case VSOCK:
241                 break;
242
243         case VLNK:
244                 kfree(node->tn_link, M_TMPFSNAME);
245                 break;
246
247         case VREG:
248                 if (node->tn_reg.tn_aobj != NULL)
249                         vm_pager_deallocate(node->tn_reg.tn_aobj);
250                 node->tn_reg.tn_aobj = NULL;
251                 pages = node->tn_reg.tn_aobj_pages;
252                 break;
253
254         default:
255                 panic("tmpfs_free_node: type %p %d", node, (int)node->tn_type);
256         }
257
258         objcache_put(tmp->tm_node_pool, node);
259
260         TMPFS_LOCK(tmp);
261         tmp->tm_pages_used -= pages;
262         TMPFS_UNLOCK(tmp);
263         TMPFS_NODE_UNLOCK(node);
264 }
265
266 /* --------------------------------------------------------------------- */
267
268 /*
269  * Allocates a new directory entry for the node node with a name of name.
270  * The new directory entry is returned in *de.
271  *
272  * The link count of node is increased by one to reflect the new object
273  * referencing it.
274  *
275  * Returns zero on success or an appropriate error code on failure.
276  */
277 int
278 tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
279     const char *name, uint16_t len, struct tmpfs_dirent **de)
280 {
281         struct tmpfs_dirent *nde;
282
283
284         nde = (struct tmpfs_dirent *)objcache_get(tmp->tm_dirent_pool, M_WAITOK);
285         nde->td_name = kmalloc(len, M_TMPFSNAME, M_WAITOK);
286         nde->td_namelen = len;
287         bcopy(name, nde->td_name, len);
288         nde->td_name[len] = '\0';
289
290         nde->td_node = node;
291
292         TMPFS_NODE_LOCK(node);
293         node->tn_links++;
294         TMPFS_NODE_UNLOCK(node);
295
296         *de = nde;
297
298         return 0;
299 }
300
301 /* --------------------------------------------------------------------- */
302
303 /*
304  * Frees a directory entry.  It is the caller's responsibility to destroy
305  * the node referenced by it if needed.
306  *
307  * The link count of node is decreased by one to reflect the removal of an
308  * object that referenced it.  This only happens if 'node_exists' is true;
309  * otherwise the function will not access the node referred to by the
310  * directory entry, as it may already have been released from the outside.
311  */
312 void
313 tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de,
314     boolean_t node_exists)
315 {
316         if (node_exists) {
317                 struct tmpfs_node *node;
318
319                 node = de->td_node;
320
321                 TMPFS_NODE_LOCK(node);
322                 TMPFS_ASSERT_ELOCKED(node);
323                 KKASSERT(node->tn_links > 0);
324                 node->tn_links--;
325                 TMPFS_NODE_UNLOCK(node);
326         }
327
328         kfree(de->td_name, M_TMPFSNAME);
329         objcache_put(tmp->tm_dirent_pool, de);
330 }
331
332 /* --------------------------------------------------------------------- */
333
334 /*
335  * Allocates a new vnode for the node node or returns a new reference to
336  * an existing one if the node had already a vnode referencing it.  The
337  * resulting locked vnode is returned in *vpp.
338  *
339  * Returns zero on success or an appropriate error code on failure.
340  */
341 int
342 tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, int lkflag,
343     struct vnode **vpp)
344 {
345         int error = 0;
346         struct vnode *vp;
347
348 loop:
349         TMPFS_NODE_LOCK(node);
350         if ((vp = node->tn_vnode) != NULL) {
351                 KKASSERT((node->tn_vpstate & TMPFS_VNODE_DOOMED) == 0);
352                 TMPFS_NODE_UNLOCK(node);
353                 (void) vget(vp, lkflag | LK_EXCLUSIVE | LK_RETRY);
354
355                 /*
356                  * Make sure the vnode is still there after
357                  * getting the interlock to avoid racing a free.
358                  */
359                 if (node->tn_vnode == NULL || node->tn_vnode != vp) {
360                         vput(vp);
361                         goto loop;
362                 }
363
364                 goto out;
365         }
366
367         if ((node->tn_vpstate & TMPFS_VNODE_DOOMED) ||
368             (node->tn_type == VDIR && node->tn_dir.tn_parent == NULL)) {
369                 TMPFS_NODE_UNLOCK(node);
370                 error = ENOENT;
371                 vp = NULL;
372                 goto out;
373         }
374
375         /*
376          * otherwise lock the vp list while we call getnewvnode
377          * since that can block.
378          */
379         if (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) {
380                 node->tn_vpstate |= TMPFS_VNODE_WANT;
381                 error = tsleep((caddr_t) &node->tn_vpstate,
382                     PINTERLOCKED | PCATCH, "tmpfs_alloc_vp", 0);
383                 TMPFS_NODE_UNLOCK(node);
384                 if (error)
385                         return error;
386
387                 goto loop;
388         } else
389                 node->tn_vpstate |= TMPFS_VNODE_ALLOCATING;
390
391         TMPFS_NODE_UNLOCK(node);
392
393         /* Get a new vnode and associate it with our node. */
394         error = getnewvnode(VT_TMPFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE);
395         if (error != 0)
396                 goto unlock;
397         KKASSERT(vp != NULL);
398
399         vp->v_data = node;
400         vp->v_type = node->tn_type;
401
402         /* Type-specific initialization. */
403         switch (node->tn_type) {
404         case VBLK:
405                 /* FALLTHROUGH */
406         case VCHR:
407                 /* FALLTHROUGH */
408         case VSOCK:
409                 break;
410         case VREG:
411                 vinitvmio(vp, node->tn_size);
412                 break;
413         case VLNK:
414                 if (node->tn_size >= vp->v_mount->mnt_maxsymlinklen)
415                         vinitvmio(vp, node->tn_size);
416                 break;
417         case VFIFO:
418                 vp->v_ops = &mp->mnt_vn_fifo_ops;
419                 break;
420         case VDIR:
421                 vinitvmio(vp, node->tn_size);
422                 KKASSERT(node->tn_dir.tn_parent != NULL);
423                 break;
424
425         default:
426                 panic("tmpfs_alloc_vp: type %p %d", node, (int)node->tn_type);
427         }
428
429         insmntque(vp, mp);
430
431 unlock:
432         TMPFS_NODE_LOCK(node);
433
434         KKASSERT(node->tn_vpstate & TMPFS_VNODE_ALLOCATING);
435         node->tn_vpstate &= ~TMPFS_VNODE_ALLOCATING;
436         node->tn_vnode = vp;
437
438         if (node->tn_vpstate & TMPFS_VNODE_WANT) {
439                 node->tn_vpstate &= ~TMPFS_VNODE_WANT;
440                 TMPFS_NODE_UNLOCK(node);
441                 wakeup((caddr_t) &node->tn_vpstate);
442         } else
443                 TMPFS_NODE_UNLOCK(node);
444
445 out:
446         *vpp = vp;
447
448         KKASSERT(IFF(error == 0, *vpp != NULL && vn_islocked(*vpp)));
449 #ifdef INVARIANTS
450         TMPFS_NODE_LOCK(node);
451         KKASSERT(*vpp == node->tn_vnode);
452         TMPFS_NODE_UNLOCK(node);
453 #endif
454
455         return error;
456 }
457
458 /* --------------------------------------------------------------------- */
459
460 /*
461  * Destroys the association between the vnode vp and the node it
462  * references.
463  */
464 void
465 tmpfs_free_vp(struct vnode *vp)
466 {
467         struct tmpfs_node *node;
468
469         node = VP_TO_TMPFS_NODE(vp);
470
471         TMPFS_NODE_LOCK(node);
472         KKASSERT(lockcount(TMPFS_NODE_MTX(node)) > 0);
473         node->tn_vnode = NULL;
474         TMPFS_NODE_UNLOCK(node);
475         vp->v_data = NULL;
476 }
477
478 /* --------------------------------------------------------------------- */
479
480 /*
481  * Allocates a new file of type 'type' and adds it to the parent directory
482  * 'dvp'; this addition is done using the component name given in 'cnp'.
483  * The ownership of the new file is automatically assigned based on the
484  * credentials of the caller (through 'cnp'), the group is set based on
485  * the parent directory and the mode is determined from the 'vap' argument.
486  * If successful, *vpp holds a vnode to the newly created file and zero
487  * is returned.  Otherwise *vpp is NULL and the function returns an
488  * appropriate error code.
489  */
490 int
491 tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
492     struct namecache *ncp, struct ucred *cred, char *target)
493 {
494         int error;
495         struct tmpfs_dirent *de;
496         struct tmpfs_mount *tmp;
497         struct tmpfs_node *dnode;
498         struct tmpfs_node *node;
499         struct tmpfs_node *parent;
500
501         tmp = VFS_TO_TMPFS(dvp->v_mount);
502         dnode = VP_TO_TMPFS_DIR(dvp);
503         *vpp = NULL;
504
505         /* If the entry we are creating is a directory, we cannot overflow
506          * the number of links of its parent, because it will get a new
507          * link. */
508         if (vap->va_type == VDIR) {
509                 /* Ensure that we do not overflow the maximum number of links
510                  * imposed by the system. */
511                 KKASSERT(dnode->tn_links <= LINK_MAX);
512                 if (dnode->tn_links == LINK_MAX) {
513                         return EMLINK;
514                 }
515
516                 parent = dnode;
517                 KKASSERT(parent != NULL);
518         } else
519                 parent = NULL;
520
521         /* Allocate a node that represents the new file. */
522         error = tmpfs_alloc_node(tmp, vap->va_type, cred->cr_uid,
523             dnode->tn_gid, vap->va_mode, parent, target, vap->va_rmajor, vap->va_rminor, &node);
524         if (error != 0)
525                 return error;
526
527         /* Allocate a directory entry that points to the new file. */
528         error = tmpfs_alloc_dirent(tmp, node, ncp->nc_name, ncp->nc_nlen,
529             &de);
530         if (error != 0) {
531                 tmpfs_free_node(tmp, node);
532                 return error;
533         }
534
535         /* Allocate a vnode for the new file. */
536         error = tmpfs_alloc_vp(dvp->v_mount, node, LK_EXCLUSIVE, vpp);
537         if (error != 0) {
538                 tmpfs_free_dirent(tmp, de, TRUE);
539                 tmpfs_free_node(tmp, node);
540                 return error;
541         }
542
543         /* Now that all required items are allocated, we can proceed to
544          * insert the new node into the directory, an operation that
545          * cannot fail. */
546         tmpfs_dir_attach(dvp, de);
547
548         return error;
549 }
550
551 /* --------------------------------------------------------------------- */
552
553 /*
554  * Attaches the directory entry de to the directory represented by vp.
555  * Note that this does not change the link count of the node pointed by
556  * the directory entry, as this is done by tmpfs_alloc_dirent.
557  */
558 void
559 tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de)
560 {
561         struct tmpfs_node *dnode;
562
563         dnode = VP_TO_TMPFS_DIR(vp);
564
565         crit_enter();
566         TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_dirhead, de, td_entries);
567         crit_exit();
568
569         TMPFS_NODE_LOCK(dnode);
570         TMPFS_ASSERT_ELOCKED(dnode);
571         dnode->tn_size += sizeof(struct tmpfs_dirent);
572         dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
573             TMPFS_NODE_MODIFIED;
574         TMPFS_NODE_UNLOCK(dnode);
575 }
576
577 /* --------------------------------------------------------------------- */
578
579 /*
580  * Detaches the directory entry de from the directory represented by vp.
581  * Note that this does not change the link count of the node pointed by
582  * the directory entry, as this is done by tmpfs_free_dirent.
583  */
584 void
585 tmpfs_dir_detach(struct vnode *vp, struct tmpfs_dirent *de)
586 {
587         struct tmpfs_node *dnode;
588
589         dnode = VP_TO_TMPFS_DIR(vp);
590
591
592         crit_enter();
593         if (dnode->tn_dir.tn_readdir_lastp == de) {
594                 dnode->tn_dir.tn_readdir_lastn = 0;
595                 dnode->tn_dir.tn_readdir_lastp = NULL;
596         }
597
598         TAILQ_REMOVE(&dnode->tn_dir.tn_dirhead, de, td_entries);
599         crit_exit();
600
601         TMPFS_NODE_LOCK(dnode);
602         TMPFS_ASSERT_ELOCKED(dnode);
603         dnode->tn_size -= sizeof(struct tmpfs_dirent);
604         dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
605             TMPFS_NODE_MODIFIED;
606         TMPFS_NODE_UNLOCK(dnode);
607 }
608
609 /* --------------------------------------------------------------------- */
610
611 /*
612  * Looks for a directory entry in the directory represented by node.
613  * 'ncp' describes the name of the entry to look for.  Note that the .
614  * and .. components are not allowed as they do not physically exist
615  * within directories.
616  *
617  * Returns a pointer to the entry when found, otherwise NULL.
618  */
619 struct tmpfs_dirent *
620 tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f,
621     struct namecache *ncp)
622 {
623         void *found;
624         struct tmpfs_dirent *de;
625         int len = ncp->nc_nlen;
626
627         TMPFS_VALIDATE_DIR(node);
628
629         found = 0;
630         TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) {
631                 if (f != NULL && de->td_node != f)
632                     continue;
633                 if (len == de->td_namelen) {
634                         if (!memcmp(ncp->nc_name, de->td_name, len)) {
635                                 found = node;
636                                 break;
637                         }
638                 }
639         }
640
641         TMPFS_NODE_LOCK(node);
642         node->tn_status |= TMPFS_NODE_ACCESSED;
643         TMPFS_NODE_UNLOCK(node);
644
645         return found ? de : NULL;
646 }
647
648 /* --------------------------------------------------------------------- */
649
650 /*
651  * Helper function for tmpfs_readdir.  Creates a '.' entry for the given
652  * directory and returns it in the uio space.  The function returns 0
653  * on success, -1 if there was not enough space in the uio structure to
654  * hold the directory entry or an appropriate error code if another
655  * error happens.
656  */
657 int
658 tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio)
659 {
660         int error;
661         struct dirent dent;
662         int dirsize;
663
664         TMPFS_VALIDATE_DIR(node);
665         KKASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOT);
666
667         dent.d_ino = node->tn_id;
668         dent.d_type = DT_DIR;
669         dent.d_namlen = 1;
670         dent.d_name[0] = '.';
671         dent.d_name[1] = '\0';
672         dirsize = _DIRENT_DIRSIZ(&dent);
673
674         if (dirsize > uio->uio_resid)
675                 error = -1;
676         else {
677                 error = uiomove((caddr_t)&dent, dirsize, uio);
678                 if (error == 0)
679                         uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT;
680         }
681
682         node->tn_status |= TMPFS_NODE_ACCESSED;
683
684         return error;
685 }
686
687 /* --------------------------------------------------------------------- */
688
689 /*
690  * Helper function for tmpfs_readdir.  Creates a '..' entry for the given
691  * directory and returns it in the uio space.  The function returns 0
692  * on success, -1 if there was not enough space in the uio structure to
693  * hold the directory entry or an appropriate error code if another
694  * error happens.
695  */
696 int
697 tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio)
698 {
699         int error;
700         struct dirent dent;
701         int dirsize;
702
703         TMPFS_VALIDATE_DIR(node);
704         KKASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT);
705
706         /*
707          * Return ENOENT if the current node is already removed.
708          */
709         if (node->tn_dir.tn_parent == NULL) {
710                 return (ENOENT);
711         }
712
713         TMPFS_NODE_LOCK(node->tn_dir.tn_parent);
714         dent.d_ino = node->tn_dir.tn_parent->tn_id;
715         TMPFS_NODE_UNLOCK(node->tn_dir.tn_parent);
716
717         dent.d_type = DT_DIR;
718         dent.d_namlen = 2;
719         dent.d_name[0] = '.';
720         dent.d_name[1] = '.';
721         dent.d_name[2] = '\0';
722         dirsize = _DIRENT_DIRSIZ(&dent);
723
724         if (dirsize > uio->uio_resid)
725                 error = -1;
726         else {
727                 error = uiomove((caddr_t)&dent, dirsize, uio);
728                 if (error == 0) {
729                         struct tmpfs_dirent *de;
730
731                         de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
732                         if (de == NULL)
733                                 uio->uio_offset = TMPFS_DIRCOOKIE_EOF;
734                         else
735                                 uio->uio_offset = tmpfs_dircookie(de);
736                 }
737         }
738
739         node->tn_status |= TMPFS_NODE_ACCESSED;
740
741         return error;
742 }
743
744 /* --------------------------------------------------------------------- */
745
746 /*
747  * Lookup a directory entry by its associated cookie.
748  */
749 struct tmpfs_dirent *
750 tmpfs_dir_lookupbycookie(struct tmpfs_node *node, off_t cookie)
751 {
752         struct tmpfs_dirent *de;
753
754         if (cookie == node->tn_dir.tn_readdir_lastn &&
755             node->tn_dir.tn_readdir_lastp != NULL) {
756                 return node->tn_dir.tn_readdir_lastp;
757         }
758
759         TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) {
760                 if (tmpfs_dircookie(de) == cookie) {
761                         break;
762                 }
763         }
764
765         return de;
766 }
767
768 /* --------------------------------------------------------------------- */
769
770 /*
771  * Helper function for tmpfs_readdir.  Returns as much directory entries
772  * as can fit in the uio space.  The read starts at uio->uio_offset.
773  * The function returns 0 on success, -1 if there was not enough space
774  * in the uio structure to hold the directory entry or an appropriate
775  * error code if another error happens.
776  */
777 int
778 tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp)
779 {
780         int error;
781         off_t startcookie;
782         struct tmpfs_dirent *de;
783
784         TMPFS_VALIDATE_DIR(node);
785
786         /* Locate the first directory entry we have to return.  We have cached
787          * the last readdir in the node, so use those values if appropriate.
788          * Otherwise do a linear scan to find the requested entry. */
789         startcookie = uio->uio_offset;
790         KKASSERT(startcookie != TMPFS_DIRCOOKIE_DOT);
791         KKASSERT(startcookie != TMPFS_DIRCOOKIE_DOTDOT);
792         if (startcookie == TMPFS_DIRCOOKIE_EOF) {
793                 return 0;
794         } else {
795                 de = tmpfs_dir_lookupbycookie(node, startcookie);
796         }
797         if (de == NULL) {
798                 return EINVAL;
799         }
800
801         /* Read as much entries as possible; i.e., until we reach the end of
802          * the directory or we exhaust uio space. */
803         do {
804                 struct dirent d;
805                 int reclen;
806
807                 /* Create a dirent structure representing the current
808                  * tmpfs_node and fill it. */
809                 d.d_ino = de->td_node->tn_id;
810                 switch (de->td_node->tn_type) {
811                 case VBLK:
812                         d.d_type = DT_BLK;
813                         break;
814
815                 case VCHR:
816                         d.d_type = DT_CHR;
817                         break;
818
819                 case VDIR:
820                         d.d_type = DT_DIR;
821                         break;
822
823                 case VFIFO:
824                         d.d_type = DT_FIFO;
825                         break;
826
827                 case VLNK:
828                         d.d_type = DT_LNK;
829                         break;
830
831                 case VREG:
832                         d.d_type = DT_REG;
833                         break;
834
835                 case VSOCK:
836                         d.d_type = DT_SOCK;
837                         break;
838
839                 default:
840                         panic("tmpfs_dir_getdents: type %p %d",
841                             de->td_node, (int)de->td_node->tn_type);
842                 }
843                 d.d_namlen = de->td_namelen;
844                 KKASSERT(de->td_namelen < sizeof(d.d_name));
845                 bcopy(de->td_name, d.d_name, d.d_namlen);
846                 d.d_name[d.d_namlen] = '\0';
847                 reclen = _DIRENT_RECLEN(d.d_namlen);
848
849                 /* Stop reading if the directory entry we are treating is
850                  * bigger than the amount of data that can be returned. */
851                 if (reclen > uio->uio_resid) {
852                         error = -1;
853                         break;
854                 }
855
856                 /* Copy the new dirent structure into the output buffer and
857                  * advance pointers. */
858                 error = uiomove((caddr_t)&d, reclen, uio);
859
860                 (*cntp)++;
861                 de = TAILQ_NEXT(de, td_entries);
862         } while (error == 0 && uio->uio_resid > 0 && de != NULL);
863
864         /* Update the offset and cache. */
865         if (de == NULL) {
866                 uio->uio_offset = TMPFS_DIRCOOKIE_EOF;
867                 node->tn_dir.tn_readdir_lastn = 0;
868                 node->tn_dir.tn_readdir_lastp = NULL;
869         } else {
870                 node->tn_dir.tn_readdir_lastn = uio->uio_offset = tmpfs_dircookie(de);
871                 node->tn_dir.tn_readdir_lastp = de;
872         }
873         node->tn_status |= TMPFS_NODE_ACCESSED;
874
875         return error;
876 }
877
878 /* --------------------------------------------------------------------- */
879
880 /*
881  * Resizes the aobj associated to the regular file pointed to by vp to
882  * the size newsize.  'vp' must point to a vnode that represents a regular
883  * file.  'newsize' must be positive.
884  *
885  * pass trivial as 1 when buf content will be overwritten, otherwise set 0
886  * to be zero filled.
887  *
888  * Returns zero on success or an appropriate error code on failure.
889  */
890 int
891 tmpfs_reg_resize(struct vnode *vp, off_t newsize, int trivial)
892 {
893         int error;
894         size_t newpages, oldpages;
895         struct tmpfs_mount *tmp;
896         struct tmpfs_node *node;
897         off_t oldsize;
898         int biosize = vp->v_mount->mnt_stat.f_iosize;
899
900 #ifdef INVARIANTS
901         KKASSERT(vp->v_type == VREG);
902         KKASSERT(newsize >= 0);
903 #endif
904
905         node = VP_TO_TMPFS_NODE(vp);
906         tmp = VFS_TO_TMPFS(vp->v_mount);
907
908         /* Convert the old and new sizes to the number of pages needed to
909          * store them.  It may happen that we do not need to do anything
910          * because the last allocated page can accommodate the change on
911          * its own. */
912         oldsize = node->tn_size;
913         oldpages = round_page(oldsize) / PAGE_SIZE;
914         KKASSERT(oldpages == node->tn_reg.tn_aobj_pages);
915         newpages = round_page(newsize) / PAGE_SIZE;
916
917         if (newpages > oldpages &&
918             newpages - oldpages > TMPFS_PAGES_AVAIL(tmp)) {
919                 error = ENOSPC;
920                 goto out;
921         }
922
923         TMPFS_LOCK(tmp);
924         tmp->tm_pages_used += (newpages - oldpages);
925         TMPFS_UNLOCK(tmp);
926
927         TMPFS_NODE_LOCK(node);
928         node->tn_reg.tn_aobj_pages = newpages;
929         node->tn_size = newsize;
930         TMPFS_NODE_UNLOCK(node);
931
932         if (newsize < oldsize)
933                 error = nvtruncbuf(vp, newsize, biosize, -1);
934         else
935                 error = nvextendbuf(vp, oldsize, newsize, biosize, biosize,
936                                     -1, -1, trivial);
937
938 out:
939         return error;
940 }
941
942 /* --------------------------------------------------------------------- */
943
944 /*
945  * Change flags of the given vnode.
946  * Caller should execute tmpfs_update on vp after a successful execution.
947  * The vnode must be locked on entry and remain locked on exit.
948  */
949 int
950 tmpfs_chflags(struct vnode *vp, int flags, struct ucred *cred)
951 {
952         int error;
953         struct tmpfs_node *node;
954         int fmode, mode;
955
956         KKASSERT(vn_islocked(vp));
957
958         node = VP_TO_TMPFS_NODE(vp);
959
960         /* Disallow this operation if the file system is mounted read-only. */
961         if (vp->v_mount->mnt_flag & MNT_RDONLY)
962                 return EROFS;
963
964         fmode = FFLAGS(node->tn_flags);
965         mode = 0;
966         if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
967                 return EINVAL;
968         if (fmode & (FWRITE | O_TRUNC)) {
969                 if (vp->v_type == VDIR) {
970                         return EISDIR;
971                 }
972                 error = vn_writechk(vp, NULL);
973                 if (error)
974                         return (error);
975
976                 mode |= VWRITE;
977         }
978         if (fmode & FREAD)
979                 mode |= VREAD;
980         if (mode) {
981                 error = VOP_ACCESS(vp, mode, cred);
982                 if (error)
983                         return (error);
984         }
985         /*
986          * Unprivileged processes are not permitted to unset system
987          * flags, or modify flags if any system flags are set.
988          */
989         TMPFS_NODE_LOCK(node);
990         if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) {
991 #if 0
992                 if (node->tn_flags
993                   & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) {
994                         error = securelevel_gt(cred, 0);
995                         if (error)
996                                 return (error);
997                 }
998                 /* Snapshot flag cannot be set or cleared */
999                 if (((flags & SF_SNAPSHOT) != 0 &&
1000                   (node->tn_flags & SF_SNAPSHOT) == 0) ||
1001                   ((flags & SF_SNAPSHOT) == 0 &&
1002                   (node->tn_flags & SF_SNAPSHOT) != 0))
1003                         return (EPERM);
1004 #endif
1005                 node->tn_flags = flags;
1006         } else {
1007                 if (node->tn_flags
1008                   & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
1009                   (flags & UF_SETTABLE) != flags)
1010                         return (EPERM);
1011                 node->tn_flags &= SF_SETTABLE;
1012                 node->tn_flags |= (flags & UF_SETTABLE);
1013         }
1014         node->tn_status |= TMPFS_NODE_CHANGED;
1015         TMPFS_NODE_UNLOCK(node);
1016
1017         KKASSERT(vn_islocked(vp));
1018
1019         return 0;
1020 }
1021
1022 /* --------------------------------------------------------------------- */
1023
1024 /*
1025  * Change access mode on the given vnode.
1026  * Caller should execute tmpfs_update on vp after a successful execution.
1027  * The vnode must be locked on entry and remain locked on exit.
1028  */
1029 int
1030 tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred)
1031 {
1032         int error;
1033         struct tmpfs_node *node;
1034         int fmode, accmode;
1035
1036         KKASSERT(vn_islocked(vp));
1037
1038         node = VP_TO_TMPFS_NODE(vp);
1039
1040         /* Disallow this operation if the file system is mounted read-only. */
1041         if (vp->v_mount->mnt_flag & MNT_RDONLY)
1042                 return EROFS;
1043
1044         /* Immutable or append-only files cannot be modified, either. */
1045         if (node->tn_flags & (IMMUTABLE | APPEND))
1046                 return EPERM;
1047
1048         fmode = FFLAGS(node->tn_flags);
1049         accmode = 0;
1050         if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
1051                 return EINVAL;
1052         if (fmode & (FWRITE | O_TRUNC)) {
1053                 if (vp->v_type == VDIR) {
1054                         return EISDIR;
1055                 }
1056                 error = vn_writechk(vp, NULL);
1057                 if (error)
1058                         return (error);
1059
1060                 accmode |= VWRITE;
1061         }
1062         if (fmode & FREAD)
1063                 accmode |= VREAD;
1064         if (accmode) {
1065                 error = VOP_ACCESS(vp, accmode, cred);
1066                 if (error)
1067                         return (error);
1068         }
1069
1070         /*
1071          * Privileged processes may set the sticky bit on non-directories,
1072          * as well as set the setgid bit on a file with a group that the
1073          * process is not a member of.
1074          */
1075         if (vp->v_type != VDIR && (mode & S_ISTXT)) {
1076                 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0))
1077                         return (EFTYPE);
1078         }
1079         if (!groupmember(node->tn_gid, cred) && (mode & S_ISGID)) {
1080                 error = priv_check_cred(cred, PRIV_VFS_SETGID, 0);
1081                 if (error)
1082                         return (error);
1083         }
1084
1085
1086         TMPFS_NODE_LOCK(node);
1087         node->tn_mode &= ~ALLPERMS;
1088         node->tn_mode |= mode & ALLPERMS;
1089
1090         node->tn_status |= TMPFS_NODE_CHANGED;
1091         TMPFS_NODE_UNLOCK(node);
1092
1093         KKASSERT(vn_islocked(vp));
1094
1095         return 0;
1096 }
1097
1098 /* --------------------------------------------------------------------- */
1099
1100 /*
1101  * Change ownership of the given vnode.  At least one of uid or gid must
1102  * be different than VNOVAL.  If one is set to that value, the attribute
1103  * is unchanged.
1104  * Caller should execute tmpfs_update on vp after a successful execution.
1105  * The vnode must be locked on entry and remain locked on exit.
1106  */
1107 int
1108 tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred)
1109 {
1110         int error;
1111         struct tmpfs_node *node;
1112         uid_t ouid;
1113         gid_t ogid;
1114         int fmode, mode;
1115
1116         KKASSERT(vn_islocked(vp));
1117
1118         node = VP_TO_TMPFS_NODE(vp);
1119
1120         /* Assign default values if they are unknown. */
1121         KKASSERT(uid != VNOVAL || gid != VNOVAL);
1122         if (uid == VNOVAL)
1123                 uid = node->tn_uid;
1124         if (gid == VNOVAL)
1125                 gid = node->tn_gid;
1126         KKASSERT(uid != VNOVAL && gid != VNOVAL);
1127
1128         /* Disallow this operation if the file system is mounted read-only. */
1129         if (vp->v_mount->mnt_flag & MNT_RDONLY)
1130                 return EROFS;
1131
1132         /* Immutable or append-only files cannot be modified, either. */
1133         if (node->tn_flags & (IMMUTABLE | APPEND))
1134                 return EPERM;
1135
1136         fmode = FFLAGS(node->tn_flags);
1137         mode = 0;
1138         if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
1139                 return EINVAL;
1140         if (fmode & (FWRITE | O_TRUNC)) {
1141                 if (vp->v_type == VDIR) {
1142                         return EISDIR;
1143                 }
1144                 error = vn_writechk(vp, NULL);
1145                 if (error)
1146                         return (error);
1147
1148                 mode |= VWRITE;
1149         }
1150         if (fmode & FREAD)
1151                 mode |= VREAD;
1152         if (mode) {
1153                 error = VOP_ACCESS(vp, mode, cred);
1154                 if (error)
1155                         return (error);
1156         }
1157
1158         /*
1159          * To change the owner of a file, or change the group of a file to a
1160          * group of which we are not a member, the caller must have
1161          * privilege.
1162          */
1163         if ((uid != node->tn_uid ||
1164             (gid != node->tn_gid && !groupmember(gid, cred))) &&
1165             (error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0)))
1166                 return (error);
1167
1168         ogid = node->tn_gid;
1169         ouid = node->tn_uid;
1170
1171         TMPFS_NODE_LOCK(node);
1172         node->tn_uid = uid;
1173         node->tn_gid = gid;
1174
1175         node->tn_status |= TMPFS_NODE_CHANGED;
1176
1177         if ((node->tn_mode & (S_ISUID | S_ISGID)) && (ouid != uid || ogid != gid)) {
1178                 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0))
1179                         node->tn_mode &= ~(S_ISUID | S_ISGID);
1180         }
1181         TMPFS_NODE_UNLOCK(node);
1182
1183         KKASSERT(vn_islocked(vp));
1184
1185         return 0;
1186 }
1187
1188 /* --------------------------------------------------------------------- */
1189
1190 /*
1191  * Change size of the given vnode.
1192  * Caller should execute tmpfs_update on vp after a successful execution.
1193  * The vnode must be locked on entry and remain locked on exit.
1194  */
1195 int
1196 tmpfs_chsize(struct vnode *vp, u_quad_t size, struct ucred *cred)
1197 {
1198         int error;
1199         struct tmpfs_node *node;
1200
1201         KKASSERT(vn_islocked(vp));
1202
1203         node = VP_TO_TMPFS_NODE(vp);
1204
1205         /* Decide whether this is a valid operation based on the file type. */
1206         error = 0;
1207         switch (vp->v_type) {
1208         case VDIR:
1209                 return EISDIR;
1210
1211         case VREG:
1212                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
1213                         return EROFS;
1214                 break;
1215
1216         case VBLK:
1217                 /* FALLTHROUGH */
1218         case VCHR:
1219                 /* FALLTHROUGH */
1220         case VFIFO:
1221                 /* Allow modifications of special files even if in the file
1222                  * system is mounted read-only (we are not modifying the
1223                  * files themselves, but the objects they represent). */
1224                 return 0;
1225
1226         default:
1227                 /* Anything else is unsupported. */
1228                 return EOPNOTSUPP;
1229         }
1230
1231         /* Immutable or append-only files cannot be modified, either. */
1232         if (node->tn_flags & (IMMUTABLE | APPEND))
1233                 return EPERM;
1234
1235         error = tmpfs_truncate(vp, size);
1236         /* tmpfs_truncate will raise the NOTE_EXTEND and NOTE_ATTRIB kevents
1237          * for us, as will update tn_status; no need to do that here. */
1238
1239         KKASSERT(vn_islocked(vp));
1240
1241         return error;
1242 }
1243
1244 /* --------------------------------------------------------------------- */
1245
1246 /*
1247  * Change access and modification times of the given vnode.
1248  * Caller should execute tmpfs_update on vp after a successful execution.
1249  * The vnode must be locked on entry and remain locked on exit.
1250  */
1251 int
1252 tmpfs_chtimes(struct vnode *vp, struct timespec *atime, struct timespec *mtime,
1253         int vaflags, struct ucred *cred)
1254 {
1255         int error;
1256         struct tmpfs_node *node;
1257         int fmode, mode;
1258
1259         KKASSERT(vn_islocked(vp));
1260
1261         node = VP_TO_TMPFS_NODE(vp);
1262
1263         /* Disallow this operation if the file system is mounted read-only. */
1264         if (vp->v_mount->mnt_flag & MNT_RDONLY)
1265                 return EROFS;
1266
1267         /* Immutable or append-only files cannot be modified, either. */
1268         if (node->tn_flags & (IMMUTABLE | APPEND))
1269                 return EPERM;
1270
1271         /* Determine if the user have proper privilege to update time. */
1272         fmode = FFLAGS(node->tn_flags);
1273         mode = 0;
1274         if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
1275                 return EINVAL;
1276         if (fmode & (FWRITE | O_TRUNC)) {
1277                 if (vp->v_type == VDIR) {
1278                         return EISDIR;
1279                 }
1280                 error = vn_writechk(vp, NULL);
1281                 if (error)
1282                         return (error);
1283
1284                 mode |= VWRITE;
1285         }
1286         if (fmode & FREAD)
1287                 mode |= VREAD;
1288
1289         if (mode) {
1290                 if (vaflags & VA_UTIMES_NULL) {
1291                         error = VOP_ACCESS(vp, mode, cred);
1292                         if (error)
1293                                 error = VOP_ACCESS(vp, VWRITE, cred);
1294                 } else
1295                         error = VOP_ACCESS(vp, mode, cred);
1296                 if (error)
1297                         return (error);
1298         }
1299
1300         TMPFS_NODE_LOCK(node);
1301         if (atime->tv_sec != VNOVAL && atime->tv_nsec != VNOVAL)
1302                 node->tn_status |= TMPFS_NODE_ACCESSED;
1303
1304         if (mtime->tv_sec != VNOVAL && mtime->tv_nsec != VNOVAL)
1305                 node->tn_status |= TMPFS_NODE_MODIFIED;
1306
1307         TMPFS_NODE_UNLOCK(node);
1308
1309         tmpfs_itimes(vp, atime, mtime);
1310
1311         KKASSERT(vn_islocked(vp));
1312
1313         return 0;
1314 }
1315
1316 /* --------------------------------------------------------------------- */
1317 /* Sync timestamps */
1318 void
1319 tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
1320     const struct timespec *mod)
1321 {
1322         struct tmpfs_node *node;
1323         struct timespec now;
1324
1325         node = VP_TO_TMPFS_NODE(vp);
1326
1327         if ((node->tn_status & (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
1328             TMPFS_NODE_CHANGED)) == 0)
1329                 return;
1330
1331         vfs_timestamp(&now);
1332
1333         TMPFS_NODE_LOCK(node);
1334         if (node->tn_status & TMPFS_NODE_ACCESSED) {
1335                 if (acc == NULL)
1336                          acc = &now;
1337                 node->tn_atime = acc->tv_sec;
1338                 node->tn_atimensec = acc->tv_nsec;
1339         }
1340         if (node->tn_status & TMPFS_NODE_MODIFIED) {
1341                 if (mod == NULL)
1342                         mod = &now;
1343                 node->tn_mtime = mod->tv_sec;
1344                 node->tn_mtimensec = mod->tv_nsec;
1345         }
1346         if (node->tn_status & TMPFS_NODE_CHANGED) {
1347                 node->tn_ctime = now.tv_sec;
1348                 node->tn_ctimensec = now.tv_nsec;
1349         }
1350         node->tn_status &=
1351             ~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED);
1352         TMPFS_NODE_UNLOCK(node);
1353 }
1354
1355 /* --------------------------------------------------------------------- */
1356
1357 void
1358 tmpfs_update(struct vnode *vp)
1359 {
1360
1361         tmpfs_itimes(vp, NULL, NULL);
1362 }
1363
1364 /* --------------------------------------------------------------------- */
1365
1366 int
1367 tmpfs_truncate(struct vnode *vp, off_t length)
1368 {
1369         int error;
1370         struct tmpfs_node *node;
1371
1372         node = VP_TO_TMPFS_NODE(vp);
1373
1374         if (length < 0) {
1375                 error = EINVAL;
1376                 goto out;
1377         }
1378
1379         if (node->tn_size == length) {
1380                 error = 0;
1381                 goto out;
1382         }
1383
1384         if (length > VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
1385                 return (EFBIG);
1386
1387
1388         error = tmpfs_reg_resize(vp, length, 1);
1389
1390         if (error == 0) {
1391                 TMPFS_NODE_LOCK(node);
1392                 node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
1393                 TMPFS_NODE_UNLOCK(node);
1394         }
1395
1396 out:
1397         tmpfs_update(vp);
1398
1399         return error;
1400 }
1401
1402 /* --------------------------------------------------------------------- */
1403
1404 static ino_t
1405 tmpfs_fetch_ino(void)
1406 {
1407         ino_t   ret;
1408
1409         spin_lock_wr(&ino_lock);
1410         ret = t_ino++;
1411         spin_unlock_wr(&ino_lock);
1412
1413         return ret;
1414 }