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