vboxfs_vnode.c revision 99eccc8f34de2d4b6af556ba2f5f0c756af237c7
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * VirtualBox File System for Solaris Guests, vnode implementation.
35473cad6d5d5b57348c66f0cfdd7d51d6071ee7vboxsync * Portions contributed by: Ronald.
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * Copyright (C) 2009-2010 Oracle Corporation
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * available from http://www.virtualbox.org. This file is free software;
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * you can redistribute it and/or modify it under the terms of the GNU
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * General Public License (GPL) as published by the Free Software
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * The contents of this file may alternatively be used under the terms
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * of the Common Development and Distribution License Version 1.0
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * VirtualBox OSE distribution, in which case the provisions of the
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * CDDL are applicable instead of those of the GPL.
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * You may elect to license modified versions of this file under the
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * terms and conditions of either the GPL or the CDDL or both.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Shared Folder File System is used from Solaris when run as a guest operating
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * system on VirtualBox, though is meant to be usable with any hypervisor that
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * can provide similar functionality. The sffs code handles all the Solaris
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * specific semantics and relies on a provider module to actually access
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * directories, files, etc. The provider interfaces are described in
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * "vboxfs_prov.h" and the module implementing them is shipped as part of the
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * VirtualBox Guest Additions for Solaris.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * The shared folder file system is similar to a networked file system,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * but with some caveats. The sffs code caches minimal information and proxies
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * out to the provider whenever possible. Here are some things that are
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * handled in this code and not by the proxy:
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * - a way to open ".." from any already open directory
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * - st_ino numbers
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * - detecting directory changes that happened on the host.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * The implementation builds a cache of information for every file/directory
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * ever accessed in all mounted sffs filesystems using sf_node structures.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * This information for both open or closed files can become invalid if
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * asynchronous changes are made on the host. Solaris should not panic() in
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * this event, but some file system operations may return unexpected errors.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Information for such directories or files while they have active vnodes
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * is removed from the regular cache and stored in a "stale" bucket until
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * the vnode becomes completely inactive.
691076bd437d5cd23673a24c5ba7d4cd77127354vboxsync * We suppport only read-only mmap (VBOXVFS_WITH_MMAP) i.e. MAP_SHARED,
691076bd437d5cd23673a24c5ba7d4cd77127354vboxsync * MAP_PRIVATE in PROT_READ, this data caching would not be coherent with
691076bd437d5cd23673a24c5ba7d4cd77127354vboxsync * normal simultaneous read()/write() operations, nor will it be coherent
691076bd437d5cd23673a24c5ba7d4cd77127354vboxsync * with data access on the host. Writable mmap(MAP_SHARED) access is not
691076bd437d5cd23673a24c5ba7d4cd77127354vboxsync * implemented, as guaranteeing any kind of coherency with concurrent
691076bd437d5cd23673a24c5ba7d4cd77127354vboxsync * activity on the host would be near impossible with the existing
691076bd437d5cd23673a24c5ba7d4cd77127354vboxsync * interfaces.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * A note about locking. sffs is not a high performance file system.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * No fine grained locking is done. The one sffs_lock protects just about
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * everything.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * For now we'll use an I/O buffer that doesn't page fault for VirtualBox
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * to transfer data into.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * sfnode_compare() is needed for AVL tree functionality.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * The nodes are sorted by mounted filesystem, then path. If the
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * nodes are stale, the node pointer itself is used to force uniqueness.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsfnode_compare(const void *a, const void *b)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync diff = (uintptr_t)y->sf_sffs - (uintptr_t)x->sf_sffs;
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (-1);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (1);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Construct a new pathname given an sfnode plus an optional tail component.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * This handles ".." and "."
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncstatic char *
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (strcmp(tail, ".") == 0 || strcmp(tail, "..") == 0)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync p = kmem_alloc(strlen(node->sf_path) + 1 + strlen(tail) + 1, KM_SLEEP);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (p);
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * Clears the (cached) directory listing for the node.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Open the provider file associated with a vnode. Holding the file open is
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * the only way we have of trying to have a vnode continue to refer to the
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * same host file in the host in light of the possibility of host side renames.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfprov_open(node->sf_sffs->sf_handle, node->sf_path, &fp);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * get a new vnode reference for an sfnode
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync LogFlowFunc((" %s gets vnode 0x%p\n", node->sf_path, vp));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Allocate and initialize a new sfnode and assign it a vnode
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * build the sfnode
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync node->sf_is_stale = 0; /* never stale at creation */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync node->sf_vnode = NULL; /* do this before any sfnode_get_vnode() */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * add the new node to our cache
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync panic("sffs_create_sfnode(%s): duplicate sfnode_t", path);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * destroy an sfnode
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync LogFlowFunc(("sffs_destroy(%s)%s\n", node->sf_path, node->sf_is_stale ? " stale": ""));
35473cad6d5d5b57348c66f0cfdd7d51d6071ee7vboxsync panic("sfnode_destroy(%s) has %d children", node->sf_path, node->sf_children);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync panic("sfnode_destroy(%s) has active vnode", node->sf_path);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync panic("sfnode_destroy(%s) not found", node->sf_path);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync kmem_free(node->sf_path, strlen(node->sf_path) + 1);
16e6d031ca3d1ed4d88ae56fb94d9ad6e4d89c6bvboxsync panic("sfnode_destroy parent (%s) has no child", parent->sf_path);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Some sort of host operation on an sfnode has failed or it has been
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * deleted. Mark this node and any children as stale, deleting knowledge
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * about any which do not have active vnodes or children
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * This also handle deleting an inactive node that was already stale.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * First deal with any children of a directory node.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * If a directory becomes stale, anything below it becomes stale too.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * quit when no longer seeing children of node
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Either mark the child as stale or destroy it
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync LogFlowFunc(("sffs_make_stale(%s) sub\n", n->sf_path));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Now deal with the given node.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (node->sf_vnode == NULL && node->sf_children == 0) {
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync LogFlowFunc(("sffs_make_stale(%s)\n", node->sf_path));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (avl_find(&stale_sfnodes, node, &where) != NULL)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync panic("sffs_make_stale(%s) duplicates", node->sf_path);
6479169ec893c18a646cec595e4e214492d180f0vboxsync return (sfnode_cur_time_usec() - node->sf_stat_time) <
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync error = sfprov_get_attr(node->sf_sffs->sf_handle, node->sf_path,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Rename a file or a directory
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsfnode_rename(sfnode_t *node, sfnode_t *newparent, char *path)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Have to remove anything existing that had the new name.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Do the renaming, deal with any children of this node first.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * quit when no longer seeing children of node
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync strncmp(node->sf_path, n->sf_path, old_len) != 0 ||
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Rename the child:
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * - build the new path name
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * - unlink the AVL node
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * - assign the new name
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * - re-insert the AVL name
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync tail = n->sf_path + old_len; /* includes initial "/" */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync LogFlowFunc(("sfnode_rname(%s to %s) sub\n", n->sf_path, new_path));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Deal with the given node.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync panic("sfnode_rename(%s) not in sfnodes", node->sf_path);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync LogFlowFunc(("sfnode_rname(%s to %s)\n", node->sf_path, path));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync kmem_free(node->sf_path, strlen(node->sf_path) + 1);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync panic("sfnode_rename(%s) duplicates", node->sf_path);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * change the parent
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync panic("sfnode_rename(%s) no parent", node->sf_path);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync panic("sfnode_rename(%s) parent has no child", node->sf_path);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Look for a cached node, if not found either handle ".." or try looking
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * via the provider. Create an entry in sfnodes if found but not cached yet.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * If the create flag is set, a file or directory is created. If the file
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * already existed, an error is returned.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Nodes returned from this routine always have a vnode with its ref count
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * bumped by 1.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * handle referencing myself
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (strcmp(name, "") == 0 || strcmp(name, ".") == 0)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * deal with parent
2084a447d1acb619df7c393fac41b79d517e4b3dvboxsync * Look for an existing node.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * No entry for this path currently.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Check if the file exists with the provider and get the type from
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfprov_create(dir->sf_sffs->sf_handle, fullpath, &fp);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfprov_mkdir(dir->sf_sffs->sf_handle, fullpath, &fp);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync else if (S_ISDIR(m))
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync else if (S_ISREG(m))
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync else if (S_ISLNK(m))
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * If no errors, make a new node and return it.
6479169ec893c18a646cec595e4e214492d180f0vboxsync node = sfnode_make(dir->sf_sffs, fullpath, type, fp, dir, stat,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * uid and gid in sffs determine owner and group for all files.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsfnode_access(sfnode_t *node, mode_t mode, cred_t *cr)
6479169ec893c18a646cec595e4e214492d180f0vboxsync * get the mode from the cache or provider
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * mask off the permissions based on uid/gid
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (mode == 0) {
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = secpolicy_vnode_access(cr, vp, sffs->sf_uid, mode);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Everything below this point are the vnode operations used by Solaris VFS
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Get the directory entry names from the host. This gets all
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * entries. These are stored in a linked list of sffs_dirents_t
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * buffers, each of which contains a list of dirent64_t's.
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync error = sfprov_readdir(dir->sf_sffs->sf_handle, dir->sf_path,
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync * Validate and skip to the desired offset.
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync if (cur_buf == NULL && offset != uiop->uio_loffset) {
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync if (cur_buf != NULL && offset != uiop->uio_loffset) {
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync step = sizeof(sffs_stat_t) + dirent->sf_entry.d_reclen;
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync dirent = (struct sffs_dirent *) (((char *) dirent) + step);
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * Lookup each of the names, so that we have ino's, and copy to
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * result buffer.
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync } else if (strcmp(dirent->sf_entry.d_name, "..") == 0) {
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync node = sfnode_lookup(dir, dirent->sf_entry.d_name, VNON,
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync error = uiomove(&dirent->sf_entry, dirent->sf_entry.d_reclen, UIO_READ, uiop);
72cc0d1a8b7c8406808a92eb0b9eb58bf6f8c3aavboxsync offset += sizeof(sffs_stat_t) + dirent->sf_entry.d_reclen;
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * HERE JOE.. this may need more logic, need to look at other file systems
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * HERE JOE.. this may need more logic, need to look at other file systems
69132a0ec44f2ef9702c43e6c051cffb051d83a2vboxsync vap->va_mode = sffs->sf_dmode != ~0 ? (sffs->sf_dmode & 0777) : vap->va_mode;
a51cca35cccb7500e3f5c28c0615d3c82973003avboxsync vap->va_mode = sffs->sf_fmode != ~0 ? (sffs->sf_fmode & 0777) : vap->va_mode;
144c0e9632fc5508a2bdb7269b5857f1b9a072f8vboxsync vap->va_mode = sffs->sf_fmode != ~0 ? (sffs->sf_fmode & 0777) : vap->va_mode;
2703e64e42f9ce8800260f5112364cb6368711ffvboxsync vap->va_nblocks = (node->sf_stat.sf_alloc + 511) / 512;
f65dabff4474710524235022d328b737f174fc1dvboxsync error = sfprov_set_attr(node->sf_sffs->sf_handle, node->sf_path,
f65dabff4474710524235022d328b737f174fc1dvboxsync vap->va_mask, mode, vap->va_atime, vap->va_mtime, vap->va_ctime);
f65dabff4474710524235022d328b737f174fc1dvboxsync /* we only support changing the length of the file */
f65dabff4474710524235022d328b737f174fc1dvboxsync error = sfprov_set_size(node->sf_sffs->sf_handle, node->sf_path,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
14a3a4c9d0c43ff4b0e32ee6e45e5c842527dc6dvboxsync (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
35473cad6d5d5b57348c66f0cfdd7d51d6071ee7vboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfprov_read(node->sf_file, sffs_buffer, offset, &done);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync } while (error == 0 && uio->uio_resid > 0 && done > 0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * a partial read is never an error
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * We have to hold this lock for a long time to keep
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * multiple FAPPEND writes from intermixing
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
35473cad6d5d5b57348c66f0cfdd7d51d6071ee7vboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = uiomove(sffs_buffer, bytes, UIO_WRITE, uiop);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync } while (error == 0 && uiop->uio_resid > 0 && done > 0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * A short write is never really an error.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsffs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Lookup an entry in a directory and create a new vnode if found.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/* ARGSUSED3 */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync char *name, /* the name of the file or directory */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * dvp must be a directory
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * An empty component name or just "." means the directory itself.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Don't do any further lookup or checking.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (strcmp(name, "") == 0 || strcmp(name, ".") == 0) {
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Check permission to look at this directory. We always allow "..".
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Lookup the node.
1519f0483877fddc0a03ab7e3382124f889bb36avboxsync node = sfnode_lookup(VN2SFN(dvp), name, VNON, NULL, 0, NULL);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * this is used for regular files, not mkdir
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * is this a pre-existing file?
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync else if (error != 0)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Operation on a pre-existing file.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (vp->v_type == VDIR && (mode & VWRITE) == VWRITE) {
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * handle truncating an existing file
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync if (vp->v_type == VREG && (vap->va_mask & AT_SIZE) &&
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Create a new node. First check for a race creating it.
1519f0483877fddc0a03ab7e3382124f889bb36avboxsync node = sfnode_lookup(VN2SFN(dvp), name, VNON, NULL, 0, NULL);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Doesn't exist yet and we have the lock, so create it.
1519f0483877fddc0a03ab7e3382124f889bb36avboxsync node = sfnode_lookup(VN2SFN(dvp), name, VREG, NULL, 0, &lookuperr);
6e89506dd9d878449c4850f0ef4ade3424e2f1c1vboxsync error = sfprov_set_attr(node->sf_sffs->sf_handle, node->sf_path,
6e89506dd9d878449c4850f0ef4ade3424e2f1c1vboxsync cmn_err(CE_WARN, "sffs_create: set_mode(%s, %o) failed"
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * These should never happen
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Do an unlocked look up first
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sffs_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Must be able to write in current directory
1519f0483877fddc0a03ab7e3382124f889bb36avboxsync node = sfnode_lookup(VN2SFN(dvp), nm, VDIR, NULL, 0, &lookuperr);
6e89506dd9d878449c4850f0ef4ade3424e2f1c1vboxsync error = sfprov_set_attr(node->sf_sffs->sf_handle, node->sf_path,
6e89506dd9d878449c4850f0ef4ade3424e2f1c1vboxsync cmn_err(CE_WARN, "sffs_mkdir: set_mode(%s, %o) failed"
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Return error when removing . and ..
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sffs_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, NULL);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfnode_access(VN2SFN(dvp), VEXEC | VWRITE, cred);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * If anything else is using this vnode, then fail the remove.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Why? Windows hosts can't remove something that is open,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * so we have to sfprov_close() it first.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * There is no errno for this - since it's not a problem on UNIX,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * but EINVAL is the closest.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Remove the directory on the host and mark the node as stale.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfprov_rmdir(node->sf_sffs->sf_handle, node->sf_path);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync /* Use seg_kpm driver if possible (64-bit) */
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync ASSERT(segaccess == S_READ || segaccess == S_WRITE);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync return (ppmapin(ppage, PROT_READ | ((segaccess == S_WRITE) ? PROT_WRITE : 0), (caddr_t)-1));
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * Called when there's no page in the cache. This will create new page(s) and read
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * the file data into it.
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync ppages = page_create_va(dvp, io_off, io_len, PG_WAIT | PG_EXCL, segp, addr);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync ppages = pvn_read_kluster(dvp, off, segp, addr, &io_off, &io_len, off, pagelistsize, 0);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync /* If page already exists return success */
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync return (0);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * Map & read page-by-page.
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync error = sfprov_read(node->sf_file, virtaddr, io_off, &bytes);
7aa325a10935ed82649b38021832545e9af807b7vboxsync * If we reuse pages without zero'ing them, one process can mmap() and read-past the length
7aa325a10935ed82649b38021832545e9af807b7vboxsync * to read previously mmap'd contents (from possibly other processes).
ebbe78c52653f516133cf68ac0199b35c1d96ddfvboxsync cmn_err(CE_WARN, "sffs_readpages: sfprov_read() failed. error=%d bytes=%u\n", error, bytes);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync /* Get rid of all kluster pages read & bail. */
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * Fill in the pagelist from kluster at the requested offset.
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync pvn_plist_init(ppages, pagelist, pagelistsize, off, io_len, segaccess);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync ASSERT(pagelist == NULL || (*pagelist)->p_offset == off);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync return (0);
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync/*ARGSUSED*/
dbd602ecc07512999944bedae1e2d09c88f2298bvboxsync /* Don't bother about faultahead for now. */
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync return (0);
81c0cfc4db8e08dc6b8b365a25a71d3dae66a879vboxsync * The buffer passed to sffs_write may be mmap'd so we may get a
81c0cfc4db8e08dc6b8b365a25a71d3dae66a879vboxsync * pagefault there, in which case we'll end up here with this thread
81c0cfc4db8e08dc6b8b365a25a71d3dae66a879vboxsync * already owning the mutex. Mutexes aren't recursive.
dbd602ecc07512999944bedae1e2d09c88f2298bvboxsync /* Don't map pages past end of the file. */
dbd602ecc07512999944bedae1e2d09c88f2298bvboxsync if (off + len > node->sf_stat.sf_size + PAGEOFFSET)
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync while (len > 0)
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * Look for pages in the requested offset range, or create them if we can't find any.
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync if ((*pagelist = page_lookup(dvp, off, SE_SHARED)) != NULL)
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync else if ((error = sffs_readpages(dvp, off, pagelist, pagelistsize, segp, addr, segaccess)) != 0)
dbd602ecc07512999944bedae1e2d09c88f2298bvboxsync * Fill the page list array with any pages left in the cache.
dbd602ecc07512999944bedae1e2d09c88f2298bvboxsync && (*pagelist++ = page_lookup_nowait(dvp, off, SE_SHARED)))
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync/*ARGSUSED*/
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * We don't support PROT_WRITE mmaps. For normal writes we do not map and IO via
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * vop_putpage() either, therefore, afaik this shouldn't ever be called.
a2907076474e923411cc5046492a88787ba377fevboxsync/*ARGSUSED*/
ebbe78c52653f516133cf68ac0199b35c1d96ddfvboxsync * This would not get invoked i.e. via pvn_vplist_dirty() since we don't support
ebbe78c52653f516133cf68ac0199b35c1d96ddfvboxsync * PROT_WRITE mmaps and therefore will not have dirty pages.
a2907076474e923411cc5046492a88787ba377fevboxsync pvn_write_done(ppage, B_INVAL | B_ERROR | B_FORCE);
a2907076474e923411cc5046492a88787ba377fevboxsync return (0);
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync/*ARGSUSED*/
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * Invocation: mmap()->smmap_common()->VOP_MAP()->sffs_map(). Once the
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * segment driver creates the new segment via segvn_create(), it'll
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync * invoke down the line VOP_ADDMAP()->sffs_addmap()
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync if (vn_has_mandatory_locks(dvp, node->sf_stat.sf_mode))
0360c14b2b3750bd2c90d935775ccdb05da307c9vboxsync as_unmap(asp, *addrp, len); /* User specified address, remove any previous mappings */
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync error = choose_addr(asp, addrp, len, off, ADDR_VACALIGN, flags);
0360c14b2b3750bd2c90d935775ccdb05da307c9vboxsync error = as_map(asp, *addrp, len, segvn_create, &vnodeargs);
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync/*ARGSUSED*/
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync return (0);
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync/*ARGSUSED*/
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync return (0);
a2907076474e923411cc5046492a88787ba377fevboxsync#endif /* VBOXVFS_WITH_MMAP */
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync/*ARGSUSED*/
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync error = sfprov_readlink(node->sf_sffs->sf_handle, node->sf_path, target,
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync error = uiomove(target, strlen(target), UIO_READ, uiop);
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync/*ARGSUSED*/
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync * These should never happen
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync * Basic checks.
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync if (sfnode_lookup(VN2SFN(dvp), linkname, VNON, NULL, 0, NULL) != NULL) {
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync * Create symlink. Note that we ignore vap->va_mode because generally
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync * we can't change the attributes of the symlink itself.
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync error = sfprov_symlink(dir->sf_sffs->sf_handle, fullpath, target,
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync node = sfnode_lookup(dir, linkname, VLNK, &stat, sfnode_cur_time_usec(),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * These should never happen
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfnode_access(VN2SFN(dvp), VEXEC | VWRITE, cred);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * If anything else is using this vnode, then fail the remove.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Why? Windows hosts can't sfprov_remove() a file that is open,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * so we have to sfprov_close() it first.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * There is no errno for this - since it's not a problem on UNIX,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * but ETXTBSY is the closest.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Remove the file on the host and mark the node as stale.
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync error = sfprov_remove(node->sf_sffs->sf_handle, node->sf_path,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * make sure we have permission to do the rename
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfnode_access(VN2SFN(old_dir), VEXEC | VWRITE, cred);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfnode_access(VN2SFN(new_dir), VEXEC | VWRITE, cred);
1519f0483877fddc0a03ab7e3382124f889bb36avboxsync node = sfnode_lookup(VN2SFN(old_dir), old_nm, VNON, NULL, 0, NULL);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Rename the file on the host and in our caches.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync newpath = sfnode_construct_path(VN2SFN(new_dir), new_nm);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = sfprov_rename(node->sf_sffs->sf_handle, node->sf_path, newpath,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsffs_fsync(vnode_t *vp, int flag, cred_t *cr, caller_context_t *ct)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Ask the host to sync any data it may have cached for open files.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * This may be the last reference, possibly time to close the file and
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * destroy the vnode. If the sfnode is stale, we'll destroy that too.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsffs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * nothing to do if this isn't the last use
a2907076474e923411cc5046492a88787ba377fevboxsync /* We're fine with releasing the vnode lock here as we should be covered by the sffs_lock */
ebbe78c52653f516133cf68ac0199b35c1d96ddfvboxsync /* We won't have any dirty pages, this will just invalidate (destroy) the pages and move it to the cachelist. */
a2907076474e923411cc5046492a88787ba377fevboxsync pvn_vplist_dirty(vp, 0 /* offset */, sffs_discardpage, B_INVAL, cr);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * destroy the vnode
35473cad6d5d5b57348c66f0cfdd7d51d6071ee7vboxsync LogFlowFunc((" %s vnode cleared\n", node->sf_path));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Close the sf_file for the node.
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * Free the directory entries for the node. This should normally
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * have been taken care of in sffs_close(), but better safe than
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * If the node is stale, we can also destroy it.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * All the work for this is really done in lookup.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsffs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * All the work for this is really done in inactive.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*ARGSUSED*/
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * Free the directory entries for the node. We do this on this call
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * here because the directory node may not become inactive for a long
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * time after the readdir is over. Case in point, if somebody cd's into
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * the directory then it won't become inactive until they cd away again.
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * In such a case we would end up with the directory listing not getting
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * updated (i.e. the result of 'ls' always being the same) until they
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * change the working directory.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/* ARGSUSED */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsffs_seek(vnode_t *v, offset_t o, offset_t *no, caller_context_t *ct)
16e6d031ca3d1ed4d88ae56fb94d9ad6e4d89c6bvboxsync return (0);
16e6d031ca3d1ed4d88ae56fb94d9ad6e4d89c6bvboxsync if (*no >= offset && *no <= offset + cur_buf->sf_len)
16e6d031ca3d1ed4d88ae56fb94d9ad6e4d89c6bvboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * By returning an error for this, we prevent anything in sffs from
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * being re-exported by NFS
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/* ARGSUSED */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncsffs_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * vnode operations for regular files
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync VOPNAME_INACTIVE, { .vop_inactive = sffs_inactive },
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync VOPNAME_PATHCONF, { .vop_pathconf = sffs_pathconf },
99eccc8f34de2d4b6af556ba2f5f0c756af237c7vboxsync VOPNAME_READLINK, { .vop_readlink = sffs_readlink },
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Also, init and fini functions...
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync err = vn_make_ops("sffs", sffs_ops_template, &sffs_ops);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync avl_create(&sfnodes, sfnode_compare, sizeof (sfnode_t),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync avl_create(&stale_sfnodes, sfnode_compare, sizeof (sfnode_t),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Utility at unmount to get all nodes in that mounted filesystem removed.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Check that no vnodes are active.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (-1);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (-1);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (-1);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * All clear to destroy all node information. Since there are no
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * vnodes, the make stale will cause deletion.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return (0);
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync/* Debug helper functions */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync node->sf_type == VREG ? "VREG" : "other", node->sf_type));