Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision 34f62f8e9b560136ad11f9d0048bab607fe59aeb)
+++ uspace/srv/fs/fat/fat.h	(revision 869e546b5cba8feb1640276da3963cca97942b52)
@@ -140,4 +140,6 @@
 } __attribute__ ((packed)) fat_dentry_t;
 
+typedef uint16_t fat_cluster_t;
+
 typedef enum {
 	FAT_INVALID,
@@ -146,14 +148,57 @@
 } fat_node_type_t;
 
+struct fat_node;
+
+/** FAT index structure.
+ *
+ * This structure exists to help us to overcome certain limitations of the FAT
+ * file system design.  The problem with FAT is that it is hard to find
+ * an entity which could represent a VFS index.  There are two candidates:
+ *
+ * a) number of the node's first cluster
+ * b) the pair of the parent directory's first cluster and the dentry index
+ *    within the parent directory
+ *
+ * We need VFS indices to be:
+ * A) unique
+ * B) stable in time, at least until the next mount
+ *
+ * Unfortunately a) does not meet the A) criterion because zero-length files
+ * will have the first cluster field cleared.  And b) does not meet the B)
+ * criterion because unlink() and rename() will both free up the original
+ * dentry, which contains all the essential info about the file.
+ *
+ * Therefore, a completely opaque indices are used and the FAT server maintains
+ * a mapping between them and otherwise nice b) variant.  On rename(), the VFS
+ * index stays unaltered, while the internal FAT "physical tree address"
+ * changes.  The unlink case is also handled this way thanks to an in-core node
+ * pointer embedded in the index structure.
+ */
+typedef struct {
+	dev_handle_t	dev_handle;
+	fs_index_t	index;
+	/**
+	 * Parent first cluster.
+	 * Zero is used if this node is not linked, in which case nodep must
+	 * contain a pointer to the in-core node structure.
+	 * One is used when the parent is the root directory.
+	 */
+	fat_cluster_t	pfc;
+	/** Parent directory entry index. */
+	unsigned	pdi;
+	/** Pointer to in-core node instance. */
+	struct fat_node	*nodep;
+} fat_idx_t;
+
 /** FAT in-core node. */
-typedef struct {
-	/** Protects an instance of this type. */
-	futex_t			lock;
+typedef struct fat_node {
 	fat_node_type_t		type;
-	/** VFS index is the node's first allocated cluster. */
-	fs_index_t		index;
-	/** VFS index of the parent node. */
-	fs_index_t		pindex;
-	dev_handle_t		dev_handle;
+	fat_idx_t		*idx;
+	/**
+	 *  Node's first cluster.
+	 *  Zero is used for zero-length nodes.
+	 *  One is used to mark root directory.
+	 */
+	fat_cluster_t		firstc;
 	/** FAT in-core node hash table link. */
 	link_t 			fin_link;
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 34f62f8e9b560136ad11f9d0048bab607fe59aeb)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 869e546b5cba8feb1640276da3963cca97942b52)
@@ -54,7 +54,4 @@
 #define FIN_KEY_INDEX		1
 
-/** Futex protecting both fin_hash and ffn_head. */
-futex_t fin_futex = FUTEX_INITIALIZER;
-
 /** Hash table of FAT in-core nodes. */
 hash_table_t fin_hash;
@@ -116,7 +113,13 @@
 }
 
+static fat_idx_t *fat_idx_map(fat_cluster_t pfc, unsigned pdi)
+{
+	return NULL;	/* TODO */
+}
 
 #define FAT_BS(b)		((fat_bs_t *)((b)->data))
 
+#define FAT_CLST_RES0	0x0000
+#define FAT_CLST_RES1	0x0001	/* internally used to mark root directory */
 #define FAT_CLST_FIRST	0x0002
 #define FAT_CLST_BAD	0xfff7
@@ -124,12 +127,5 @@
 #define FAT_CLST_LAST8  0xffff
 
