Commit 68f70527 authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher Committed by Han-Wen Nienhuys

fs: addNewChild(): handle concurrent FORGETs

As seen in debug logs like shown below, concurrent
FORGETs and inode number reuse could make use give
an Inode to the kernel that has already been deleted
from the nodes[] map.

With this change, I can no langer trigger a panic
in xfstests generic/007.

Fixes https://github.com/hanwen/go-fuse/issues/324

Nodes that appear to change type are not handled yet
(actually caused by inode number reuse), but this is
a separate problem.

Debug log:

  17:09:07.651735 rx 84444: CREATE i13632136 {0100644 [WRONLY,TRUNC,CREAT,0x8000] (022)} ["XXXXXXXXXXXX.38"] 16b
  17:09:07.651790 tx 84444:     OK, {i13632483 g1 {M0100644 SZ=0 L=1 0:0 B0*4096 i0:13632483 A 1572192547.650470 M 1572192547.650470 C 1572192547.650470} &{7 0 0}}
  [...]
  17:09:07.684439 rx 87988: CREATE i13632119 {0100644 [CREAT,TRUNC,WRONLY,0x8000] (022)} ["XXXXXXXXXXXX.37"] 16b
  [...]
  17:09:07.684472 rx 87992: FORGET i13632483 {Nlookup=1}
  17:09:07.684483 tx 87988:     OK, {i13632483 g1 {M0100644 SZ=0 L=1 0:0 B0*4096 i0:13632483 A 1572192547.683470 M 1572192547.683470 C 1572192547.683470} &{8 0 0}}
  [...]
  17:09:07.684557 rx 88006: FLUSH i13632483 {Fh 8}
  17:09:07.684560 unknown node 13632483
  17:09:07.684564 tx 88002:     OK,  "XXXXXXXXXXXX.830"
  panic: unknown node 13632483

Change-Id: Ibb1a7a6a459d2e4133a4e512e0816e8ed950a8d7
parent 713e99eb
...@@ -123,7 +123,13 @@ func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, file F ...@@ -123,7 +123,13 @@ func (b *rawBridge) addNewChild(parent *Inode, name string, child *Inode, file F
parent.setEntry(name, child) parent.setEntry(name, child)
b.mu.Lock() b.mu.Lock()
// Due to concurrent FORGETs, lookupCount may have dropped to zero.
// This means it MAY have been deleted from nodes[] already. Add it back.
if child.lookupCount == 0 {
b.nodes[child.stableAttr.Ino] = child
}
child.lookupCount++ child.lookupCount++
child.changeCounter++
var fh uint32 var fh uint32
if file != nil { if file != nil {
......
...@@ -64,9 +64,8 @@ type Inode struct { ...@@ -64,9 +64,8 @@ type Inode struct {
// Following data is mutable. // Following data is mutable.
// protected by bridge.mu
// file handles. // file handles.
// protected by bridge.mu
openFiles []uint32 openFiles []uint32
// mu protects the following mutable fields. When locking // mu protects the following mutable fields. When locking
...@@ -78,6 +77,7 @@ type Inode struct { ...@@ -78,6 +77,7 @@ type Inode struct {
// from the tree, even if there are no live references. This // from the tree, even if there are no live references. This
// must be set on creation, and can only be changed to false // must be set on creation, and can only be changed to false
// by calling removeRef. // by calling removeRef.
// When you change this, you MUST increment changeCounter.
persistent bool persistent bool
// changeCounter increments every time the mutable state // changeCounter increments every time the mutable state
...@@ -90,9 +90,15 @@ type Inode struct { ...@@ -90,9 +90,15 @@ type Inode struct {
changeCounter uint32 changeCounter uint32
// Number of kernel refs to this node. // Number of kernel refs to this node.
// When you change this, you MUST increment changeCounter.
lookupCount uint64 lookupCount uint64
// Children of this Inode.
// When you change this, you MUST increment changeCounter.
children map[string]*Inode children map[string]*Inode
// Parents of this Inode. Can be more than one due to hard links.
// When you change this, you MUST increment changeCounter.
parents map[parentData]struct{} parents map[parentData]struct{}
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment