[vbox-dev] [PATCH] performance improvements for Solaris guest shared folders

Life is hard, and then you die ronald at innovation.ch
Sat Nov 5 11:29:32 GMT 2011


On Tue, Jan 18, 2011 at 10:45:16AM +0100, Frank Mehnert wrote:
> 
> On Sunday 16 January 2011 11:50:06 Life is hard, and then you die wrote:
> > Attached are some patches to improve the performance of shared-folders
> > in Solaris guests. Together they speed up things between 2 to 4 times:
> > operations like untarring and deleting whole directory tree are
> > typically 2 to 2.5 times faster, and when running builds that include
> > things like building Solaris packages I see a speedup of 3 to almost 4.
> > The bulk of the speedup comes from the second (file open) patch.
> > 
> > These patches assume my previously sent patches have been applied.
> > 
> > Licensed under MIT/public-domain.
> 
> Thank you very much for this code contribution! We will revise it a bit
> later as our colleague which maintains this code is currently not
> available.

I don't want to appear pushy, but since I've seen that some work has
been done in recent weeks on the Solaris shared-folders code, I'm
wondering if you might have time to review the patches. I rebased them
onto svn rev 39192 (and updated to VB 4.1.6) and they appear to still
work fine on Solaris 10u8 (after disabling the mmap support - see
https://www.virtualbox.org/ticket/9856).

For your convenience I've attached the rebased patches (in the order
they should be applied), though all in one email instead of spread
over 4 separate emails like last Jan.


  Cheers,

  Ronald

-------------- next part --------------

