diff --git a/.gitignore b/.gitignore
index 49902ee..0e5fba7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/ostree-2016.1.tar.xz
+SOURCES/ostree-2016.5.tar.xz
diff --git a/.ostree.metadata b/.ostree.metadata
index 9866fa3..a6bd2f6 100644
--- a/.ostree.metadata
+++ b/.ostree.metadata
@@ -1 +1 @@
-5d21ed6bb5299ce90a98b7697f5e08e6646f3554 SOURCES/ostree-2016.1.tar.xz
+07eef2576680daa2bd8c7fd190462eb400a013c8 SOURCES/ostree-2016.5.tar.xz
diff --git a/SOURCES/0001-fetcher-Fix-hung-GTlsInteraction.patch b/SOURCES/0001-fetcher-Fix-hung-GTlsInteraction.patch
deleted file mode 100644
index be64038..0000000
--- a/SOURCES/0001-fetcher-Fix-hung-GTlsInteraction.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 5adafd767406820cce260c567a1b936610e8d67a Mon Sep 17 00:00:00 2001
-From: Matthew Barnes <mbarnes@redhat.com>
-Date: Tue, 9 Feb 2016 00:58:17 +0000
-Subject: [PATCH] fetcher: Fix hung GTlsInteraction
-
-The GTlsInteraction instance must be created in the session thread
-so it uses the correct GMainContext.
----
- src/libostree/ostree-fetcher.c | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
-diff --git a/src/libostree/ostree-fetcher.c b/src/libostree/ostree-fetcher.c
-index 665286c..b922321 100644
---- a/src/libostree/ostree-fetcher.c
-+++ b/src/libostree/ostree-fetcher.c
-@@ -277,7 +277,12 @@ static void
- session_thread_set_tls_interaction_cb (ThreadClosure *thread_closure,
-                                        gpointer data)
- {
--  GTlsInteraction *interaction = data;
-+  GTlsCertificate *cert = data;
-+  glnx_unref_object OstreeTlsCertInteraction *interaction = NULL;
-+
-+  /* The GTlsInteraction instance must be created in the
-+   * session thread so it uses the correct GMainContext. */
-+  interaction = _ostree_tls_cert_interaction_new (cert);
- 
-   g_object_set (thread_closure->session,
-                 SOUP_SESSION_TLS_INTERACTION,
-@@ -645,7 +650,7 @@ _ostree_fetcher_set_client_cert (OstreeFetcher   *self,
- #ifdef HAVE_LIBSOUP_CLIENT_CERTS
-   session_thread_idle_add (self->thread_closure,
-                            session_thread_set_tls_interaction_cb,
--                           _ostree_tls_cert_interaction_new (cert),
-+                           g_object_ref (cert),
-                            (GDestroyNotify) g_object_unref);
- #else
-   g_warning ("This version of OSTree is compiled without client side certificate support");
--- 
-1.8.3.1
-
diff --git a/SOURCES/0001-pull-Ensure-we-always-process-queue-only-from-main-t.patch b/SOURCES/0001-pull-Ensure-we-always-process-queue-only-from-main-t.patch
new file mode 100644
index 0000000..63a04d8
--- /dev/null
+++ b/SOURCES/0001-pull-Ensure-we-always-process-queue-only-from-main-t.patch
@@ -0,0 +1,186 @@
+From 0271ce020f3e8c30044632f4e4bfa673b051f233 Mon Sep 17 00:00:00 2001
+From: Colin Walters <walters@verbum.org>
+Date: Thu, 16 Jun 2016 22:16:27 -0400
+Subject: [PATCH] pull: Ensure we always process queue only from main thread
+
+I was easily reproducing a hang on pulls with thousands of requests on
+current git master.  The initial symptom seemed to be that there are
+multiple code paths where we don't invoke
+`session_thread_process_pending_queue()`.  We really need to do
+that any time we remove something from the outstanding queue,
+to ensure it gets filled again.
+
+A further issue is that we were tying the lifecycle of the pending
+object to the `GTask`, but the task could be unref'd from the main
+thread (via a `GSource` on the main thread), and that introduced
+threadsafety issues, because the hash table and other data suddenly
+could be concurrently modified.
+
+Both of these need to be fixed together.  First, we introduce
+`Arc<Pending>`, and ensure that both the main and worker threads hold
+references.
+
+Second, we ensure that we re-process the queue *immediately* whenever
+a task is done, inside the worker thread, rather than doing it
+incidentally via an unref.  This architecture is quite similar to what
+the outside pull code is doing.
+---
+ src/libostree/ostree-fetcher.c | 55 ++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 47 insertions(+), 8 deletions(-)
+
+diff --git a/src/libostree/ostree-fetcher.c b/src/libostree/ostree-fetcher.c
+index d956d95..313df6a 100644
+--- a/src/libostree/ostree-fetcher.c
++++ b/src/libostree/ostree-fetcher.c
+@@ -67,7 +67,12 @@ typedef struct {
+   guint64 total_downloaded;
+ } ThreadClosure;
+ 
++static void
++session_thread_process_pending_queue (ThreadClosure *thread_closure);
++
+ typedef struct {
++  volatile int ref_count;
++
+   ThreadClosure *thread_closure;
+   SoupURI *uri;
+ 
+@@ -186,10 +191,22 @@ pending_task_compare (gconstpointer a,
+          (priority_a < priority_b) ? -1 : 1;
+ }
+ 
++static OstreeFetcherPendingURI *
++pending_uri_ref (OstreeFetcherPendingURI *pending)
++{
++  g_return_val_if_fail (pending != NULL, NULL);
++  g_return_val_if_fail (pending->ref_count > 0, NULL);
++
++  g_atomic_int_inc (&pending->ref_count);
++
++  return pending;
++}
++
+ static void
+-pending_uri_free (OstreeFetcherPendingURI *pending)
++pending_uri_unref (OstreeFetcherPendingURI *pending)
+ {
+-  g_hash_table_remove (pending->thread_closure->outstanding, pending);
++  if (!g_atomic_int_dec_and_test (&pending->ref_count))
++    return;
+ 
+   g_clear_pointer (&pending->thread_closure, thread_closure_unref);
+ 
+@@ -331,8 +348,7 @@ session_thread_process_pending_queue (ThreadClosure *thread_closure)
+       pending = g_task_get_task_data (task);
+       cancellable = g_task_get_cancellable (task);
+ 
+-      /* pending_uri_free() removes this. */
+-      g_hash_table_add (thread_closure->outstanding, pending);
++      g_hash_table_add (thread_closure->outstanding, pending_uri_ref (pending));
+ 
+       soup_request_send_async (pending->request,
+                                cancellable,
+@@ -540,7 +556,7 @@ _ostree_fetcher_constructed (GObject *object)
+   self->thread_closure->tmpdir_dfd = -1;
+   self->thread_closure->tmpdir_lock = empty_lockfile;
+ 
+-  self->thread_closure->outstanding = g_hash_table_new (NULL, NULL);
++  self->thread_closure->outstanding = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)pending_uri_unref);
+   self->thread_closure->output_stream_set = g_hash_table_new_full (NULL, NULL,
+                                                                    (GDestroyNotify) NULL,
+                                                                    (GDestroyNotify) g_object_unref);
+@@ -743,6 +759,18 @@ on_stream_read (GObject        *object,
+                 gpointer        user_data);
+ 
+ static void
++remove_pending_rerun_queue (OstreeFetcherPendingURI *pending)
++{
++  /* Hold a temporary ref to ensure the reference to
++   * pending->thread_closure is valid.
++   */
++  pending_uri_ref (pending);
++  g_hash_table_remove (pending->thread_closure->outstanding, pending);
++  session_thread_process_pending_queue (pending->thread_closure);
++  pending_uri_unref (pending);
++}
++
++static void
+ on_out_splice_complete (GObject        *object,
+                         GAsyncResult   *result,
+                         gpointer        user_data) 
+@@ -770,7 +798,10 @@ on_out_splice_complete (GObject        *object,
+ 
+  out:
+   if (local_error)
+-    g_task_return_error (task, local_error);
++    {
++      g_task_return_error (task, local_error);
++      remove_pending_rerun_queue (pending);
++    }
+ 
+   g_object_unref (task);
+ }
+@@ -802,6 +833,7 @@ on_stream_read (GObject        *object,
+       g_task_return_pointer (task,
+                              g_strdup (pending->out_tmpfile),
+                              (GDestroyNotify) g_free);
++      remove_pending_rerun_queue (pending);
+     }
+   else
+     {
+@@ -837,7 +869,10 @@ on_stream_read (GObject        *object,
+ 
+  out:
+   if (local_error)
+-    g_task_return_error (task, local_error);
++    {
++      g_task_return_error (task, local_error);
++      remove_pending_rerun_queue (pending);
++    }
+ 
+   g_object_unref (task);
+ }
+@@ -883,6 +918,7 @@ on_request_sent (GObject        *object,
+                                      g_strdup (pending->out_tmpfile),
+                                      (GDestroyNotify) g_free);
+             }
++          remove_pending_rerun_queue (pending);
+           goto out;
+         }
+       else if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+@@ -947,6 +983,7 @@ on_request_sent (GObject        *object,
+       g_task_return_pointer (task,
+                              g_object_ref (pending->request_body),
+                              (GDestroyNotify) g_object_unref);
++      remove_pending_rerun_queue (pending);
+     }
+   
+  out:
+@@ -955,6 +992,7 @@ on_request_sent (GObject        *object,
+       if (pending->request_body)
+         (void) g_input_stream_close (pending->request_body, NULL, NULL);
+       g_task_return_error (task, local_error);
++      remove_pending_rerun_queue (pending);
+     }
+ 
+   g_object_unref (task);
+@@ -979,6 +1017,7 @@ ostree_fetcher_request_uri_internal (OstreeFetcher         *self,
+ 
+   /* SoupRequest is created in session thread. */
+   pending = g_new0 (OstreeFetcherPendingURI, 1);
++  pending->ref_count = 1;
+   pending->thread_closure = thread_closure_ref (self->thread_closure);
+   pending->uri = soup_uri_copy (uri);
+   pending->max_size = max_size;
+@@ -986,7 +1025,7 @@ ostree_fetcher_request_uri_internal (OstreeFetcher         *self,
+ 
+   task = g_task_new (self, cancellable, callback, user_data);
+   g_task_set_source_tag (task, source_tag);
+-  g_task_set_task_data (task, pending, (GDestroyNotify) pending_uri_free);
++  g_task_set_task_data (task, pending, (GDestroyNotify) pending_uri_unref);
+ 
+   /* We'll use the GTask priority for our own priority queue. */
+   g_task_set_priority (task, priority);
+-- 
+2.5.5
+
diff --git a/SPECS/ostree.spec b/SPECS/ostree.spec
index 3c6a33f..e28e414 100644
--- a/SPECS/ostree.spec
+++ b/SPECS/ostree.spec
@@ -1,12 +1,14 @@
 Summary: Tool for managing bootable, immutable filesystem trees
 Name: ostree
-Version: 2016.1
-Release: 2.atomic%{?dist}
-#VCS: git:git://git.gnome.org/ostree
-Source0: http://ftp.gnome.org/pub/GNOME/sources/ostree/%{version}/ostree-%{version}.tar.xz
+Version: 2016.5
+Release: 3.atomic%{?dist}
+#VCS: git:https://github.com/ostreedev/ostree
+# The source tarball is generated via make -C packaging dist-snapshot
+# which handles git submodules.
+Source0: %{name}-%{version}.tar.xz
 Source1: 91-ostree.preset
 Patch0: 0001-ostree-remount-Explicitly-set-tmp-to-01777.patch
-Patch1: 0001-fetcher-Fix-hung-GTlsInteraction.patch
+Patch1: 0001-pull-Ensure-we-always-process-queue-only-from-main-t.patch
 License: LGPLv2+
 URL: http://live.gnome.org/OSTree
 
@@ -24,6 +26,7 @@ BuildRequires: libattr-devel
 BuildRequires: pkgconfig(libarchive)
 BuildRequires: pkgconfig(libselinux)
 BuildRequires: pkgconfig(liblzma)
+BuildRequires: pkgconfig(fuse)
 BuildRequires: pkgconfig(e2p)
 BuildRequires: libcap-devel
 BuildRequires: gpgme-devel
@@ -61,6 +64,12 @@ Requires: grub2
 %description grub2
 GRUB2 integration for OSTree
 
+%package fuse
+Summary: FUSE utilities for ostree
+
+%description fuse
+%{summary}
+
 %prep
 %autosetup -n ostree-%{version} -Sgit
 
@@ -104,6 +113,9 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man*/*.gz
 %{_prefix}/lib/systemd/system-preset/91-ostree.preset
 
+%files fuse
+%{_bindir}/rofiles-fuse
+
 %files devel
 %{_libdir}/lib*.so
 %{_includedir}/*
@@ -117,6 +129,11 @@ rm -rf $RPM_BUILD_ROOT
 %{_libexecdir}/ostree/grub2*
 
 %changelog
+* Tue Apr 19 2016 Colin Walters <walters@redhat.com> - 2016.5-2.atomic
+- New upstream version
+- Backport patch for detected race conditions in pull
+- Split off new fuse package with rofiles-fuse
+
 * Tue Feb 09 2016 Colin Walters <walters@redhat.com> - 2016.1-2.atomic
 - Backport patch to fix GTlsInteraction