xref: /netbsd-src/sys/fs/tmpfs/tmpfs_subr.c (revision f81322cf185a4db50f71fcf7701f20198272620e)
1 /*	$NetBSD: tmpfs_subr.c,v 1.18 2006/02/16 14:57:50 jmmv Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9  * 2005 program.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * Efficient memory file system supporting functions.
42  */
43 
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: tmpfs_subr.c,v 1.18 2006/02/16 14:57:50 jmmv Exp $");
46 
47 #include <sys/param.h>
48 #include <sys/dirent.h>
49 #include <sys/event.h>
50 #include <sys/malloc.h>
51 #include <sys/mount.h>
52 #include <sys/namei.h>
53 #include <sys/time.h>
54 #include <sys/stat.h>
55 #include <sys/systm.h>
56 #include <sys/swap.h>
57 #include <sys/vnode.h>
58 
59 #include <uvm/uvm.h>
60 
61 #include <miscfs/specfs/specdev.h>
62 #include <fs/tmpfs/tmpfs.h>
63 #include <fs/tmpfs/tmpfs_fifoops.h>
64 #include <fs/tmpfs/tmpfs_specops.h>
65 #include <fs/tmpfs/tmpfs_vnops.h>
66 
67 /* --------------------------------------------------------------------- */
68 
69 /*
70  * Allocates a new node of type 'type' inside the 'tmp' mount point, with
71  * its owner set to 'uid', its group to 'gid' and its mode set to 'mode',
72  * using the credentials of the process 'p'.
73  *
74  * If the node type is set to 'VDIR', then the parent parameter must point
75  * to the parent directory of the node being created.  It may only be NULL
76  * while allocating the root node.
77  *
78  * If the node type is set to 'VBLK' or 'VCHR', then the rdev parameter
79  * specifies the device the node represents.
80  *
81  * If the node type is set to 'VLNK', then the parameter target specifies
82  * the file name of the target file for the symbolic link that is being
83  * created.
84  *
85  * Note that new nodes are retrieved from the available list if it has
86  * items or, if it is empty, from the node pool as long as there is enough
87  * space to create them.
88  *
89  * Returns zero on success or an appropriate error code on failure.
90  */
91 int
92 tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type,
93     uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *parent,
94     char *target, dev_t rdev, struct proc *p, struct tmpfs_node **node)
95 {
96 	struct tmpfs_node *nnode;
97 
98 	/* If the root directory of the 'tmp' file system is not yet
99 	 * allocated, this must be the request to do it. */
100 	KASSERT(IMPLIES(tmp->tm_root == NULL, parent == NULL && type == VDIR));
101 
102 	KASSERT(IFF(type == VLNK, target != NULL));
103 	KASSERT(IFF(type == VBLK || type == VCHR, rdev != VNOVAL));
104 
105 	KASSERT(uid != VNOVAL && gid != VNOVAL && mode != VNOVAL);
106 
107 	nnode = NULL;
108 	if (LIST_EMPTY(&tmp->tm_nodes_avail)) {
109 		KASSERT(tmp->tm_nodes_last <= tmp->tm_nodes_max);
110 		if (tmp->tm_nodes_last == tmp->tm_nodes_max)
111 			return ENOSPC;
112 
113 		nnode =
114 		    (struct tmpfs_node *)TMPFS_POOL_GET(&tmp->tm_node_pool, 0);
115 		if (nnode == NULL)
116 			return ENOSPC;
117 		nnode->tn_id = tmp->tm_nodes_last++;
118 		nnode->tn_gen = 0;
119 	} else {
120 		nnode = LIST_FIRST(&tmp->tm_nodes_avail);
121 		LIST_REMOVE(nnode, tn_entries);
122 		nnode->tn_gen++;
123 	}
124 	KASSERT(nnode != NULL);
125 	LIST_INSERT_HEAD(&tmp->tm_nodes_used, nnode, tn_entries);
126 
127 	/* Generic initialization. */
128 	nnode->tn_type = type;
129 	nnode->tn_size = 0;
130 	nnode->tn_status = 0;
131 	nnode->tn_flags = 0;
132 	nnode->tn_links = 0;
133 	(void)nanotime(&nnode->tn_atime);
134 	nnode->tn_birthtime = nnode->tn_ctime = nnode->tn_mtime =
135 	    nnode->tn_atime;
136 	nnode->tn_uid = uid;
137 	nnode->tn_gid = gid;
138 	nnode->tn_mode = mode;
139 	nnode->tn_lockf = NULL;
140 	nnode->tn_vnode = NULL;
141 
142 	/* Type-specific initialization. */
143 	switch (nnode->tn_type) {
144 	case VBLK:
145 	case VCHR:
146 		nnode->tn_spec.tn_dev.tn_rdev = rdev;
147 		break;
148 
149 	case VDIR:
150 		TAILQ_INIT(&nnode->tn_spec.tn_dir.tn_dir);
151 		nnode->tn_spec.tn_dir.tn_parent =
152 		    (parent == NULL) ? nnode : parent;
153 		nnode->tn_spec.tn_dir.tn_readdir_lastn = 0;
154 		nnode->tn_spec.tn_dir.tn_readdir_lastp = NULL;
155 		nnode->tn_links++;
156 		nnode->tn_spec.tn_dir.tn_parent->tn_links++;
157 		break;
158 
159 	case VFIFO:
160 		/* FALLTHROUGH */
161 	case VSOCK:
162 		break;
163 
164 	case VLNK:
165 		KASSERT(strlen(target) < MAXPATHLEN);
166 		nnode->tn_size = strlen(target);
167 		nnode->tn_spec.tn_lnk.tn_link =
168 		    tmpfs_str_pool_get(&tmp->tm_str_pool, nnode->tn_size, 0);
169 		if (nnode->tn_spec.tn_lnk.tn_link == NULL) {
170 			nnode->tn_type = VNON;
171 			tmpfs_free_node(tmp, nnode);
172 			return ENOSPC;
173 		}
174 		memcpy(nnode->tn_spec.tn_lnk.tn_link, target, nnode->tn_size);
175 		break;
176 
177 	case VREG:
178 		nnode->tn_spec.tn_reg.tn_aobj =
179 		    uao_create(INT32_MAX - PAGE_SIZE, 0);
180 		nnode->tn_spec.tn_reg.tn_aobj_pages = 0;
181 		break;
182 
183 	default:
184 		KASSERT(0);
185 	}
186 
187 	*node = nnode;
188 	return 0;
189 }
190 
191 /* --------------------------------------------------------------------- */
192 
193 /*
194  * Destroys the node pointed to by node from the file system 'tmp'.
195  * If the node does not belong to the given mount point, the results are
196  * unpredicted.
197  *
198  * If the node references a directory; no entries are allowed because
199  * their removal could need a recursive algorithm, something forbidden in
200  * kernel space.  Furthermore, there is not need to provide such
201  * functionality (recursive removal) because the only primitives offered
202  * to the user are the removal of empty directories and the deletion of
203  * individual files.
204  *
205  * Note that nodes are not really deleted; in fact, when a node has been
206  * allocated, it cannot be deleted during the whole life of the file
207  * system.  Instead, they are moved to the available list and remain there
208  * until reused.
209  */
210 void
211 tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node)
212 {
213 	ino_t id;
214 	unsigned long gen;
215 	size_t pages;
216 
217 	switch (node->tn_type) {
218 	case VNON:
219 		/* Do not do anything.  VNON is provided to let the
220 		 * allocation routine clean itself easily by avoiding
221 		 * duplicating code in it. */
222 		/* FALLTHROUGH */
223 	case VBLK:
224 		/* FALLTHROUGH */
225 	case VCHR:
226 		/* FALLTHROUGH */
227 	case VDIR:
228 		/* FALLTHROUGH */
229 	case VFIFO:
230 		/* FALLTHROUGH */
231 	case VSOCK:
232 		pages = 0;
233 		break;
234 
235 	case VLNK:
236 		tmpfs_str_pool_put(&tmp->tm_str_pool,
237 		    node->tn_spec.tn_lnk.tn_link, node->tn_size);
238 		pages = 0;
239 		break;
240 
241 	case VREG:
242 		if (node->tn_spec.tn_reg.tn_aobj != NULL)
243 			uao_detach(node->tn_spec.tn_reg.tn_aobj);
244 		pages = node->tn_spec.tn_reg.tn_aobj_pages;
245 		break;
246 
247 	default:
248 		KASSERT(0);
249 		pages = 0; /* Shut up gcc when !DIAGNOSTIC. */
250 		break;
251 	}
252 
253 	tmp->tm_pages_used -= pages;
254 
255 	LIST_REMOVE(node, tn_entries);
256 	id = node->tn_id;
257 	gen = node->tn_gen;
258 	memset(node, 0, sizeof(struct tmpfs_node));
259 	node->tn_id = id;
260 	node->tn_type = VNON;
261 	node->tn_gen = gen;
262 	LIST_INSERT_HEAD(&tmp->tm_nodes_avail, node, tn_entries);
263 }
264 
265 /* --------------------------------------------------------------------- */
266 
267 /*
268  * Allocates a new directory entry for the node node with a name of name.
269  * The new directory entry is returned in *de.
270  *
271  * The link count of node is increased by one to reflect the new object
272  * referencing it.
273  *
274  * Returns zero on success or an appropriate error code on failure.
275  */
276 int
277 tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
278     const char *name, uint16_t len, struct tmpfs_dirent **de)
279 {
280 	struct tmpfs_dirent *nde;
281 
282 	nde = (struct tmpfs_dirent *)TMPFS_POOL_GET(&tmp->tm_dirent_pool, 0);
283 	if (nde == NULL)
284 		return ENOSPC;
285 
286 	nde->td_name = tmpfs_str_pool_get(&tmp->tm_str_pool, len, 0);
287 	if (nde->td_name == NULL) {
288 		TMPFS_POOL_PUT(&tmp->tm_dirent_pool, nde);
289 		return ENOSPC;
290 	}
291 	nde->td_namelen = len;
292 	memcpy(nde->td_name, name, len);
293 	nde->td_node = node;
294 
295 	node->tn_links++;
296 	*de = nde;
297 
298 	return 0;
299 }
300 
301 /* --------------------------------------------------------------------- */
302 
303 /*
304  * Frees a directory entry.  It is the caller's responsibility to destroy
305  * the node referenced by it if needed.
306  *
307  * The link count of node is decreased by one to reflect the removal of an
308  * object that referenced it.  This only happens if 'node_exists' is true;
309  * otherwise the function will not access the node referred to by the
310  * directory entry, as it may already have been released from the outside.
311  */
312 void
313 tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de,
314     boolean_t node_exists)
315 {
316 	if (node_exists) {
317 		struct tmpfs_node *node;
318 
319 		node = de->td_node;
320 
321 		KASSERT(node->tn_links > 0);
322 		node->tn_links--;
323 	}
324 
325 	tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name, de->td_namelen);
326 	TMPFS_POOL_PUT(&tmp->tm_dirent_pool, de);
327 }
328 
329 /* --------------------------------------------------------------------- */
330 
331 /*
332  * Allocates a new vnode for the node node or returns a new reference to
333  * an existing one if the node had already a vnode referencing it.  The
334  * resulting locked vnode is returned in *vpp.
335  *
336  * Returns zero on success or an appropriate error code on failure.
337  */
338 int
339 tmpfs_alloc_vp(struct mount *mp, struct tmpfs_node *node, struct vnode **vpp)
340 {
341 	int error;
342 	struct vnode *nvp;
343 	struct vnode *vp;
344 
345 	vp = NULL;
346 
347 	if (node->tn_vnode != NULL) {
348 		vp = node->tn_vnode;
349 		vget(vp, LK_EXCLUSIVE | LK_RETRY);
350 		error = 0;
351 		goto out;
352 	}
353 
354 	/* Get a new vnode and associate it with our node. */
355 	error = getnewvnode(VT_TMPFS, mp, tmpfs_vnodeop_p, &vp);
356 	if (error != 0)
357 		goto out;
358 	KASSERT(vp != NULL);
359 
360 	error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
361 	if (error != 0) {
362 		vp->v_data = NULL;
363 		ungetnewvnode(vp);
364 		vp = NULL;
365 		goto out;
366 	}
367 
368 	vp->v_data = node;
369 	vp->v_type = node->tn_type;
370 
371 	/* Type-specific initialization. */
372 	switch (node->tn_type) {
373 	case VBLK:
374 		/* FALLTHROUGH */
375 	case VCHR:
376 		vp->v_op = tmpfs_specop_p;
377 		nvp = checkalias(vp, node->tn_spec.tn_dev.tn_rdev, mp);
378 		if (nvp != NULL) {
379 			/* Discard unneeded vnode, but save its inode. */
380 			nvp->v_data = vp->v_data;
381 			vp->v_data = NULL;
382 
383 			/* XXX spec_vnodeops has no locking, so we have to
384 			 * do it explicitly. */
385 			VOP_UNLOCK(vp, 0);
386 			vp->v_op = spec_vnodeop_p;
387 			vp->v_flag &= ~VLOCKSWORK;
388 			vrele(vp);
389 			vgone(vp);
390 
391 			/* Reinitialize aliased node. */
392 			vp = nvp;
393 			error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
394 			if (error != 0) {
395 				vp->v_data = NULL;
396 				vp = NULL;
397 				goto out;
398 			}
399 		}
400 		break;
401 
402 	case VDIR:
403 		vp->v_flag = node->tn_spec.tn_dir.tn_parent == node ? VROOT : 0;
404 		break;
405 
406 	case VFIFO:
407 		vp->v_op = tmpfs_fifoop_p;
408 		break;
409 
410 	case VLNK:
411 		/* FALLTHROUGH */
412 	case VREG:
413 		/* FALLTHROUGH */
414 	case VSOCK:
415 		break;
416 
417 	default:
418 		KASSERT(0);
419 	}
420 
421 	uvm_vnp_setsize(vp, node->tn_size);
422 
423 	error = 0;
424 
425 out:
426 	*vpp = node->tn_vnode = vp;
427 
428 	KASSERT(IFF(error == 0, *vpp != NULL && VOP_ISLOCKED(*vpp)));
429 	KASSERT(*vpp == node->tn_vnode);
430 
431 	return error;
432 }
433 
434 /* --------------------------------------------------------------------- */
435 
436 /*
437  * Destroys the association between the vnode vp and the node it
438  * references.
439  */
440 void
441 tmpfs_free_vp(struct vnode *vp)
442 {
443 	struct tmpfs_node *node;
444 
445 	node = VP_TO_TMPFS_NODE(vp);
446 
447 	node->tn_vnode = NULL;
448 	vp->v_data = NULL;
449 }
450 
451 /* --------------------------------------------------------------------- */
452 
453 /*
454  * Allocates a new file of type 'type' and adds it to the parent directory
455  * 'dvp'; this addition is done using the component name given in 'cnp'.
456  * The ownership of the new file is automatically assigned based on the
457  * credentials of the caller (through 'cnp'), the group is set based on
458  * the parent directory and the mode is determined from the 'vap' argument.
459  * If successful, *vpp holds a vnode to the newly created file and zero
460  * is returned.  Otherwise *vpp is NULL and the function returns an
461  * appropriate error code.
462  */
463 int
464 tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
465     struct componentname *cnp, char *target)
466 {
467 	int error;
468 	struct tmpfs_dirent *de;
469 	struct tmpfs_mount *tmp;
470 	struct tmpfs_node *dnode;
471 	struct tmpfs_node *node;
472 	struct tmpfs_node *parent;
473 
474 	KASSERT(VOP_ISLOCKED(dvp));
475 	KASSERT(cnp->cn_flags & HASBUF);
476 
477 	tmp = VFS_TO_TMPFS(dvp->v_mount);
478 	dnode = VP_TO_TMPFS_DIR(dvp);
479 	*vpp = NULL;
480 
481 	/* If the entry we are creating is a directory, we cannot overflow
482 	 * the number of links of its parent, because it will get a new
483 	 * link. */
484 	if (vap->va_type == VDIR) {
485 		/* Ensure that we do not overflow the maximum number of links
486 		 * imposed by the system. */
487 		KASSERT(dnode->tn_links <= LINK_MAX);
488 		if (dnode->tn_links == LINK_MAX) {
489 			error = EMLINK;
490 			goto out;
491 		}
492 
493 		parent = dnode;
494 	} else
495 		parent = NULL;
496 
497 	/* Allocate a node that represents the new file. */
498 	error = tmpfs_alloc_node(tmp, vap->va_type, cnp->cn_cred->cr_uid,
499 	    dnode->tn_gid, vap->va_mode, parent, target, vap->va_rdev,
500 	    cnp->cn_lwp->l_proc, &node);
501 	if (error != 0)
502 		goto out;
503 
504 	/* Allocate a directory entry that points to the new file. */
505 	error = tmpfs_alloc_dirent(tmp, node, cnp->cn_nameptr, cnp->cn_namelen,
506 	    &de);
507 	if (error != 0) {
508 		tmpfs_free_node(tmp, node);
509 		goto out;
510 	}
511 
512 	/* Allocate a vnode for the new file. */
513 	error = tmpfs_alloc_vp(dvp->v_mount, node, vpp);
514 	if (error != 0) {
515 		tmpfs_free_dirent(tmp, de, TRUE);
516 		tmpfs_free_node(tmp, node);
517 		goto out;
518 	}
519 
520 	/* Now that all required items are allocated, we can proceed to
521 	 * insert the new node into the directory, an operation that
522 	 * cannot fail. */
523 	tmpfs_dir_attach(dvp, de);
524 	VN_KNOTE(dvp, NOTE_WRITE);
525 
526 out:
527 	if (error != 0 || !(cnp->cn_flags & SAVESTART))
528 		PNBUF_PUT(cnp->cn_pnbuf);
529 	vput(dvp);
530 
531 	KASSERT(!VOP_ISLOCKED(dvp));
532 	KASSERT(IFF(error == 0, *vpp != NULL));
533 
534 	return error;
535 }
536 
537 /* --------------------------------------------------------------------- */
538 
539 /*
540  * Attaches the directory entry de to the directory represented by vp.
541  * Note that this does not change the link count of the node pointed by
542  * the directory entry, as this is done by tmpfs_alloc_dirent.
543  */
544 void
545 tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de)
546 {
547 	struct tmpfs_node *dnode;
548 
549 	dnode = VP_TO_TMPFS_DIR(vp);
550 
551 	TAILQ_INSERT_TAIL(&dnode->tn_spec.tn_dir.tn_dir, de, td_entries);
552 	dnode->tn_size += sizeof(struct tmpfs_dirent);
553 	dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
554 	    TMPFS_NODE_MODIFIED;
555 	uvm_vnp_setsize(vp, dnode->tn_size);
556 }
557 
558 /* --------------------------------------------------------------------- */
559 
560 /*
561  * Detaches the directory entry de from the directory represented by vp.
562  * Note that this does not change the link count of the node pointed by
563  * the directory entry, as this is done by tmpfs_free_dirent.
564  */
565 void
566 tmpfs_dir_detach(struct vnode *vp, struct tmpfs_dirent *de)
567 {
568 	struct tmpfs_node *dnode;
569 
570 	KASSERT(VOP_ISLOCKED(vp));
571 
572 	dnode = VP_TO_TMPFS_DIR(vp);
573 
574 	if (dnode->tn_spec.tn_dir.tn_readdir_lastp == de) {
575 		dnode->tn_spec.tn_dir.tn_readdir_lastn = 0;
576 		dnode->tn_spec.tn_dir.tn_readdir_lastp = NULL;
577 	}
578 
579 	TAILQ_REMOVE(&dnode->tn_spec.tn_dir.tn_dir, de, td_entries);
580 	dnode->tn_size -= sizeof(struct tmpfs_dirent);
581 	dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
582 	    TMPFS_NODE_MODIFIED;
583 	uvm_vnp_setsize(vp, dnode->tn_size);
584 }
585 
586 /* --------------------------------------------------------------------- */
587 
588 /*
589  * Looks for a directory entry in the directory represented by node.
590  * 'cnp' describes the name of the entry to look for.  Note that the .
591  * and .. components are not allowed as they do not physically exist
592  * within directories.
593  *
594  * Returns a pointer to the entry when found, otherwise NULL.
595  */
596 struct tmpfs_dirent *
597 tmpfs_dir_lookup(struct tmpfs_node *node, struct componentname *cnp)
598 {
599 	boolean_t found;
600 	struct tmpfs_dirent *de;
601 
602 	KASSERT(IMPLIES(cnp->cn_namelen == 1, cnp->cn_nameptr[0] != '.'));
603 	KASSERT(IMPLIES(cnp->cn_namelen == 2, !(cnp->cn_nameptr[0] == '.' &&
604 	    cnp->cn_nameptr[1] == '.')));
605 	TMPFS_VALIDATE_DIR(node);
606 
607 	node->tn_status |= TMPFS_NODE_ACCESSED;
608 
609 	found = 0;
610 	TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {
611 		KASSERT(cnp->cn_namelen < 0xffff);
612 		if (de->td_namelen == (uint16_t)cnp->cn_namelen &&
613 		    memcmp(de->td_name, cnp->cn_nameptr, de->td_namelen) == 0) {
614 			found = 1;
615 			break;
616 		}
617 	}
618 
619 	return found ? de : NULL;
620 }
621 
622 /* --------------------------------------------------------------------- */
623 
624 /*
625  * Helper function for tmpfs_readdir.  Creates a '.' entry for the given
626  * directory and returns it in the uio space.  The function returns 0
627  * on success, -1 if there was not enough space in the uio structure to
628  * hold the directory entry or an appropriate error code if another
629  * error happens.
630  */
631 int
632 tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio)
633 {
634 	int error;
635 	struct dirent dent;
636 
637 	TMPFS_VALIDATE_DIR(node);
638 	KASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOT);
639 
640 	dent.d_fileno = node->tn_id;
641 	dent.d_type = DT_DIR;
642 	dent.d_namlen = 1;
643 	dent.d_name[0] = '.';
644 	dent.d_name[1] = '\0';
645 	dent.d_reclen = _DIRENT_SIZE(&dent);
646 
647 	if (dent.d_reclen > uio->uio_resid)
648 		error = -1;
649 	else {
650 		error = uiomove(&dent, dent.d_reclen, uio);
651 		if (error == 0)
652 			uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT;
653 	}
654 
655 	node->tn_status |= TMPFS_NODE_ACCESSED;
656 
657 	return error;
658 }
659 
660 /* --------------------------------------------------------------------- */
661 
662 /*
663  * Helper function for tmpfs_readdir.  Creates a '..' entry for the given
664  * directory and returns it in the uio space.  The function returns 0
665  * on success, -1 if there was not enough space in the uio structure to
666  * hold the directory entry or an appropriate error code if another
667  * error happens.
668  */
669 int
670 tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio)
671 {
672 	int error;
673 	struct dirent dent;
674 
675 	TMPFS_VALIDATE_DIR(node);
676 	KASSERT(uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT);
677 
678 	dent.d_fileno = node->tn_spec.tn_dir.tn_parent->tn_id;
679 	dent.d_type = DT_DIR;
680 	dent.d_namlen = 2;
681 	dent.d_name[0] = '.';
682 	dent.d_name[1] = '.';
683 	dent.d_name[2] = '\0';
684 	dent.d_reclen = _DIRENT_SIZE(&dent);
685 
686 	if (dent.d_reclen > uio->uio_resid)
687 		error = -1;
688 	else {
689 		error = uiomove(&dent, dent.d_reclen, uio);
690 		if (error == 0) {
691 			struct tmpfs_dirent *de;
692 
693 			de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir);
694 			if (de == NULL)
695 				uio->uio_offset = TMPFS_DIRCOOKIE_EOF;
696 			else
697 				uio->uio_offset = TMPFS_DIRCOOKIE(de);
698 		}
699 	}
700 
701 	node->tn_status |= TMPFS_NODE_ACCESSED;
702 
703 	return error;
704 }
705 
706 /* --------------------------------------------------------------------- */
707 
708 /*
709  * Lookup a directory entry by its associated cookie.
710  */
711 struct tmpfs_dirent *
712 tmpfs_dir_lookupbycookie(struct tmpfs_node *node, off_t cookie)
713 {
714 	struct tmpfs_dirent *de;
715 
716 	if (cookie == node->tn_spec.tn_dir.tn_readdir_lastn &&
717 	    node->tn_spec.tn_dir.tn_readdir_lastp != NULL) {
718 		return node->tn_spec.tn_dir.tn_readdir_lastp;
719 	}
720 
721 	TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {
722 		if (TMPFS_DIRCOOKIE(de) == cookie) {
723 			break;
724 		}
725 	}
726 
727 	return de;
728 }
729 
730 /* --------------------------------------------------------------------- */
731 
732 /*
733  * Helper function for tmpfs_readdir.  Returns as much directory entries
734  * as can fit in the uio space.  The read starts at uio->uio_offset.
735  * The function returns 0 on success, -1 if there was not enough space
736  * in the uio structure to hold the directory entry or an appropriate
737  * error code if another error happens.
738  */
739 int
740 tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp)
741 {
742 	int error;
743 	off_t startcookie;
744 	struct tmpfs_dirent *de;
745 
746 	TMPFS_VALIDATE_DIR(node);
747 
748 	/* Locate the first directory entry we have to return.  We have cached
749 	 * the last readdir in the node, so use those values if appropriate.
750 	 * Otherwise do a linear scan to find the requested entry. */
751 	startcookie = uio->uio_offset;
752 	KASSERT(startcookie != TMPFS_DIRCOOKIE_DOT);
753 	KASSERT(startcookie != TMPFS_DIRCOOKIE_DOTDOT);
754 	if (startcookie == TMPFS_DIRCOOKIE_EOF) {
755 		return 0;
756 	} else {
757 		de = tmpfs_dir_lookupbycookie(node, startcookie);
758 	}
759 	if (de == NULL) {
760 		return EINVAL;
761 	}
762 
763 	/* Read as much entries as possible; i.e., until we reach the end of
764 	 * the directory or we exhaust uio space. */
765 	do {
766 		struct dirent d;
767 
768 		/* Create a dirent structure representing the current
769 		 * tmpfs_node and fill it. */
770 		d.d_fileno = de->td_node->tn_id;
771 		switch (de->td_node->tn_type) {
772 		case VBLK:
773 			d.d_type = DT_BLK;
774 			break;
775 
776 		case VCHR:
777 			d.d_type = DT_CHR;
778 			break;
779 
780 		case VDIR:
781 			d.d_type = DT_DIR;
782 			break;
783 
784 		case VFIFO:
785 			d.d_type = DT_FIFO;
786 			break;
787 
788 		case VLNK:
789 			d.d_type = DT_LNK;
790 			break;
791 
792 		case VREG:
793 			d.d_type = DT_REG;
794 			break;
795 
796 		case VSOCK:
797 			d.d_type = DT_SOCK;
798 			break;
799 
800 		default:
801 			KASSERT(0);
802 		}
803 		d.d_namlen = de->td_namelen;
804 		KASSERT(de->td_namelen < sizeof(d.d_name));
805 		(void)memcpy(d.d_name, de->td_name, de->td_namelen);
806 		d.d_name[de->td_namelen] = '\0';
807 		d.d_reclen = _DIRENT_SIZE(&d);
808 
809 		/* Stop reading if the directory entry we are treating is
810 		 * bigger than the amount of data that can be returned. */
811 		if (d.d_reclen > uio->uio_resid) {
812 			error = -1;
813 			break;
814 		}
815 
816 		/* Copy the new dirent structure into the output buffer and
817 		 * advance pointers. */
818 		error = uiomove(&d, d.d_reclen, uio);
819 
820 		(*cntp)++;
821 		de = TAILQ_NEXT(de, td_entries);
822 	} while (error == 0 && uio->uio_resid > 0 && de != NULL);
823 
824 	/* Update the offset and cache. */
825 	if (de == NULL) {
826 		uio->uio_offset = TMPFS_DIRCOOKIE_EOF;
827 		node->tn_spec.tn_dir.tn_readdir_lastn = 0;
828 		node->tn_spec.tn_dir.tn_readdir_lastp = NULL;
829 	} else {
830 		node->tn_spec.tn_dir.tn_readdir_lastn = uio->uio_offset =
831 		    TMPFS_DIRCOOKIE(de);
832 		node->tn_spec.tn_dir.tn_readdir_lastp = de;
833 	}
834 
835 	node->tn_status |= TMPFS_NODE_ACCESSED;
836 
837 	return error;
838 }
839 
840 /* --------------------------------------------------------------------- */
841 
842 /*
843  * Resizes the aobj associated to the regular file pointed to by vp to
844  * the size newsize.  'vp' must point to a vnode that represents a regular
845  * file.  'newsize' must be positive.
846  *
847  * Returns zero on success or an appropriate error code on failure.
848  */
849 int
850 tmpfs_reg_resize(struct vnode *vp, off_t newsize)
851 {
852 	int error;
853 	size_t newpages, oldpages;
854 	struct tmpfs_mount *tmp;
855 	struct tmpfs_node *node;
856 	off_t oldsize;
857 
858 	KASSERT(vp->v_type == VREG);
859 	KASSERT(newsize >= 0);
860 
861 	node = VP_TO_TMPFS_NODE(vp);
862 	tmp = VFS_TO_TMPFS(vp->v_mount);
863 
864 	/* Convert the old and new sizes to the number of pages needed to
865 	 * store them.  It may happen that we do not need to do anything
866 	 * because the last allocated page can accommodate the change on
867 	 * its own. */
868 	oldsize = node->tn_size;
869 	oldpages = round_page(oldsize) / PAGE_SIZE;
870 	KASSERT(oldpages == node->tn_spec.tn_reg.tn_aobj_pages);
871 	newpages = round_page(newsize) / PAGE_SIZE;
872 
873 	if (newpages > oldpages &&
874 	    newpages - oldpages > TMPFS_PAGES_AVAIL(tmp)) {
875 		error = ENOSPC;
876 		goto out;
877 	}
878 
879 	node->tn_spec.tn_reg.tn_aobj_pages = newpages;
880 
881 	tmp->tm_pages_used += (newpages - oldpages);
882 	node->tn_size = newsize;
883 	uvm_vnp_setsize(vp, newsize);
884 	if (newsize < oldsize) {
885 		int zerolen = MIN(round_page(newsize), node->tn_size) - newsize;
886 
887 		/*
888 		 * free "backing store"
889 		 */
890 
891 		if (newpages < oldpages) {
892 			struct uvm_object *uobj;
893 
894 			uobj = node->tn_spec.tn_reg.tn_aobj;
895 
896 			simple_lock(&uobj->vmobjlock);
897 			uao_dropswap_range(uobj, newpages, oldpages);
898 			simple_unlock(&uobj->vmobjlock);
899 		}
900 
901 		/*
902 		 * zero out the truncated part of the last page.
903 		 */
904 
905 		uvm_vnp_zerorange(vp, newsize, zerolen);
906 	}
907 
908 	error = 0;
909 
910 out:
911 	return error;
912 }
913 
914 /* --------------------------------------------------------------------- */
915 
916 /*
917  * Returns information about the number of available memory pages,
918  * including physical and virtual ones.
919  *
920  * If 'total' is TRUE, the value returned is the total amount of memory
921  * pages configured for the system (either in use or free).
922  * If it is FALSE, the value returned is the amount of free memory pages.
923  *
924  * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid
925  * excessive memory usage.
926  *
927  */
928 size_t
929 tmpfs_mem_info(boolean_t total)
930 {
931 	size_t size;
932 
933 	size = 0;
934 	size += uvmexp.swpgavail;
935 	if (!total) {
936 		size -= uvmexp.swpgonly;
937 	}
938 	size += uvmexp.free;
939 	size += uvmexp.filepages;
940 	if (size > uvmexp.wired) {
941 		size -= uvmexp.wired;
942 	} else {
943 		size = 0;
944 	}
945 
946 	return size;
947 }
948 
949 /* --------------------------------------------------------------------- */
950 
951 /*
952  * Change flags of the given vnode.
953  * Caller should execute tmpfs_update on vp after a successful execution.
954  * The vnode must be locked on entry and remain locked on exit.
955  */
956 int
957 tmpfs_chflags(struct vnode *vp, int flags, struct ucred *cred, struct proc *p)
958 {
959 	int error;
960 	struct tmpfs_node *node;
961 
962 	KASSERT(VOP_ISLOCKED(vp));
963 
964 	node = VP_TO_TMPFS_NODE(vp);
965 
966 	/* Disallow this operation if the file system is mounted read-only. */
967 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
968 		return EROFS;
969 
970 	/* XXX: The following comes from UFS code, and can be found in
971 	 * several other file systems.  Shouldn't this be centralized
972 	 * somewhere? */
973 	if (cred->cr_uid != node->tn_uid &&
974 	    (error = suser(cred, &p->p_acflag)))
975 		return error;
976 	if (cred->cr_uid == 0) {
977 		/* The super-user is only allowed to change flags if the file
978 		 * wasn't protected before and the securelevel is zero. */
979 		if ((node->tn_flags & (SF_IMMUTABLE | SF_APPEND)) &&
980 		    securelevel > 0)
981 			return EPERM;
982 		node->tn_flags = flags;
983 	} else {
984 		/* Regular users can change flags provided they only want to
985 		 * change user-specific ones, not those reserved for the
986 		 * super-user. */
987 		if ((node->tn_flags & (SF_IMMUTABLE | SF_APPEND)) ||
988 		    (flags & UF_SETTABLE) != flags)
989 			return EPERM;
990 		if ((node->tn_flags & SF_SETTABLE) != (flags & SF_SETTABLE))
991 			return EPERM;
992 		node->tn_flags &= SF_SETTABLE;
993 		node->tn_flags |= (flags & UF_SETTABLE);
994 	}
995 
996 	node->tn_status |= TMPFS_NODE_CHANGED;
997 	VN_KNOTE(vp, NOTE_ATTRIB);
998 
999 	KASSERT(VOP_ISLOCKED(vp));
1000 
1001 	return 0;
1002 }
1003 
1004 /* --------------------------------------------------------------------- */
1005 
1006 /*
1007  * Change access mode on the given vnode.
1008  * Caller should execute tmpfs_update on vp after a successful execution.
1009  * The vnode must be locked on entry and remain locked on exit.
1010  */
1011 int
1012 tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct proc *p)
1013 {
1014 	int error;
1015 	struct tmpfs_node *node;
1016 
1017 	KASSERT(VOP_ISLOCKED(vp));
1018 
1019 	node = VP_TO_TMPFS_NODE(vp);
1020 
1021 	/* Disallow this operation if the file system is mounted read-only. */
1022 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1023 		return EROFS;
1024 
1025 	/* Immutable or append-only files cannot be modified, either. */
1026 	if (node->tn_flags & (IMMUTABLE | APPEND))
1027 		return EPERM;
1028 
1029 	/* XXX: The following comes from UFS code, and can be found in
1030 	 * several other file systems.  Shouldn't this be centralized
1031 	 * somewhere? */
1032 	if (cred->cr_uid != node->tn_uid &&
1033 	    (error = suser(cred, &p->p_acflag)))
1034 		return error;
1035 	if (cred->cr_uid != 0) {
1036 		if (vp->v_type != VDIR && (mode & S_ISTXT))
1037 			return EFTYPE;
1038 
1039 		if (!groupmember(node->tn_gid, cred) && (mode & S_ISGID))
1040 			return EPERM;
1041 	}
1042 
1043 	node->tn_mode = (mode & ALLPERMS);
1044 
1045 	node->tn_status |= TMPFS_NODE_CHANGED;
1046 	VN_KNOTE(vp, NOTE_ATTRIB);
1047 
1048 	KASSERT(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 proc *p)
1065 {
1066 	int error;
1067 	struct tmpfs_node *node;
1068 
1069 	KASSERT(VOP_ISLOCKED(vp));
1070 
1071 	node = VP_TO_TMPFS_NODE(vp);
1072 
1073 	/* Assign default values if they are unknown. */
1074 	KASSERT(uid != VNOVAL || gid != VNOVAL);
1075 	if (uid == VNOVAL)
1076 		uid = node->tn_uid;
1077 	if (gid == VNOVAL)
1078 		gid = node->tn_gid;
1079 	KASSERT(uid != VNOVAL && gid != VNOVAL);
1080 
1081 	/* Disallow this operation if the file system is mounted read-only. */
1082 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1083 		return EROFS;
1084 
1085 	/* Immutable or append-only files cannot be modified, either. */
1086 	if (node->tn_flags & (IMMUTABLE | APPEND))
1087 		return EPERM;
1088 
1089 	/* XXX: The following comes from UFS code, and can be found in
1090 	 * several other file systems.  Shouldn't this be centralized
1091 	 * somewhere? */
1092 	if ((cred->cr_uid != node->tn_uid || uid != node->tn_uid ||
1093 	    (gid != node->tn_gid && !(cred->cr_gid == node->tn_gid ||
1094 	     groupmember(gid, cred)))) &&
1095 	    ((error = suser(cred, &p->p_acflag)) != 0))
1096 		return error;
1097 
1098 	node->tn_uid = uid;
1099 	node->tn_gid = gid;
1100 
1101 	node->tn_status |= TMPFS_NODE_CHANGED;
1102 	VN_KNOTE(vp, NOTE_ATTRIB);
1103 
1104 	KASSERT(VOP_ISLOCKED(vp));
1105 
1106 	return 0;
1107 }
1108 
1109 /* --------------------------------------------------------------------- */
1110 
1111 /*
1112  * Change size of the given vnode.
1113  * Caller should execute tmpfs_update on vp after a successful execution.
1114  * The vnode must be locked on entry and remain locked on exit.
1115  */
1116 int
1117 tmpfs_chsize(struct vnode *vp, u_quad_t size, struct ucred *cred,
1118     struct proc *p)
1119 {
1120 	int error;
1121 	struct tmpfs_node *node;
1122 
1123 	KASSERT(VOP_ISLOCKED(vp));
1124 
1125 	node = VP_TO_TMPFS_NODE(vp);
1126 
1127 	/* Decide whether this is a valid operation based on the file type. */
1128 	error = 0;
1129 	switch (vp->v_type) {
1130 	case VDIR:
1131 		return EISDIR;
1132 
1133 	case VREG:
1134 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
1135 			return EROFS;
1136 		break;
1137 
1138 	case VBLK:
1139 		/* FALLTHROUGH */
1140 	case VCHR:
1141 		/* FALLTHROUGH */
1142 	case VFIFO:
1143 		/* Allow modifications of special files even if in the file
1144 		 * system is mounted read-only (we are not modifying the
1145 		 * files themselves, but the objects they represent). */
1146 		return 0;
1147 
1148 	default:
1149 		/* Anything else is unsupported. */
1150 		return EOPNOTSUPP;
1151 	}
1152 
1153 	/* Immutable or append-only files cannot be modified, either. */
1154 	if (node->tn_flags & (IMMUTABLE | APPEND))
1155 		return EPERM;
1156 
1157 	error = tmpfs_truncate(vp, size);
1158 	/* tmpfs_truncate will raise the NOTE_EXTEND and NOTE_ATTRIB kevents
1159 	 * for us, as will update tn_status; no need to do that here. */
1160 
1161 	KASSERT(VOP_ISLOCKED(vp));
1162 
1163 	return error;
1164 }
1165 
1166 /* --------------------------------------------------------------------- */
1167 
1168 /*
1169  * Change access and modification times of the given vnode.
1170  * Caller should execute tmpfs_update on vp after a successful execution.
1171  * The vnode must be locked on entry and remain locked on exit.
1172  */
1173 int
1174 tmpfs_chtimes(struct vnode *vp, struct timespec *atime, struct timespec *mtime,
1175     int vaflags, struct ucred *cred, struct lwp *l)
1176 {
1177 	int error;
1178 	struct tmpfs_node *node;
1179 
1180 	KASSERT(VOP_ISLOCKED(vp));
1181 
1182 	node = VP_TO_TMPFS_NODE(vp);
1183 
1184 	/* Disallow this operation if the file system is mounted read-only. */
1185 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
1186 		return EROFS;
1187 
1188 	/* Immutable or append-only files cannot be modified, either. */
1189 	if (node->tn_flags & (IMMUTABLE | APPEND))
1190 		return EPERM;
1191 
1192 	/* XXX: The following comes from UFS code, and can be found in
1193 	 * several other file systems.  Shouldn't this be centralized
1194 	 * somewhere? */
1195 	if (cred->cr_uid != node->tn_uid &&
1196 	    (error = suser(cred, &l->l_proc->p_acflag)) &&
1197 	    ((vaflags & VA_UTIMES_NULL) == 0 ||
1198 	    (error = VOP_ACCESS(vp, VWRITE, cred, l))))
1199 		return error;
1200 
1201 	if (atime->tv_sec != VNOVAL && atime->tv_nsec != VNOVAL)
1202 		node->tn_status |= TMPFS_NODE_ACCESSED;
1203 
1204 	if (mtime->tv_sec != VNOVAL && mtime->tv_nsec != VNOVAL)
1205 		node->tn_status |= TMPFS_NODE_MODIFIED;
1206 
1207 	tmpfs_update(vp, atime, mtime, 0);
1208 
1209 	KASSERT(VOP_ISLOCKED(vp));
1210 
1211 	return 0;
1212 }
1213 
1214 /* --------------------------------------------------------------------- */
1215 
1216 /* Sync timestamps */
1217 void
1218 tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
1219     const struct timespec *mod)
1220 {
1221 	struct tmpfs_node *node;
1222 	const struct timespec *ts = NULL;
1223 	struct timespec tsb;
1224 
1225 	node = VP_TO_TMPFS_NODE(vp);
1226 
1227 	if ((node->tn_status & (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
1228 	    TMPFS_NODE_CHANGED)) == 0)
1229 		return;
1230 
1231 	if (node->tn_status & TMPFS_NODE_ACCESSED) {
1232 		if (acc == NULL)
1233 			acc = ts == NULL ? (ts = nanotime(&tsb)) : ts;
1234 		node->tn_atime = *acc;
1235 	}
1236 	if (node->tn_status & TMPFS_NODE_MODIFIED) {
1237 		if (mod == NULL)
1238 			mod = ts == NULL ? (ts = nanotime(&tsb)) : ts;
1239 		node->tn_mtime = *mod;
1240 	}
1241 	if (node->tn_status & TMPFS_NODE_CHANGED) {
1242 		if (ts == NULL)
1243 			ts = nanotime(&tsb);
1244 		node->tn_ctime = *ts;
1245 	}
1246 	node->tn_status &=
1247 	    ~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED);
1248 }
1249 
1250 /* --------------------------------------------------------------------- */
1251 
1252 void
1253 tmpfs_update(struct vnode *vp, const struct timespec *acc,
1254     const struct timespec *mod, int flags)
1255 {
1256 
1257 	struct tmpfs_node *node;
1258 
1259 	KASSERT(VOP_ISLOCKED(vp));
1260 
1261 	node = VP_TO_TMPFS_NODE(vp);
1262 
1263 	if (flags & UPDATE_CLOSE)
1264 		; /* XXX Need to do anything special? */
1265 
1266 	tmpfs_itimes(vp, acc, mod);
1267 
1268 	KASSERT(VOP_ISLOCKED(vp));
1269 }
1270 
1271 /* --------------------------------------------------------------------- */
1272 
1273 int
1274 tmpfs_truncate(struct vnode *vp, off_t length)
1275 {
1276 	boolean_t extended;
1277 	int error;
1278 	struct tmpfs_node *node;
1279 
1280 	node = VP_TO_TMPFS_NODE(vp);
1281 	extended = length > node->tn_size;
1282 
1283 	if (length < 0) {
1284 		error = EINVAL;
1285 		goto out;
1286 	}
1287 
1288 	if (node->tn_size == length) {
1289 		error = 0;
1290 		goto out;
1291 	}
1292 
1293 	error = tmpfs_reg_resize(vp, length);
1294 	if (error == 0) {
1295 		VN_KNOTE(vp, NOTE_ATTRIB | (extended ? NOTE_EXTEND : 0));
1296 		node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
1297 	}
1298 
1299 out:
1300 	tmpfs_update(vp, NULL, NULL, 0);
1301 
1302 	return error;
1303 }
1304