Commit 7090b027 authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher Committed by Han-Wen Nienhuys

fs: wait out apparent inode type change

When a inode is deleted and recreated, the inode number may
be reused, and it may appear that it has changed type.

A simple solution is to wait for the FORGET that *always*
follows the deletion. This is what this patch does.

Makes fsstress happy (tested with fsstress-loopback.bash from
gocryptfs, which is similar to xfstests generic/013).

Also fixes the test that was introduced in the last commit
(TestTypeChange).

fsstress-loopback.bash before:

    ~/go/src/github.com/rfjakob/gocryptfs/tests/stress_tests$ ./fsstress-loopback.bash
    Recompile go-fuse loopback
    Waiting for mount:  ok
    Starting fsstress loop
    1
        fsstress.1 seed = 1572931176
        fsstress.2 seed = 1572919573
        fsstress.3 seed = 1573005097
        rm
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.2/p4/d1XXXX': Is a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.2/p6/d0/d44XXXXXXXXXXXX/d4cXXXX': Is a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.3/p1/d11/d124/d12f/d154/d15a/d143/df1/d100/d135/d123/d3a': Is a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.3/p1/d11/f22': Not a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.3/p3/d0/d7e/d4b/d102/d157/d134/d12f/d14b/d17a/d130': Is a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.3/p3/d0/d7e/d4b/d102/d157/d158/df2/ff5': Not a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.3/p3/d0/d1c': Is a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.3/p0/d0/d4': Is a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.3/p2/d6/dfd/da6/df2/d124/dea/d100/d120/d131/d13e/d13b/d149/d13a/f9c': Not a directory
    rm: cannot remove '/var/tmp/fsstress-loopback.bash.qgK.mnt/fsstress.3/p2/d6/dfd/da6/df2/d124/dea/dd5/dfa/d127/d129/d14a/d117/d14c/d82': Is a directory
    ./fsstress-loopback.bash: line 1: kill: %1: no such job

