From b45c5aaf56f4c0046b7ac97edd379539b4bd1706 Mon Sep 17 00:00:00 2001
From: Kirill Smelkov <kirr@nexedi.com>
Date: Fri, 21 Feb 2020 19:50:54 +0300
Subject: [PATCH] .

---
 wcfs/client/wcfs.cpp | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/wcfs/client/wcfs.cpp b/wcfs/client/wcfs.cpp
index 06f9e4d8..17c4786c 100644
--- a/wcfs/client/wcfs.cpp
+++ b/wcfs/client/wcfs.cpp
@@ -514,7 +514,7 @@ error _Conn::resync(zodb::Tid at) {
         // TODO if file has no mappings and was not used during whole prev
         // cycle - forget and stop watching it
 
-        // XXX not yet ready f ?
+        // XXX not yet ready f
 
         // update f._headfsize and remmap to head/f zero regions that are now covered by head/f
         struct stat st;
@@ -618,7 +618,7 @@ pair<FileH, error> _Conn::open(zodb::Oid foid) {
     }
 
     // create in-flight-opening FileH entry and perform open with wconn._mu released
-    // NOTE wconn._atMu is still held because open relies on wconn.at being stable.
+    // NOTE wconn._atMu.R is still held because FileH._open relies on wconn.at being stable.
     f = adoptref(new _FileH());
     f->wconn      = newref(&wconn);
     f->foid       = foid;
@@ -688,9 +688,8 @@ error _FileH::_open() {
     tie(ack, err) = wconn->_wlink->sendReq(context::background(), fmt::sprintf("watch %s @%s", v(foid), v(wconn->at)));
     if (err != nil)
         return err;
-    if (ack != "ok") {
+    if (ack != "ok")
         return fmt::errorf("watch: %s", v(ack));
-    }
 
     retok = true;
     return nil;
@@ -702,10 +701,25 @@ error _FileH::_open() {
 error _FileH::close() {
     _FileH& fileh = *this;
     Conn    wconn = fileh.wconn;
+
+    // XXX locking ok?
+    wconn->_atMu.RLock();
+    defer([&]() {
+        wconn->_atMu.RUnlock();
+    });
+
     xerr::Contextf E("%s: close f<%s>", v(wconn), v(fileh.foid));
 
     // XXX change all fileh.mmaps to cause EFAULT on any access after fileh.close
-    // XXX "watch foid -" -> wconn.wlink (stop watching the file)
+
+    // stop watching f
+    string ack;
+    error  err;
+    tie(ack, err) = wconn->_wlink->sendReq(context::background(), fmt::sprintf("watch %s -", v(foid)));
+    if (err != nil)
+        return E(err);
+    if (ack != "ok")
+        return E(fmt::errorf("unwatch: %s", v(ack)));
 
     // remove fileh from wconn._filehTab
     // fileh.close can be called several times and after first call another
-- 
2.30.9