Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision 14f21007dc0cf82ed243c0420406da06d1dd6c47)
+++ uspace/srv/fs/fat/fat.h	(revision 9a1d8abd4768c007dc2f27c914e04be26e5a64f5)
@@ -48,4 +48,17 @@
 
 #define min(a, b)		((a) < (b) ? (a) : (b))
+
+/*
+ * Convenience macros for accessing some frequently used boot sector members.
+ */
+#define BPS(bs)		uint16_t_le2host((bs)->bps)
+#define SPC(bs)		(bs)->spc
+#define RSCNT(bs)	uint16_t_le2host((bs)->rscnt)
+#define FATCNT(bs)	(bs)->fatcnt
+#define SF(bs)		uint16_t_le2host((bs)->sec_per_fat)
+#define RDE(bs)		uint16_t_le2host((bs)->root_ent_max)
+#define TS(bs)		(uint16_t_le2host((bs)->totsec16) != 0 ? \
+			uint16_t_le2host((bs)->totsec16) : \
+			uint32_t_le2host(bs->totsec32))
 
 #define BS_BLOCK		0
@@ -198,4 +211,16 @@
 	unsigned		refcnt;
 	bool			dirty;
+
+	/*
+	 * Cache of the node's last and "current" cluster to avoid some
+	 * unnecessary FAT walks.
+	 */
+	/* Node's last cluster in FAT. */
+	bool		lastc_cached_valid;
+	fat_cluster_t	lastc_cached_value;
+	/* Node's "current" cluster, i.e. where the last I/O took place. */
+	bool		currc_cached_valid;
+	aoff64_t	currc_cached_bn;
+	fat_cluster_t	currc_cached_value;
 } fat_node_t;
 
Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision 14f21007dc0cf82ed243c0420406da06d1dd6c47)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 9a1d8abd4768c007dc2f27c914e04be26e5a64f5)
@@ -49,4 +49,15 @@
 #include <mem.h>
 
+/*
+ * Convenience macros for computing some frequently used values from the
+ * primitive boot sector members.
+ */
+#define RDS(bs)		((sizeof(fat_dentry_t) * RDE((bs))) / BPS((bs))) + \
+			(((sizeof(fat_dentry_t) * RDE((bs))) % BPS((bs))) != 0)
+#define SSA(bs)		(RSCNT((bs)) + FATCNT((bs)) * SF((bs)) + RDS(bs))
+
+#define CLBN2PBN(bs, cl, bn) \
+	(SSA((bs)) + ((cl) - FAT_CLST_FIRST) * SPC((bs)) + (bn) % SPC((bs)))
+
 /**
  * The fat_alloc_lock mutex protects all copies of the File Allocation Table
@@ -74,12 +85,7 @@
 {
 	block_t *b;
-	unsigned bps;
-	unsigned rscnt;		/* block address of the first FAT */
 	uint16_t clusters = 0;
 	fat_cluster_t clst = firstc;
 	int rc;
