vboxfs_vnode.c revision dbd602ecc07512999944bedae1e2d09c88f2298b
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.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * No file data is cached in the guest. This means we don't support mmap() yet.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * A future version could relatively easily add support for read-only
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * mmap(MAP_SHARED) and any mmap(MAP_PRIVATE). But a la ZFS, this data caching
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * would not be coherent with normal simultaneous read()/write() operations,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * nor will it be coherent with data access on the host. Writable
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * mmap(MAP_SHARED) access is possible, but guaranteeing any kind of coherency
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * with concurrent activity on the host would be near impossible with the
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * existing 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.
6479169ec893c18a646cec595e4e214492d180f0vboxsync kmem_free(node->sf_dir_stats, sizeof(*node->sf_dir_stats));
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));
dbd602ecc07512999944bedae1e2d09c88f2298bvboxsync vp->v_flag = VNOSWAP | VNOMAP; /* @todo -XXX- remove VNOMAP when ro-mmap is working*/
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);
35473cad6d5d5b57348c66f0cfdd7d51d6071ee7vboxsync panic("sfnode_destroy(%s) parent has no child", node->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) <
6479169ec893c18a646cec595e4e214492d180f0vboxsyncsfnode_get_stat(sfp_mount_t *mnt, char *path, sffs_stat_t *stat)
6479169ec893c18a646cec595e4e214492d180f0vboxsync return sfprov_get_attr(mnt, path, &stat->sf_mode, &stat->sf_size,
6479169ec893c18a646cec595e4e214492d180f0vboxsync &stat->sf_atime, &stat->sf_mtime, &stat->sf_ctime);
6479169ec893c18a646cec595e4e214492d180f0vboxsync error = sfnode_get_stat(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))
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,
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * Lookup each of the names, so that we have ino's, and copy to
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * result buffer.
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync if (offset + cur_buf->sf_len <= uiop->uio_loffset) {
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync error = uiomove(dirent, dirent->d_reclen, UIO_READ, uiop);
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
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.
dbd602ecc07512999944bedae1e2d09c88f2298bvboxsync cmn_err(CE_NOTE, "sffs_readpages io_off=%lld io_len=%lld\n", (u_longlong_t)io_off, (u_longlong_t)io_len);
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.
dbd602ecc07512999944bedae1e2d09c88f2298bvboxsync cmn_err(CE_NOTE, "sffs_readpages page-by-page reading io_off=%lld\n", (u_longlong_t)io_off);
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync error = sfprov_read(node->sf_file, virtaddr, io_off, &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);
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 cmn_err(CE_NOTE, "sffs_getpage addr=%p len=%lld off=%lld\n", addr, (u_longlong_t)len, (u_longlong_t)off);
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.
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);
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.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync 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
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * There should never be cached data, since we don't support mmap().
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 return (0);
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)
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 },
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));