diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 61c05dd9a..00f65e466 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -7,7 +7,7 @@
 	"Deps": [
 		{
 			"ImportPath": "bazil.org/fuse",
-			"Rev": "a04507d54fc3610d38ee951402d8c4acab56c7b1"
+			"Rev": "d62a1291477b51b24becf4def173bd843138c4b6"
 		},
 		{
 			"ImportPath": "bitbucket.org/kardianos/osext",
diff --git a/Godeps/_workspace/src/bazil.org/fuse/debug.go b/Godeps/_workspace/src/bazil.org/fuse/debug.go
index 78194ff20..be9f900d5 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/debug.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/debug.go
@@ -11,4 +11,11 @@ func stack() string {
 
 func nop(msg interface{}) {}
 
+// Debug is called to output debug messages, including protocol
+// traces. The default behavior is to do nothing.
+//
+// The messages have human-friendly string representations and are
+// safe to marshal to JSON.
+//
+// Implementations must not retain msg.
 var Debug func(msg interface{}) = nop
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/doc.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/doc.go
new file mode 100644
index 000000000..d4366cca5
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/doc.go
@@ -0,0 +1 @@
+package fstestutil
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go
index 34f3770f5..42240bdbe 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mounted.go
@@ -55,12 +55,12 @@ func (mnt *Mount) Close() {
 // workaround).
 //
 // After successful return, caller must clean up by calling Close.
-func Mounted(srv *fs.Server) (*Mount, error) {
+func Mounted(srv *fs.Server, options ...fuse.MountOption) (*Mount, error) {
 	dir, err := ioutil.TempDir("", "fusetest")
 	if err != nil {
 		return nil, err
 	}
-	c, err := fuse.Mount(dir)
+	c, err := fuse.Mount(dir, options...)
 	if err != nil {
 		return nil, err
 	}
@@ -100,7 +100,7 @@ func Mounted(srv *fs.Server) (*Mount, error) {
 //
 // The debug log is not enabled by default. Use `-fuse.debug` or call
 // DebugByDefault to enable.
-func MountedT(t testing.TB, filesys fs.FS) (*Mount, error) {
+func MountedT(t testing.TB, filesys fs.FS, options ...fuse.MountOption) (*Mount, error) {
 	srv := &fs.Server{
 		FS: filesys,
 	}
@@ -109,5 +109,5 @@ func MountedT(t testing.TB, filesys fs.FS) (*Mount, error) {
 			t.Logf("FUSE: %s", msg)
 		}
 	}
-	return Mounted(srv)
+	return Mounted(srv, options...)
 }
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo.go
new file mode 100644
index 000000000..4e410ebd0
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo.go
@@ -0,0 +1,14 @@
+package fstestutil
+
+// MountInfo describes a mounted file system.
+type MountInfo struct {
+	FSName string
+	Type   string
+}
+
+// GetMountInfo finds information about the mount at mnt. It is
+// intended for use by tests only, and only fetches information
+// relevant to the current tests.
+func GetMountInfo(mnt string) (*MountInfo, error) {
+	return getMountInfo(mnt)
+}
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_darwin.go
new file mode 100644
index 000000000..dc88b0b06
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_darwin.go
@@ -0,0 +1,41 @@
+package fstestutil
+
+import (
+	"regexp"
+	"syscall"
+)
+
+// cstr converts a nil-terminated C string into a Go string
+func cstr(ca []int8) string {
+	s := make([]byte, 0, len(ca))
+	for _, c := range ca {
+		if c == 0x00 {
+			break
+		}
+		s = append(s, byte(c))
+	}
+	return string(s)
+}
+
+var re = regexp.MustCompile(`\\(.)`)
+
+// unescape removes backslash-escaping. The escaped characters are not
+// mapped in any way; that is, unescape(`\n` ) == `n`.
+func unescape(s string) string {
+	return re.ReplaceAllString(s, `$1`)
+}
+
+func getMountInfo(mnt string) (*MountInfo, error) {
+	var st syscall.Statfs_t
+	err := syscall.Statfs(mnt, &st)
+	if err != nil {
+		return nil, err
+	}
+	i := &MountInfo{
+		// osx getmntent(3) fails to un-escape the data, so we do it..
+		// this might lead to double-unescaping in the future. fun.
+		// TestMountOptionFSNameEvilBackslashDouble checks for that.
+		FSName: unescape(cstr(st.Mntfromname[:])),
+	}
+	return i, nil
+}
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_linux.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_linux.go
new file mode 100644
index 000000000..c502cf59b
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/mountinfo_linux.go
@@ -0,0 +1,51 @@
+package fstestutil
+
+import (
+	"errors"
+	"io/ioutil"
+	"strings"
+)
+
+// Linux /proc/mounts shows current mounts.
+// Same format as /etc/fstab. Quoting getmntent(3):
+//
+// Since fields in the mtab and fstab files are separated by whitespace,
+// octal escapes are used to represent the four characters space (\040),
+// tab (\011), newline (\012) and backslash (\134) in those files when
+// they occur in one of the four strings in a mntent structure.
+//
+// http://linux.die.net/man/3/getmntent
+
+var fstabUnescape = strings.NewReplacer(
+	`\040`, "\040",
+	`\011`, "\011",
+	`\012`, "\012",
+	`\134`, "\134",
+)
+
+var errNotFound = errors.New("mount not found")
+
+func getMountInfo(mnt string) (*MountInfo, error) {
+	data, err := ioutil.ReadFile("/proc/mounts")
+	if err != nil {
+		return nil, err
+	}
+	for _, line := range strings.Split(string(data), "\n") {
+		fields := strings.Fields(line)
+		if len(fields) < 3 {
+			continue
+		}
+		// Fields are: fsname dir type opts freq passno
+		fsname := fstabUnescape.Replace(fields[0])
+		dir := fstabUnescape.Replace(fields[1])
+		fstype := fstabUnescape.Replace(fields[2])
+		if mnt == dir {
+			info := &MountInfo{
+				FSName: fsname,
+				Type:   fstype,
+			}
+			return info, nil
+		}
+	}
+	return nil, errNotFound
+}
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go
new file mode 100644
index 000000000..9596804c7
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go
@@ -0,0 +1,29 @@
+package fstestutil
+
+import (
+	"os"
+
+	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
+	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
+)
+
+// SimpleFS is a trivial FS that just implements the Root method.
+type SimpleFS struct {
+	Node fs.Node
+}
+
+var _ = fs.FS(SimpleFS{})
+
+func (f SimpleFS) Root() (fs.Node, fuse.Error) {
+	return f.Node, nil
+}
+
+// File can be embedded in a struct to make it look like a file.
+type File struct{}
+
+func (f File) Attr() fuse.Attr { return fuse.Attr{Mode: 0666} }
+
+// Dir can be embedded in a struct to make it look like a directory.
+type Dir struct{}
+
+func (f Dir) Attr() fuse.Attr { return fuse.Attr{Mode: os.ModeDir | 0777} }
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go b/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go
index efaa4f143..f0185140e 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go
@@ -10,7 +10,6 @@ import (
 	"reflect"
 	"strings"
 	"sync"
-	"syscall"
 	"time"
 )
 
@@ -295,6 +294,8 @@ type Server struct {
 	// Function to send debug log messages to. If nil, use fuse.Debug.
 	// Note that changing this or fuse.Debug may not affect existing
 	// calls to Serve.
+	//
+	// See fuse.Debug for the rules that log functions must follow.
 	Debug func(msg interface{})
 }
 
@@ -317,7 +318,7 @@ func (s *Server) Serve(c *fuse.Conn) error {
 
 	root, err := sc.fs.Root()
 	if err != nil {
-		return fmt.Errorf("cannot obtain root node: %v", syscall.Errno(err.(fuse.Errno)).Error())
+		return fmt.Errorf("cannot obtain root node: %v", err)
 	}
 	sc.node = append(sc.node, nil, &serveNode{inode: 1, node: root, refs: 1})
 	sc.handle = append(sc.handle, nil)
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go b/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go
index dde3ce905..c1468c3b0 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go
@@ -87,27 +87,6 @@ func (f childMapFS) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
 	return child, nil
 }
 
-// simpleFS is a trivial FS that just implements the Root method.
-type simpleFS struct {
-	node fs.Node
-}
-
-var _ = fs.FS(simpleFS{})
-
-func (f simpleFS) Root() (fs.Node, fuse.Error) {
-	return f.node, nil
-}
-
-// file can be embedded in a struct to make it look like a file.
-type file struct{}
-
-func (f file) Attr() fuse.Attr { return fuse.Attr{Mode: 0666} }
-
-// dir can be embedded in a struct to make it look like a directory.
-type dir struct{}
-
-func (f dir) Attr() fuse.Attr { return fuse.Attr{Mode: os.ModeDir | 0777} }
-
 // symlink can be embedded in a struct to make it look like a symlink.
 type symlink struct {
 	target string
@@ -261,7 +240,9 @@ func TestStatRoot(t *testing.T) {
 
 // Test Read calling ReadAll.
 
-type readAll struct{ file }
+type readAll struct {
+	fstestutil.File
+}
 
 const hi = "hello, world"
 
@@ -299,7 +280,9 @@ func TestReadAll(t *testing.T) {
 
 // Test Read.
 
-type readWithHandleRead struct{ file }
+type readWithHandleRead struct {
+	fstestutil.File
+}
 
 func (readWithHandleRead) Attr() fuse.Attr {
 	return fuse.Attr{
@@ -327,7 +310,7 @@ func TestReadAllWithHandleRead(t *testing.T) {
 // Test Release.
 
 type release struct {
-	file
+	fstestutil.File
 	record.ReleaseWaiter
 }
 
@@ -353,7 +336,7 @@ func TestRelease(t *testing.T) {
 // Test Write calling basic Write, with an fsync thrown in too.
 
 type write struct {
-	file
+	fstestutil.File
 	record.Writes
 	record.Fsyncs
 }
@@ -401,7 +384,7 @@ func TestWrite(t *testing.T) {
 // Test Write of a larger buffer.
 
 type writeLarge struct {
-	file
+	fstestutil.File
 	record.Writes
 }
 
@@ -446,7 +429,7 @@ func TestWriteLarge(t *testing.T) {
 // Test Write calling Setattr+Write+Flush.
 
 type writeTruncateFlush struct {
-	file
+	fstestutil.File
 	record.Writes
 	record.Setattrs
 	record.Flushes
@@ -479,7 +462,7 @@ func TestWriteTruncateFlush(t *testing.T) {
 // Test Mkdir.
 
 type mkdir1 struct {
-	dir
+	fstestutil.Dir
 	record.Mkdirs
 }
 
@@ -491,7 +474,7 @@ func (f *mkdir1) Mkdir(req *fuse.MkdirRequest, intr fs.Intr) (fs.Node, fuse.Erro
 func TestMkdir(t *testing.T) {
 	t.Parallel()
 	f := &mkdir1{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -513,12 +496,12 @@ func TestMkdir(t *testing.T) {
 // Test Create (and fsync)
 
 type create1file struct {
-	file
+	fstestutil.File
 	record.Fsyncs
 }
 
 type create1 struct {
-	dir
+	fstestutil.Dir
 	f create1file
 }
 
@@ -553,7 +536,7 @@ func (f *create1) Create(req *fuse.CreateRequest, resp *fuse.CreateResponse, int
 func TestCreate(t *testing.T) {
 	t.Parallel()
 	f := &create1{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -583,12 +566,12 @@ func TestCreate(t *testing.T) {
 // Test Create + Write + Remove
 
 type create3file struct {
-	file
+	fstestutil.File
 	record.Writes
 }
 
 type create3 struct {
-	dir
+	fstestutil.Dir
 	f          create3file
 	fooCreated record.MarkRecorder
 	fooRemoved record.MarkRecorder
@@ -622,7 +605,7 @@ func (f *create3) Remove(r *fuse.RemoveRequest, intr fs.Intr) fuse.Error {
 func TestCreateWriteRemove(t *testing.T) {
 	t.Parallel()
 	f := &create3{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -659,7 +642,7 @@ func (f symlink1link) Readlink(*fuse.ReadlinkRequest, fs.Intr) (string, fuse.Err
 }
 
 type symlink1 struct {
-	dir
+	fstestutil.Dir
 	record.Symlinks
 }
 
@@ -671,7 +654,7 @@ func (f *symlink1) Symlink(req *fuse.SymlinkRequest, intr fs.Intr) (fs.Node, fus
 func TestSymlink(t *testing.T) {
 	t.Parallel()
 	f := &symlink1{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -701,26 +684,26 @@ func TestSymlink(t *testing.T) {
 // Test link
 
 type link1 struct {
-	dir
+	fstestutil.Dir
 	record.Links
 }
 
 func (f *link1) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
 	if name == "old" {
-		return file{}, nil
+		return fstestutil.File{}, nil
 	}
 	return nil, fuse.ENOENT
 }
 
 func (f *link1) Link(r *fuse.LinkRequest, old fs.Node, intr fs.Intr) (fs.Node, fuse.Error) {
 	f.Links.Link(r, old, intr)
-	return file{}, nil
+	return fstestutil.File{}, nil
 }
 
 func TestLink(t *testing.T) {
 	t.Parallel()
 	f := &link1{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -745,13 +728,13 @@ func TestLink(t *testing.T) {
 // Test Rename
 
 type rename1 struct {
-	dir
+	fstestutil.Dir
 	renamed record.Counter
 }
 
 func (f *rename1) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
 	if name == "old" {
-		return file{}, nil
+		return fstestutil.File{}, nil
 	}
 	return nil, fuse.ENOENT
 }
@@ -767,7 +750,7 @@ func (f *rename1) Rename(r *fuse.RenameRequest, newDir fs.Node, intr fs.Intr) fu
 func TestRename(t *testing.T) {
 	t.Parallel()
 	f := &rename1{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -789,7 +772,7 @@ func TestRename(t *testing.T) {
 // Test mknod
 
 type mknod1 struct {
-	dir
+	fstestutil.Dir
 	record.Mknods
 }
 
@@ -805,7 +788,7 @@ func TestMknod(t *testing.T) {
 	}
 
 	f := &mknod1{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -836,7 +819,7 @@ func TestMknod(t *testing.T) {
 // Test Read served with DataHandle.
 
 type dataHandleTest struct {
-	file
+	fstestutil.File
 }
 
 func (dataHandleTest) Attr() fuse.Attr {
@@ -872,7 +855,7 @@ func TestDataHandle(t *testing.T) {
 // Test interrupt
 
 type interrupt struct {
-	file
+	fstestutil.File
 
 	// strobes to signal we have a read hanging
 	hanging chan struct{}
@@ -955,7 +938,7 @@ func TestInterrupt(t *testing.T) {
 // Test truncate
 
 type truncate struct {
-	file
+	fstestutil.File
 	record.Setattrs
 }
 
@@ -996,7 +979,7 @@ func TestTruncate0(t *testing.T) {
 // Test ftruncate
 
 type ftruncate struct {
-	file
+	fstestutil.File
 	record.Setattrs
 }
 
@@ -1046,7 +1029,7 @@ func TestFtruncate0(t *testing.T) {
 // Test opening existing file truncates
 
 type truncateWithOpen struct {
-	file
+	fstestutil.File
 	record.Setattrs
 }
 
@@ -1083,7 +1066,7 @@ func TestTruncateWithOpen(t *testing.T) {
 // Test readdir
 
 type readdir struct {
-	dir
+	fstestutil.Dir
 }
 
 func (d *readdir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
@@ -1097,7 +1080,7 @@ func (d *readdir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
 func TestReadDir(t *testing.T) {
 	t.Parallel()
 	f := &readdir{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1133,7 +1116,7 @@ func TestReadDir(t *testing.T) {
 // Test Chmod.
 
 type chmod struct {
-	file
+	fstestutil.File
 	record.Setattrs
 }
 
@@ -1169,7 +1152,7 @@ func TestChmod(t *testing.T) {
 // Test open
 
 type open struct {
-	file
+	fstestutil.File
 	record.Opens
 }
 
@@ -1233,14 +1216,14 @@ func TestOpen(t *testing.T) {
 // Test Fsync on a dir
 
 type fsyncDir struct {
-	dir
+	fstestutil.Dir
 	record.Fsyncs
 }
 
 func TestFsyncDir(t *testing.T) {
 	t.Parallel()
 	f := &fsyncDir{}
-	mnt, err := fstestutil.MountedT(t, simpleFS{f})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{f})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1278,7 +1261,7 @@ func TestFsyncDir(t *testing.T) {
 // Test Getxattr
 
 type getxattr struct {
-	file
+	fstestutil.File
 	record.Getxattrs
 }
 
@@ -1316,7 +1299,7 @@ func TestGetxattr(t *testing.T) {
 // Test Getxattr that has no space to return value
 
 type getxattrTooSmall struct {
-	file
+	fstestutil.File
 }
 
 func (f *getxattrTooSmall) Getxattr(req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse, intr fs.Intr) fuse.Error {
@@ -1347,7 +1330,7 @@ func TestGetxattrTooSmall(t *testing.T) {
 // Test Getxattr used to probe result size
 
 type getxattrSize struct {
-	file
+	fstestutil.File
 }
 
 func (f *getxattrSize) Getxattr(req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse, intr fs.Intr) fuse.Error {
@@ -1377,7 +1360,7 @@ func TestGetxattrSize(t *testing.T) {
 // Test Listxattr
 
 type listxattr struct {
-	file
+	fstestutil.File
 	record.Listxattrs
 }
 
@@ -1418,7 +1401,7 @@ func TestListxattr(t *testing.T) {
 // Test Listxattr that has no space to return value
 
 type listxattrTooSmall struct {
-	file
+	fstestutil.File
 }
 
 func (f *listxattrTooSmall) Listxattr(req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse, intr fs.Intr) fuse.Error {
@@ -1449,7 +1432,7 @@ func TestListxattrTooSmall(t *testing.T) {
 // Test Listxattr used to probe result size
 
 type listxattrSize struct {
-	file
+	fstestutil.File
 }
 
 func (f *listxattrSize) Listxattr(req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse, intr fs.Intr) fuse.Error {
@@ -1479,11 +1462,16 @@ func TestListxattrSize(t *testing.T) {
 // Test Setxattr
 
 type setxattr struct {
-	file
+	fstestutil.File
 	record.Setxattrs
 }
 
-func TestSetxattr(t *testing.T) {
+func testSetxattr(t *testing.T, size int) {
+	const linux_XATTR_NAME_MAX = 64 * 1024
+	if size > linux_XATTR_NAME_MAX && runtime.GOOS == "linux" {
+		t.Skip("large xattrs are not supported by linux")
+	}
+
 	t.Parallel()
 	f := &setxattr{}
 	mnt, err := fstestutil.MountedT(t, childMapFS{"child": f})
@@ -1492,7 +1480,9 @@ func TestSetxattr(t *testing.T) {
 	}
 	defer mnt.Close()
 
-	err = syscallx.Setxattr(mnt.Dir+"/child", "greeting", []byte("hello, world"), 0)
+	const g = "hello, world"
+	greeting := strings.Repeat(g, size/len(g)+1)[:size]
+	err = syscallx.Setxattr(mnt.Dir+"/child", "greeting", []byte(greeting), 0)
 	if err != nil {
 		t.Errorf("unexpected error: %v", err)
 		return
@@ -1510,15 +1500,27 @@ func TestSetxattr(t *testing.T) {
 		t.Errorf("Setxattr incorrect flags: %d != %d", g, e)
 	}
 
-	if g, e := string(got.Xattr), "hello, world"; g != e {
+	if g, e := string(got.Xattr), greeting; g != e {
 		t.Errorf("Setxattr incorrect data: %q != %q", g, e)
 	}
 }
 
+func TestSetxattr(t *testing.T) {
+	testSetxattr(t, 20)
+}
+
+func TestSetxattr64kB(t *testing.T) {
+	testSetxattr(t, 64*1024)
+}
+
+func TestSetxattr16MB(t *testing.T) {
+	testSetxattr(t, 16*1024*1024)
+}
+
 // Test Removexattr
 
 type removexattr struct {
-	file
+	fstestutil.File
 	record.Removexattrs
 }
 
@@ -1546,7 +1548,7 @@ func TestRemovexattr(t *testing.T) {
 // Test default error.
 
 type defaultErrno struct {
-	dir
+	fstestutil.Dir
 }
 
 func (f defaultErrno) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
@@ -1555,7 +1557,7 @@ func (f defaultErrno) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
 
 func TestDefaultErrno(t *testing.T) {
 	t.Parallel()
-	mnt, err := fstestutil.MountedT(t, simpleFS{defaultErrno{}})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{defaultErrno{}})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1580,7 +1582,7 @@ func TestDefaultErrno(t *testing.T) {
 // Test custom error.
 
 type customErrNode struct {
-	dir
+	fstestutil.Dir
 }
 
 type myCustomError struct {
@@ -1601,7 +1603,7 @@ func (f customErrNode) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
 
 func TestCustomErrno(t *testing.T) {
 	t.Parallel()
-	mnt, err := fstestutil.MountedT(t, simpleFS{customErrNode{}})
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{customErrNode{}})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1736,7 +1738,9 @@ func TestMmap(t *testing.T) {
 
 // Test direct Read.
 
-type directRead struct{ file }
+type directRead struct {
+	fstestutil.File
+}
 
 // explicitly not defining Attr and setting Size
 
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse.go b/Godeps/_workspace/src/bazil.org/fuse/fuse.go
index 7ba9af016..5d6ed81df 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/fuse.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/fuse.go
@@ -74,7 +74,8 @@
 //
 // Mount Options
 //
-// XXX
+// Behavior and metadata of the mounted file system can be changed by
+// passing MountOption values to Mount.
 //
 package fuse
 
@@ -120,13 +121,21 @@ type Conn struct {
 // visible until after Conn.Ready is closed. See Conn.MountError for
 // possible errors. Incoming requests on Conn must be served to make
 // progress.
-func Mount(dir string) (*Conn, error) {
-	// TODO(rsc): mount options (...string?)
+func Mount(dir string, options ...MountOption) (*Conn, error) {
+	conf := MountConfig{
+		options: make(map[string]string),
+	}
+	for _, option := range options {
+		if err := option(&conf); err != nil {
+			return nil, err
+		}
+	}
+
 	ready := make(chan struct{}, 1)
 	c := &Conn{
 		Ready: ready,
 	}
-	f, err := mount(dir, ready, &c.MountError)
+	f, err := mount(dir, &conf, ready, &c.MountError)
 	if err != nil {
 		return nil, err
 	}
@@ -170,6 +179,9 @@ type Header struct {
 	Uid  uint32    // user ID of process making request
 	Gid  uint32    // group ID of process making request
 	Pid  uint32    // process ID of process making request
+
+	// for returning to reqPool
+	msg *message
 }
 
 func (h *Header) String() string {
@@ -180,6 +192,20 @@ func (h *Header) Hdr() *Header {
 	return h
 }
 
+func (h *Header) noResponse() {
+	putMessage(h.msg)
+}
+
+func (h *Header) respond(out *outHeader, n uintptr) {
+	h.Conn.respond(out, n)
+	putMessage(h.msg)
+}
+
+func (h *Header) respondData(out *outHeader, n uintptr, data []byte) {
+	h.Conn.respondData(out, n, data)
+	putMessage(h.msg)
+}
+
 // An Error is a FUSE error.
 //
 // Errors messages will be visible in the debug log as part of the
@@ -279,17 +305,48 @@ func (h *Header) RespondError(err Error) {
 	// FUSE uses negative errors!
 	// TODO: File bug report against OSXFUSE: positive error causes kernel panic.
 	out := &outHeader{Error: -int32(errno), Unique: uint64(h.ID)}
-	h.Conn.respond(out, unsafe.Sizeof(*out))
+	h.respond(out, unsafe.Sizeof(*out))
 }
 
 // Maximum file write size we are prepared to receive from the kernel.
-const maxWrite = 128 * 1024
+const maxWrite = 16 * 1024 * 1024
 
 // All requests read from the kernel, without data, are shorter than
 // this.
 var maxRequestSize = syscall.Getpagesize()
 var bufSize = maxRequestSize + maxWrite
 
+// reqPool is a pool of messages.
+//
+// Lifetime of a logical message is from getMessage to putMessage.
+// getMessage is called by ReadRequest. putMessage is called by
+// Conn.ReadRequest, Request.Respond, or Request.RespondError.
+//
+// Messages in the pool are guaranteed to have conn and off zeroed,
+// buf allocated and len==bufSize, and hdr set.
+var reqPool = sync.Pool{
+	New: allocMessage,
+}
+
+func allocMessage() interface{} {
+	m := &message{buf: make([]byte, bufSize)}
+	m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
+	return m
+}
+
+func getMessage(c *Conn) *message {
+	m := reqPool.Get().(*message)
+	m.conn = c
+	return m
+}
+
+func putMessage(m *message) {
+	m.buf = m.buf[:bufSize]
+	m.conn = nil
+	m.off = 0
+	reqPool.Put(m)
+}
+
 // a message represents the bytes of a single FUSE message
 type message struct {
 	conn *Conn
@@ -298,12 +355,6 @@ type message struct {
 	off  int       // offset for reading additional fields
 }
 
-func newMessage(c *Conn) *message {
-	m := &message{conn: c, buf: make([]byte, bufSize)}
-	m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
-	return m
-}
-
 func (m *message) len() uintptr {
 	return uintptr(len(m.buf) - m.off)
 }
@@ -322,7 +373,16 @@ func (m *message) bytes() []byte {
 
 func (m *message) Header() Header {
 	h := m.hdr
-	return Header{Conn: m.conn, ID: RequestID(h.Unique), Node: NodeID(h.Nodeid), Uid: h.Uid, Gid: h.Gid, Pid: h.Pid}
+	return Header{
+		Conn: m.conn,
+		ID:   RequestID(h.Unique),
+		Node: NodeID(h.Nodeid),
+		Uid:  h.Uid,
+		Gid:  h.Gid,
+		Pid:  h.Pid,
+
+		msg: m,
+	}
 }
 
 // fileMode returns a Go os.FileMode from a Unix mode.
@@ -385,9 +445,12 @@ func (c *Conn) fd() int {
 	return int(c.dev.Fd())
 }
 
+// ReadRequest returns the next FUSE request from the kernel.
+//
+// Caller must call either Request.Respond or Request.RespondError in
+// a reasonable time. Caller must not retain Request after that call.
 func (c *Conn) ReadRequest() (Request, error) {
-	// TODO: Some kind of buffer reuse.
-	m := newMessage(c)
+	m := getMessage(c)
 loop:
 	c.rio.RLock()
 	n, err := syscall.Read(c.fd(), m.buf)
@@ -398,14 +461,17 @@ loop:
 		goto loop
 	}
 	if err != nil && err != syscall.ENODEV {
+		putMessage(m)
 		return nil, err
 	}
 	if n <= 0 {
+		putMessage(m)
 		return nil, io.EOF
 	}
 	m.buf = m.buf[:n]
 
 	if n < inHeaderSize {
+		putMessage(m)
 		return nil, errors.New("fuse: message too short")
 	}
 
@@ -421,7 +487,10 @@ loop:
 	}
 
 	if m.hdr.Len != uint32(n) {
-		return nil, fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
+		// prepare error message before returning m to pool
+		err := fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
+		putMessage(m)
+		return nil, err
 	}
 
 	m.off = inHeaderSize
@@ -821,6 +890,7 @@ loop:
 
 corrupt:
 	Debug(malformedMessage{})
+	putMessage(m)
 	return nil, fmt.Errorf("fuse: malformed message")
 
 unrecognized:
@@ -886,6 +956,8 @@ type InitRequest struct {
 	Flags        InitFlags
 }
 
+var _ = Request(&InitRequest{})
+
 func (r *InitRequest) String() string {
 	return fmt.Sprintf("Init [%s] %d.%d ra=%d fl=%v", &r.Header, r.Major, r.Minor, r.MaxReadahead, r.Flags)
 }
@@ -920,7 +992,7 @@ func (r *InitRequest) Respond(resp *InitResponse) {
 	if out.MaxWrite > maxWrite {
 		out.MaxWrite = maxWrite
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A StatfsRequest requests information about the mounted file system.
@@ -928,8 +1000,10 @@ type StatfsRequest struct {
 	Header `json:"-"`
 }
 
+var _ = Request(&StatfsRequest{})
+
 func (r *StatfsRequest) String() string {
-	return fmt.Sprintf("Statfs [%s]\n", &r.Header)
+	return fmt.Sprintf("Statfs [%s]", &r.Header)
 }
 
 // Respond replies to the request with the given response.
@@ -946,7 +1020,7 @@ func (r *StatfsRequest) Respond(resp *StatfsResponse) {
 			Frsize:  resp.Frsize,
 		},
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A StatfsResponse is the response to a StatfsRequest.
@@ -972,6 +1046,8 @@ type AccessRequest struct {
 	Mask   uint32
 }
 
+var _ = Request(&AccessRequest{})
+
 func (r *AccessRequest) String() string {
 	return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
 }
@@ -980,7 +1056,7 @@ func (r *AccessRequest) String() string {
 // To deny access, use RespondError.
 func (r *AccessRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
 // An Attr is the metadata for a single file or directory.
@@ -1057,6 +1133,8 @@ type GetattrRequest struct {
 	Header `json:"-"`
 }
 
+var _ = Request(&GetattrRequest{})
+
 func (r *GetattrRequest) String() string {
 	return fmt.Sprintf("Getattr [%s]", &r.Header)
 }
@@ -1069,7 +1147,7 @@ func (r *GetattrRequest) Respond(resp *GetattrResponse) {
 		AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
 		Attr:          resp.Attr.attr(),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A GetattrResponse is the response to a GetattrRequest.
@@ -1099,6 +1177,8 @@ type GetxattrRequest struct {
 	Position uint32
 }
 
+var _ = Request(&GetxattrRequest{})
+
 func (r *GetxattrRequest) String() string {
 	return fmt.Sprintf("Getxattr [%s] %q %d @%d", &r.Header, r.Name, r.Size, r.Position)
 }
@@ -1110,10 +1190,10 @@ func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
 			outHeader: outHeader{Unique: uint64(r.ID)},
 			Size:      uint32(len(resp.Xattr)),
 		}
-		r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+		r.respond(&out.outHeader, unsafe.Sizeof(*out))
 	} else {
 		out := &outHeader{Unique: uint64(r.ID)}
-		r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Xattr)
+		r.respondData(out, unsafe.Sizeof(*out), resp.Xattr)
 	}
 }
 
@@ -1138,6 +1218,8 @@ type ListxattrRequest struct {
 	Position uint32 // offset within attribute list
 }
 
+var _ = Request(&ListxattrRequest{})
+
 func (r *ListxattrRequest) String() string {
 	return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
 }
@@ -1149,10 +1231,10 @@ func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
 			outHeader: outHeader{Unique: uint64(r.ID)},
 			Size:      uint32(len(resp.Xattr)),
 		}
-		r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+		r.respond(&out.outHeader, unsafe.Sizeof(*out))
 	} else {
 		out := &outHeader{Unique: uint64(r.ID)}
-		r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Xattr)
+		r.respondData(out, unsafe.Sizeof(*out), resp.Xattr)
 	}
 }
 
@@ -1179,6 +1261,8 @@ type RemovexattrRequest struct {
 	Name   string // name of extended attribute
 }
 
+var _ = Request(&RemovexattrRequest{})
+
 func (r *RemovexattrRequest) String() string {
 	return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
 }
@@ -1186,7 +1270,7 @@ func (r *RemovexattrRequest) String() string {
 // Respond replies to the request, indicating that the attribute was removed.
 func (r *RemovexattrRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
 func (r *RemovexattrRequest) RespondError(err Error) {
@@ -1219,14 +1303,24 @@ type SetxattrRequest struct {
 	Xattr []byte
 }
 
+var _ = Request(&SetxattrRequest{})
+
+func trunc(b []byte, max int) ([]byte, string) {
+	if len(b) > max {
+		return b[:max], "..."
+	}
+	return b, ""
+}
+
 func (r *SetxattrRequest) String() string {
-	return fmt.Sprintf("Setxattr [%s] %q %x fl=%v @%#x", &r.Header, r.Name, r.Xattr, r.Flags, r.Position)
+	xattr, tail := trunc(r.Xattr, 16)
+	return fmt.Sprintf("Setxattr [%s] %q %x%s fl=%v @%#x", &r.Header, r.Name, xattr, tail, r.Flags, r.Position)
 }
 
 // Respond replies to the request, indicating that the extended attribute was set.
 func (r *SetxattrRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
 func (r *SetxattrRequest) RespondError(err Error) {
@@ -1240,6 +1334,8 @@ type LookupRequest struct {
 	Name   string
 }
 
+var _ = Request(&LookupRequest{})
+
 func (r *LookupRequest) String() string {
 	return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
 }
@@ -1256,7 +1352,7 @@ func (r *LookupRequest) Respond(resp *LookupResponse) {
 		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
 		Attr:           resp.Attr.attr(),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A LookupResponse is the response to a LookupRequest.
@@ -1279,6 +1375,8 @@ type OpenRequest struct {
 	Flags  OpenFlags
 }
 
+var _ = Request(&OpenRequest{})
+
 func (r *OpenRequest) String() string {
 	return fmt.Sprintf("Open [%s] dir=%v fl=%v", &r.Header, r.Dir, r.Flags)
 }
@@ -1290,7 +1388,7 @@ func (r *OpenRequest) Respond(resp *OpenResponse) {
 		Fh:        uint64(resp.Handle),
 		OpenFlags: uint32(resp.Flags),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A OpenResponse is the response to a OpenRequest.
@@ -1311,6 +1409,8 @@ type CreateRequest struct {
 	Mode   os.FileMode
 }
 
+var _ = Request(&CreateRequest{})
+
 func (r *CreateRequest) String() string {
 	return fmt.Sprintf("Create [%s] %q fl=%v mode=%v", &r.Header, r.Name, r.Flags, r.Mode)
 }
@@ -1331,7 +1431,7 @@ func (r *CreateRequest) Respond(resp *CreateResponse) {
 		Fh:        uint64(resp.Handle),
 		OpenFlags: uint32(resp.Flags),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A CreateResponse is the response to a CreateRequest.
@@ -1352,6 +1452,8 @@ type MkdirRequest struct {
 	Mode   os.FileMode
 }
 
+var _ = Request(&MkdirRequest{})
+
 func (r *MkdirRequest) String() string {
 	return fmt.Sprintf("Mkdir [%s] %q mode=%v", &r.Header, r.Name, r.Mode)
 }
@@ -1368,7 +1470,7 @@ func (r *MkdirRequest) Respond(resp *MkdirResponse) {
 		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
 		Attr:           resp.Attr.attr(),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A MkdirResponse is the response to a MkdirRequest.
@@ -1389,6 +1491,8 @@ type ReadRequest struct {
 	Size   int
 }
 
+var _ = Request(&ReadRequest{})
+
 func (r *ReadRequest) String() string {
 	return fmt.Sprintf("Read [%s] %#x %d @%#x dir=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir)
 }
@@ -1396,7 +1500,7 @@ func (r *ReadRequest) String() string {
 // Respond replies to the request with the given response.
 func (r *ReadRequest) Respond(resp *ReadResponse) {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Data)
+	r.respondData(out, unsafe.Sizeof(*out), resp.Data)
 }
 
 // A ReadResponse is the response to a ReadRequest.
@@ -1429,6 +1533,8 @@ type ReleaseRequest struct {
 	LockOwner    uint32
 }
 
+var _ = Request(&ReleaseRequest{})
+
 func (r *ReleaseRequest) String() string {
 	return fmt.Sprintf("Release [%s] %#x fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
 }
@@ -1436,7 +1542,7 @@ func (r *ReleaseRequest) String() string {
 // Respond replies to the request, indicating that the handle has been released.
 func (r *ReleaseRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
 // A DestroyRequest is sent by the kernel when unmounting the file system.
@@ -1446,6 +1552,8 @@ type DestroyRequest struct {
 	Header `json:"-"`
 }
 
+var _ = Request(&DestroyRequest{})
+
 func (r *DestroyRequest) String() string {
 	return fmt.Sprintf("Destroy [%s]", &r.Header)
 }
@@ -1453,7 +1561,7 @@ func (r *DestroyRequest) String() string {
 // Respond replies to the request.
 func (r *DestroyRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
 // A ForgetRequest is sent by the kernel when forgetting about r.Node
@@ -1463,6 +1571,8 @@ type ForgetRequest struct {
 	N      uint64
 }
 
+var _ = Request(&ForgetRequest{})
+
 func (r *ForgetRequest) String() string {
 	return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
 }
@@ -1470,6 +1580,7 @@ func (r *ForgetRequest) String() string {
 // Respond replies to the request, indicating that the forgetfulness has been recorded.
 func (r *ForgetRequest) Respond() {
 	// Don't reply to forget messages.
+	r.noResponse()
 }
 
 // A Dirent represents a single directory entry.
@@ -1562,6 +1673,8 @@ type WriteRequest struct {
 	Flags  WriteFlags
 }
 
+var _ = Request(&WriteRequest{})
+
 func (r *WriteRequest) String() string {
 	return fmt.Sprintf("Write [%s] %#x %d @%d fl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags)
 }
@@ -1589,7 +1702,7 @@ func (r *WriteRequest) Respond(resp *WriteResponse) {
 		outHeader: outHeader{Unique: uint64(r.ID)},
 		Size:      uint32(resp.Size),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A WriteResponse replies to a write indicating how many bytes were written.
@@ -1621,6 +1734,8 @@ type SetattrRequest struct {
 	Flags    uint32 // see chflags(2)
 }
 
+var _ = Request(&SetattrRequest{})
+
 func (r *SetattrRequest) String() string {
 	var buf bytes.Buffer
 	fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
@@ -1680,7 +1795,7 @@ func (r *SetattrRequest) Respond(resp *SetattrResponse) {
 		AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
 		Attr:          resp.Attr.attr(),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A SetattrResponse is the response to a SetattrRequest.
@@ -1703,6 +1818,8 @@ type FlushRequest struct {
 	LockOwner uint64
 }
 
+var _ = Request(&FlushRequest{})
+
 func (r *FlushRequest) String() string {
 	return fmt.Sprintf("Flush [%s] %#x fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner)
 }
@@ -1710,16 +1827,19 @@ func (r *FlushRequest) String() string {
 // Respond replies to the request, indicating that the flush succeeded.
 func (r *FlushRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
-// A RemoveRequest asks to remove a file or directory.
+// A RemoveRequest asks to remove a file or directory from the
+// directory r.Node.
 type RemoveRequest struct {
 	Header `json:"-"`
-	Name   string // name of extended attribute
+	Name   string // name of the entry to remove
 	Dir    bool   // is this rmdir?
 }
 
+var _ = Request(&RemoveRequest{})
+
 func (r *RemoveRequest) String() string {
 	return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
 }
@@ -1727,7 +1847,7 @@ func (r *RemoveRequest) String() string {
 // Respond replies to the request, indicating that the file was removed.
 func (r *RemoveRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
 // A SymlinkRequest is a request to create a symlink making NewName point to Target.
@@ -1736,6 +1856,8 @@ type SymlinkRequest struct {
 	NewName, Target string
 }
 
+var _ = Request(&SymlinkRequest{})
+
 func (r *SymlinkRequest) String() string {
 	return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
 }
@@ -1752,7 +1874,7 @@ func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
 		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
 		Attr:           resp.Attr.attr(),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A SymlinkResponse is the response to a SymlinkRequest.
@@ -1765,13 +1887,15 @@ type ReadlinkRequest struct {
 	Header `json:"-"`
 }
 
+var _ = Request(&ReadlinkRequest{})
+
 func (r *ReadlinkRequest) String() string {
 	return fmt.Sprintf("Readlink [%s]", &r.Header)
 }
 
 func (r *ReadlinkRequest) Respond(target string) {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respondData(out, unsafe.Sizeof(*out), []byte(target))
+	r.respondData(out, unsafe.Sizeof(*out), []byte(target))
 }
 
 // A LinkRequest is a request to create a hard link.
@@ -1781,6 +1905,8 @@ type LinkRequest struct {
 	NewName string
 }
 
+var _ = Request(&LinkRequest{})
+
 func (r *LinkRequest) String() string {
 	return fmt.Sprintf("Link [%s] node %d to %q", &r.Header, r.OldNode, r.NewName)
 }
@@ -1796,7 +1922,7 @@ func (r *LinkRequest) Respond(resp *LookupResponse) {
 		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
 		Attr:           resp.Attr.attr(),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A RenameRequest is a request to rename a file.
@@ -1806,13 +1932,15 @@ type RenameRequest struct {
 	OldName, NewName string
 }
 
+var _ = Request(&RenameRequest{})
+
 func (r *RenameRequest) String() string {
 	return fmt.Sprintf("Rename [%s] from %q to dirnode %d %q", &r.Header, r.OldName, r.NewDir, r.NewName)
 }
 
 func (r *RenameRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
 type MknodRequest struct {
@@ -1822,6 +1950,8 @@ type MknodRequest struct {
 	Rdev   uint32
 }
 
+var _ = Request(&MknodRequest{})
+
 func (r *MknodRequest) String() string {
 	return fmt.Sprintf("Mknod [%s] Name %q mode %v rdev %d", &r.Header, r.Name, r.Mode, r.Rdev)
 }
@@ -1837,7 +1967,7 @@ func (r *MknodRequest) Respond(resp *LookupResponse) {
 		AttrValidNsec:  uint32(resp.AttrValid % time.Second / time.Nanosecond),
 		Attr:           resp.Attr.attr(),
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 type FsyncRequest struct {
@@ -1848,13 +1978,15 @@ type FsyncRequest struct {
 	Dir   bool
 }
 
+var _ = Request(&FsyncRequest{})
+
 func (r *FsyncRequest) String() string {
 	return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
 }
 
 func (r *FsyncRequest) Respond() {
 	out := &outHeader{Unique: uint64(r.ID)}
-	r.Conn.respond(out, unsafe.Sizeof(*out))
+	r.respond(out, unsafe.Sizeof(*out))
 }
 
 // An InterruptRequest is a request to interrupt another pending request. The
@@ -1864,8 +1996,11 @@ type InterruptRequest struct {
 	IntrID RequestID // ID of the request to be interrupt.
 }
 
+var _ = Request(&InterruptRequest{})
+
 func (r *InterruptRequest) Respond() {
 	// nothing to do here
+	r.noResponse()
 }
 
 func (r *InterruptRequest) String() string {
@@ -1880,6 +2015,8 @@ type XXXRequest struct {
 	xxx
 }
 
+var _ = Request(&XXXRequest{})
+
 func (r *XXXRequest) String() string {
 	return fmt.Sprintf("XXX [%s] xxx", &r.Header)
 }
@@ -1890,7 +2027,7 @@ func (r *XXXRequest) Respond(resp *XXXResponse) {
 		outHeader: outHeader{Unique: uint64(r.ID)},
 		xxx,
 	}
-	r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+	r.respond(&out.outHeader, unsafe.Sizeof(*out))
 }
 
 // A XXXResponse is the response to a XXXRequest.
diff --git a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go b/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go
index a8ec12ca4..5fba53dbf 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/fuse_kernel.go
@@ -513,7 +513,7 @@ type writeOut struct {
 	Padding uint32
 }
 
-// The WriteFlags are returned in the WriteResponse.
+// The WriteFlags are passed in WriteRequest.
 type WriteFlags uint32
 
 func (fl WriteFlags) String() string {
diff --git a/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go b/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go
index 68f7c9ab1..7e74f9fed 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go
@@ -28,7 +28,13 @@ func main() {
 	}
 	mountpoint := flag.Arg(0)
 
-	c, err := fuse.Mount(mountpoint)
+	c, err := fuse.Mount(
+		mountpoint,
+		fuse.FSName("helloworld"),
+		fuse.Subtype("hellofs"),
+		fuse.LocalVolume(),
+		fuse.VolumeName("Hello world!"),
+	)
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/Godeps/_workspace/src/bazil.org/fuse/hellofs/hellofs b/Godeps/_workspace/src/bazil.org/fuse/hellofs/hellofs
new file mode 100644
index 000000000..641c0ef1c
Binary files /dev/null and b/Godeps/_workspace/src/bazil.org/fuse/hellofs/hellofs differ
diff --git a/Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go
index d5ab2960a..6253ce82d 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/mount_darwin.go
@@ -3,9 +3,11 @@ package fuse
 import (
 	"bytes"
 	"errors"
+	"fmt"
 	"os"
 	"os/exec"
 	"strconv"
+	"strings"
 	"syscall"
 )
 
@@ -50,15 +52,22 @@ func openOSXFUSEDev() (*os.File, error) {
 	}
 }
 
-func callMount(dir string, f *os.File, ready chan<- struct{}, errp *error) error {
+func callMount(dir string, conf *MountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
 	bin := "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs"
+
+	for k, v := range conf.options {
+		if strings.Contains(k, ",") || strings.Contains(v, ",") {
+			// Silly limitation but the mount helper does not
+			// understand any escaping. See TestMountOptionCommaError.
+			return fmt.Errorf("mount options cannot contain commas on OS X: %q=%q", k, v)
+		}
+	}
 	cmd := exec.Command(
 		bin,
+		"-o", conf.getOptions(),
 		// Tell osxfuse-kext how large our buffer is. It must split
 		// writes larger than this into multiple writes.
 		//
-		// TODO add buffer reuse, bump this up significantly
-		//
 		// OSXFUSE seems to ignore InitResponse.MaxWrite, and uses
 		// this instead.
 		"-o", "iosize="+strconv.FormatUint(maxWrite, 10),
@@ -95,7 +104,7 @@ func callMount(dir string, f *os.File, ready chan<- struct{}, errp *error) error
 	return err
 }
 
-func mount(dir string, ready chan<- struct{}, errp *error) (*os.File, error) {
+func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
 	f, err := openOSXFUSEDev()
 	if err == errNotLoaded {
 		err = loadOSXFUSE()
@@ -108,7 +117,7 @@ func mount(dir string, ready chan<- struct{}, errp *error) (*os.File, error) {
 	if err != nil {
 		return nil, err
 	}
-	err = callMount(dir, f, ready, errp)
+	err = callMount(dir, conf, f, ready, errp)
 	if err != nil {
 		f.Close()
 		return nil, err
diff --git a/Godeps/_workspace/src/bazil.org/fuse/mount_linux.go b/Godeps/_workspace/src/bazil.org/fuse/mount_linux.go
index ef95d093d..0748c0a5d 100644
--- a/Godeps/_workspace/src/bazil.org/fuse/mount_linux.go
+++ b/Godeps/_workspace/src/bazil.org/fuse/mount_linux.go
@@ -8,7 +8,7 @@ import (
 	"syscall"
 )
 
-func mount(dir string, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
+func mount(dir string, conf *MountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
 	// linux mount is never delayed
 	close(ready)
 
@@ -19,7 +19,12 @@ func mount(dir string, ready chan<- struct{}, errp *error) (fusefd *os.File, err
 	defer syscall.Close(fds[0])
 	defer syscall.Close(fds[1])
 
-	cmd := exec.Command("fusermount", "--", dir)
+	cmd := exec.Command(
+		"fusermount",
+		"-o", conf.getOptions(),
+		"--",
+		dir,
+	)
 	cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
 
 	writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
diff --git a/Godeps/_workspace/src/bazil.org/fuse/options.go b/Godeps/_workspace/src/bazil.org/fuse/options.go
new file mode 100644
index 000000000..643a9492d
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/options.go
@@ -0,0 +1,100 @@
+package fuse
+
+import (
+	"errors"
+	"strings"
+)
+
+// MountConfig holds the configuration for a mount operation.
+// Use it by passing MountOption values to Mount.
+type MountConfig struct {
+	options map[string]string
+}
+
+func escapeComma(s string) string {
+	s = strings.Replace(s, `\`, `\\`, -1)
+	s = strings.Replace(s, `,`, `\,`, -1)
+	return s
+}
+
+// getOptions makes a string of options suitable for passing to FUSE
+// mount flag `-o`. Returns an empty string if no options were set.
+// Any platform specific adjustments should happen before the call.
+func (m *MountConfig) getOptions() string {
+	var opts []string
+	for k, v := range m.options {
+		k = escapeComma(k)
+		if v != "" {
+			k += "=" + escapeComma(v)
+		}
+		opts = append(opts, k)
+	}
+	return strings.Join(opts, ",")
+}
+
+// MountOption is passed to Mount to change the behavior of the mount.
+type MountOption func(*MountConfig) error
+
+// FSName sets the file system name (also called source) that is
+// visible in the list of mounted file systems.
+func FSName(name string) MountOption {
+	return func(conf *MountConfig) error {
+		conf.options["fsname"] = name
+		return nil
+	}
+}
+
+// Subtype sets the subtype of the mount. The main type is always
+// `fuse`. The type in a list of mounted file systems will look like
+// `fuse.foo`.
+//
+// OS X ignores this option.
+func Subtype(fstype string) MountOption {
+	return func(conf *MountConfig) error {
+		conf.options["subtype"] = fstype
+		return nil
+	}
+}
+
+// LocalVolume sets the volume to be local (instead of network),
+// changing the behavior of Finder, Spotlight, and such.
+//
+// OS X only. Others ignore this option.
+func LocalVolume() MountOption {
+	return localVolume
+}
+
+// VolumeName sets the volume name shown in Finder.
+//
+// OS X only. Others ignore this option.
+func VolumeName(name string) MountOption {
+	return volumeName(name)
+}
+
+var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOther and AllowRoot")
+
+// AllowOther allows other users to access the file system.
+//
+// Only one of AllowOther or AllowRoot can be used.
+func AllowOther() MountOption {
+	return func(conf *MountConfig) error {
+		if _, ok := conf.options["allow_root"]; ok {
+			return ErrCannotCombineAllowOtherAndAllowRoot
+		}
+		conf.options["allow_other"] = ""
+		return nil
+	}
+}
+
+// AllowRoot allows other users to access the file system.
+//
+// Only one of AllowOther or AllowRoot can be used.
+func AllowRoot() MountOption {
+	return func(conf *MountConfig) error {
+		if _, ok := conf.options["allow_other"]; ok {
+			return ErrCannotCombineAllowOtherAndAllowRoot
+		}
+		conf.options["allow_root"] = ""
+		return nil
+	}
+}
diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_darwin.go b/Godeps/_workspace/src/bazil.org/fuse/options_darwin.go
new file mode 100644
index 000000000..15aedbcfc
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/options_darwin.go
@@ -0,0 +1,13 @@
+package fuse
+
+func localVolume(conf *MountConfig) error {
+	conf.options["local"] = ""
+	return nil
+}
+
+func volumeName(name string) MountOption {
+	return func(conf *MountConfig) error {
+		conf.options["volname"] = name
+		return nil
+	}
+}
diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_darwin_test.go b/Godeps/_workspace/src/bazil.org/fuse/options_darwin_test.go
new file mode 100644
index 000000000..be031f606
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/options_darwin_test.go
@@ -0,0 +1,27 @@
+package fuse_test
+
+import (
+	"testing"
+
+	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
+	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
+)
+
+func TestMountOptionCommaError(t *testing.T) {
+	t.Parallel()
+	// this test is not tied to FSName, but needs just some option
+	// with string content
+	var name = "FuseTest,Marker"
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
+		fuse.FSName(name),
+	)
+	switch {
+	case err == nil:
+		mnt.Close()
+		t.Fatal("expected an error about commas")
+	case err.Error() == `mount options cannot contain commas on OS X: "fsname"="FuseTest,Marker"`:
+		// all good
+	default:
+		t.Fatalf("expected an error about commas, got: %v", err)
+	}
+}
diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_linux.go b/Godeps/_workspace/src/bazil.org/fuse/options_linux.go
new file mode 100644
index 000000000..69dd406ba
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/options_linux.go
@@ -0,0 +1,13 @@
+package fuse
+
+func dummyOption(conf *MountConfig) error {
+	return nil
+}
+
+func localVolume(conf *MountConfig) error {
+	return nil
+}
+
+func volumeName(name string) MountOption {
+	return dummyOption
+}
diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_test.go b/Godeps/_workspace/src/bazil.org/fuse/options_test.go
new file mode 100644
index 000000000..91d615d93
--- /dev/null
+++ b/Godeps/_workspace/src/bazil.org/fuse/options_test.go
@@ -0,0 +1,141 @@
+package fuse_test
+
+import (
+	"runtime"
+	"testing"
+
+	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
+	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
+)
+
+func init() {
+	fstestutil.DebugByDefault()
+}
+
+func TestMountOptionFSName(t *testing.T) {
+	t.Parallel()
+	const name = "FuseTestMarker"
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
+		fuse.FSName(name),
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer mnt.Close()
+
+	info, err := fstestutil.GetMountInfo(mnt.Dir)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, e := info.FSName, name; g != e {
+		t.Errorf("wrong FSName: %q != %q", g, e)
+	}
+}
+
+func testMountOptionFSNameEvil(t *testing.T, evil string) {
+	t.Parallel()
+	var name = "FuseTest" + evil + "Marker"
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
+		fuse.FSName(name),
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer mnt.Close()
+
+	info, err := fstestutil.GetMountInfo(mnt.Dir)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, e := info.FSName, name; g != e {
+		t.Errorf("wrong FSName: %q != %q", g, e)
+	}
+}
+
+func TestMountOptionFSNameEvilComma(t *testing.T) {
+	if runtime.GOOS == "darwin" {
+		// see TestMountOptionCommaError for a test that enforces we
+		// at least give a nice error, instead of corrupting the mount
+		// options
+		t.Skip("TODO: OS X gets this wrong, commas in mount options cannot be escaped at all")
+	}
+	testMountOptionFSNameEvil(t, ",")
+}
+
+func TestMountOptionFSNameEvilSpace(t *testing.T) {
+	testMountOptionFSNameEvil(t, " ")
+}
+
+func TestMountOptionFSNameEvilTab(t *testing.T) {
+	testMountOptionFSNameEvil(t, "\t")
+}
+
+func TestMountOptionFSNameEvilNewline(t *testing.T) {
+	testMountOptionFSNameEvil(t, "\n")
+}
+
+func TestMountOptionFSNameEvilBackslash(t *testing.T) {
+	testMountOptionFSNameEvil(t, `\`)
+}
+
+func TestMountOptionFSNameEvilBackslashDouble(t *testing.T) {
+	// catch double-unescaping, if it were to happen
+	testMountOptionFSNameEvil(t, `\\`)
+}
+
+func TestMountOptionSubtype(t *testing.T) {
+	if runtime.GOOS == "darwin" {
+		t.Skip("OS X does not support Subtype")
+	}
+	t.Parallel()
+	const name = "FuseTestMarker"
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
+		fuse.Subtype(name),
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer mnt.Close()
+
+	info, err := fstestutil.GetMountInfo(mnt.Dir)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if g, e := info.Type, "fuse."+name; g != e {
+		t.Errorf("wrong Subtype: %q != %q", g, e)
+	}
+}
+
+// TODO test LocalVolume
+
+// TODO test AllowOther; hard because needs system-level authorization
+
+func TestMountOptionAllowOtherThenAllowRoot(t *testing.T) {
+	t.Parallel()
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
+		fuse.AllowOther(),
+		fuse.AllowRoot(),
+	)
+	if err == nil {
+		mnt.Close()
+	}
+	if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e {
+		t.Fatalf("wrong error: %v != %v", g, e)
+	}
+}
+
+// TODO test AllowRoot; hard because needs system-level authorization
+
+func TestMountOptionAllowRootThenAllowOther(t *testing.T) {
+	t.Parallel()
+	mnt, err := fstestutil.MountedT(t, fstestutil.SimpleFS{fstestutil.Dir{}},
+		fuse.AllowRoot(),
+		fuse.AllowOther(),
+	)
+	if err == nil {
+		mnt.Close()
+	}
+	if g, e := err, fuse.ErrCannotCombineAllowOtherAndAllowRoot; g != e {
+		t.Fatalf("wrong error: %v != %v", g, e)
+	}
+}