-
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
 
 	if (firstc == FAT_CLST_RES0) {
@@ -99,8 +105,9 @@
 		if (lastc)
 			*lastc = clst;	/* remember the last cluster number */
-		fsec = (clst * sizeof(fat_cluster_t)) / bps;
-		fidx = clst % (bps / sizeof(fat_cluster_t));
+		fsec = (clst * sizeof(fat_cluster_t)) / BPS(bs);
+		fidx = clst % (BPS(bs) / sizeof(fat_cluster_t));
 		/* read FAT1 */
-		rc = block_get(&b, dev_handle, rscnt + fsec, BLOCK_FLAGS_NONE);
+		rc = block_get(&b, dev_handle, RSCNT(bs) + fsec,
+		    BLOCK_FLAGS_NONE);
 		if (rc != EOK)
 			return rc;
@@ -125,7 +132,5 @@
  * @param block		Pointer to a block pointer for storing result.
  * @param bs		Buffer holding the boot sector of the file system.
- * @param dev_handle	Device handle of the file system.
- * @param firstc	First cluster used by the file. Can be zero if the file
- *			is empty.
+ * @param nodep		FAT node.
  * @param bn		Block number.
  * @param flags		Flags passed to libblock.
@@ -134,16 +139,75 @@
  */
 int
+fat_block_get(block_t **block, struct fat_bs *bs, fat_node_t *nodep,
+    aoff64_t bn, int flags)
+{
+	fat_cluster_t firstc = nodep->firstc;
+	fat_cluster_t currc;
+	aoff64_t relbn = bn;
+	int rc;
+
+	if (!nodep->size)
+		return ELIMIT;
+
+	if (nodep->firstc == FAT_CLST_ROOT) 
+		goto fall_through;
+
+	if (((((nodep->size - 1) / BPS(bs)) / SPC(bs)) == bn / SPC(bs)) &&
+	    nodep->lastc_cached_valid) {
+	    	/*
+		 * This is a request to read a block within the last cluster
+		 * when fortunately we have the last cluster number cached.
+		 */
+		return block_get(block, nodep->idx->dev_handle,
+		    CLBN2PBN(bs, nodep->lastc_cached_value, bn), flags);
+	}
+
+	if (nodep->currc_cached_valid && bn >= nodep->currc_cached_bn) {
+		/*
+		 * We can start with the cluster cached by the previous call to
+		 * fat_block_get().
+		 */
+		firstc = nodep->currc_cached_value;
+		relbn -= (nodep->currc_cached_bn / SPC(bs)) * SPC(bs);
+	}
+
+fall_through:
+	rc = _fat_block_get(block, bs, nodep->idx->dev_handle, firstc,
+	    &currc, relbn, flags);
+	if (rc != EOK)
+		return rc;
+	
+	/*
+	 * Update the "current" cluster cache.
+	 */
+	nodep->currc_cached_valid = true;
+	nodep->currc_cached_bn = bn;
+	nodep->currc_cached_value = currc;
+
+	return rc;
+}
+
+/** Read block from file located on a FAT file system.
+ *
+ * @param block		Pointer to a block pointer for storing result.
+ * @param bs		Buffer holding the boot sector of the file system.
+ * @param dev_handle	Device handle of the file system.
+ * @param fcl		First cluster used by the file. Can be zero if the file
+ *			is empty.
+ * @param clp		If not NULL, address where the cluster containing bn
+ *			will be stored.
+ *			stored 
+ * @param bn		Block number.
+ * @param flags		Flags passed to libblock.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
 _fat_block_get(block_t **block, fat_bs_t *bs, dev_handle_t dev_handle,
-    fat_cluster_t firstc, aoff64_t bn, int flags)
-{
-	unsigned bps;
-	unsigned rscnt;		/* block address of the first FAT */
-	unsigned rde;
-	unsigned rds;		/* root directory size */
-	unsigned sf;
-	unsigned ssa;		/* size of the system area */
+    fat_cluster_t fcl, fat_cluster_t *clp, aoff64_t bn, int flags)
+{
 	uint16_t clusters;
 	unsigned max_clusters;
-	fat_cluster_t lastc;
+	fat_cluster_t c;
 	int rc;
 
@@ -151,33 +215,25 @@
 	 * This function can only operate on non-zero length files.
 	 */
-	if (firstc == FAT_CLST_RES0)
+	if (fcl == FAT_CLST_RES0)
 		return ELIMIT;
 
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
-	rde = uint16_t_le2host(bs->root_ent_max);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-
-	rds = (sizeof(fat_dentry_t) * rde) / bps;
-	rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
-	ssa = rscnt + bs->fatcnt * sf + rds;
-
-	if (firstc == FAT_CLST_ROOT) {
+	if (fcl == FAT_CLST_ROOT) {
 		/* root directory special case */
-		assert(bn < rds);
-		rc = block_get(block, dev_handle, rscnt + bs->fatcnt * sf + bn,
-		    flags);
+		assert(bn < RDS(bs));
+		rc = block_get(block, dev_handle,
+		    RSCNT(bs) + FATCNT(bs) * SF(bs) + bn, flags);
 		return rc;
 	}
 
-	max_clusters = bn / bs->spc;
-	rc = fat_cluster_walk(bs, dev_handle, firstc, &lastc, &clusters,
-	    max_clusters);
+	max_clusters = bn / SPC(bs);
+	rc = fat_cluster_walk(bs, dev_handle, fcl, &c, &clusters, max_clusters);
 	if (rc != EOK)
 		return rc;
 	assert(clusters == max_clusters);
 
-	rc = block_get(block, dev_handle,
-	    ssa + (lastc - FAT_CLST_FIRST) * bs->spc + bn % bs->spc, flags);
+	rc = block_get(block, dev_handle, CLBN2PBN(bs, c, bn), flags);
+
+	if (clp)
+		*clp = c;
 
 	return rc;
@@ -198,24 +254,19 @@
 int fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, aoff64_t pos)
 {
-	uint16_t bps;
-	unsigned spc;
 	block_t *b;
 	aoff64_t o, boundary;
 	int rc;
 
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	
-	boundary = ROUND_UP(nodep->size, bps * spc);
+	boundary = ROUND_UP(nodep->size, BPS(bs) * SPC(bs));
 
 	/* zero out already allocated space */
 	for (o = nodep->size; o < pos && o < boundary;
-	    o = ALIGN_DOWN(o + bps, bps)) {
-	    	int flags = (o % bps == 0) ?
+	    o = ALIGN_DOWN(o + BPS(bs), BPS(bs))) {
+	    	int flags = (o % BPS(bs) == 0) ?
 		    BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE;
-		rc = fat_block_get(&b, bs, nodep, o / bps, flags);
-		if (rc != EOK)
-			return rc;
-		memset(b->data + o % bps, 0, bps - o % bps);
+		rc = fat_block_get(&b, bs, nodep, o / BPS(bs), flags);
+		if (rc != EOK)
+			return rc;
+		memset(b->data + o % BPS(bs), 0, BPS(bs) - o % BPS(bs));
 		b->dirty = true;		/* need to sync node */
 		rc = block_put(b);
@@ -228,10 +279,10 @@
 	
 	/* zero out the initial part of the new cluster chain */
-	for (o = boundary; o < pos; o += bps) {
+	for (o = boundary; o < pos; o += BPS(bs)) {
 		rc = _fat_block_get(&b, bs, nodep->idx->dev_handle, mcl,
-		    (o - boundary) / bps, BLOCK_FLAGS_NOREAD);
-		if (rc != EOK)
-			return rc;
-		memset(b->data, 0, min(bps, pos - o));
+		    NULL, (o - boundary) / BPS(bs), BLOCK_FLAGS_NOREAD);
+		if (rc != EOK)
+			return rc;
+		memset(b->data, 0, min(BPS(bs), pos - o));
 		b->dirty = true;		/* need to sync node */
 		rc = block_put(b);
@@ -257,19 +308,13 @@
 {
 	block_t *b;
-	uint16_t bps;
-	uint16_t rscnt;
-	uint16_t sf;
 	fat_cluster_t *cp;
 	int rc;
 
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-
-	rc = block_get(&b, dev_handle, rscnt + sf * fatno +
-	    (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
+	rc = block_get(&b, dev_handle, RSCNT(bs) + SF(bs) * fatno +
+	    (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK)
 		return rc;
-	cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
+	cp = (fat_cluster_t *)b->data +
+	    clst % (BPS(bs) / sizeof(fat_cluster_t));
 	*value = uint16_t_le2host(*cp);
 	rc = block_put(b);
@@ -293,20 +338,14 @@
 {
 	block_t *b;
-	uint16_t bps;
-	uint16_t rscnt;
-	uint16_t sf;
 	fat_cluster_t *cp;
 	int rc;
 
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-
-	assert(fatno < bs->fatcnt);
-	rc = block_get(&b, dev_handle, rscnt + sf * fatno +
-	    (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
+	assert(fatno < FATCNT(bs));
+	rc = block_get(&b, dev_handle, RSCNT(bs) + SF(bs) * fatno +
+	    (clst * sizeof(fat_cluster_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK)
 		return rc;
-	cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
+	cp = (fat_cluster_t *)b->data +
+	    clst % (BPS(bs) / sizeof(fat_cluster_t));
 	*cp = host2uint16_t_le(value);
 	b->dirty = true;		/* need to sync block */
@@ -364,11 +403,4 @@
     fat_cluster_t *mcl, fat_cluster_t *lcl)
 {
-	uint16_t bps;
-	uint16_t rscnt;
-	uint16_t sf;
-	uint32_t ts;
-	unsigned rde;
-	unsigned rds;
-	unsigned ssa;
 	block_t *blk;
 	fat_cluster_t *lifo;	/* stack for storing free cluster numbers */ 
@@ -380,16 +412,4 @@
 	if (!lifo)
 		return ENOMEM;
-	
-	bps = uint16_t_le2host(bs->bps);
-	rscnt = uint16_t_le2host(bs->rscnt);
-	sf = uint16_t_le2host(bs->sec_per_fat);
-	rde = uint16_t_le2host(bs->root_ent_max);
-	ts = (uint32_t) uint16_t_le2host(bs->totsec16);
-	if (ts == 0)
-		ts = uint32_t_le2host(bs->totsec32);
-
-	rds = (sizeof(fat_dentry_t) * rde) / bps;
-	rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
-	ssa = rscnt + bs->fatcnt * sf + rds;
 	
 	/*
@@ -397,9 +417,10 @@
 	 */
 	fibril_mutex_lock(&fat_alloc_lock);
-	for (b = 0, cl = 0; b < sf; b++) {
-		rc = block_get(&blk, dev_handle, rscnt + b, BLOCK_FLAGS_NONE);
+	for (b = 0, cl = 0; b < SF(bs); b++) {
+		rc = block_get(&blk, dev_handle, RSCNT(bs) + b,
+		    BLOCK_FLAGS_NONE);
 		if (rc != EOK)
 			goto error;
-		for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) {
+		for (c = 0; c < BPS(bs) / sizeof(fat_cluster_t); c++, cl++) {
 			/*
 			 * Check if the cluster is physically there. This check
@@ -408,5 +429,6 @@
 			 * from the size of the file allocation table.
 			 */
-			if ((cl >= 2) && ((cl - 2) * bs->spc + ssa >= ts)) {
+			if ((cl >= 2) &&
+			    ((cl - 2) * SPC(bs) + SSA(bs) >= TS(bs))) {
 				rc = block_put(blk);
 				if (rc != EOK)
@@ -511,33 +533,44 @@
  * @param nodep		Node representing the file.
  * @param mcl		First cluster of the cluster chain to append.
+ * @param lcl		Last cluster of the cluster chain to append.
  *
  * @return		EOK on success or a negative error code.
  */
-int fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl)
+int
+fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl,
+    fat_cluster_t lcl)
 {
 	dev_handle_t dev_handle = nodep->idx->dev_handle;
-	fat_cluster_t lcl;
+	fat_cluster_t lastc;
 	uint16_t numc;
 	uint8_t fatno;
 	int rc;
 
-	rc = fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl, &numc,
-	    (uint16_t) -1);
-	if (rc != EOK)
-		return rc;
-
-	if (numc == 0) {
-		/* No clusters allocated to the node yet. */
-		nodep->firstc = mcl;
-		nodep->dirty = true;		/* need to sync node */
-		return EOK;
+	if (nodep->lastc_cached_valid) {
+		lastc = nodep->lastc_cached_value;
+		nodep->lastc_cached_valid = false;
+	} else {
+		rc = fat_cluster_walk(bs, dev_handle, nodep->firstc, &lastc,
+		    &numc, (uint16_t) -1);
+		if (rc != EOK)
+			return rc;
+
+		if (numc == 0) {
+			/* No clusters allocated to the node yet. */
+			nodep->firstc = mcl;
+			nodep->dirty = true;	/* need to sync node */
+			return EOK;
+		}
 	}
 
 	for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
-		rc = fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lcl,
+		rc = fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lastc,
 		    mcl);
 		if (rc != EOK)
 			return rc;
 	}
+
+	nodep->lastc_cached_valid = true;
+	nodep->lastc_cached_value = lcl;
 
 	return EOK;
@@ -548,5 +581,5 @@
  * @param bs		Buffer holding the boot sector of the file system.
  * @param nodep		FAT node where the chopping will take place.
- * @param lastc		Last cluster which will remain in the node. If this
+ * @param lcl		Last cluster which will remain in the node. If this
  *			argument is FAT_CLST_RES0, then all clusters will
  *			be chopped off.
@@ -554,10 +587,17 @@
  * @return		EOK on success or a negative return code.
  */
-int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lastc)
-{
-	int rc;
-
+int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lcl)
+{
+	int rc;
 	dev_handle_t dev_handle = nodep->idx->dev_handle;
-	if (lastc == FAT_CLST_RES0) {
+
+	/*
+	 * Invalidate cached cluster numbers.
+	 */
+	nodep->lastc_cached_valid = false;
+	if (nodep->currc_cached_value != lcl)
+		nodep->currc_cached_valid = false;
+
+	if (lcl == FAT_CLST_RES0) {
 		/* The node will have zero size and no clusters allocated. */
 		rc = fat_free_clusters(bs, dev_handle, nodep->firstc);
@@ -570,5 +610,5 @@
 		unsigned fatno;
 
-		rc = fat_get_cluster(bs, dev_handle, FAT1, lastc, &nextc);
+		rc = fat_get_cluster(bs, dev_handle, FAT1, lcl, &nextc);
 		if (rc != EOK)
 			return rc;
@@ -576,5 +616,5 @@
 		/* Terminate the cluster chain in all copies of FAT. */
 		for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
-			rc = fat_set_cluster(bs, dev_handle, fatno, lastc,
+			rc = fat_set_cluster(bs, dev_handle, fatno, lcl,
 			    FAT_CLST_LAST1);
 			if (rc != EOK)
@@ -588,4 +628,10 @@
 	}
 
+	/*
+	 * Update and re-enable the last cluster cache.
+	 */
+	nodep->lastc_cached_valid = true;
+	nodep->lastc_cached_value = lcl;
+
 	return EOK;
 }
@@ -596,15 +642,12 @@
 	int i;
 	block_t *b;
-	unsigned bps;
-	int rc;
-
-	bps = uint16_t_le2host(bs->bps);
-	
-	for (i = 0; i < bs->spc; i++) {
-		rc = _fat_block_get(&b, bs, dev_handle, c, i,
+	int rc;
+
+	for (i = 0; i < SPC(bs); i++) {
+		rc = _fat_block_get(&b, bs, dev_handle, c, NULL, i,
 		    BLOCK_FLAGS_NOREAD);
 		if (rc != EOK)
 			return rc;
-		memset(b->data, 0, bps);
+		memset(b->data, 0, BPS(bs));
 		b->dirty = true;
 		rc = block_put(b);
Index: uspace/srv/fs/fat/fat_fat.h
===================================================================
--- uspace/srv/fs/fat/fat_fat.h	(revision 14f21007dc0cf82ed243c0420406da06d1dd6c47)
+++ uspace/srv/fs/fat/fat_fat.h	(revision 9a1d8abd4768c007dc2f27c914e04be26e5a64f5)
@@ -64,13 +64,11 @@
     fat_cluster_t *, uint16_t *, uint16_t);
 
-#define fat_block_get(b, bs, np, bn, flags) \
-    _fat_block_get((b), (bs), (np)->idx->dev_handle, (np)->firstc, (bn), \
-    (flags))
-
+extern int fat_block_get(block_t **, struct fat_bs *, struct fat_node *,
+    aoff64_t, int);
 extern int _fat_block_get(block_t **, struct fat_bs *, dev_handle_t,
-    fat_cluster_t, aoff64_t, int);
+    fat_cluster_t, fat_cluster_t *, aoff64_t, int);
 
 extern int fat_append_clusters(struct fat_bs *, struct fat_node *,
-    fat_cluster_t);
+    fat_cluster_t, fat_cluster_t);
 extern int fat_chop_clusters(struct fat_bs *, struct fat_node *,
     fat_cluster_t);
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 14f21007dc0cf82ed243c0420406da06d1dd6c47)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 9a1d8abd4768c007dc2f27c914e04be26e5a64f5)
@@ -60,4 +60,7 @@
 #define FS_NODE(node)	((node) ? (node)->bp : NULL)
 
+#define DPS(bs)		(BPS((bs)) / sizeof(fat_dentry_t))
+#define BPC(bs)		(BPS((bs)) * SPC((bs)))
+
 /** Mutex protecting the list of cached free FAT nodes. */
 static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
@@ -101,4 +104,9 @@
 	node->refcnt = 0;
 	node->dirty = false;
+	node->lastc_cached_valid = false;
+	node->lastc_cached_value = FAT_CLST_LAST1;
+	node->currc_cached_valid = false;
+	node->currc_cached_bn = 0;
+	node->currc_cached_value = FAT_CLST_LAST1;
 }
 
@@ -108,6 +116,4 @@
 	fat_bs_t *bs;
 	fat_dentry_t *d;
-	uint16_t bps;
-	unsigned dps;
 	int rc;
 	
@@ -115,14 +121,13 @@
 
 	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);
+	    NULL, (node->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
+	    BLOCK_FLAGS_NONE);
 	if (rc != EOK)
 		return rc;
 
-	d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
+	d = ((fat_dentry_t *)b->data) + (node->idx->pdi % DPS(bs));
 
 	d->firstc = host2uint16_t_le(node->firstc);
@@ -266,7 +271,4 @@
 	fat_dentry_t *d;
 	fat_node_t *nodep = NULL;
-	unsigned bps;
-	unsigned spc;
-	unsigned dps;
 	int rc;
 
@@ -298,11 +300,8 @@
 
 	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);
+	rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc, NULL,
+	    (idxp->pdi * sizeof(fat_dentry_t)) / BPS(bs), BLOCK_FLAGS_NONE);
 	if (rc != EOK) {
 		(void) fat_node_put(FS_NODE(nodep));
@@ -310,5 +309,5 @@
 	}
 
-	d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
+	d = ((fat_dentry_t *)b->data) + (idxp->pdi % DPS(bs));
 	if (d->attr & FAT_ATTR_SUBDIR) {
 		/* 
@@ -330,5 +329,5 @@
 			return rc;
 		}
-		nodep->size = bps * spc * clusters;
+		nodep->size = BPS(bs) * SPC(bs) * clusters;
 	} else {
 		nodep->type = FAT_FILE;
@@ -368,6 +367,4 @@
 	char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
 	unsigned i, j;
-	unsigned bps;		/* bytes per sector */
-	unsigned dps;		/* dentries per sector */
 	unsigned blocks;
 	fat_dentry_t *d;
@@ -377,7 +374,5 @@
 	fibril_mutex_lock(&parentp->idx->lock);
 	bs = block_bb_get(parentp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-	blocks = parentp->size / bps;
+	blocks = parentp->size / BPS(bs);
 	for (i = 0; i < blocks; i++) {
 		rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
@@ -386,5 +381,5 @@
 			return rc;
 		}
-		for (j = 0; j < dps; j++) { 
+		for (j = 0; j < DPS(bs); j++) { 
 			d = ((fat_dentry_t *)b->data) + j;
 			switch (fat_classify_dentry(d)) {
@@ -414,5 +409,5 @@
 				fat_idx_t *idx = fat_idx_get_by_pos(
 				    parentp->idx->dev_handle, parentp->firstc,
-				    i * dps + j);
+				    i * DPS(bs) + j);
 				fibril_mutex_unlock(&parentp->idx->lock);
 				if (!idx) {
@@ -513,9 +508,7 @@
 	fat_bs_t *bs;
 	fat_cluster_t mcl, lcl;
-	uint16_t bps;
 	int rc;
 
 	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
 	if (flags & L_DIRECTORY) {
 		/* allocate a cluster */
@@ -546,5 +539,5 @@
 		nodep->type = FAT_DIRECTORY;
 		nodep->firstc = mcl;
-		nodep->size = bps * bs->spc;
+		nodep->size = BPS(bs) * SPC(bs);
 	} else {
 		nodep->type = FAT_FILE;
@@ -609,6 +602,4 @@
 	block_t *b;
 	unsigned i, j;
-	uint16_t bps;
-	unsigned dps;
 	unsigned blocks;
 	fat_cluster_t mcl, lcl;
@@ -640,8 +631,6 @@
 	fibril_mutex_lock(&parentp->idx->lock);
 	bs = block_bb_get(parentp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-
-	blocks = parentp->size / bps;
+
+	blocks = parentp->size / BPS(bs);
 
 	for (i = 0; i < blocks; i++) {
@@ -651,5 +640,5 @@
 			return rc;
 		}
-		for (j = 0; j < dps; j++) {
+		for (j = 0; j < DPS(bs); j++) {
 			d = ((fat_dentry_t *)b->data) + j;
 			switch (fat_classify_dentry(d)) {
@@ -691,5 +680,5 @@
 		return rc;
 	}
-	rc = fat_append_clusters(bs, parentp, mcl);
+	rc = fat_append_clusters(bs, parentp, mcl, lcl);
 	if (rc != EOK) {
 		(void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
@@ -697,5 +686,5 @@
 		return rc;
 	}
-	parentp->size += bps * bs->spc;
+	parentp->size += BPS(bs) * SPC(bs);
 	parentp->dirty = true;		/* need to sync node */
 	rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
@@ -771,5 +760,5 @@
 
 	childp->idx->pfc = parentp->firstc;
-	childp->idx->pdi = i * dps + j;
+	childp->idx->pdi = i * DPS(bs) + j;
 	fibril_mutex_unlock(&childp->idx->lock);
 
@@ -793,5 +782,4 @@
 	fat_bs_t *bs;
 	fat_dentry_t *d;
-	uint16_t bps;
 	block_t *b;
 	bool has_children;
@@ -812,13 +800,12 @@
 	fibril_mutex_lock(&childp->idx->lock);
 	bs = block_bb_get(childp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
 
 	rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
-	    (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
+	    NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
 	    BLOCK_FLAGS_NONE);
 	if (rc != EOK) 
 		goto error;
 	d = (fat_dentry_t *)b->data +
-	    (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
+	    (childp->idx->pdi % (BPS(bs) / sizeof(fat_dentry_t)));
 	/* mark the dentry as not-currently-used */
 	d->name[0] = FAT_DENTRY_ERASED;
@@ -852,6 +839,4 @@
 	fat_bs_t *bs;
 	fat_node_t *nodep = FAT_NODE(fn);
-	unsigned bps;
-	unsigned dps;
 	unsigned blocks;
 	block_t *b;
@@ -866,8 +851,6 @@
 	fibril_mutex_lock(&nodep->idx->lock);
 	bs = block_bb_get(nodep->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-
-	blocks = nodep->size / bps;
+
+	blocks = nodep->size / BPS(bs);
 
 	for (i = 0; i < blocks; i++) {
@@ -879,5 +862,5 @@
 			return rc;
 		}
-		for (j = 0; j < dps; j++) {
+		for (j = 0; j < DPS(bs); j++) {
 			d = ((fat_dentry_t *)b->data) + j;
 			switch (fat_classify_dentry(d)) {
@@ -976,6 +959,4 @@
 	enum cache_mode cmode;
 	fat_bs_t *bs;
-	uint16_t bps;
-	uint16_t rde;
 	
 	/* Accept the mount options */
@@ -1014,9 +995,5 @@
 	bs = block_bb_get(dev_handle);
 	
-	/* Read the number of root directory entries. */
-	bps = uint16_t_le2host(bs->bps);
-	rde = uint16_t_le2host(bs->root_ent_max);
-
-	if (bps != BS_SIZE) {
+	if (BPS(bs) != BS_SIZE) {
 		block_fini(dev_handle);
 		ipc_answer_0(rid, ENOTSUP);
@@ -1025,5 +1002,5 @@
 
 	/* Initialize the block cache */
-	rc = block_cache_init(dev_handle, bps, 0 /* XXX */, cmode);
+	rc = block_cache_init(dev_handle, BPS(bs), 0 /* XXX */, cmode);
 	if (rc != EOK) {
 		block_fini(dev_handle);
@@ -1087,5 +1064,5 @@
 	rootp->refcnt = 1;
 	rootp->lnkcnt = 0;	/* FS root is not linked */
-	rootp->size = rde * sizeof(fat_dentry_t);
+	rootp->size = RDE(bs) * sizeof(fat_dentry_t);
 	rootp->idx = ridxp;
 	ridxp->nodep = rootp;
@@ -1165,5 +1142,4 @@
 	fat_node_t *nodep;
 	fat_bs_t *bs;
-	uint16_t bps;
 	size_t bytes;
 	block_t *b;
@@ -1191,5 +1167,4 @@
 
 	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
 
 	if (nodep->type == FAT_FILE) {
@@ -1204,7 +1179,7 @@
 			(void) async_data_read_finalize(callid, NULL, 0);
 		} else {
-			bytes = min(len, bps - pos % bps);
+			bytes = min(len, BPS(bs) - pos % BPS(bs));
 			bytes = min(bytes, nodep->size - pos);
-			rc = fat_block_get(&b, bs, nodep, pos / bps,
+			rc = fat_block_get(&b, bs, nodep, pos / BPS(bs),
 			    BLOCK_FLAGS_NONE);
 			if (rc != EOK) {
@@ -1214,6 +1189,6 @@
 				return;
 			}
-			(void) async_data_read_finalize(callid, b->data + pos % bps,
-			    bytes);
+			(void) async_data_read_finalize(callid,
+			    b->data + pos % BPS(bs), bytes);
 			rc = block_put(b);
 			if (rc != EOK) {
@@ -1230,6 +1205,6 @@
 
 		assert(nodep->type == FAT_DIRECTORY);
-		assert(nodep->size % bps == 0);
-		assert(bps % sizeof(fat_dentry_t) == 0);
+		assert(nodep->size % BPS(bs) == 0);
+		assert(BPS(bs) % sizeof(fat_dentry_t) == 0);
 
 		/*
@@ -1239,6 +1214,6 @@
 		 * the position pointer accordingly.
 		 */
-		bnum = (pos * sizeof(fat_dentry_t)) / bps;
-		while (bnum < nodep->size / bps) {
+		bnum = (pos * sizeof(fat_dentry_t)) / BPS(bs);
+		while (bnum < nodep->size / BPS(bs)) {
 			aoff64_t o;
 
@@ -1247,6 +1222,6 @@
 			if (rc != EOK)
 				goto err;
-			for (o = pos % (bps / sizeof(fat_dentry_t));
-			    o < bps / sizeof(fat_dentry_t);
+			for (o = pos % (BPS(bs) / sizeof(fat_dentry_t));
+			    o < BPS(bs) / sizeof(fat_dentry_t);
 			    o++, pos++) {
 				d = ((fat_dentry_t *)b->data) + o;
@@ -1306,7 +1281,4 @@
 	size_t bytes, size;
 	block_t *b;
-	uint16_t bps;
-	unsigned spc;
-	unsigned bpc;		/* bytes per cluster */
 	aoff64_t boundary;
 	int flags = BLOCK_FLAGS_NONE;
@@ -1334,7 +1306,4 @@
 
 	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	bpc = bps * spc;
 
 	/*
@@ -1345,9 +1314,9 @@
 	 * value signalizing a smaller number of bytes written. 
 	 */ 
-	bytes = min(len, bps - pos % bps);
-	if (bytes == bps)
+	bytes = min(len, BPS(bs) - pos % BPS(bs));
+	if (bytes == BPS(bs))
 		flags |= BLOCK_FLAGS_NOREAD;
 	
-	boundary = ROUND_UP(nodep->size, bpc);
+	boundary = ROUND_UP(nodep->size, BPC(bs));
 	if (pos < boundary) {
 		/*
@@ -1364,5 +1333,5 @@
 			return;
 		}
-		rc = fat_block_get(&b, bs, nodep, pos / bps, flags);
+		rc = fat_block_get(&b, bs, nodep, pos / BPS(bs), flags);
 		if (rc != EOK) {
 			(void) fat_node_put(fn);
@@ -1371,6 +1340,6 @@
 			return;
 		}
-		(void) async_data_write_finalize(callid, b->data + pos % bps,
-		    bytes);
+		(void) async_data_write_finalize(callid,
+		    b->data + pos % BPS(bs), bytes);
 		b->dirty = true;		/* need to sync block */
 		rc = block_put(b);
@@ -1396,5 +1365,5 @@
 		fat_cluster_t mcl, lcl; 
  
-		nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
+		nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
 		/* create an independent chain of nclsts clusters in all FATs */
 		rc = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
@@ -1415,6 +1384,6 @@
 			return;
 		}
-		rc = _fat_block_get(&b, bs, dev_handle, lcl, (pos / bps) % spc,
-		    flags);
+		rc = _fat_block_get(&b, bs, dev_handle, lcl, NULL,
+		    (pos / BPS(bs)) % SPC(bs), flags);
 		if (rc != EOK) {
 			(void) fat_free_clusters(bs, dev_handle, mcl);
@@ -1424,6 +1393,6 @@
 			return;
 		}
-		(void) async_data_write_finalize(callid, b->data + pos % bps,
-		    bytes);
+		(void) async_data_write_finalize(callid,
+		    b->data + pos % BPS(bs), bytes);
 		b->dirty = true;		/* need to sync block */
 		rc = block_put(b);
@@ -1438,5 +1407,5 @@
 		 * node's cluster chain.
 		 */
-		rc = fat_append_clusters(bs, nodep, mcl);
+		rc = fat_append_clusters(bs, nodep, mcl, lcl);
 		if (rc != EOK) {
 			(void) fat_free_clusters(bs, dev_handle, mcl);
@@ -1462,7 +1431,4 @@
 	fat_node_t *nodep;
 	fat_bs_t *bs;
-	uint16_t bps;
-	uint8_t spc;
-	unsigned bpc;	/* bytes per cluster */
 	int rc;
 
@@ -1479,7 +1445,4 @@
 
 	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	spc = bs->spc;
-	bpc = bps * spc;
 
 	if (nodep->size == size) {
@@ -1491,5 +1454,5 @@
 		 */
 		rc = EINVAL;
-	} else if (ROUND_UP(nodep->size, bpc) == ROUND_UP(size, bpc)) {
+	} else if (ROUND_UP(nodep->size, BPC(bs)) == ROUND_UP(size, BPC(bs))) {
 		/*
 		 * The node will be shrunk, but no clusters will be deallocated.
@@ -1509,5 +1472,5 @@
 			fat_cluster_t lastc;
 			rc = fat_cluster_walk(bs, dev_handle, nodep->firstc,
-			    &lastc, NULL, (size - 1) / bpc);
+			    &lastc, NULL, (size - 1) / BPC(bs));
 			if (rc != EOK)
 				goto out;