After (with typechangeDebug = true):

    $ ./fsstress-loopback.bash
    Recompile go-fuse loopback
    Waiting for mount:  ok
    Starting fsstress loop
    1
        fsstress.1 seed = 1574198874
        fsstress.2 seed = 1574016238
    17:51:25.770396 Ino:13634604 typechange 0x8000 -> 0xa000, sleep=0s
    17:51:25.890382 Ino:13899580 typechange 0xa000 -> 0x8000, sleep=0s
    17:51:25.890400 Ino:13899580 typechange 0xa000 -> 0x8000, sleep=1µs
    17:51:25.890412 Ino:13899580 typechange 0xa000 -> 0x8000, sleep=1.41µs
        fsstress.3 seed = 1574847533
    17:51:27.472057 Ino:14158985 typechange 0x4000 -> 0x8000, sleep=0s
    17:51:27.472070 Ino:14158985 typechange 0x4000 -> 0x8000, sleep=1µs
    17:51:27.472304 Ino:14158985 typechange 0x8000 -> 0x4000, sleep=0s
    17:51:27.478628 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=0s
    17:51:27.478640 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=1µs
    17:51:27.478700 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=1.051µs
    17:51:27.478747 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=1.817µs
    17:51:27.478796 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=3.18µs
    17:51:27.478840 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=5.718µs
    17:51:27.478884 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=8.396µs
    17:51:27.478976 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=10.784µs
    17:51:27.479024 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=13.017µs
    17:51:27.479067 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=16.065µs
    17:51:27.479108 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=19.767µs
    17:51:27.479145 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=27.427µs
    17:51:27.479240 Ino:14159000 typechange 0x8000 -> 0x4000, sleep=36.272µs
    17:51:27.500756 Ino:14291431 typechange 0x4000 -> 0x8000, sleep=0s
    17:51:27.500770 Ino:14291431 typechange 0x4000 -> 0x8000, sleep=1µs
    17:51:27.500779 Ino:14291431 typechange 0x4000 -> 0x8000, sleep=1.873µs
    17:51:27.521194 Ino:14291506 typechange 0x4000 -> 0x8000, sleep=0s
    17:51:27.521207 Ino:14291506 typechange 0x4000 -> 0x8000, sleep=1µs
        rm
    2
        fsstress.1 seed = 1574600636
        fsstress.2 seed = 1574203490
    17:51:29.009666 Ino:12209562 typechange 0x4000 -> 0xa000, sleep=0s
    17:51:29.010068 Ino:12209562 typechange 0x4000 -> 0xa000, sleep=1µs
    17:51:29.010078 Ino:12209562 typechange 0x4000 -> 0xa000, sleep=1.79µs
    17:51:29.010179 Ino:12209562 typechange 0x4000 -> 0xa000, sleep=3.331µs
    17:51:29.010255 Ino:12209562 typechange 0x4000 -> 0xa000, sleep=4.537µs
    17:51:29.010364 Ino:12209562 typechange 0x4000 -> 0xa000, sleep=8.354µs
    17:51:29.010416 Ino:12209562 typechange 0x4000 -> 0xa000, sleep=8.897µs
        fsstress.3 seed = 1573917850
    17:51:33.623359 Ino:14291439 typechange 0x8000 -> 0x4000, sleep=0s
    17:51:33.623378 Ino:14291439 typechange 0x8000 -> 0x4000, sleep=1µs
    17:51:33.623392 Ino:14291439 typechange 0x8000 -> 0x4000, sleep=1.378µs
    17:51:33.644130 Ino:14291494 typechange 0x8000 -> 0x4000, sleep=0s
    17:51:33.644151 Ino:14291494 typechange 0x8000 -> 0x4000, sleep=1µs
    17:51:33.644159 Ino:14291494 typechange 0x8000 -> 0x4000, sleep=1.072µs
    17:51:33.654370 Ino:14291501 typechange 0x8000 -> 0x4000, sleep=0s
    17:51:33.654384 Ino:14291501 typechange 0x8000 -> 0x4000, sleep=1µs
    17:51:33.654393 Ino:14291501 typechange 0x8000 -> 0x4000, sleep=1.588µs
    17:51:33.654399 Ino:14291501 typechange 0x8000 -> 0x4000, sleep=2.639µs
    17:51:33.655098 Ino:14291476 typechange 0x4000 -> 0x8000, sleep=0s
    17:51:33.667216 Ino:14291504 typechange 0x4000 -> 0x8000, sleep=0s
    17:51:33.667228 Ino:14291504 typechange 0x4000 -> 0x8000, sleep=1µs
    17:51:33.667236 Ino:14291504 typechange 0x4000 -> 0x8000, sleep=1.443µs
    17:51:33.667242 Ino:14291504 typechange 0x4000 -> 0x8000, sleep=2.286µs
        rm
    3
        fsstress.1 seed = 1574749722
        fsstress.2 seed = 1574328972
    17:51:35.220180 Ino:13771167 typechange 0x8000 -> 0xa000, sleep=0s
    17:51:35.220205 Ino:13771167 typechange 0x8000 -> 0xa000, sleep=1µs
    17:51:35.514144 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=0s
    17:51:35.514165 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=1µs
    17:51:35.514172 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=1.739µs
    17:51:35.515875 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=1.969µs
    17:51:35.516021 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=3.744µs
    17:51:35.516094 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=4.308µs
    17:51:35.516514 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=5.112µs
    17:51:35.516765 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=5.299µs
    17:51:35.516870 Ino:13771355 typechange 0x4000 -> 0xa000, sleep=8.169µs
    17:51:36.429950 Ino:13771381 typechange 0x8000 -> 0xa000, sleep=0s
    17:51:36.430068 Ino:13771381 typechange 0x8000 -> 0xa000, sleep=1µs
    17:51:36.430082 Ino:13771381 typechange 0x8000 -> 0xa000, sleep=1.071µs
    17:51:36.547108 Ino:13899567 typechange 0x8000 -> 0x4000, sleep=0s
    17:51:36.547121 Ino:13899567 typechange 0x8000 -> 0x4000, sleep=1µs
    17:51:36.547158 Ino:13899567 typechange 0x8000 -> 0x4000, sleep=1.907µs
    17:51:36.547181 Ino:13899567 typechange 0x8000 -> 0x4000, sleep=2.358µs
    17:51:38.112588 Ino:13771503 typechange 0x8000 -> 0xa000, sleep=0s
    17:51:38.112602 Ino:13771503 typechange 0x8000 -> 0xa000, sleep=1µs
    17:51:38.112611 Ino:13771503 typechange 0x8000 -> 0xa000, sleep=1.11µs
    17:51:38.524020 Ino:13899675 typechange 0xa000 -> 0x8000, sleep=0s
    17:51:38.524042 Ino:13899675 typechange 0xa000 -> 0x8000, sleep=1µs

