Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 69a60c4719c00c65754e37637d85664db3fa149f)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 20235a356988dff15276fd66d391230fc9b32591)
@@ -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;
