Index: uspace/srv/fs/fat/fat_dentry.c
===================================================================
--- uspace/srv/fs/fat/fat_dentry.c	(revision 30eab785e6a70045734d7630e93628c7c1f85f3d)
+++ uspace/srv/fs/fat/fat_dentry.c	(revision 39b0a51454b0612c72d33b798ecc3c89ee13b849)
@@ -180,4 +180,33 @@
 }
 
+void fat_dentry_vollabel_get(const fat_dentry_t *d, char *buf)
+{
+	unsigned int i;
+	
+	for (i = 0; i < FAT_NAME_LEN; i++) {
+		if (d->name[i] == FAT_PAD)
+			break;
+		
+		if (d->name[i] == FAT_DENTRY_E5_ESC)
+			*buf++ = 0xe5;
+		else
+			*buf++ = d->name[i];
+	}
+	
+	for (i = 0; i < FAT_EXT_LEN; i++) {
+		if (d->ext[i] == FAT_PAD) {
+			*buf = '\0';
+			return;
+		}
+		
+		if (d->ext[i] == FAT_DENTRY_E5_ESC)
+			*buf++ = 0xe5;
+		else
+			*buf++ = d->ext[i];
+	}
+	
+	*buf = '\0';
+}
+
 fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *d)
 {
@@ -191,5 +220,5 @@
 	if (d->attr & FAT_ATTR_VOLLABEL) {
 		/* volume label entry */
-		return FAT_DENTRY_SKIP;
+		return FAT_DENTRY_VOLLABEL;
 	}
 	if (d->name[0] == FAT_DENTRY_ERASED) {
Index: uspace/srv/fs/fat/fat_dentry.h
===================================================================
--- uspace/srv/fs/fat/fat_dentry.h	(revision 30eab785e6a70045734d7630e93628c7c1f85f3d)
+++ uspace/srv/fs/fat/fat_dentry.h	(revision 39b0a51454b0612c72d33b798ecc3c89ee13b849)
@@ -45,4 +45,5 @@
 #define FAT_NAME_LEN		8
 #define FAT_EXT_LEN		3
+#define FAT_VOLLABEL_LEN	11
 
 #define FAT_NAME_DOT		".       "
@@ -98,5 +99,6 @@
 	FAT_DENTRY_FREE,
 	FAT_DENTRY_VALID,
-	FAT_DENTRY_LFN
+	FAT_DENTRY_LFN,
+	FAT_DENTRY_VOLLABEL
 } fat_dentry_clsf_t;
 
@@ -138,4 +140,5 @@
 extern void fat_dentry_name_get(const fat_dentry_t *, char *);
 extern void fat_dentry_name_set(fat_dentry_t *, const char *);
+extern void fat_dentry_vollabel_get(const fat_dentry_t *, char *);
 extern fat_dentry_clsf_t fat_classify_dentry(const fat_dentry_t *);
 extern uint8_t fat_dentry_chksum(uint8_t *);
Index: uspace/srv/fs/fat/fat_directory.c
===================================================================
--- uspace/srv/fs/fat/fat_directory.c	(revision 30eab785e6a70045734d7630e93628c7c1f85f3d)
+++ uspace/srv/fs/fat/fat_directory.c	(revision 39b0a51454b0612c72d33b798ecc3c89ee13b849)
@@ -223,7 +223,8 @@
 			*de = d;
 			return EOK;
-		default:
 		case FAT_DENTRY_SKIP:
 		case FAT_DENTRY_FREE:
+		case FAT_DENTRY_VOLLABEL:
+		default:
 			long_entry_count = 0;
 			long_entry = false;
@@ -252,5 +253,5 @@
 	while (!flag && fat_directory_prev(di) == EOK) {
 		if (fat_directory_get(di, &d) == EOK &&
-		    fat_classify_dentry(d) == FAT_DENTRY_LFN &&			
+		    fat_classify_dentry(d) == FAT_DENTRY_LFN &&	
 		    checksum == FAT_LFN_CHKSUM(d)) {
 			if (FAT_IS_LFN(d))
@@ -473,4 +474,5 @@
 			case FAT_DENTRY_LFN:
 			case FAT_DENTRY_SKIP:
+			case FAT_DENTRY_VOLLABEL:
 			default:
 				found = 0;
@@ -523,10 +525,39 @@
 		case FAT_DENTRY_LFN:
 		case FAT_DENTRY_SKIP:
+		case FAT_DENTRY_VOLLABEL:
 		case FAT_DENTRY_FREE:
 			break;
 		}
-	} while (fat_directory_next(di) == EOK);	
+	} while (fat_directory_next(di) == EOK);
 
 	return false;
