diff --git a/Cargo.lock b/Cargo.lock
index 84f9f8ccd13..e2938b5f8c2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1080,12 +1080,13 @@ dependencies = [
 name = "ra_batch"
 version = "0.1.0"
 dependencies = [
+ "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_db 0.1.0",
  "ra_hir 0.1.0",
  "ra_ide_api 0.1.0",
  "ra_project_model 0.1.0",
- "ra_vfs 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ra_vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_vfs_glob 0.1.0",
  "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1191,7 +1192,7 @@ dependencies = [
  "ra_project_model 0.1.0",
  "ra_syntax 0.1.0",
  "ra_text_edit 0.1.0",
- "ra_vfs 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ra_vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_vfs_glob 0.1.0",
  "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1300,7 +1301,7 @@ dependencies = [
 
 [[package]]
 name = "ra_vfs"
-version = "0.2.8"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1318,7 +1319,7 @@ name = "ra_vfs_glob"
 version = "0.1.0"
 dependencies = [
  "globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "ra_vfs 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ra_vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2120,7 +2121,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
 "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
 "checksum ra_rustc_lexer 0.1.0-pre.3 (registry+https://github.com/rust-lang/crates.io-index)" = "04371af481820ff8d35c7d12b503eb09cf9e1bd246269bf4a33e3d8c54fa3a4a"
-"checksum ra_vfs 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9e891866e1bb03f50a28cc01e3f244a62107c301ae674ba06b2e7a9b310ae75a"
+"checksum ra_vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc8b709e0b7ceec822513451b610df1b9370b01953a8bc545a041a6b3bfef01"
 "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
 "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
 "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml
index 8e23826a41c..5fc2703ee9f 100644
--- a/crates/ra_batch/Cargo.toml
+++ b/crates/ra_batch/Cargo.toml
@@ -7,8 +7,9 @@ authors = ["rust-analyzer developers"]
 [dependencies]
 log = "0.4.5"
 rustc-hash = "1.0"
+crossbeam-channel = "0.3.5"
 
-ra_vfs = "0.2.0"
+ra_vfs = "0.3.0"
 ra_vfs_glob = { path = "../ra_vfs_glob" }
 ra_db = { path = "../ra_db" }
 ra_ide_api = { path = "../ra_ide_api" }
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
index f458ea30035..4e5bad04439 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -2,10 +2,11 @@ use std::{collections::HashSet, error::Error, path::Path};
 
 use rustc_hash::FxHashMap;
 
+use crossbeam_channel::{unbounded, Receiver};
 use ra_db::{CrateGraph, FileId, SourceRootId};
 use ra_ide_api::{AnalysisChange, AnalysisHost, FeatureFlags};
 use ra_project_model::{PackageRoot, ProjectWorkspace};
-use ra_vfs::{RootEntry, Vfs, VfsChange};
+use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask};
 use ra_vfs_glob::RustPackageFilterBuilder;
 
 type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
@@ -21,6 +22,8 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId,
     let root = std::env::current_dir()?.join(root);
     let ws = ProjectWorkspace::discover(root.as_ref())?;
     let project_roots = ws.to_roots();
+    let (sender, receiver) = unbounded();
+    let sender = Box::new(move |t| sender.send(t).unwrap());
     let (mut vfs, roots) = Vfs::new(
         project_roots
             .iter()
@@ -33,6 +36,7 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId,
                 )
             })
             .collect(),
+        sender,
     );
     let crate_graph = ws.to_crate_graph(&mut |path: &Path| {
         let vfs_file = vfs.load(path);
@@ -53,7 +57,7 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId,
             (source_root_id, project_root)
         })
         .collect::<FxHashMap<_, _>>();
-    let host = load(&source_roots, crate_graph, &mut vfs);
+    let host = load(&source_roots, crate_graph, &mut vfs, receiver);
     Ok((host, source_roots))
 }
 
@@ -61,6 +65,7 @@ pub fn load(
     source_roots: &FxHashMap<SourceRootId, PackageRoot>,
     crate_graph: CrateGraph,
     vfs: &mut Vfs,
+    receiver: Receiver<VfsTask>,
 ) -> AnalysisHost {
     let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
     let mut host = AnalysisHost::new(lru_cap, FeatureFlags::default());
@@ -68,7 +73,6 @@ pub fn load(
     analysis_change.set_crate_graph(crate_graph);
 
     // wait until Vfs has loaded all roots
-    let receiver = vfs.task_receiver().clone();
     let mut roots_loaded = HashSet::new();
     for task in receiver {
         vfs.handle_task(task);
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index afeac0d8a4c..e271c257bc9 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -16,7 +16,7 @@ lsp-types = { version = "0.60.0", features = ["proposed"] }
 rustc-hash = "1.0"
 parking_lot = "0.9.0"
 
-ra_vfs = "0.2.7"
+ra_vfs = "0.3.0"
 thread_worker = { path = "../thread_worker" }
 ra_syntax = { path = "../ra_syntax" }
 ra_text_edit = { path = "../ra_text_edit" }
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index ce25ff162aa..45bd52769bf 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -217,7 +217,7 @@ fn main_loop_inner(
                 Err(RecvError) => Err("client exited without shutdown")?,
             },
             recv(task_receiver) -> task => Event::Task(task.unwrap()),
-            recv(state.vfs.read().task_receiver()) -> task => match task {
+            recv(state.task_receiver) -> task => match task {
                 Ok(task) => Event::Vfs(task),
                 Err(RecvError) => Err("vfs died")?,
             },
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 6696dff71c6..cc796446986 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -3,6 +3,7 @@ use std::{
     sync::Arc,
 };
 
+use crossbeam_channel::{unbounded, Receiver};
 use gen_lsp_server::ErrorCode;
 use lsp_types::Url;
 use parking_lot::RwLock;
@@ -10,7 +11,7 @@ use ra_ide_api::{
     Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData,
     SourceRootId,
 };
-use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot};
+use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask};
 use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
 use relative_path::RelativePathBuf;
 
@@ -39,6 +40,7 @@ pub struct WorldState {
     pub workspaces: Arc<Vec<ProjectWorkspace>>,
     pub analysis_host: AnalysisHost,
     pub vfs: Arc<RwLock<Vfs>>,
+    pub task_receiver: Receiver<VfsTask>,
     pub latest_requests: Arc<RwLock<LatestRequests>>,
 }
 
@@ -80,8 +82,9 @@ impl WorldState {
                 RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter())
             }));
         }
-
-        let (mut vfs, vfs_roots) = Vfs::new(roots);
+        let (task_sender, task_receiver) = unbounded();
+        let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
+        let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender);
         let roots_to_scan = vfs_roots.len();
         for r in vfs_roots {
             let vfs_root_path = vfs.root2path(r);
@@ -109,6 +112,7 @@ impl WorldState {
             workspaces: Arc::new(workspaces),
             analysis_host,
             vfs: Arc::new(RwLock::new(vfs)),
+            task_receiver,
             latest_requests: Default::default(),
         }
     }
diff --git a/crates/ra_vfs_glob/Cargo.toml b/crates/ra_vfs_glob/Cargo.toml
index 0390d7da167..09ba3d3bfec 100644
--- a/crates/ra_vfs_glob/Cargo.toml
+++ b/crates/ra_vfs_glob/Cargo.toml
@@ -5,5 +5,5 @@ version = "0.1.0"
 authors = ["rust-analyzer developers"]
 
 [dependencies]
-ra_vfs = "0.2.0"
+ra_vfs = "0.3.0"
 globset = "0.4.4"