diff --git a/fuse/fsinode.go b/fuse/fsinode.go
index 7609b201c3d2af044713d2ad5d38ecda82123783..997d60e67dc0dda3418b85c426020da8dd19a7f3 100644
--- a/fuse/fsinode.go
+++ b/fuse/fsinode.go
@@ -92,6 +92,10 @@ func (me *fsInode) SetInode(node *inode) {
 	me.inode = node
 }
 
+func (me *fsInode) Inode() *inode {
+	return me.inode
+}
+
 ////////////////////////////////////////////////////////////////
 
 func (me *fsInode) Readlink(c *Context) ([]byte, Status) {
@@ -188,8 +192,19 @@ func (me *fsInode) Rename(oldName string, newParent *fsInode, newName string, co
 	return me.fs.Rename(oldPath, newPath, context)
 }
 
-func (me *fsInode) Link(name string, existing *fsInode, context *Context) (code Status) {
-	return me.fs.Link(existing.GetPath(), filepath.Join(me.GetPath(), name), context)
+func (me *fsInode) Link(name string, existing *fsInode, context *Context) (fi *os.FileInfo, newNode *fsInode, code Status) {
+	newPath := filepath.Join(me.GetPath(), name)
+	oldPath := existing.GetPath()
+	code = me.fs.Link(oldPath, newPath, context)
+	if code.Ok() {
+		oldFi, _ := me.fs.GetAttr(oldPath, context)
+		fi, _ = me.fs.GetAttr(newPath, context)
+		if oldFi != nil && fi != nil && oldFi.Ino != 0 && oldFi.Ino == fi.Ino {
+			return fi, existing, OK
+		}
+		newNode = me.createChild(name)
+	}
+	return 
 }
 
 func (me *fsInode) Create(name string, flags uint32, mode uint32, context *Context) (file File, fi *os.FileInfo, newNode *fsInode, code Status) {
diff --git a/fuse/fsmount.go b/fuse/fsmount.go
index 3902b4c315787f279d5edd2ed6afde54306db74d..e493d5652c38684d2535287e93bd9bdb4ae22fe0 100644
--- a/fuse/fsmount.go
+++ b/fuse/fsmount.go
@@ -47,17 +47,17 @@ func (me *fileSystemMount) setOwner(attr *Attr) {
 		attr.Owner = *me.options.Owner
 	}
 }
-func (me *fileSystemMount) fileInfoToEntry(fi *os.FileInfo, out *EntryOut) {
+func (me *fileSystemMount) fileInfoToEntry(fi *os.FileInfo) (out *EntryOut) {
+	out = &EntryOut{}
 	SplitNs(me.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
 	SplitNs(me.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
+	CopyFileInfo(fi, &out.Attr)
+	me.setOwner(&out.Attr)
 	if !fi.IsDirectory() {
 		fi.Nlink = 1
 	}
-
-	CopyFileInfo(fi, &out.Attr)
-	me.setOwner(&out.Attr)
+	return out
 }
-
 	
 func (me *fileSystemMount) fileInfoToAttr(fi *os.FileInfo, out *AttrOut) {
 	CopyFileInfo(fi, &out.Attr)
diff --git a/fuse/fsops.go b/fuse/fsops.go
index 6e654f0de1696c5f4991d96feeab8afce5774b65..4fcea9145472f0150c764121cb98df08a59d1e2c 100644
--- a/fuse/fsops.go
+++ b/fuse/fsops.go
@@ -33,11 +33,11 @@ func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, looku
 	mount.treeLock.Lock()
 	defer mount.treeLock.Unlock()
 	mount.mountInode.lookupCount += lookupCount
-	out = &EntryOut{
-		NodeId:     mount.mountInode.nodeId,
-		Generation: 1, // where to get the generation?
-	}
-	mount.fileInfoToEntry(fi, out)
+	out = mount.fileInfoToEntry(fi)
+	out.NodeId = mount.mountInode.nodeId
+
+	// We don't do NFS.
+	out.Generation = 1
 	return out, OK, mount.mountInode
 }
 
@@ -60,11 +60,9 @@ func (me *FileSystemConnector) internalLookup(parent *inode, name string, lookup
 	}
 
 	if child != nil && code.Ok() {
-		out = &EntryOut{
-			NodeId:     child.nodeId,
-			Generation: 1, // where to get the generation?
-		}
-		parent.mount.fileInfoToEntry(fi, out)	
+		out = parent.mount.fileInfoToEntry(fi)	
+		out.NodeId = child.nodeId
+		out.Generation = 1
 		return out, OK, child
 	}
 	
@@ -203,8 +201,7 @@ func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name stri
 
 func (me *FileSystemConnector) createChild(parent *inode, name string, fi *os.FileInfo, fsi *fsInode) (out *EntryOut, child *inode) {
 	child = parent.createChild(name, fi.IsDirectory(), fsi, me)
-	out = &EntryOut{}
-	parent.mount.fileInfoToEntry(fi, out)
+	out = parent.mount.fileInfoToEntry(fi)
 	out.Ino = child.nodeId
 	out.NodeId = child.nodeId
 	return out, child
@@ -270,20 +267,26 @@ func (me *FileSystemConnector) Rename(header *InHeader, input *RenameIn, oldName
 	return code
 }
 
-func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, filename string) (out *EntryOut, code Status) {
+func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, name string) (out *EntryOut, code Status) {
 	existing := me.getInodeData(input.Oldnodeid)
 	parent := me.getInodeData(header.NodeId)
 
 	if existing.mount != parent.mount {
 		return nil, EXDEV
 	}
-
-	code = parent.fsInode.Link(filename, existing.fsInode, &header.Context)
+	
+	fi, fsInode, code := parent.fsInode.Link(name, existing.fsInode, &header.Context)
 	if !code.Ok() {
 		return nil, code
 	}
-	// TODO - revise this for real hardlinks?
-	out, code, _ = me.internalLookup(parent, filename, 1, &header.Context)
+
+	if fsInode.Inode() == nil {
+		out, _ = me.createChild(parent, name, fi, fsInode)
+	} else {
+		out = parent.mount.fileInfoToEntry(fi)
+		out.Ino = fsInode.Inode().nodeId
+		out.NodeId = out.Ino
+	}
 	return out, code
 }
 
diff --git a/fuse/loopback_test.go b/fuse/loopback_test.go
index ee6163eb1a6913286a7f265a7f0adcdc118438db..b4cb79c30fde64d59efafbe8cf2878c2358e55a3 100644
--- a/fuse/loopback_test.go
+++ b/fuse/loopback_test.go
@@ -243,11 +243,17 @@ func TestLink(t *testing.T) {
 	err = os.Link(me.mountFile, mountSubfile)
 	CheckSuccess(err)
 
+	subfi, err := os.Lstat(mountSubfile)
+	CheckSuccess(err)
 	fi, err := os.Lstat(me.origFile)
+	CheckSuccess(err)
+
 	if fi.Nlink != 2 {
 		t.Errorf("Expect 2 links: %v", fi)
 	}
-
+	if fi.Ino != subfi.Ino {
+		t.Errorf("Link succeeded, but inode numbers different: %v %v", fi.Ino, subfi.Ino)
+	}
 	f, err := os.Open(mountSubfile)
 
 	var buf [1024]byte