+}
+
+/** Find volume label entry in a directory.
+ *
+ * @return EOK on success, ENOENT if not found, EIO on I/O error
+ */
+int fat_directory_vollabel_get(fat_directory_t *di, char *label)
+{
+	fat_dentry_t *d;
+	int rc;
+
+	fat_directory_seek(di, 0);
+	do {
+		rc = fat_directory_get(di, &d);
+		if (rc != EOK)
+			return EIO;
+
+		switch (fat_classify_dentry(d)) {
+		case FAT_DENTRY_VOLLABEL:
+			fat_dentry_vollabel_get(d, label);
+			return EOK;
+		default:
+			break;
+		}
+	} while (fat_directory_next(di) == EOK);
+
+	/* Not found */
+	return ENOENT;
 }
 
Index: uspace/srv/fs/fat/fat_directory.h
===================================================================
--- uspace/srv/fs/fat/fat_directory.h	(revision 30eab785e6a70045734d7630e93628c7c1f85f3d)
+++ uspace/srv/fs/fat/fat_directory.h	(revision 39b0a51454b0612c72d33b798ecc3c89ee13b849)
@@ -72,4 +72,5 @@
     const char *);
 extern int fat_directory_expand(fat_directory_t *);
+extern int fat_directory_vollabel_get(fat_directory_t *, char *);
 
 #endif
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 30eab785e6a70045734d7630e93628c7c1f85f3d)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 39b0a51454b0612c72d33b798ecc3c89ee13b849)
@@ -785,4 +785,5 @@
 			case FAT_DENTRY_SKIP:
 			case FAT_DENTRY_FREE:
+			case FAT_DENTRY_VOLLABEL:
 				continue;
 			case FAT_DENTRY_LAST:
@@ -909,9 +910,6 @@
 };
 
