diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index c210926..ff5659e 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -1050,16 +1050,21 @@ ARDOUR_UI::update_disk_space()
 		return;
 	}
 
-	framecnt_t frames = _session->available_capture_duration();
+	boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
 	char buf[64];
 	framecnt_t fr = _session->frame_rate();
 
-	if (frames == max_framecnt) {
+	if (!opt_frames) {
+		/* Available space is unknown */
+		snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">?</span>"));
+	} else if (opt_frames.get_value_or (0) == max_framecnt) {
 		snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
 	} else {
 		rec_enabled_streams = 0;
 		_session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
 
+		framecnt_t frames = opt_frames.get_value_or (0);
+
 		if (rec_enabled_streams) {
 			frames /= rec_enabled_streams;
 		}
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index d31d1f9..55a8ecb 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -669,7 +669,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
 	/* s/w "RAID" management */
 
-	framecnt_t available_capture_duration();
+	boost::optional<framecnt_t> available_capture_duration();
 
 	/* I/O bundles */
 
@@ -1328,16 +1328,21 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 	/* S/W RAID */
 
 	struct space_and_path {
-		uint32_t blocks; /* 4kB blocks */
+		uint32_t blocks;     ///< 4kB blocks
+		bool blocks_unknown; ///< true if blocks is unknown
 		std::string path;
 
-		space_and_path() {
-			blocks = 0;
-		}
+		space_and_path ()
+			: blocks (0)
+			, blocks_unknown (true)
+		{}
 	};
 
 	struct space_and_path_ascending_cmp {
 		bool operator() (space_and_path a, space_and_path b) {
+			if (a.blocks_unknown != b.blocks_unknown) {
+				return !a.blocks_unknown;
+			}
 			return a.blocks > b.blocks;
 		}
 	};
@@ -1347,6 +1352,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 	std::vector<space_and_path> session_dirs;
 	std::vector<space_and_path>::iterator last_rr_session_dir;
 	uint32_t _total_free_4k_blocks;
+	/** If this is true, _total_free_4k_blocks is not definite,
+	    as one or more of the session directories' filesystems
+	    could not report free space.
+	*/
+	bool _total_free_4k_blocks_uncertain;
 	Glib::Mutex space_lock;
 
 	bool no_questions_about_missing_files;
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 559ca64..529813f 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -143,6 +143,7 @@ Session::Session (AudioEngine &eng,
 	, _all_route_group (new RouteGroup (*this, "all"))
 	, routes (new RouteList)
 	, _total_free_4k_blocks (0)
+	, _total_free_4k_blocks_uncertain (false)
 	, _bundles (new BundleList)
 	, _bundle_xml_node (0)
 	, _current_trans (0)
@@ -3501,9 +3502,16 @@ Session::graph_reordered ()
 	}
 }
 
-framecnt_t
+/** @return Number of frames that there is disk space available to write,
+ *  if known.
+ */
+boost::optional<framecnt_t>
 Session::available_capture_duration ()
 {
+	if (_total_free_4k_blocks_uncertain) {
+		return boost::optional<framecnt_t> ();
+	}
+	
 	float sample_bytes_on_disk = 4.0; // keep gcc happy
 
 	switch (config.get_native_file_data_format()) {
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index e729a7b..30f8571 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -46,6 +46,10 @@
 #include <sys/mount.h>
 #endif
 
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
 #include <glib.h>
 
 #include <glibmm.h>
@@ -2079,23 +2083,48 @@ Session::save_template (string template_name)
 void
 Session::refresh_disk_space ()
 {
-#if HAVE_SYS_VFS_H
-	struct statfs statfsbuf;
-	vector<space_and_path>::iterator i;
+#if HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H
+	
 	Glib::Mutex::Lock lm (space_lock);
-	double scale;
 
 	/* get freespace on every FS that is part of the session path */
 
 	_total_free_4k_blocks = 0;
+	_total_free_4k_blocks_uncertain = false;
 
-	for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
-		statfs ((*i).path.c_str(), &statfsbuf);
+	for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+
+		struct statfs statfsbuf;
+		statfs (i->path.c_str(), &statfsbuf);
 
-		scale = statfsbuf.f_bsize/4096.0;
+		double const scale = statfsbuf.f_bsize / 4096.0;
 
-		(*i).blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
-		_total_free_4k_blocks += (*i).blocks;
+		/* See if this filesystem is read-only */
+		struct statvfs statvfsbuf;
+		statvfs (i->path.c_str(), &statvfsbuf);
+
+		/* f_bavail can be 0 if it is undefined for whatever
+		   filesystem we are looking at; Samba shares mounted
+		   via GVFS are an example of this.
+		*/
+		if (statfsbuf.f_bavail == 0) {
+			/* block count unknown */
+			i->blocks = 0;
+			i->blocks_unknown = true;
+		} else if (statvfsbuf.f_flag & ST_RDONLY) {
+			/* read-only filesystem */
+			i->blocks = 0;
+			i->blocks_unknown = false;
+		} else {
+			/* read/write filesystem with known space */
+			i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
+			i->blocks_unknown = false;
+		}
+
+		_total_free_4k_blocks += i->blocks;
+		if (i->blocks_unknown) {
+			_total_free_4k_blocks_uncertain = true;
+		}
 	}
 #endif
 }
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index ee86a20..2e465e9 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -288,6 +288,7 @@ def configure(conf):
     conf.define('CURRENT_SESSION_FILE_VERSION', CURRENT_SESSION_FILE_VERSION)
 
     conf.check(header_name='sys/vfs.h', define_name='HAVE_SYS_VFS_H',mandatory=False)
+    conf.check(header_name='sys/statvfs.h', define_name='HAVE_SYS_STATVFS_H',mandatory=False)
 
     conf.check(header_name='jack/session.h', uselib = [ 'JACK' ],
                define_name='HAVE_JACK_SESSION')