Fix parameter to panic() call.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
index c932111..7975b10 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
@@ -312,7 +312,8 @@ top:
 	if (parent != NULL) {
 		sfnode_clear_dir_list(parent);
 		if (parent->sf_children == 0)
-			panic("sfnode_destroy(%s) parent has no child", node->sf_path);
+			panic("sfnode_destroy parent(%s) has no child",
+			    parent->sf_path);
 		--parent->sf_children;
 		if (parent->sf_children == 0 &&
 		    parent->sf_is_stale &&
-------------- next part --------------

Always show current stat-ttl in mount options, even when default value
is being used.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
index ca5b4d2..a72cb60 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
@@ -356,6 +356,9 @@ sffs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
 	    ddi_strtol(optval, NULL, 10, &val) == 0 &&
 	    (int)val == val)
 		stat_ttl = val;
+        else
+		vfs_setmntopt(vfsp, "stat_ttl", VBOXSOLQUOTE(DEF_STAT_TTL_MS),
+		    0);
 
 	/*
 	 * whether to honor fsync
-------------- next part --------------

Fix directory seeking bug. The d_off field in the returned dirent's was
wrong, so seek'ing to those would result in an invalid seek. This was
causing commands like 'du' to not work properly.

Also added better seek-bounds checking for potential seeks.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
index 85c27bf..9beae72 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
@@ -877,12 +877,12 @@ sfprov_readdir(
 	uint32_t numbytes;
 	uint32_t nents;
 	uint32_t size;
-	uint32_t cnt;
 	sffs_dirents_t *cur_buf;
 	sffs_stats_t *cur_stats;
 	struct dirent64 *dirent;
 	sffs_stat_t *stat;
 	unsigned short reclen;
+	off_t offset;
 
 	*dirents = NULL;
 	*stats = NULL;
@@ -936,7 +936,7 @@ sfprov_readdir(
 		goto done;
 	}
 
-	cnt = 0;
+	offset = 0;
 	for (;;) {
 		numbytes = infobuff_alloc;
 		error = vboxCallDirInfo(&vbox_client, &fp->map, fp->handle,
@@ -990,10 +990,11 @@ sfprov_readdir(
 			    (((char *) &cur_buf->sf_entries[0]) + cur_buf->sf_len);
 			strcpy(&dirent->d_name[0], info->name.String.utf8);
 			dirent->d_reclen = reclen;
-			dirent->d_off = cnt;
+
+			offset += reclen;
+			dirent->d_off = offset;
 
 			cur_buf->sf_len += reclen;
-			++cnt;
 
 			/* save the stats */
 			stat = &cur_stats->sf_stats[cur_stats->sf_num];
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
index fb28a75..254f8bc 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
@@ -2124,6 +2124,23 @@ sffs_seek(vnode_t *v, offset_t o, offset_t *no, caller_context_t *ct)
 {
 	if (*no < 0 || *no > MAXOFFSET_T)
 		return (EINVAL);
+
+	if (v->v_type == VDIR) {
+		sffs_dirents_t *cur_buf = VN2SFN(v)->sf_dir_list;
+		off_t offset = 0;
+
+		if (cur_buf == NULL)
+			return (0);
+
+		while (cur_buf != NULL) {
+			if (*no >= offset && *no <= offset + cur_buf->sf_len)
+				return (0);
+			offset += cur_buf->sf_len;
+			cur_buf = cur_buf->sf_next;
+		}
+		return (EINVAL);
+	}
+
 	return (0);
 }
 
-------------- next part --------------

Fix nasty bug when reading large directories. The dirent's and stats were
located in two separate, parallel buffers; but when calling readdir with
a non-zero offset we were skipping through only the dirent's, thereby ending
up associating the wrong stats with these dirents.

This fix merges the two buffers into one structure, thereby both eliminating
the possibility of this bug and also simplifying the code.

Also included is proper validation of the offset that is passed in to
readdir.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
index 9beae72..7e12d9b 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
@@ -863,8 +863,7 @@ int
 sfprov_readdir(
 	sfp_mount_t *mnt,
 	char *path,
-	sffs_dirents_t **dirents,
-	sffs_stats_t **stats)
+	sffs_dirents_t **dirents)
 {
 	int error;
 	char *cp;
@@ -878,21 +877,20 @@ sfprov_readdir(
 	uint32_t nents;
 	uint32_t size;
 	sffs_dirents_t *cur_buf;
-	sffs_stats_t *cur_stats;
-	struct dirent64 *dirent;
+	struct sffs_dirent *dirent;
 	sffs_stat_t *stat;
 	unsigned short reclen;
+	unsigned short entlen;
 	off_t offset;
 
 	*dirents = NULL;
-	*stats = NULL;
 
 	error = sfprov_open(mnt, path, &fp);
 	if (error != 0)
 		return (ENOENT);
 
 	/*
-	 * Allocate the first dirents and stats buffers.
+	 * Allocate the first dirents buffers.
 	 */
 	*dirents = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
 	if (*dirents == NULL) {
@@ -903,15 +901,6 @@ sfprov_readdir(
 	cur_buf->sf_next = NULL;
 	cur_buf->sf_len = 0;
 
-	*stats = kmem_alloc(sizeof(**stats), KM_SLEEP);
-	if (*stats == NULL) {
-		error = (ENOSPC);
-		goto done;
-	}
-	cur_stats = *stats;
-	cur_stats->sf_next = NULL;
-	cur_stats->sf_num = 0;
-
 	/*
 	 * Create mask that VBox expects. This needs to be the directory path,
 	 * plus a "*" wildcard to get all files.
@@ -963,7 +952,8 @@ sfprov_readdir(
 		for (info = infobuff; (char *) info < (char *) infobuff + numbytes; nents--) {
 			/* expand buffers if we need more space */
 			reclen = DIRENT64_RECLEN(strlen(info->name.String.utf8));
-			if (SFFS_DIRENTS_OFF + cur_buf->sf_len + reclen > SFFS_DIRENTS_SIZE) {
+			entlen = sizeof(sffs_stat_t) + reclen;
+			if (SFFS_DIRENTS_OFF + cur_buf->sf_len + entlen > SFFS_DIRENTS_SIZE) {
 				cur_buf->sf_next = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP);
 				if (cur_buf->sf_next == NULL) {
 					error = ENOSPC;
@@ -974,31 +964,17 @@ sfprov_readdir(
 				cur_buf->sf_len = 0;
 			}
 
-			if (cur_stats->sf_num >= SFFS_STATS_LEN) {
-				cur_stats->sf_next = kmem_alloc(sizeof(**stats), KM_SLEEP);
-				if (cur_stats->sf_next == NULL) {
-					error = (ENOSPC);
-					goto done;
-				}
-				cur_stats = cur_stats->sf_next;
-				cur_stats->sf_next = NULL;
-				cur_stats->sf_num = 0;
-			}
-
 			/* create the dirent with the name, offset, and len */
-			dirent = (dirent64_t *)
+			dirent = (struct sffs_dirent *)
 			    (((char *) &cur_buf->sf_entries[0]) + cur_buf->sf_len);
-			strcpy(&dirent->d_name[0], info->name.String.utf8);
-			dirent->d_reclen = reclen;
-
-			offset += reclen;
-			dirent->d_off = offset;
+			strcpy(&dirent->sf_entry.d_name[0], info->name.String.utf8);
+			dirent->sf_entry.d_reclen = reclen;
 
-			cur_buf->sf_len += reclen;
+			offset += entlen;
+			dirent->sf_entry.d_off = offset;
 
 			/* save the stats */
-			stat = &cur_stats->sf_stats[cur_stats->sf_num];
-			++cur_stats->sf_num;
+			stat = &dirent->sf_stat;
 
 			sfprov_mode_from_fmode(&stat->sf_mode, info->Info.Attr.fMode);
 			stat->sf_size = info->Info.cbObject;
@@ -1007,6 +983,8 @@ sfprov_readdir(
 			sfprov_ftime_from_timespec(&stat->sf_ctime, &info->Info.ChangeTime);
 
 			/* next info */
+			cur_buf->sf_len += entlen;
+
 			size = offsetof (SHFLDIRINFO, name.String) + info->name.u16Size;
 			info = (SHFLDIRINFO *) ((uintptr_t) info + size);
 		}
@@ -1025,11 +1003,6 @@ done:
 			kmem_free(*dirents, SFFS_DIRENTS_SIZE);
 			*dirents = cur_buf;
 		}
-		while (*stats) {
-			cur_stats = (*stats)->sf_next;
-			kmem_free(*stats, sizeof(**stats));
-			*stats = cur_stats;
-		}
 	}
 	if (infobuff != NULL)
 		kmem_free(infobuff, infobuff_alloc);
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
index 1fd1fa0..c04f1f9 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
@@ -123,19 +123,9 @@ extern int sfprov_rename(sfp_mount_t *, char *from, char *to, uint_t is_dir);
  * Read directory entries.
  */
 /*
- * a singly linked list of buffers, each containing an array of dirent's.
+ * a singly linked list of buffers, each containing an array of stat's+dirent's.
  * sf_len is length of the sf_entries array, in bytes.
  */
-typedef struct sffs_dirents {
-	struct sffs_dirents	*sf_next;
-	len_t			sf_len;
-	dirent64_t		sf_entries[1];
-} sffs_dirents_t;
-
-#define SFFS_DIRENTS_SIZE	8192
-#define SFFS_DIRENTS_OFF	(offsetof(sffs_dirents_t, sf_entries[0]))
-#define SFFS_STATS_LEN		100
-
 typedef struct sffs_stat {
 	mode_t		sf_mode;
 	off_t		sf_size;
@@ -144,14 +134,20 @@ typedef struct sffs_stat {
 	timestruc_t	sf_ctime;
 } sffs_stat_t;
 
-typedef struct sffs_stats {
-	struct sffs_stats	*sf_next;
-	len_t			sf_num;
-	sffs_stat_t		sf_stats[SFFS_STATS_LEN];
-} sffs_stats_t;
+typedef struct sffs_dirents {
+	struct sffs_dirents	*sf_next;
+	len_t			sf_len;
+	struct sffs_dirent {
+		sffs_stat_t	sf_stat;
+		dirent64_t	sf_entry;	/* this is variable length */
+	}			sf_entries[1];
+} sffs_dirents_t;
+
+#define SFFS_DIRENTS_SIZE	8192
+#define SFFS_DIRENTS_OFF	(offsetof(sffs_dirents_t, sf_entries[0]))
 
-extern int sfprov_readdir(sfp_mount_t *mnt, char *path, sffs_dirents_t **dirents,
-    sffs_stats_t **stats);
+extern int sfprov_readdir(sfp_mount_t *mnt, char *path,
+    sffs_dirents_t **dirents);
 
 #ifdef	__cplusplus
 }
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
index 254f8bc..d54f3c3 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
@@ -170,12 +170,6 @@ sfnode_clear_dir_list(sfnode_t *node)
 		kmem_free(node->sf_dir_list, SFFS_DIRENTS_SIZE);
 		node->sf_dir_list = next;
 	}
-
-	while (node->sf_dir_stats != NULL) {
-		sffs_stats_t *next = node->sf_dir_stats->sf_next;
-		kmem_free(node->sf_dir_stats, sizeof(*node->sf_dir_stats));
-		node->sf_dir_stats = next;
-	}
 }
 
 /*
@@ -261,7 +255,6 @@ sfnode_make(
 	if (parent)
 		++parent->sf_children;
 	node->sf_dir_list = NULL;
-	node->sf_dir_stats = NULL;
 	if (stat != NULL) {
 		node->sf_stat = *stat;
 		node->sf_stat_time = stat_time;
@@ -702,11 +695,10 @@ sffs_readdir(
 {
 	sfnode_t *dir = VN2SFN(vp);
 	sfnode_t *node;
-	struct dirent64 *dirent;
+	struct sffs_dirent *dirent = NULL;
 	sffs_dirents_t *cur_buf;
-	sffs_stats_t *cur_stats;
-	int cur_snum;
-	offset_t offset;
+	offset_t offset = 0;
+	offset_t orig_off = uiop->uio_loffset;
 	int dummy_eof;
 	int error = 0;
 
@@ -734,61 +726,92 @@ sffs_readdir(
 
 	if (dir->sf_dir_list == NULL) {
 		error = sfprov_readdir(dir->sf_sffs->sf_handle, dir->sf_path,
-		    &dir->sf_dir_list, &dir->sf_dir_stats);
+		    &dir->sf_dir_list);
 		if (error != 0)
 			goto done;
 	}
 
 	/*
+	 * Validate and skip to the desired offset.
+	 */
+	cur_buf = dir->sf_dir_list;
+	offset = 0;
+
+	while (cur_buf != NULL &&
+	    offset + cur_buf->sf_len <= uiop->uio_loffset) {
+		offset += cur_buf->sf_len;
+		cur_buf = cur_buf->sf_next;
+	}
+
+	if (cur_buf == NULL && offset != uiop->uio_loffset) {
+		error = EINVAL;
+		goto done;
+	}
+	if (cur_buf != NULL && offset != uiop->uio_loffset) {
+		offset_t off = offset;
+		int step;
+		dirent = &cur_buf->sf_entries[0];
+
+		while (off < uiop->uio_loffset) {
+			if (dirent->sf_entry.d_off == uiop->uio_loffset)
+				break;
+			step = sizeof(sffs_stat_t) + dirent->sf_entry.d_reclen;
+			dirent = (struct sffs_dirent *) (((char *) dirent) + step);
+			off += step;
+		}
+
+		if (off >= uiop->uio_loffset) {
+			error = EINVAL;
+			goto done;
+		}
+	}
+
+	offset = uiop->uio_loffset - offset;
+
+	/*
 	 * Lookup each of the names, so that we have ino's, and copy to
 	 * result buffer.
 	 */
-	offset = 0;
-	cur_buf = dir->sf_dir_list;
-	cur_stats = dir->sf_dir_stats;
-	cur_snum = 0;
 	while (cur_buf != NULL) {
-		if (offset + cur_buf->sf_len <= uiop->uio_loffset) {
-			offset += cur_buf->sf_len;
+		if (offset >= cur_buf->sf_len) {
 			cur_buf = cur_buf->sf_next;
+			offset  = 0;
 			continue;
 		}
 
-		if (cur_snum >= SFFS_STATS_LEN) {
-			cur_stats = cur_stats->sf_next;
-			cur_snum = 0;
-		}
-
-		dirent = (dirent64_t *)
-		    (((char *) &cur_buf->sf_entries[0]) +
-		     (uiop->uio_loffset - offset));
-		if (dirent->d_reclen > uiop->uio_resid)
+		dirent = (struct sffs_dirent *)
+		    (((char *) &cur_buf->sf_entries[0]) + offset);
+		if (dirent->sf_entry.d_reclen > uiop->uio_resid)
 			break;
 
-		if (strcmp(dirent->d_name, ".") == 0) {
+		if (strcmp(dirent->sf_entry.d_name, ".") == 0) {
 			node = dir;
-		} else if (strcmp(dirent->d_name, "..") == 0) {
+		} else if (strcmp(dirent->sf_entry.d_name, "..") == 0) {
 			node = dir->sf_parent;
 			if (node == NULL)
 				node = dir;
 		} else {
-			node = sfnode_lookup(dir, dirent->d_name, VNON,
-			    &cur_stats->sf_stats[cur_snum],
-			    sfnode_cur_time_usec(), NULL);
+			node = sfnode_lookup(dir, dirent->sf_entry.d_name, VNON,
+			    &dirent->sf_stat, sfnode_cur_time_usec(), NULL);
 			if (node == NULL)
 				panic("sffs_readdir() lookup failed");
 		}
-		dirent->d_ino = node->sf_ino;
+		dirent->sf_entry.d_ino = node->sf_ino;
 
-		error = uiomove(dirent, dirent->d_reclen, UIO_READ, uiop);
-		++cur_snum;
+		error = uiomove(&dirent->sf_entry, dirent->sf_entry.d_reclen,
+		    UIO_READ, uiop);
 		if (error != 0)
 			break;
+
+		uiop->uio_loffset = dirent->sf_entry.d_off;
+		offset += sizeof(sffs_stat_t) + dirent->sf_entry.d_reclen;
 	}
 	if (error == 0 && cur_buf == NULL)
 		*eofp = 1;
 done:
 	mutex_exit(&sffs_lock);
+	if (error != 0)
+		uiop->uio_loffset = orig_off;
 	return (error);
 }
 
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.h
index 5da140d..456b948 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.h
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.h
@@ -59,7 +59,6 @@ typedef struct sfnode {
 	sffs_stat_t	sf_stat;	/* cached file attrs for this node */
 	uint64_t	sf_stat_time;	/* last-modified time of sf_stat */
 	sffs_dirents_t	*sf_dir_list;	/* list of entries for this directory */
-	sffs_stats_t	*sf_dir_stats;	/* file attrs for the above entries */
 } sfnode_t;
 
 #define VN2SFN(vp) ((sfnode_t *)(vp)->v_data)
-------------- next part --------------

Removed duplicate obj-info copying code and simplified getting file attrs.
There are no functional changes.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
index 7e12d9b..d37c41d 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
@@ -527,6 +527,16 @@ sfprov_ftime_from_timespec(timestruc_t *time, RTTIMESPEC *ts)
 	time->tv_nsec = nanosec % UINT64_C(1000000000);
 }
 
+static void
+sfprov_stat_from_info(sffs_stat_t *stat, SHFLFSOBJINFO *info)
+{
+	sfprov_mode_from_fmode(&stat->sf_mode, info->Attr.fMode);
+	stat->sf_size = info->cbObject;
+	sfprov_ftime_from_timespec(&stat->sf_atime, &info->AccessTime);
+	sfprov_ftime_from_timespec(&stat->sf_mtime, &info->ModificationTime);
+	sfprov_ftime_from_timespec(&stat->sf_ctime, &info->ChangeTime);
+}
+
 int
 sfprov_get_atime(sfp_mount_t *mnt, char *path, timestruc_t *time)
 {
@@ -567,14 +577,7 @@ sfprov_get_ctime(sfp_mount_t *mnt, char *path, timestruc_t *time)
 }
 
 int
-sfprov_get_attr(
-	sfp_mount_t *mnt,
-	char *path,
-	mode_t *mode,
-	uint64_t *size,
-	timestruc_t *atime,
-	timestruc_t *mtime,
-	timestruc_t *ctime)
+sfprov_get_attr(sfp_mount_t *mnt, char *path, sffs_stat_t *attr)
 {
 	int rc;
 	SHFLFSOBJINFO info;
@@ -583,16 +586,7 @@ sfprov_get_attr(
 	if (rc)
 		return (rc);
 
-	if (mode)
-		sfprov_mode_from_fmode(mode, info.Attr.fMode);
-	if (size != NULL)
-		*size = info.cbObject;
-	if (atime != NULL)
-		sfprov_ftime_from_timespec(atime, &info.AccessTime);
-	if (mtime != NULL)
-		sfprov_ftime_from_timespec(mtime, &info.ModificationTime);
-	if (ctime != NULL)
-		sfprov_ftime_from_timespec(ctime, &info.ChangeTime);
+	sfprov_stat_from_info(attr, &info);
 
 	return (0);
 }
@@ -878,7 +872,6 @@ sfprov_readdir(
 	uint32_t size;
 	sffs_dirents_t *cur_buf;
 	struct sffs_dirent *dirent;
-	sffs_stat_t *stat;
 	unsigned short reclen;
 	unsigned short entlen;
 	off_t offset;
@@ -974,13 +967,7 @@ sfprov_readdir(
 			dirent->sf_entry.d_off = offset;
 
 			/* save the stats */
-			stat = &dirent->sf_stat;
-
-			sfprov_mode_from_fmode(&stat->sf_mode, info->Info.Attr.fMode);
-			stat->sf_size = info->Info.cbObject;
-			sfprov_ftime_from_timespec(&stat->sf_atime, &info->Info.AccessTime);
-			sfprov_ftime_from_timespec(&stat->sf_mtime, &info->Info.ModificationTime);
-			sfprov_ftime_from_timespec(&stat->sf_ctime, &info->Info.ChangeTime);
+			sfprov_stat_from_info(&dirent->sf_stat, &info->Info);
 
 			/* next info */
 			cur_buf->sf_len += entlen;
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
index c04f1f9..ed37d79 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
@@ -98,13 +98,20 @@ extern int sfprov_fsync(sfp_file_t *fp);
 /*
  * get/set information about a file (or directory) using pathname
  */
+typedef struct sffs_stat {
+	mode_t		sf_mode;
+	off_t		sf_size;
+	timestruc_t	sf_atime;
+	timestruc_t	sf_mtime;
+	timestruc_t	sf_ctime;
+} sffs_stat_t;
+
 extern int sfprov_get_mode(sfp_mount_t *, char *, mode_t *);
 extern int sfprov_get_size(sfp_mount_t *, char *, uint64_t *);
 extern int sfprov_get_atime(sfp_mount_t *, char *, timestruc_t *);
 extern int sfprov_get_mtime(sfp_mount_t *, char *, timestruc_t *);
 extern int sfprov_get_ctime(sfp_mount_t *, char *, timestruc_t *);
-extern int sfprov_get_attr(sfp_mount_t *, char *, mode_t *, uint64_t *,
-   timestruc_t *, timestruc_t *, timestruc_t *);
+extern int sfprov_get_attr(sfp_mount_t *, char *, sffs_stat_t *);
 extern int sfprov_set_attr(sfp_mount_t *, char *, uint_t, mode_t,
    timestruc_t, timestruc_t, timestruc_t);
 extern int sfprov_set_size(sfp_mount_t *, char *, uint64_t);
@@ -126,14 +133,6 @@ extern int sfprov_rename(sfp_mount_t *, char *from, char *to, uint_t is_dir);
  * a singly linked list of buffers, each containing an array of stat's+dirent's.
  * sf_len is length of the sf_entries array, in bytes.
  */
-typedef struct sffs_stat {
-	mode_t		sf_mode;
-	off_t		sf_size;
-	timestruc_t	sf_atime;
-	timestruc_t	sf_mtime;
-	timestruc_t	sf_ctime;
-} sffs_stat_t;
-
 typedef struct sffs_dirents {
 	struct sffs_dirents	*sf_next;
 	len_t			sf_len;
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
index d54f3c3..036022d 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
@@ -406,13 +406,6 @@ sfnode_stat_cached(sfnode_t *node)
 	    node->sf_sffs->sf_stat_ttl * 1000L;
 }
 
-static int
-sfnode_get_stat(sfp_mount_t *mnt, char *path, sffs_stat_t *stat)
-{
-	return sfprov_get_attr(mnt, path, &stat->sf_mode, &stat->sf_size,
-	    &stat->sf_atime, &stat->sf_mtime, &stat->sf_ctime);
-}
-
 static void
 sfnode_invalidate_stat_cache(sfnode_t *node)
 {
@@ -424,7 +417,7 @@ sfnode_update_stat_cache(sfnode_t *node)
 {
 	int error;
 
-	error = sfnode_get_stat(node->sf_sffs->sf_handle, node->sf_path,
+	error = sfprov_get_attr(node->sf_sffs->sf_handle, node->sf_path,
 	    &node->sf_stat);
 	if (error == ENOENT)
 		sfnode_make_stale(node);
@@ -605,7 +598,7 @@ sfnode_lookup(
 		type = VNON;
 		if (stat == NULL) {
 			stat = &tmp_stat;
-			error = sfnode_get_stat(dir->sf_sffs->sf_handle,
+			error = sfprov_get_attr(dir->sf_sffs->sf_handle,
 			    fullpath, stat);
 			stat_time = sfnode_cur_time_usec();
 		} else {
-------------- next part --------------

Add symlink support.
    
Note that renaming symlinks currently only works if the symlink points to an
existing object - this is an issue with the underlying vboxCallRename().

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
index d37c41d..52da908 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
@@ -120,6 +120,18 @@ sfprov_disconnect(sfp_connection_t *conn)
 	vboxUninit();
 }
 
+int
+sfprov_set_show_symlinks(void)
+{
+	int rc;
+
+	rc = vboxCallSetSymlinks(&vbox_client);
+	if (RT_FAILURE(rc))
+		return (sfprov_vbox2errno(rc));
+
+	return (0);
+}
+
 
 /*
  * representation of an active mount point
@@ -793,14 +805,15 @@ sfprov_mkdir(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
 }
 
 int
-sfprov_remove(sfp_mount_t *mnt, char *path)
+sfprov_remove(sfp_mount_t *mnt, char *path, uint_t is_link)
 {
 	int rc;
 	SHFLSTRING *str;
 	int size;
 
 	str = sfprov_string(path, &size);
-	rc = vboxCallRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_FILE);
+	rc = vboxCallRemove(&vbox_client, &mnt->map, str,
+	    SHFL_REMOVE_FILE | (is_link ? SHFL_REMOVE_SYMLINK : 0));
 	kmem_free(str, size);
 	if (RT_FAILURE(rc))
 		return (sfprov_vbox2errno(rc));
@@ -998,3 +1011,56 @@ done:
 	sfprov_close(fp);
 	return (error);
 }
+
+int
+sfprov_readlink(
+	sfp_mount_t *mnt,
+	char *path,
+	char *target,
+	size_t tgt_size)
+{
+	int rc;
+	SHFLSTRING *str;
+	int size;
+
+	str = sfprov_string(path, &size);
+
+	rc = vboxReadLink(&vbox_client, &mnt->map, str, (uint32_t) tgt_size,
+	    target);
+	if (RT_FAILURE(rc))
+		rc = sfprov_vbox2errno(rc);
+
+	kmem_free(str, size);
+	return (rc);
+}
+
+int
+sfprov_symlink(
+	sfp_mount_t *mnt,
+	char *linkname,
+	char *target,
+	sffs_stat_t *stat)
+{
+	int rc;
+	SHFLSTRING *lnk, *tgt;
+	int lnk_size, tgt_size;
+	SHFLFSOBJINFO info;
+
+	lnk = sfprov_string(linkname, &lnk_size);
+	tgt = sfprov_string(target, &tgt_size);
+
+	rc = vboxCallSymlink(&vbox_client, &mnt->map, lnk, tgt, &info);
+	if (RT_FAILURE(rc)) {
+		rc = sfprov_vbox2errno(rc);
+		goto done;
+	}
+
+	if (stat != NULL)
+		sfprov_stat_from_info(stat, &info);
+
+done:
+	kmem_free(lnk, lnk_size);
+	kmem_free(tgt, tgt_size);
+
+	return (rc);
+}
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
index ed37d79..e073ddb 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
@@ -121,7 +121,7 @@ extern int sfprov_set_size(sfp_mount_t *, char *, uint64_t);
  * File/Directory operations
  */
 extern int sfprov_trunc(sfp_mount_t *, char *);
-extern int sfprov_remove(sfp_mount_t *, char *path);
+extern int sfprov_remove(sfp_mount_t *, char *path, uint_t is_link);
 extern int sfprov_mkdir(sfp_mount_t *, char *path, sfp_file_t **fp);
 extern int sfprov_rmdir(sfp_mount_t *, char *path);
 extern int sfprov_rename(sfp_mount_t *, char *from, char *to, uint_t is_dir);
@@ -148,6 +148,16 @@ typedef struct sffs_dirents {
 extern int sfprov_readdir(sfp_mount_t *mnt, char *path,
     sffs_dirents_t **dirents);
 
+
+/*
+ * Symbolic link operations
+ */
+extern int sfprov_set_show_symlinks(void);
+extern int sfprov_readlink(sfp_mount_t *, char *path, char *target,
+    size_t tgt_size);
+extern int sfprov_symlink(sfp_mount_t *, char *linkname, char *target,
+    sffs_stat_t *stat);
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
index a72cb60..198131c 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
@@ -190,6 +190,12 @@ sffs_init(int fstype, char *name)
 		return (ENODEV);
 	}
 
+	error = sfprov_set_show_symlinks();
+	if (error != 0) {
+		cmn_err(CE_WARN, "sffs_init: Host unable to show symlinks, "
+		    "rc=%d", error);
+	}
+
 	error = vfs_setfsops(fstype, sffs_vfsops_template, NULL);
 	if (error != 0) {
 		cmn_err(CE_WARN, "sffs_init: bad vfs ops template");
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
index 036022d..b7c5b44 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
@@ -611,6 +611,8 @@ sfnode_lookup(
 			type = VDIR;
 		else if (S_ISREG(m))
 			type = VREG;
+		else if (S_ISLNK(m))
+			type = VLNK;
 	}
 
 	if (err)
@@ -1871,6 +1873,153 @@ sffs_delmap(
 
 /*ARGSUSED*/
 static int
+sffs_readlink(
+	vnode_t		*vp,
+	uio_t		*uiop,
+	cred_t		*cred
+#if !defined(VBOX_VFS_SOLARIS_10U6)
+	,
+	caller_context_t *ct
+#endif
+	)
+{
+	sfnode_t	*node;
+	int		error = 0;
+	char		*target = NULL;
+
+	if (uiop->uio_iovcnt != 1)
+		return (EINVAL);
+
+	if (vp->v_type != VLNK)
+		return (EINVAL);
+
+	mutex_enter(&sffs_lock);
+	node = VN2SFN(vp);
+
+	target = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+	error = sfprov_readlink(node->sf_sffs->sf_handle, node->sf_path, target,
+	    MAXPATHLEN);
+	if (error)
+		goto done;
+
+	error = uiomove(target, strlen(target), UIO_READ, uiop);
+
+done:
+	mutex_exit(&sffs_lock);
+	if (target)
+		kmem_free(target, MAXPATHLEN);
+	return (error);
+}
+
+
+/*ARGSUSED*/
+static int
+sffs_symlink(
+	vnode_t		*dvp,
+	char		*linkname,
+	vattr_t		*vap,
+	char		*target,
+	cred_t		*cred
+#if !defined(VBOX_VFS_SOLARIS_10U6)
+	,
+	caller_context_t *ct,
+	int		flags
+#endif
+	)
+{
+	sfnode_t	 *dir;
+	sfnode_t	 *node;
+	sffs_stat_t	 stat;
+	int		 error = 0;
+	char		 *fullpath;
+
+	/*
+	 * These should never happen
+	 */
+	ASSERT(linkname != NULL);
+	ASSERT(strcmp(linkname, "") != 0);
+	ASSERT(strcmp(linkname, ".") != 0);
+	ASSERT(strcmp(linkname, "..") != 0);
+
+	/*
+	 * Basic checks.
+	 */
+	if (vap->va_type != VLNK)
+		return (EINVAL);
+
+	mutex_enter(&sffs_lock);
+
+	if (sfnode_lookup(VN2SFN(dvp), linkname, VNON, NULL, 0, NULL) != NULL) {
+		error = EEXIST;
+		goto done;
+	}
+
+	dir = VN2SFN(dvp);
+	error = sfnode_access(dir, VWRITE, cred);
+	if (error)
+		goto done;
+
+	/*
+	 * Create symlink. Note that we ignore vap->va_mode because generally
+	 * we can't change the attributes of the symlink itself.
+	 */
+	fullpath = sfnode_construct_path(dir, linkname);
+	error = sfprov_symlink(dir->sf_sffs->sf_handle, fullpath, target,
+	    &stat);
+	kmem_free(fullpath, strlen(fullpath) + 1);
+	if (error)
+		goto done;
+
+	node = sfnode_lookup(dir, linkname, VLNK, &stat, sfnode_cur_time_usec(),
+	    NULL);
+
+	sfnode_invalidate_stat_cache(dir);
+	sfnode_clear_dir_list(dir);
+
+done:
+	mutex_exit(&sffs_lock);
+	return (error);
+}
+
+static sfnode_t *
+sfnode_resolve_link(sfnode_t *node, int *err)
+{
+	int	error = 0;
+	char	*target = NULL;
+
+	ASSERT(MUTEX_HELD(&sffs_lock));
+
+	if (err == NULL)
+		err = &error;
+
+	target = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+	/*
+	 * Follow symlinks until we reach a non-symlink.
+	 */
+	while (node->sf_type == VLNK) {
+		*err = sfprov_readlink(node->sf_sffs->sf_handle, node->sf_path,
+		    target, MAXPATHLEN);
+		if (*err) {
+			node = NULL;
+			goto done;
+		}
+
+		ASSERT(node->sf_parent != NULL);
+		node = sfnode_lookup(node->sf_parent, target, VNON, NULL, 0, err);
+		if (node == NULL)
+			goto done;
+	}
+
+done:
+	if (target)
+		kmem_free(target, MAXPATHLEN);
+	return (node);
+}
+
+/*ARGSUSED*/
+static int
 sffs_remove(
 	vnode_t		*dvp,
 	char		*name,
@@ -1920,7 +2069,8 @@ sffs_remove(
 	 */
 	sfnode_invalidate_stat_cache(VN2SFN(dvp));
 
-	error = sfprov_remove(node->sf_sffs->sf_handle, node->sf_path);
+	error = sfprov_remove(node->sf_sffs->sf_handle, node->sf_path,
+	    node->sf_type == VLNK);
 	if (error == ENOENT || error == 0)
 		sfnode_make_stale(node);
 
@@ -1946,6 +2096,7 @@ sffs_rename(
 	char		*newpath;
 	int		error;
 	sfnode_t	*node;
+	sfnode_t	*res_node;
 
 	if (strcmp(new_nm, "") == 0 ||
 	    strcmp(new_nm, ".") == 0 ||
@@ -1979,8 +2130,21 @@ sffs_rename(
 	sfnode_invalidate_stat_cache(VN2SFN(new_dir));
 
 	newpath = sfnode_construct_path(VN2SFN(new_dir), new_nm);
+
+	/*
+	 * Hack because vboxCallRename doesn't support renaming symlinks
+	 * properly. By getting node type of what the symlink points to we
+	 * can work around things, but this still fails if the symlink points
+	 * to a non-existent object (with ENOENT).
+	 *
+	 * Remove sfnode_resolve_link when vboxCallRename is fixed.
+	 */
+	res_node = sfnode_resolve_link(node, &error);
+	if (res_node == NULL)
+		res_node = node;
+
 	error = sfprov_rename(node->sf_sffs->sf_handle, node->sf_path, newpath,
-	    node->sf_type == VDIR);
+	    res_node->sf_type == VDIR);
 	if (error == 0)
 		sfnode_rename(node, VN2SFN(new_dir), newpath);
 	else {
@@ -2191,12 +2355,14 @@ const fs_operation_def_t sffs_ops_template[] = {
 	VOPNAME_PATHCONF,	sffs_pathconf,
 	VOPNAME_READ,		sffs_read,
 	VOPNAME_READDIR,	sffs_readdir,
+	VOPNAME_READLINK,	sffs_readlink,
 	VOPNAME_REMOVE,		sffs_remove,
 	VOPNAME_RENAME,		sffs_rename,
 	VOPNAME_RMDIR,		sffs_rmdir,
 	VOPNAME_SEEK,		sffs_seek,
 	VOPNAME_SETATTR,	sffs_setattr,
 	VOPNAME_SPACE,		sffs_space,
+	VOPNAME_SYMLINK,	sffs_symlink,
 	VOPNAME_WRITE,		sffs_write,
 
 # ifdef VBOXVFS_WITH_MMAP
@@ -2222,12 +2388,14 @@ const fs_operation_def_t sffs_ops_template[] = {
 	VOPNAME_PATHCONF,	{ .vop_pathconf = sffs_pathconf },
 	VOPNAME_READ,		{ .vop_read = sffs_read },
 	VOPNAME_READDIR,	{ .vop_readdir = sffs_readdir },
+	VOPNAME_READLINK,	{ .vop_readlink = sffs_readlink },
 	VOPNAME_REMOVE,		{ .vop_remove = sffs_remove },
 	VOPNAME_RENAME,		{ .vop_rename = sffs_rename },
 	VOPNAME_RMDIR,		{ .vop_rmdir = sffs_rmdir },
 	VOPNAME_SEEK,		{ .vop_seek = sffs_seek },
 	VOPNAME_SETATTR,	{ .vop_setattr = sffs_setattr },
 	VOPNAME_SPACE,		{ .vop_space = sffs_space },
+	VOPNAME_SYMLINK,	{ .vop_symlink = sffs_symlink },
 	VOPNAME_WRITE,		{ .vop_write = sffs_write },
 
 # ifdef VBOXVFS_WITH_MMAP
@@ -2340,6 +2508,7 @@ sfnode_print(sfnode_t *node)
 	Log((" type=%s (%d)",
 	    node->sf_type == VDIR ? "VDIR" :
 	    node->sf_type == VNON ? "VNON" :
+	    node->sf_type == VLNK ? "VLNK" :
 	    node->sf_type == VREG ? "VREG" : "other", node->sf_type));
 	Log((" ino=%d", (uint_t)node->sf_ino));
 	Log((" path=%s", node->sf_path));
diff --git a/doc/manual/en_US/user_GuestAdditions.xml b/doc/manual/en_US/user_GuestAdditions.xml
index c0e4180..fd3b135 100644
--- a/doc/manual/en_US/user_GuestAdditions.xml
+++ b/doc/manual/en_US/user_GuestAdditions.xml
@@ -954,7 +954,7 @@ EndSection</screen>
         </listitem>
 
         <listitem>
-          <para>Currently only Linux Guest Additions support symlinks.</para>
+          <para>Currently only Linux and Solaris Guest Additions support symlinks.</para>
         </listitem>
       </orderedlist></para>
 
-------------- next part --------------

Return correct allocated size in getattr.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
index 52da908..d76ba0f 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
@@ -544,6 +544,7 @@ sfprov_stat_from_info(sffs_stat_t *stat, SHFLFSOBJINFO *info)
 {
 	sfprov_mode_from_fmode(&stat->sf_mode, info->Attr.fMode);
 	stat->sf_size = info->cbObject;
+	stat->sf_alloc = info->cbAllocated;
 	sfprov_ftime_from_timespec(&stat->sf_atime, &info->AccessTime);
 	sfprov_ftime_from_timespec(&stat->sf_mtime, &info->ModificationTime);
 	sfprov_ftime_from_timespec(&stat->sf_ctime, &info->ChangeTime);
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
index e073ddb..7b917d8 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
@@ -101,6 +101,7 @@ extern int sfprov_fsync(sfp_file_t *fp);
 typedef struct sffs_stat {
 	mode_t		sf_mode;
 	off_t		sf_size;
+	off_t		sf_alloc;
 	timestruc_t	sf_atime;
 	timestruc_t	sf_mtime;
 	timestruc_t	sf_ctime;
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
index b7c5b44..e5a33d2 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
@@ -907,7 +907,7 @@ sffs_getattr(
 
 	vap->va_size = node->sf_stat.sf_size;
 	vap->va_blksize = 512;
-	vap->va_nblocks = (vap->va_size + 511) / 512;
+	vap->va_nblocks = (node->sf_stat.sf_alloc + 511) / 512;
 
 done:
 	mutex_exit(&sffs_lock);
-------------- next part --------------

Consolidated separate volinfo calls into one, thereby both simplifying the
code and making the statvfs call several times faster.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
index d76ba0f..e58c85d 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
@@ -184,7 +184,7 @@ sfprov_unmount(sfp_mount_t *mnt)
  * query information about a mounted file system
  */
 int
-sfprov_get_blksize(sfp_mount_t *mnt, uint64_t *blksize)
+sfprov_get_fsinfo(sfp_mount_t *mnt, sffs_fsinfo_t *fsinfo)
 {
 	int rc;
 	SHFLVOLINFO info;
@@ -194,69 +194,15 @@ sfprov_get_blksize(sfp_mount_t *mnt, uint64_t *blksize)
 	    (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
 	if (RT_FAILURE(rc))
 		return (EINVAL);
-	*blksize = info.ulBytesPerAllocationUnit;
-	return (0);
-}
 
-int
-sfprov_get_blksused(sfp_mount_t *mnt, uint64_t *blksused)
-{
-	int rc;
-	SHFLVOLINFO info;
-	uint32_t bytes = sizeof(SHFLVOLINFO);
-
-	rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
-	    (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
-	if (RT_FAILURE(rc))
-		return (EINVAL);
-	*blksused = (info.ullTotalAllocationBytes -
+	fsinfo->blksize = info.ulBytesPerAllocationUnit;
+	fsinfo->blksused = (info.ullTotalAllocationBytes -
 	    info.ullAvailableAllocationBytes) / info.ulBytesPerAllocationUnit;
-	return (0);
-}
-
-int
-sfprov_get_blksavail(sfp_mount_t *mnt, uint64_t *blksavail)
-{
-	int rc;
-	SHFLVOLINFO info;
-	uint32_t bytes = sizeof(SHFLVOLINFO);
-
-	rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
-	    (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
-	if (RT_FAILURE(rc))
-		return (EINVAL);
-	*blksavail =
+	fsinfo->blksavail =
 	    info.ullAvailableAllocationBytes / info.ulBytesPerAllocationUnit;
-	return (0);
-}
+	fsinfo->maxnamesize = info.fsProperties.cbMaxComponent;
+	fsinfo->readonly = info.fsProperties.fReadOnly;
 
-int
-sfprov_get_maxnamesize(sfp_mount_t *mnt, uint32_t *maxnamesize)
-{
-	int rc;
-	SHFLVOLINFO info;
-	uint32_t bytes = sizeof(SHFLVOLINFO);
-
-	rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
-	    (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
-	if (RT_FAILURE(rc))
-		return (EINVAL);
-	*maxnamesize = info.fsProperties.cbMaxComponent;
-	return (0);
-}
-
-int
-sfprov_get_readonly(sfp_mount_t *mnt, uint32_t *readonly)
-{
-	int rc;
-	SHFLVOLINFO info;
-	uint32_t bytes = sizeof(SHFLVOLINFO);
-
-	rc = vboxCallFSInfo(&vbox_client, &mnt->map, 0,
-	    (SHFL_INFO_GET | SHFL_INFO_VOLUME), &bytes, (SHFLDIRINFO *)&info);
-	if (RT_FAILURE(rc))
-		return (EINVAL);
-	*readonly = info.fsProperties.fReadOnly;
 	return (0);
 }
 
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
index 7b917d8..0092faa 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
@@ -71,11 +71,15 @@ extern int sfprov_unmount(sfp_mount_t *);
 /*
  * query information about a mounted file system
  */
-extern int sfprov_get_blksize(sfp_mount_t *, uint64_t *);
-extern int sfprov_get_blksused(sfp_mount_t *, uint64_t *);
-extern int sfprov_get_blksavail(sfp_mount_t *, uint64_t *);
-extern int sfprov_get_maxnamesize(sfp_mount_t *, uint32_t *);
-extern int sfprov_get_readonly(sfp_mount_t *, uint32_t *);
+typedef struct sffs_fsinfo {
+	uint64_t blksize;
+	uint64_t blksused;
+	uint64_t blksavail;
+	uint32_t maxnamesize;
+	uint32_t readonly;
+} sffs_fsinfo_t;
+
+extern int sfprov_get_fsinfo(sfp_mount_t *, sffs_fsinfo_t *);
 
 /*
  * File operations: open/close/read/write/etc.
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
index 198131c..fedaa34 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
@@ -524,47 +524,36 @@ static int
 sffs_statvfs(vfs_t *vfsp, statvfs64_t *sbp)
 {
 	sffs_data_t *sffs = (sffs_data_t *)vfsp->vfs_data;
-	uint64_t x;
-	uint32_t u;
+	sffs_fsinfo_t fsinfo;
 	dev32_t d32;
 	int error;
 
 	bzero(sbp, sizeof(*sbp));
-	error = sfprov_get_blksize(sffs->sf_handle, &x);
+	error = sfprov_get_fsinfo(sffs->sf_handle, &fsinfo);
 	if (error != 0)
 		return (error);
-	sbp->f_bsize = x;
-	sbp->f_frsize = x;
 
-	error = sfprov_get_blksavail(sffs->sf_handle, &x);
-	if (error != 0)
-		return (error);
-	sbp->f_bfree = x;
-	sbp->f_bavail = x;
-	sbp->f_files = x / 4;	/* some kind of reasonable value */
-	sbp->f_ffree = x / 4;
-	sbp->f_favail = x / 4;
+	sbp->f_bsize = fsinfo.blksize;
+	sbp->f_frsize = fsinfo.blksize;
 
-	error = sfprov_get_blksused(sffs->sf_handle, &x);
-	if (error != 0)
-		return (error);
-	sbp->f_blocks = x + sbp->f_bavail;
+	sbp->f_bfree = fsinfo.blksavail;
+	sbp->f_bavail = fsinfo.blksavail;
+	sbp->f_files = fsinfo.blksavail / 4; /* some kind of reasonable value */
+	sbp->f_ffree = fsinfo.blksavail / 4;
+	sbp->f_favail = fsinfo.blksavail / 4;
+
+	sbp->f_blocks = fsinfo.blksused + sbp->f_bavail;
 
 	(void) cmpldev(&d32, vfsp->vfs_dev);
 	sbp->f_fsid = d32;
 	strcpy(&sbp->f_basetype[0], "sffs");
 	sbp->f_flag |= ST_NOSUID;
 
-	error = sfprov_get_readonly(sffs->sf_handle, &u);
-	if (error != 0)
-		return (error);
-	if (u)
+	if (fsinfo.readonly)
 		sbp->f_flag |= ST_RDONLY;
 
-	error = sfprov_get_maxnamesize(sffs->sf_handle, &u);
-	if (error != 0)
-		return (error);
-	sbp->f_namemax = u;
+	sbp->f_namemax = fsinfo.maxnamesize;
+
 	return (0);
 }
 
-------------- next part --------------

Don't open the underlying file unless really requested.
    
Opening the underlying file is somewhat expensive, and not necessary when
doing things like reading directories or getting attributes. By only opening
it when necessary we can speed up directory operations, including things like
recursive deletes, substantially.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
index e5a33d2..0118db3 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
@@ -214,7 +214,6 @@ sfnode_get_vnode(sfnode_t *node)
 		vp->v_data = node;
 		node->sf_vnode = vp;
 	}
-	sfnode_open(node);
 	return (node->sf_vnode);
 }
 
@@ -2260,7 +2259,19 @@ sffs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
 static int
 sffs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 {
-	return (0);
+	sfnode_t *node;
+	int error = 0;
+
+	mutex_enter(&sffs_lock);
+
+	node = VN2SFN(*vpp);
+	sfnode_open(node);
+	if (node->sf_file == NULL)
+		error = EINVAL;
+
+	mutex_exit(&sffs_lock);
+
+	return (error);
 }
 
 /*
@@ -2294,6 +2305,11 @@ sffs_close(
 
 	sfnode_invalidate_stat_cache(node);
 
+	if (node->sf_file != NULL && vp->v_count <= 1) {
+		(void)sfprov_close(node->sf_file);
+		node->sf_file = NULL;
+	}
+
 	mutex_exit(&sffs_lock);
 	return (0);
 }
-------------- next part --------------

Factored out mode-to-fmode conversion and grouped conversion routines at
top of file. No functional changes.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
index e58c85d..ba1b21c 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
@@ -207,6 +207,114 @@ sfprov_get_fsinfo(sfp_mount_t *mnt, sffs_fsinfo_t *fsinfo)
 }
 
 /*
+ * file/directory information conversions.
+ */
+static void
+sfprov_fmode_from_mode(RTFMODE *fMode, mode_t mode)
+{
+	RTFMODE m = 0;
+
+#define mode_set(r) ((mode & (S_##r)) ? RTFS_UNIX_##r : 0)
+	m  = mode_set (ISUID);
+	m |= mode_set (ISGID);
+	m |= (mode & S_ISVTX) ? RTFS_UNIX_ISTXT : 0;
+	m |= mode_set (IRUSR);
+	m |= mode_set (IWUSR);
+	m |= mode_set (IXUSR);
+	m |= mode_set (IRGRP);
+	m |= mode_set (IWGRP);
+	m |= mode_set (IXGRP);
+	m |= mode_set (IROTH);
+	m |= mode_set (IWOTH);
+	m |= mode_set (IXOTH);
+
+	if (S_ISDIR(mode))
+		m |= RTFS_TYPE_DIRECTORY;
+	else if (S_ISREG(mode))
+		m |= RTFS_TYPE_FILE;
+	else if (S_ISFIFO(mode))
+		m |= RTFS_TYPE_FIFO;
+	else if (S_ISCHR(mode))
+		m |= RTFS_TYPE_DEV_CHAR;
+	else if (S_ISBLK(mode))
+		m |= RTFS_TYPE_DEV_BLOCK;
+	else if (S_ISLNK(mode))
+		m |= RTFS_TYPE_SYMLINK;
+	else if (S_ISSOCK(mode))
+		m |= RTFS_TYPE_SOCKET;
+	else
+		m |= RTFS_TYPE_FILE;
+
+	*fMode = m;
+}
+
+static void
+sfprov_mode_from_fmode(mode_t *mode, RTFMODE fMode)
+{
+	mode_t m = 0;
+
+	if (RTFS_IS_DIRECTORY(fMode))
+		m |= S_IFDIR;
+	else if (RTFS_IS_FILE(fMode))
+		m |= S_IFREG;
+	else if (RTFS_IS_FIFO(fMode))
+		m |= S_IFIFO;
+	else if (RTFS_IS_DEV_CHAR(fMode))
+		m |= S_IFCHR;
+	else if (RTFS_IS_DEV_BLOCK(fMode))
+		m |= S_IFBLK;
+	else if (RTFS_IS_SYMLINK(fMode))
+		m |= S_IFLNK;
+	else if (RTFS_IS_SOCKET(fMode))
+		m |= S_IFSOCK;
+
+	if (fMode & RTFS_UNIX_IRUSR)
+		m |= S_IRUSR;
+	if (fMode & RTFS_UNIX_IWUSR)
+		m |= S_IWUSR;
+	if (fMode & RTFS_UNIX_IXUSR)
+		m |= S_IXUSR;
+	if (fMode & RTFS_UNIX_IRGRP)
+		m |= S_IRGRP;
+	if (fMode & RTFS_UNIX_IWGRP)
+		m |= S_IWGRP;
+	if (fMode & RTFS_UNIX_IXGRP)
+		m |= S_IXGRP;
+	if (fMode & RTFS_UNIX_IROTH)
+		m |= S_IROTH;
+	if (fMode & RTFS_UNIX_IWOTH)
+		m |= S_IWOTH;
+	if (fMode & RTFS_UNIX_IXOTH)
+		m |= S_IXOTH;
+	if (fMode & RTFS_UNIX_ISUID)
+		m |= S_ISUID;
+	if (fMode & RTFS_UNIX_ISGID)
+		m |= S_ISGID;
+	if (fMode & RTFS_UNIX_ISTXT)
+		m |= S_ISVTX;
+	*mode = m;
+}
+
+static void
+sfprov_ftime_from_timespec(timestruc_t *time, RTTIMESPEC *ts)
+{
+	uint64_t nanosec = RTTimeSpecGetNano(ts);
+	time->tv_sec = nanosec / UINT64_C(1000000000);
+	time->tv_nsec = nanosec % UINT64_C(1000000000);
+}
+
+static void
+sfprov_stat_from_info(sffs_stat_t *stat, SHFLFSOBJINFO *info)
+{
+	sfprov_mode_from_fmode(&stat->sf_mode, info->Attr.fMode);
+	stat->sf_size = info->cbObject;
+	stat->sf_alloc = info->cbAllocated;
+	sfprov_ftime_from_timespec(&stat->sf_atime, &info->AccessTime);
+	sfprov_ftime_from_timespec(&stat->sf_mtime, &info->ModificationTime);
+	sfprov_ftime_from_timespec(&stat->sf_ctime, &info->ChangeTime);
+}
+
+/*
  * File operations: open/close/read/write/etc.
  *
  * open/create can return any relevant errno, however ENOENT
@@ -401,56 +509,6 @@ sfprov_getinfo(sfp_mount_t *mnt, char *path, PSHFLFSOBJINFO info)
 /*
  * get information about a file (or directory)
  */
-static void
-sfprov_mode_from_fmode(mode_t *mode, RTFMODE fMode)
-{
-	mode_t m = 0;
-
-	if (RTFS_IS_DIRECTORY(fMode))
-		m |= S_IFDIR;
-	else if (RTFS_IS_FILE(fMode))
-		m |= S_IFREG;
-	else if (RTFS_IS_FIFO(fMode))
-		m |= S_IFIFO;
-	else if (RTFS_IS_DEV_CHAR(fMode))
-		m |= S_IFCHR;
-	else if (RTFS_IS_DEV_BLOCK(fMode))
-		m |= S_IFBLK;
-	else if (RTFS_IS_SYMLINK(fMode))
-		m |= S_IFLNK;
-	else if (RTFS_IS_SOCKET(fMode))
-		m |= S_IFSOCK;
-
-	if (fMode & RTFS_UNIX_IRUSR)
-		m |= S_IRUSR;
-	if (fMode & RTFS_UNIX_IWUSR)
-		m |= S_IWUSR;
-	if (fMode & RTFS_UNIX_IXUSR)
-		m |= S_IXUSR;
-	if (fMode & RTFS_UNIX_IRGRP)
-		m |= S_IRGRP;
-	if (fMode & RTFS_UNIX_IWGRP)
-		m |= S_IWGRP;
-	if (fMode & RTFS_UNIX_IXGRP)
-		m |= S_IXGRP;
-	if (fMode & RTFS_UNIX_IROTH)
-		m |= S_IROTH;
-	if (fMode & RTFS_UNIX_IWOTH)
-		m |= S_IWOTH;
-	if (fMode & RTFS_UNIX_IXOTH)
-		m |= S_IXOTH;
-	if (fMode & RTFS_UNIX_ISUID)
-		m |= S_ISUID;
-	if (fMode & RTFS_UNIX_ISGID)
-		m |= S_ISGID;
-	if (fMode & RTFS_UNIX_ISTXT)
-		m |= S_ISVTX;
-	*mode = m;
-}
-
-/*
- * get information about a file (or directory)
- */
 int
 sfprov_get_mode(sfp_mount_t *mnt, char *path, mode_t *mode)
 {
@@ -477,25 +535,6 @@ sfprov_get_size(sfp_mount_t *mnt, char *path, uint64_t *size)
 	return (0);
 }
 
-static void
-sfprov_ftime_from_timespec(timestruc_t *time, RTTIMESPEC *ts)
-{
-	uint64_t nanosec = RTTimeSpecGetNano(ts);
-	time->tv_sec = nanosec / UINT64_C(1000000000);
-	time->tv_nsec = nanosec % UINT64_C(1000000000);
-}
-
-static void
-sfprov_stat_from_info(sffs_stat_t *stat, SHFLFSOBJINFO *info)
-{
-	sfprov_mode_from_fmode(&stat->sf_mode, info->Attr.fMode);
-	stat->sf_size = info->cbObject;
-	stat->sf_alloc = info->cbAllocated;
-	sfprov_ftime_from_timespec(&stat->sf_atime, &info->AccessTime);
-	sfprov_ftime_from_timespec(&stat->sf_mtime, &info->ModificationTime);
-	sfprov_ftime_from_timespec(&stat->sf_ctime, &info->ChangeTime);
-}
-
 int
 sfprov_get_atime(sfp_mount_t *mnt, char *path, timestruc_t *time)
 {
@@ -595,40 +634,8 @@ sfprov_set_attr(
 	}
 
 	RT_ZERO(info);
-	if (mask & AT_MODE) {
-#define mode_set(r) ((mode & (S_##r)) ? RTFS_UNIX_##r : 0)
-
-		info.Attr.fMode  = mode_set (ISUID);
-		info.Attr.fMode |= mode_set (ISGID);
-		info.Attr.fMode |= (mode & S_ISVTX) ? RTFS_UNIX_ISTXT : 0;
-		info.Attr.fMode |= mode_set (IRUSR);
-		info.Attr.fMode |= mode_set (IWUSR);
-		info.Attr.fMode |= mode_set (IXUSR);
-		info.Attr.fMode |= mode_set (IRGRP);
-		info.Attr.fMode |= mode_set (IWGRP);
-		info.Attr.fMode |= mode_set (IXGRP);
-		info.Attr.fMode |= mode_set (IROTH);
-		info.Attr.fMode |= mode_set (IWOTH);
-		info.Attr.fMode |= mode_set (IXOTH);
-
-		if (S_ISDIR(mode))
-			info.Attr.fMode |= RTFS_TYPE_DIRECTORY;
-		else if (S_ISREG(mode))
-			info.Attr.fMode |= RTFS_TYPE_FILE;
-		else if (S_ISFIFO(mode))
-			info.Attr.fMode |= RTFS_TYPE_FIFO;
-		else if (S_ISCHR(mode))
-			info.Attr.fMode |= RTFS_TYPE_DEV_CHAR;
-		else if (S_ISBLK(mode))
-			info.Attr.fMode |= RTFS_TYPE_DEV_BLOCK;
-		else if (S_ISLNK(mode))
-			info.Attr.fMode |= RTFS_TYPE_SYMLINK;
-		else if (S_ISSOCK(mode))
-			info.Attr.fMode |= RTFS_TYPE_SOCKET;
-		else
-			info.Attr.fMode |= RTFS_TYPE_FILE;
-	}
-
+	if (mask & AT_MODE)
+		sfprov_fmode_from_mode(&info.Attr.fMode, mode);
 	if (mask & AT_ATIME)
 		sfprov_timespec_from_ftime(&info.AccessTime, atime);
 	if (mask & AT_MTIME)
-------------- next part --------------

Pass file/dir mode directly to create/mkdir call instead of using a separate
set_attr call, and cache the returned stats.

diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
index ba1b21c..85a7248 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
@@ -326,7 +326,12 @@ struct sfp_file {
 };
 
 int
-sfprov_create(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
+sfprov_create(
+	sfp_mount_t *mnt,
+	char *path,
+	mode_t mode,
+	sfp_file_t **fp,
+	sffs_stat_t *stat)
 {
 
 	int rc;
@@ -336,8 +341,9 @@ sfprov_create(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
 	sfp_file_t *newfp;
 
 	str = sfprov_string(path, &size);
-	parms.Handle = 0;
+	parms.Handle = SHFL_HANDLE_NIL;
 	parms.Info.cbObject = 0;
+	sfprov_fmode_from_mode(&parms.Info.Attr.fMode, mode);
 	parms.CreateFlags = SHFL_CF_ACT_CREATE_IF_NEW |
 	    SHFL_CF_ACT_REPLACE_IF_EXISTS | SHFL_CF_ACCESS_READWRITE;
 	rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
@@ -358,6 +364,7 @@ sfprov_create(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
 	newfp->handle = parms.Handle;
 	newfp->map = mnt->map;
 	*fp = newfp;
+	sfprov_stat_from_info(stat, &parms.Info);
 	return (0);
 }
 
@@ -728,7 +735,12 @@ fail2:
  * Directory operations
  */
 int
-sfprov_mkdir(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
+sfprov_mkdir(
+	sfp_mount_t *mnt,
+	char *path,
+	mode_t mode,
+	sfp_file_t **fp,
+	sffs_stat_t *stat)
 {
 	int rc;
 	SHFLCREATEPARMS parms;
@@ -737,8 +749,9 @@ sfprov_mkdir(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
 	sfp_file_t *newfp;
 
 	str = sfprov_string(path, &size);
-	parms.Handle = 0;
+	parms.Handle = SHFL_HANDLE_NIL;
 	parms.Info.cbObject = 0;
+	sfprov_fmode_from_mode(&parms.Info.Attr.fMode, mode);
 	parms.CreateFlags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_CREATE_IF_NEW |
 	    SHFL_CF_ACT_FAIL_IF_EXISTS | SHFL_CF_ACCESS_READ;
 	rc = vboxCallCreate(&vbox_client, &mnt->map, str, &parms);
@@ -755,6 +768,7 @@ sfprov_mkdir(sfp_mount_t *mnt, char *path, sfp_file_t **fp)
 	newfp->handle = parms.Handle;
 	newfp->map = mnt->map;
 	*fp = newfp;
+	sfprov_stat_from_info(stat, &parms.Info);
 	return (0);
 }
 
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
index 0092faa..623cd45 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
@@ -87,9 +87,19 @@ extern int sfprov_get_fsinfo(sfp_mount_t *, sffs_fsinfo_t *);
  * open/create can return any relevant errno, however ENOENT
  * generally means that the host file didn't exist.
  */
+typedef struct sffs_stat {
+	mode_t		sf_mode;
+	off_t		sf_size;
+	off_t		sf_alloc;
+	timestruc_t	sf_atime;
+	timestruc_t	sf_mtime;
+	timestruc_t	sf_ctime;
+} sffs_stat_t;
+
 typedef struct sfp_file sfp_file_t;
 
-extern int sfprov_create(sfp_mount_t *, char *path, sfp_file_t **fp);
+extern int sfprov_create(sfp_mount_t *, char *path, mode_t mode,
+    sfp_file_t **fp, sffs_stat_t *stat);
 extern int sfprov_open(sfp_mount_t *, char *path, sfp_file_t **fp);
 extern int sfprov_close(sfp_file_t *fp);
 extern int sfprov_read(sfp_file_t *, char * buffer, uint64_t offset,
@@ -102,15 +112,6 @@ extern int sfprov_fsync(sfp_file_t *fp);
 /*
  * get/set information about a file (or directory) using pathname
  */
-typedef struct sffs_stat {
-	mode_t		sf_mode;
-	off_t		sf_size;
-	off_t		sf_alloc;
-	timestruc_t	sf_atime;
-	timestruc_t	sf_mtime;
-	timestruc_t	sf_ctime;
-} sffs_stat_t;
-
 extern int sfprov_get_mode(sfp_mount_t *, char *, mode_t *);
 extern int sfprov_get_size(sfp_mount_t *, char *, uint64_t *);
 extern int sfprov_get_atime(sfp_mount_t *, char *, timestruc_t *);
@@ -127,7 +128,8 @@ extern int sfprov_set_size(sfp_mount_t *, char *, uint64_t);
  */
 extern int sfprov_trunc(sfp_mount_t *, char *);
 extern int sfprov_remove(sfp_mount_t *, char *path, uint_t is_link);
-extern int sfprov_mkdir(sfp_mount_t *, char *path, sfp_file_t **fp);
+extern int sfprov_mkdir(sfp_mount_t *, char *path, mode_t mode,
+    sfp_file_t **fp, sffs_stat_t *stat);
 extern int sfprov_rmdir(sfp_mount_t *, char *path);
 extern int sfprov_rename(sfp_mount_t *, char *from, char *to, uint_t is_dir);
 
diff --git a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
index 0118db3..0469a82 100644
--- a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
+++ b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
@@ -535,6 +535,7 @@ sfnode_lookup(
 	sfnode_t *dir,
 	char *name,
 	vtype_t create,
+	mode_t c_mode,
 	sffs_stat_t *stat,
 	uint64_t stat_time,
 	int *err)
@@ -587,10 +588,16 @@ sfnode_lookup(
 	 */
 	if (create == VREG) {
 		type = VREG;
-		error = sfprov_create(dir->sf_sffs->sf_handle, fullpath, &fp);
+		stat = &tmp_stat;
+		error = sfprov_create(dir->sf_sffs->sf_handle, fullpath, c_mode,
+		    &fp, stat);
+		stat_time = sfnode_cur_time_usec();
 	} else if (create == VDIR) {
 		type = VDIR;
-		error = sfprov_mkdir(dir->sf_sffs->sf_handle, fullpath, &fp);
+		stat = &tmp_stat;
+		error = sfprov_mkdir(dir->sf_sffs->sf_handle, fullpath, c_mode,
+		    &fp, stat);
+		stat_time = sfnode_cur_time_usec();
 	} else {
 		mode_t m;
 		fp = NULL;
@@ -786,7 +793,7 @@ sffs_readdir(
 				node = dir;
 		} else {
 			node = sfnode_lookup(dir, dirent->sf_entry.d_name, VNON,
-			    &dirent->sf_stat, sfnode_cur_time_usec(), NULL);
+			    0, &dirent->sf_stat, sfnode_cur_time_usec(), NULL);
 			if (node == NULL)
 				panic("sffs_readdir() lookup failed");
 		}
@@ -1218,7 +1225,7 @@ sffs_lookup(
 	/*
 	 * Lookup the node.
 	 */
-	node = sfnode_lookup(VN2SFN(dvp), name, VNON, NULL, 0, NULL);
+	node = sfnode_lookup(VN2SFN(dvp), name, VNON, 0, NULL, 0, NULL);
 	if (node != NULL)
 		*vpp = sfnode_get_vnode(node);
 	mutex_exit(&sffs_lock);
@@ -1313,7 +1320,7 @@ sffs_create(
 	 * Create a new node. First check for a race creating it.
 	 */
 	mutex_enter(&sffs_lock);
-	node = sfnode_lookup(VN2SFN(dvp), name, VNON, NULL, 0, NULL);
+	node = sfnode_lookup(VN2SFN(dvp), name, VNON, 0, NULL, 0, NULL);
 	if (node != NULL) {
 		mutex_exit(&sffs_lock);
 		return (EEXIST);
@@ -1324,15 +1331,8 @@ sffs_create(
 	 */
 	sfnode_invalidate_stat_cache(VN2SFN(dvp));
 	int lookuperr;
-	node = sfnode_lookup(VN2SFN(dvp), name, VREG, NULL, 0, &lookuperr);
-	if (node && (vap->va_mask & AT_MODE)) {
-		timestruc_t dummy;
-		error = sfprov_set_attr(node->sf_sffs->sf_handle, node->sf_path,
-		    AT_MODE, vap->va_mode, dummy, dummy, dummy);
-		if (error)
-			cmn_err(CE_WARN, "sffs_create: set_mode(%s, %o) failed"
-			    " rc=%d", node->sf_path, vap->va_mode, error);
-	}
+	node = sfnode_lookup(VN2SFN(dvp), name, VREG,
+	    (vap->va_mask & AT_MODE) ? vap->va_mode : 0, NULL, 0, &lookuperr);
 
 	if (node && node->sf_parent)
 		sfnode_clear_dir_list(node->sf_parent);
@@ -1391,15 +1391,8 @@ sffs_mkdir(
 
 	sfnode_invalidate_stat_cache(VN2SFN(dvp));
 	int lookuperr = EACCES;
-	node = sfnode_lookup(VN2SFN(dvp), nm, VDIR, NULL, 0, &lookuperr);
-	if (node && (va->va_mask & AT_MODE)) {
-		timestruc_t dummy;
-		error = sfprov_set_attr(node->sf_sffs->sf_handle, node->sf_path,
-		    AT_MODE, va->va_mode, dummy, dummy, dummy);
-		if (error)
-			cmn_err(CE_WARN, "sffs_mkdir: set_mode(%s, %o) failed"
-			    " rc=%d", node->sf_path, va->va_mode, error);
-	}
+	node = sfnode_lookup(VN2SFN(dvp), nm, VDIR,
+	    (va->va_mask & AT_MODE) ? va->va_mode : 0, NULL, 0, &lookuperr);
 
 	if (node && node->sf_parent)
 		sfnode_clear_dir_list(node->sf_parent);
@@ -1949,7 +1942,8 @@ sffs_symlink(
 
 	mutex_enter(&sffs_lock);
 
-	if (sfnode_lookup(VN2SFN(dvp), linkname, VNON, NULL, 0, NULL) != NULL) {
+	if (sfnode_lookup(VN2SFN(dvp), linkname, VNON, 0, NULL, 0, NULL) !=
+	    NULL) {
 		error = EEXIST;
 		goto done;
 	}
@@ -1970,8 +1964,8 @@ sffs_symlink(
 	if (error)
 		goto done;
 
-	node = sfnode_lookup(dir, linkname, VLNK, &stat, sfnode_cur_time_usec(),
-	    NULL);
+	node = sfnode_lookup(dir, linkname, VLNK, 0, &stat,
+	    sfnode_cur_time_usec(), NULL);
 
 	sfnode_invalidate_stat_cache(dir);
 	sfnode_clear_dir_list(dir);
@@ -2006,7 +2000,8 @@ sfnode_resolve_link(sfnode_t *node, int *err)
 		}
 
 		ASSERT(node->sf_parent != NULL);
-		node = sfnode_lookup(node->sf_parent, target, VNON, NULL, 0, err);
+		node = sfnode_lookup(node->sf_parent, target, VNON, 0, NULL, 0,
+		    err);
 		if (node == NULL)
 			goto done;
 	}
@@ -2115,7 +2110,7 @@ sffs_rename(
 	if (error)
 		goto done;
 
-	node = sfnode_lookup(VN2SFN(old_dir), old_nm, VNON, NULL, 0, NULL);
+	node = sfnode_lookup(VN2SFN(old_dir), old_nm, VNON, 0, NULL, 0, NULL);
 	if (node == NULL) {
 		error = ENOENT;
 		goto done;


More information about the vbox-dev mailing list