/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Julio M. Merino Vidal, developed as part of Google's Summer of Code
* 2005 program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Efficient memory file system.
*
* tmpfs is a file system that uses NetBSD's virtual memory sub-system
* (the well-known UVM) to store file data and metadata in an efficient
* way. This means that it does not follow the structure of an on-disk
* file system because it simply does not need to. Instead, it uses
* memory-specific data structures and algorithms to automatically
* allocate and release resources.
*/
/* Allocate the tmpfs mount structure and fill it. */
tmp = kmem_zalloc(sizeof(tmpfs_mount_t), KM_SLEEP);
tmp->tm_nodes_max = nodes;
tmp->tm_nodes_cnt = 0;
LIST_INIT(&tmp->tm_nodes);
/*
* Parent of the root inode is itself. Also, root inode has no
* directory entry (i.e. is never attached), thus hold an extra
* reference (link) for it.
*/
root->tn_links++;
root->tn_spec.tn_dir.tn_parent = root;
tmp->tm_root = root;
vrele(vp);
/* Finalize all pending I/O. */
error = vflush(mp, NULL, flags);
if (error != 0)
return error;
/*
* First round, detach and destroy all directory entries.
* Also, clear the pointers to the vnodes - they are gone.
*/
LIST_FOREACH(node, &tmp->tm_nodes, tn_entries) {
tmpfs_dirent_t *de;
node->tn_vnode = NULL;
if (node->tn_type != VDIR) {
continue;
}
while ((de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir)) != NULL) {
cnode = de->td_node;
if (cnode && cnode != TMPFS_NODE_WHITEOUT) {
cnode->tn_vnode = NULL;
}
tmpfs_dir_detach(node, de);
tmpfs_free_dirent(tmp, de);
}
/* Extra virtual entry (itself for the root). */
node->tn_links--;
}
/* Release the reference on root (diagnostic). */
node = tmp->tm_root;
node->tn_links--;
/* Second round, destroy all inodes. */
while ((node = LIST_FIRST(&tmp->tm_nodes)) != NULL) {
tmpfs_free_node(tmp, node);
}
mutex_enter(&tmp->tm_lock);
/* XXX big oof .. use a better data structure */
LIST_FOREACH(node, &tmp->tm_nodes, tn_entries) {
if (node->tn_id == tfh.tf_id) {
/* Prevent this node from disappearing. */
atomic_inc_32(&node->tn_holdcount);
break;
}
}
mutex_exit(&tmp->tm_lock);
if (node == NULL)
return ESTALE;
error = vcache_get(mp, &node, sizeof(node), vpp);
/* If this node has been reclaimed free it now. */
if (atomic_dec_32_nv(&node->tn_holdcount) == TMPFS_NODE_RECLAIMED) {
KASSERT(error != 0);
tmpfs_free_node(tmp, node);
}
if (error)
return (error == ENOENT ? ESTALE : error);
error = vn_lock(*vpp, lktype);
if (error) {
vrele(*vpp);
*vpp = NULL;
return error;
}
if (TMPFS_NODE_GEN(node) != tfh.tf_gen) {
vput(*vpp);
*vpp = NULL;
return ESTALE;
}