Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 17bf6589140203b151bde03d340d98bd7a813224)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 0fc1e5d76be00c32f5334cd23903352fdd5fd5bf)
@@ -65,197 +65,4 @@
 static LIST_INITIALIZE(ffn_head);
 
-static void fat_node_initialize(fat_node_t *node)
-{
-	fibril_mutex_initialize(&node->lock);
-	node->bp = NULL;
-	node->idx = NULL;
-	node->type = 0;
-	link_initialize(&node->ffn_link);
-	node->size = 0;
-	node->lnkcnt = 0;
-	node->refcnt = 0;
-	node->dirty = false;
-}
-
-static int fat_node_sync(fat_node_t *node)
-{
-	block_t *b;
-	fat_bs_t *bs;
-	fat_dentry_t *d;
-	uint16_t bps;
-	unsigned dps;
-	int rc;
-	
-	assert(node->dirty);
-
-	bs = block_bb_get(node->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-	
-	/* Read the block that contains the dentry of interest. */
-	rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,
-	    (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
-	if (rc != EOK)
-		return rc;
-
-	d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
-
-	d->firstc = host2uint16_t_le(node->firstc);
-	if (node->type == FAT_FILE) {
-		d->size = host2uint32_t_le(node->size);
-	} else if (node->type == FAT_DIRECTORY) {
-		d->attr = FAT_ATTR_SUBDIR;
-	}
-	
-	/* TODO: update other fields? (e.g time fields) */
-	
-	b->dirty = true;		/* need to sync block */
-	rc = block_put(b);
-	return rc;
-}
-
-static int fat_node_get_new(fat_node_t **nodepp)
-{
-	fs_node_t *fn;
-	fat_node_t *nodep;
-	int rc;
-
-	fibril_mutex_lock(&ffn_mutex);
-	if (!list_empty(&ffn_head)) {
-		/* Try to use a cached free node structure. */
-		fat_idx_t *idxp_tmp;
-		nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
-		if (!fibril_mutex_trylock(&nodep->lock))
-			goto skip_cache;
-		idxp_tmp = nodep->idx;
-		if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
-			fibril_mutex_unlock(&nodep->lock);
-			goto skip_cache;
-		}
-		list_remove(&nodep->ffn_link);
-		fibril_mutex_unlock(&ffn_mutex);
-		if (nodep->dirty) {
-			rc = fat_node_sync(nodep);
-			if (rc != EOK) {
-				idxp_tmp->nodep = NULL;
-				fibril_mutex_unlock(&nodep->lock);
-				fibril_mutex_unlock(&idxp_tmp->lock);
-				free(nodep->bp);
-				free(nodep);
-				return rc;
-			}
-		}
-		idxp_tmp->nodep = NULL;
-		fibril_mutex_unlock(&nodep->lock);
-		fibril_mutex_unlock(&idxp_tmp->lock);
-		fn = FS_NODE(nodep);
-	} else {
-skip_cache:
-		/* Try to allocate a new node structure. */
-		fibril_mutex_unlock(&ffn_mutex);
-		fn = (fs_node_t *)malloc(sizeof(fs_node_t));
-		if (!fn)
-			return ENOMEM;
-		nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
-		if (!nodep) {
-			free(fn);
-			return ENOMEM;
-		}
-	}
-	fat_node_initialize(nodep);
-	fs_node_initialize(fn);
-	fn->data = nodep;
-	nodep->bp = fn;
-	
-	*nodepp = nodep;
-	return EOK;
-}
-
-/** Internal version of fat_node_get().
- *
- * @param idxp		Locked index structure.
- */
-static fat_node_t *fat_node_get_core(fat_idx_t *idxp)
-{
-	block_t *b;
-	fat_bs_t *bs;
-	fat_dentry_t *d;
-	fat_node_t *nodep = NULL;
-	unsigned bps;
-	unsigned spc;
-	unsigned dps;
-	int rc;
-
-	if (idxp->nodep) {
-		/*
-		 * We are lucky.
-		 * The node is already instantiated in memory.
-		 */
-		fibril_mutex_lock(&idxp->nodep->lock);
-		if (!idxp->nodep->refcnt++) {
-			fibril_mutex_lock(&ffn_mutex);
-			list_remove(&idxp->nodep->ffn_link);
-			fibril_mutex_unlock(&ffn_mutex);
-		}
-		fibril_mutex_unlock(&idxp->nodep->lock);
-		return idxp->nodep;
-	}
-
-	/*
-	 * We must instantiate the node from the file system.
-	 */
-	
-	assert(idxp->pfc);
-
-	rc = fat_node_get_new(&nodep);
-	if (rc != EOK)
-		return NULL;
-
-	bs = block_bb_get(idxp->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	dps = bps / sizeof(fat_dentry_t);
-
-	/* Read the block that contains the dentry of interest. */
-	rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,
-	    (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
-	assert(rc == EOK);
-
-	d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
-	if (d->attr & FAT_ATTR_SUBDIR) {
-		/* 
-		 * The only directory which does not have this bit set is the
-		 * root directory itself. The root directory node is handled
-		 * and initialized elsewhere.
-		 */
-		nodep->type = FAT_DIRECTORY;
-		/*
-		 * Unfortunately, the 'size' field of the FAT dentry is not
-		 * defined for the directory entry type. We must determine the
-		 * size of the directory by walking the FAT.
-		 */
-		uint16_t clusters;
-		rc = fat_clusters_get(&clusters, bs, idxp->dev_handle,
-		    uint16_t_le2host(d->firstc));
-		assert(rc == EOK);
-		nodep->size = bps * spc * clusters;
-	} else {
-		nodep->type = FAT_FILE;
-		nodep->size = uint32_t_le2host(d->size);
-	}
-	nodep->firstc = uint16_t_le2host(d->firstc);
-	nodep->lnkcnt = 1;
-	nodep->refcnt = 1;
-
-	rc = block_put(b);
-	assert(rc == EOK);
-
-	/* Link the idx structure with the node structure. */
-	nodep->idx = idxp;
-	idxp->nodep = nodep;
-
-	return nodep;
-}
-
 /*
  * Forward declarations of FAT libfs operations.
@@ -276,4 +83,211 @@
 static bool fat_is_directory(fs_node_t *);
 static bool fat_is_file(fs_node_t *node);
+
+/*
+ * Helper functions.
+ */
+static void fat_node_initialize(fat_node_t *node)
+{
+	fibril_mutex_initialize(&node->lock);
+	node->bp = NULL;
+	node->idx = NULL;
+	node->type = 0;
+	link_initialize(&node->ffn_link);
+	node->size = 0;
+	node->lnkcnt = 0;
+	node->refcnt = 0;
+	node->dirty = false;
+}
+
+static int fat_node_sync(fat_node_t *node)
+{
+	block_t *b;
+	fat_bs_t *bs;
+	fat_dentry_t *d;
+	uint16_t bps;
+	unsigned dps;
+	int rc;
+	
+	assert(node->dirty);
+
+	bs = block_bb_get(node->idx->dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+	dps = bps / sizeof(fat_dentry_t);
+	
+	/* Read the block that contains the dentry of interest. */
+	rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,
+	    (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
+
+	d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
+
+	d->firstc = host2uint16_t_le(node->firstc);
+	if (node->type == FAT_FILE) {
+		d->size = host2uint32_t_le(node->size);
+	} else if (node->type == FAT_DIRECTORY) {
+		d->attr = FAT_ATTR_SUBDIR;
+	}
+	
+	/* TODO: update other fields? (e.g time fields) */
+	
+	b->dirty = true;		/* need to sync block */
+	rc = block_put(b);
+	return rc;
+}
+
+static int fat_node_get_new(fat_node_t **nodepp)
+{
+	fs_node_t *fn;
+	fat_node_t *nodep;
+	int rc;
+
+	fibril_mutex_lock(&ffn_mutex);
+	if (!list_empty(&ffn_head)) {
+		/* Try to use a cached free node structure. */
+		fat_idx_t *idxp_tmp;
+		nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
+		if (!fibril_mutex_trylock(&nodep->lock))
+			goto skip_cache;
+		idxp_tmp = nodep->idx;
+		if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
+			fibril_mutex_unlock(&nodep->lock);
+			goto skip_cache;
+		}
+		list_remove(&nodep->ffn_link);
+		fibril_mutex_unlock(&ffn_mutex);
+		if (nodep->dirty) {
+			rc = fat_node_sync(nodep);
+			if (rc != EOK) {
+				idxp_tmp->nodep = NULL;
+				fibril_mutex_unlock(&nodep->lock);
+				fibril_mutex_unlock(&idxp_tmp->lock);
+				free(nodep->bp);
+				free(nodep);
+				return rc;
+			}
+		}
+		idxp_tmp->nodep = NULL;
+		fibril_mutex_unlock(&nodep->lock);
+		fibril_mutex_unlock(&idxp_tmp->lock);
+		fn = FS_NODE(nodep);
+	} else {
+skip_cache:
+		/* Try to allocate a new node structure. */
+		fibril_mutex_unlock(&ffn_mutex);
+		fn = (fs_node_t *)malloc(sizeof(fs_node_t));
+		if (!fn)
+			return ENOMEM;
+		nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
+		if (!nodep) {
+			free(fn);
+			return ENOMEM;
+		}
+	}
+	fat_node_initialize(nodep);
+	fs_node_initialize(fn);
+	fn->data = nodep;
+	nodep->bp = fn;
+	
+	*nodepp = nodep;
+	return EOK;
+}
+
+/** Internal version of fat_node_get().
+ *
+ * @param idxp		Locked index structure.
+ */
+static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp)
+{
+	block_t *b;
+	fat_bs_t *bs;
+	fat_dentry_t *d;
+	fat_node_t *nodep = NULL;
+	unsigned bps;
+	unsigned spc;
+	unsigned dps;
+	int rc;
+
+	if (idxp->nodep) {
+		/*
+		 * We are lucky.
+		 * The node is already instantiated in memory.
+		 */
+		fibril_mutex_lock(&idxp->nodep->lock);
+		if (!idxp->nodep->refcnt++) {
+			fibril_mutex_lock(&ffn_mutex);
+			list_remove(&idxp->nodep->ffn_link);
+			fibril_mutex_unlock(&ffn_mutex);
+		}
+		fibril_mutex_unlock(&idxp->nodep->lock);
+		*nodepp = idxp->nodep;
+		return EOK;
+	}
+
+	/*
+	 * We must instantiate the node from the file system.
+	 */
+	
+	assert(idxp->pfc);
+
+	rc = fat_node_get_new(&nodep);
+	if (rc != EOK)
+		return rc;
+
+	bs = block_bb_get(idxp->dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+	spc = bs->spc;
+	dps = bps / sizeof(fat_dentry_t);
+
+	/* Read the block that contains the dentry of interest. */
+	rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,
+	    (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		(void) fat_node_put(FS_NODE(nodep));
+		return rc;
+	}
+
+	d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
+	if (d->attr & FAT_ATTR_SUBDIR) {
+		/* 
+		 * The only directory which does not have this bit set is the
+		 * root directory itself. The root directory node is handled
+		 * and initialized elsewhere.
+		 */
+		nodep->type = FAT_DIRECTORY;
+		/*
+		 * Unfortunately, the 'size' field of the FAT dentry is not
+		 * defined for the directory entry type. We must determine the
+		 * size of the directory by walking the FAT.
+		 */
+		uint16_t clusters;
+		rc = fat_clusters_get(&clusters, bs, idxp->dev_handle,
+		    uint16_t_le2host(d->firstc));
+		if (rc != EOK) {
+			(void) fat_node_put(FS_NODE(nodep));
+			return rc;
+		}
+		nodep->size = bps * spc * clusters;
+	} else {
+		nodep->type = FAT_FILE;
+		nodep->size = uint32_t_le2host(d->size);
+	}
+	nodep->firstc = uint16_t_le2host(d->firstc);
+	nodep->lnkcnt = 1;
+	nodep->refcnt = 1;
+
+	rc = block_put(b);
+	if (rc != EOK) {
+		(void) fat_node_put(FS_NODE(nodep));
+		return rc;
+	}
+
+	/* Link the idx structure with the node structure. */
+	nodep->idx = idxp;
+	idxp->nodep = nodep;
+
+	*nodepp = nodep;
+	return EOK;
+}
 
 /*
@@ -351,5 +365,6 @@
 					return ENOMEM;
 				}
-				nodep = fat_node_get_core(idx);
+				rc = fat_node_get_core(&nodep, idx);
+				assert(rc == EOK);
 				fibril_mutex_unlock(&idx->lock);
 				rc = block_put(b);
@@ -374,4 +389,5 @@
 	fat_node_t *nodep;
 	fat_idx_t *idxp;
+	int rc;
 
 	idxp = fat_idx_get_by_index(dev_handle, index);
@@ -381,8 +397,9 @@
 	}
 	/* idxp->lock held */
-	nodep = fat_node_get_core(idxp);
+	rc = fat_node_get_core(&nodep, idxp);
 	fibril_mutex_unlock(&idxp->lock);
-	*rfn = FS_NODE(nodep);
-	return EOK;
+	if (rc == EOK)
+		*rfn = FS_NODE(nodep);
+	return rc;
 }
 
