From 60194645507aac2448614f1cbf5a427f165bd14c Mon Sep 17 00:00:00 2001
From: Kirill Smelkov <kirr@nexedi.com>
Date: Mon, 1 Jul 2019 11:59:18 +0300
Subject: [PATCH] .

---
 wcfs/wcfs.go | 39 ++++++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 15 deletions(-)

diff --git a/wcfs/wcfs.go b/wcfs/wcfs.go
index 9ce596a..d30354e 100644
--- a/wcfs/wcfs.go
+++ b/wcfs/wcfs.go
@@ -692,15 +692,17 @@ func traceZWatch(format string, argv ...interface{}) {
 // zwatcher watches for ZODB changes.
 //
 // see "4) when we receive an invalidation message from ZODB ..."
+/*
 func (root *Root) zwatcher(ctx context.Context, zwatchq chan zodb.Event) {
 	err := root._zwatcher(ctx, zwatchq)
 	if err != nil {
 		panic(err)	// XXX -> wg.Wait in main
 	}
 }
+*/
 
-func (root *Root) _zwatcher(ctx context.Context, zwatchq chan zodb.Event) (err error) {
-	defer xerr.Contextf(&err, "zwatch %s", root.zstor.URL())
+func (root *Root) zwatcher(ctx context.Context, zwatchq chan zodb.Event) (err error) {
+	defer xerr.Contextf(&err, "zwatch %s", root.zstor.URL())	// XXX err ctx recheck
 	// XXX error   -> always EIO for data operations
 	// XXX unmount -> stop
 	traceZWatch(">>>")
@@ -2163,7 +2165,7 @@ func _main() (err error) {
 		NoPool: true,
 	})
 	if err != nil {
-		log.Fatal(err)
+		return err
 	}
 	zhead.Cache().Lock()
 	zhead.Cache().SetControl(&zodbCacheControl{})
@@ -2220,7 +2222,7 @@ func _main() (err error) {
 
 	fssrv, fsconn, err := mount(mntpt, root, opts)
 	if err != nil {
-		log.Fatal(err)
+		return err
 	}
 	groot   = root		// FIXME temp workaround (see ^^^)
 	gfsconn = fsconn	// FIXME ----//----
@@ -2231,7 +2233,7 @@ func _main() (err error) {
 	kfuse := fmt.Sprintf("kernel FUSE (API %d.%d)", kinit.Major, kinit.Minor)
 	supports := kinit.SupportsNotify
 	if !(supports(fuse.NOTIFY_STORE_CACHE) && supports(fuse.NOTIFY_RETRIEVE_CACHE)) {
-		log.Fatalf("%s does not support pagecache control", kfuse)
+		return fmt.Errorf("%s does not support pagecache control", kfuse)
 	}
 	// make a bold warning if kernel does not support explicit cache invalidation
 	// (patch sent upstream; see notes.txt -> "Notes on OS pagecache control")
@@ -2265,32 +2267,39 @@ func _main() (err error) {
 		fsNode: newFSNode(fSticky),
 	})
 
-	// XXX place = ok?
-	// XXX ctx = ok?	XXX -> joined ctx for fs.Serve + zwatcher ?
-	// XXX wait for zwatcher shutdown + log from it error
-	go root.zwatcher(ctx, zwatchq)
-
 	// TODO handle autoexit
 	// (exit when kernel forgets all our inodes - wcfs.py keeps .wcfs/zurl
 	//  opened, so when all inodes has been forgotten - we know all wcfs.py clients exited)
 	_ = autoexit
 
-	// serve client requests.
+	// spawn filesystem server.
 	//
 	// use `go serve` + `waitMount` not just `serve` - because waitMount
 	// cares to disable OS calling poll on us.
 	// ( if we don't disable polling - fs serving can get stuck - see
 	//   https://github.com/hanwen/go-fuse/commit/4f10e248eb for details )
-	done := make(chan struct{})
+	serveCtx, serveCancel := context.WithCancel(context.Background())
 	go func () {
+		defer serveCancel()
 		fssrv.Serve()
-		close(done)
 	}()
 	err = fssrv.WaitMount()
 	if err != nil {
-		log.Fatal(err) // XXX err ctx?
+		return err	// XXX err ctx?
+	}
+
+	// filesystem server is serving requests.
+	// run zwatcher and wait for it to complete.
+	// zwatcher completes either normally - due to filesystem unmount, or fails.
+	// if zwatcher fails - switch filesystem to return EIO instead of stale data.
+	err = root.zwatcher(serveCtx, zwatchq)
+	if errors.Cause(err) != context.Canceled {
+		log.Error(err)
+		log.Errorf("-> switching filesystem to EIO mode")
+		// XXX switch fs to EIO mode
 	}
-	<-done
 
+	// wait for unmount
+	<-serveCtx.Done()
 	return nil
 }
-- 
2.30.9