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