Change-Id: I6120ce76730018d22898127290f492fa9f85a957
parent 53f16b0a
...@@ -7,6 +7,7 @@ package fs ...@@ -7,6 +7,7 @@ package fs
import ( import (
"context" "context"
"log" "log"
"math/rand"
"sync" "sync"
"syscall" "syscall"
"time" "time"
...@@ -76,6 +77,12 @@ func (b *rawBridge) newInodeUnlocked(ops InodeEmbedder, id StableAttr, persisten ...@@ -76,6 +77,12 @@ func (b *rawBridge) newInodeUnlocked(ops InodeEmbedder, id StableAttr, persisten
} }
} }
// Only the file type bits matter
id.Mode = id.Mode & syscall.S_IFMT
if id.Mode == 0 {
id.Mode = fuse.S_IFREG
}
// the same node can be looked up through 2 paths in parallel, eg. // the same node can be looked up through 2 paths in parallel, eg.
// //
// root // root
...@@ -87,14 +94,23 @@ func (b *rawBridge) newInodeUnlocked(ops InodeEmbedder, id StableAttr, persisten ...@@ -87,14 +94,23 @@ func (b *rawBridge) newInodeUnlocked(ops InodeEmbedder, id StableAttr, persisten
// dir1.Lookup("file") and dir2.Lookup("file") are executed // dir1.Lookup("file") and dir2.Lookup("file") are executed
// simultaneously. The matching StableAttrs ensure that we return the // simultaneously. The matching StableAttrs ensure that we return the
// same node. // same node.
old := b.nodes[id.Ino] var t time.Duration
if old != nil { for {
return old old := b.nodes[id.Ino]
} if old == nil {
break
id.Mode = id.Mode &^ 07777 }
if id.Mode == 0 { if old.stableAttr == id {
id.Mode = fuse.S_IFREG return old
}
b.mu.Unlock()
const typechangeDebug = false
if typechangeDebug {
log.Printf("Ino:%d typechange %#x -> %#x, sleep=%v", old.stableAttr.Ino, old.stableAttr.Mode,
id.Mode, t)
}
t = expSleep(t)
b.mu.Lock()
} }
b.nodes[id.Ino] = ops.embed() b.nodes[id.Ino] = ops.embed()
...@@ -102,6 +118,21 @@ func (b *rawBridge) newInodeUnlocked(ops InodeEmbedder, id StableAttr, persisten ...@@ -102,6 +118,21 @@ func (b *rawBridge) newInodeUnlocked(ops InodeEmbedder, id StableAttr, persisten
return ops.embed() return ops.embed()
} }
// expSleep sleeps for time `t` and returns an exponentially increasing value
// for the next sleep time, capped at 1 ms.
func expSleep(t time.Duration) time.Duration {
if t == 0 {
return time.Microsecond
}
time.Sleep(t)
// Next sleep is between t and 2*t
t += time.Duration(rand.Int63n(int64(t)))
if t >= time.Millisecond {
return time.Millisecond
}
return t
}
func (b *rawBridge) newInode(ctx context.Context, ops InodeEmbedder, id StableAttr, persistent bool) *Inode { func (b *rawBridge) newInode(ctx context.Context, ops InodeEmbedder, id StableAttr, persistent bool) *Inode {
ch := b.newInodeUnlocked(ops, id, persistent) ch := b.newInodeUnlocked(ops, id, persistent)
if ch != ops.embed() { if ch != ops.embed() {
......
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