-/** Convert cluster number to an index within a FAT.
- *
- * Format Identifier and cluster numbering is considered.
- */
-#define C2FAT_IDX(c)	(1 + (c) - FAT_CLST_FIRST)
-
-static block_t *fat_block_get(dev_handle_t dev_handle, fs_index_t index,
-    off_t offset)
+static block_t *fat_block_get(fat_node_t *nodep, off_t offset)
 {
 	block_t *bb;
@@ -144,8 +140,8 @@
 	unsigned ssa;		/* size of the system area */
 	unsigned clusters;
-	unsigned clst = index;
+	fat_cluster_t clst = nodep->firstc;
 	unsigned i;
 
-	bb = block_get(dev_handle, BS_BLOCK);
+	bb = block_get(nodep->idx->dev_handle, BS_BLOCK);
 	bps = uint16_t_le2host(FAT_BS(bb)->bps);
 	spc = FAT_BS(bb)->spc;
@@ -160,8 +156,9 @@
 	ssa = rscnt + fatcnt * sf + rds;
 
-	if (!index) {
+	if (nodep->idx->index == FAT_CLST_RES1) {
 		/* root directory special case */
 		assert(offset < rds);
-		b = block_get(dev_handle, rscnt + fatcnt * sf + offset);
+		b = block_get(nodep->idx->dev_handle,
+		    rscnt + fatcnt * sf + offset);
 		return b;
 	}
@@ -173,9 +170,9 @@
 
 		assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
-		fsec = (C2FAT_IDX(clst) * sizeof(uint16_t)) / bps;
-		fidx = C2FAT_IDX(clst) % (bps / sizeof(uint16_t));
+		fsec = (clst * sizeof(fat_cluster_t)) / bps;
+		fidx = clst % (bps / sizeof(fat_cluster_t));
 		/* read FAT1 */
-		b = block_get(dev_handle, rscnt + fsec);
-		clst = uint16_t_le2host(((uint16_t *)b->data)[fidx]);
+		b = block_get(nodep->idx->dev_handle, rscnt + fsec);
+		clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
 		assert(clst != FAT_CLST_BAD);
 		assert(clst < FAT_CLST_LAST1);
@@ -183,6 +180,6 @@
 	}
 
-	b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
-	    offset % spc);
+	b = block_get(nodep->idx->dev_handle, ssa +
+	    (clst - FAT_CLST_FIRST) * spc + offset % spc);
 
 	return b;
@@ -191,9 +188,6 @@
 static void fat_node_initialize(fat_node_t *node)
 {
-	futex_initialize(&node->lock, 1);
+	node->idx = NULL;
 	node->type = 0;
-	node->index = 0;
-	node->pindex = 0;
-	node->dev_handle = 0;
 	link_initialize(&node->fin_link);
 	link_initialize(&node->ffn_link);
@@ -295,5 +289,5 @@
 	block_t *b;
 
-	bps = fat_bps_get(parentp->dev_handle);
+	bps = fat_bps_get(parentp->idx->dev_handle);
 	dps = bps / sizeof(fat_dentry_t);
 	blocks = parentp->size / bps + (parentp->size % bps != 0);
@@ -301,5 +295,5 @@
 		unsigned dentries;
 		
-		b = fat_block_get(parentp->dev_handle, parentp->index, i);
+		b = fat_block_get(parentp, i);
 		dentries = (i == blocks - 1) ?
 		    parentp->size % sizeof(fat_dentry_t) :
@@ -320,6 +314,8 @@
 			if (strcmp(name, component) == 0) {
 				/* hit */
-				void *node = fat_node_get(parentp->dev_handle,
-				    (fs_index_t)uint16_t_le2host(d->firstc));
+				fat_idx_t *idx = fat_idx_map(parentp->firstc,
+				    i * dps + j);
+				void *node = fat_node_get(idx->dev_handle,
+				    idx->index);
 				block_put(b);
 				return node;
@@ -337,5 +333,5 @@
 	if (!fnodep)
 		return 0;
-	return fnodep->index;
+	return fnodep->idx->index;
 }
 
@@ -362,5 +358,5 @@
 		return false;
 
-	bps = fat_bps_get(nodep->dev_handle);
+	bps = fat_bps_get(nodep->idx->dev_handle);
 	dps = bps / sizeof(fat_dentry_t);
 
@@ -371,5 +367,5 @@
 		fat_dentry_t *d;
 	
-		b = fat_block_get(nodep->dev_handle, nodep->index, i);
+		b = fat_block_get(nodep, i);
 		dentries = (i == blocks - 1) ?
 		    nodep->size % sizeof(fat_dentry_t) :
@@ -399,5 +395,5 @@
 static void *fat_root_get(dev_handle_t dev_handle)
 {
-	return fat_node_get(dev_handle, 0);	
+	return fat_node_get(dev_handle, FAT_CLST_RES1);
 }
 