-/*
- * FAT VFS_OUT operations.
- */
-
-static int fat_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
+static int fat_fs_open(service_id_t service_id, enum cache_mode cmode,
+    fs_node_t **rrfn, fat_idx_t **rridxp)
 {
 	fat_bs_t *bs;
@@ -939,5 +937,5 @@
 
 	/* Initialize the block cache */
-	rc = block_cache_init(service_id, BPS(bs), 0 /* XXX */, CACHE_MODE_WB);
+	rc = block_cache_init(service_id, BPS(bs), 0 /* XXX */, cmode);
 	if (rc != EOK) {
 		block_fini(service_id);
@@ -947,9 +945,136 @@
 	/* Do some simple sanity checks on the file system. */
 	rc = fat_sanity_check(bs, service_id);
-
+	if (rc != EOK) {
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+
+	rc = fat_idx_init_by_service_id(service_id);
+	if (rc != EOK) {
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		return rc;
+	}
+
+	/* Initialize the root node. */
+	fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
+	if (!rfn) {
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		fat_idx_fini_by_service_id(service_id);
+		return ENOMEM;
+	}
+
+	fs_node_initialize(rfn);
+	fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
+	if (!rootp) {
+		free(rfn);
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		fat_idx_fini_by_service_id(service_id);
+		return ENOMEM;
+	}
+	fat_node_initialize(rootp);
+
+	fat_idx_t *ridxp = fat_idx_get_by_pos(service_id, FAT_CLST_ROOTPAR, 0);
+	if (!ridxp) {
+		free(rfn);
+		free(rootp);
+		(void) block_cache_fini(service_id);
+		block_fini(service_id);
+		fat_idx_fini_by_service_id(service_id);
+		return ENOMEM;
+	}
+	assert(ridxp->index == 0);
+	/* ridxp->lock held */
+
+	rootp->type = FAT_DIRECTORY;
+	rootp->firstc = FAT_ROOT_CLST(bs);
+	rootp->refcnt = 1;
+	rootp->lnkcnt = 0;	/* FS root is not linked */
+
+	if (FAT_IS_FAT32(bs)) {
+		uint32_t clusters;
+		rc = fat_clusters_get(&clusters, bs, service_id, rootp->firstc);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&ridxp->lock);
+			free(rfn);
+			free(rootp);
+			(void) block_cache_fini(service_id);
+			block_fini(service_id);
+			fat_idx_fini_by_service_id(service_id);
+			return ENOTSUP;
+		}
+		rootp->size = BPS(bs) * SPC(bs) * clusters;
+	} else
+		rootp->size = RDE(bs) * sizeof(fat_dentry_t);
+
+	rootp->idx = ridxp;
+	ridxp->nodep = rootp;
+	rootp->bp = rfn;
+	rfn->data = rootp;
+
+	fibril_mutex_unlock(&ridxp->lock);
+
+	*rrfn = rfn;
+	*rridxp = ridxp;
+
+	return EOK;
+}
+
+static void fat_fs_close(service_id_t service_id, fs_node_t *rfn)
+{
+	free(rfn->data);
+	free(rfn);
 	(void) block_cache_fini(service_id);
 	block_fini(service_id);
-
-	return rc;
+	fat_idx_fini_by_service_id(service_id);
+}
+
+/*
+ * FAT VFS_OUT operations.
+ */
+
+static int fat_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
+{
+	fat_bs_t *bs;
+	fat_idx_t *ridxp;
+	fs_node_t *rfn;
+	fat_node_t *nodep;
+	fat_directory_t di;
+	char label[FAT_VOLLABEL_LEN + 1];
+	int i;
+	int rc;
+
+	rc = fat_fs_open(service_id, CACHE_MODE_WT, &rfn, &ridxp);
+	if (rc != EOK)
+		return rc;
+
+	nodep = FAT_NODE(rfn);
+
+	rc = fat_directory_open(nodep, &di);
+	if (rc != EOK)
+		return rc;
+
+	rc = fat_directory_vollabel_get(&di, label);
+	if (rc != EOK) {
+		/* No label in root directory. Read label from the BS */
+		bs = block_bb_get(service_id);
+		i = FAT_VOLLABEL_LEN;
+		while (i > 0 && bs->label[i - 1] == FAT_PAD)
+			--i;
+
+		/* XXX Deal with non-ASCII characters */
+		memcpy(label, bs->label, i);
+		label[i] = '\0';
+	}
+
+	str_cpy(info->label, FS_LABEL_MAXLEN + 1, label);
+
+	fat_directory_close(&di);
+	fat_fs_close(service_id, rfn);
+
+	return EOK;
 }
 
@@ -959,6 +1084,7 @@
 {
 	enum cache_mode cmode = CACHE_MODE_WB;
-	fat_bs_t *bs;
 	fat_instance_t *instance;
+	fat_idx_t *ridxp;
+	fs_node_t *rfn;
 	int rc;
 
@@ -978,6 +1104,5 @@
 	}
 
-	/* initialize libblock */
-	rc = block_init(service_id, BS_SIZE);
+	rc = fat_fs_open(service_id, cmode, &rfn, &ridxp);
 	if (rc != EOK) {
 		free(instance);
@@ -985,124 +1110,18 @@
 	}
 
-	/* prepare the boot block */
-	rc = block_bb_read(service_id, BS_BLOCK);
-	if (rc != EOK) {
-		free(instance);
-		block_fini(service_id);
-		return rc;
-	}
-
-	/* get the buffer with the boot sector */
-	bs = block_bb_get(service_id);
-	
-	if (BPS(bs) != BS_SIZE) {
-		free(instance);
-		block_fini(service_id);
-		return ENOTSUP;
-	}
-
-	/* Initialize the block cache */
-	rc = block_cache_init(service_id, BPS(bs), 0 /* XXX */, cmode);
-	if (rc != EOK) {
-		free(instance);
-		block_fini(service_id);
-		return rc;
-	}
-
-	/* Do some simple sanity checks on the file system. */
-	rc = fat_sanity_check(bs, service_id);
-	if (rc != EOK) {
-		free(instance);
-		(void) block_cache_fini(service_id);
-		block_fini(service_id);
-		return rc;
-	}
-
-	rc = fat_idx_init_by_service_id(service_id);
-	if (rc != EOK) {
-		free(instance);
-		(void) block_cache_fini(service_id);
-		block_fini(service_id);
-		return rc;
-	}
-
-	/* Initialize the root node. */
-	fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
-	if (!rfn) {
-		free(instance);
-		(void) block_cache_fini(service_id);
-		block_fini(service_id);
-		fat_idx_fini_by_service_id(service_id);
-		return ENOMEM;
-	}
-
-	fs_node_initialize(rfn);
-	fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
-	if (!rootp) {
-		free(instance);
-		free(rfn);
-		(void) block_cache_fini(service_id);
-		block_fini(service_id);
-		fat_idx_fini_by_service_id(service_id);
-		return ENOMEM;
-	}
-	fat_node_initialize(rootp);
-
-	fat_idx_t *ridxp = fat_idx_get_by_pos(service_id, FAT_CLST_ROOTPAR, 0);
-	if (!ridxp) {
-		free(instance);
-		free(rfn);
-		free(rootp);
-		(void) block_cache_fini(service_id);
-		block_fini(service_id);
-		fat_idx_fini_by_service_id(service_id);
-		return ENOMEM;
-	}
-	assert(ridxp->index == 0);
-	/* ridxp->lock held */
-
-	rootp->type = FAT_DIRECTORY;
-	rootp->firstc = FAT_ROOT_CLST(bs);
-	rootp->refcnt = 1;
-	rootp->lnkcnt = 0;	/* FS root is not linked */
-
-	if (FAT_IS_FAT32(bs)) {
-		uint32_t clusters;
-		rc = fat_clusters_get(&clusters, bs, service_id, rootp->firstc);
-		if (rc != EOK) {
-			fibril_mutex_unlock(&ridxp->lock);
-			free(instance);
-			free(rfn);
-			free(rootp);
-			(void) block_cache_fini(service_id);
-			block_fini(service_id);
-			fat_idx_fini_by_service_id(service_id);
-			return ENOTSUP;
-		}
-		rootp->size = BPS(bs) * SPC(bs) * clusters;
-	} else
-		rootp->size = RDE(bs) * sizeof(fat_dentry_t);
+	fibril_mutex_lock(&ridxp->lock);
 
 	rc = fs_instance_create(service_id, instance);
 	if (rc != EOK) {
 		fibril_mutex_unlock(&ridxp->lock);
+		fat_fs_close(service_id, rfn);
 		free(instance);
-		free(rfn);
-		free(rootp);
-		(void) block_cache_fini(service_id);
-		block_fini(service_id);
-		fat_idx_fini_by_service_id(service_id);
-		return rc;
-	}
-
-	rootp->idx = ridxp;
-	ridxp->nodep = rootp;
-	rootp->bp = rfn;
-	rfn->data = rootp;
+		return rc;
+	}
 
 	fibril_mutex_unlock(&ridxp->lock);
 
 	*index = ridxp->index;
-	*size = rootp->size;
+	*size = FAT_NODE(rfn)->size;
 
 	return EOK;
@@ -1174,5 +1193,4 @@
 	 */
 	(void) fat_node_put(fn);
-	(void) fat_node_put(fn);
 
 	/*
@@ -1182,7 +1200,5 @@
 	 */
 	(void) fat_node_fini_by_service_id(service_id);
-	fat_idx_fini_by_service_id(service_id);
-	(void) block_cache_fini(service_id);
-	block_fini(service_id);
+	fat_fs_close(service_id, fn);
 
 	void *data;
