patch-2.4.15 linux/drivers/block/loop.c

Next file: linux/drivers/block/paride/pd.c
Previous file: linux/drivers/block/cpqarray.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.14/linux/drivers/block/loop.c linux/drivers/block/loop.c
@@ -180,12 +180,15 @@
 	unsigned size, offset;
 	int len;
 
+	down(&mapping->host->i_sem);
 	index = pos >> PAGE_CACHE_SHIFT;
 	offset = pos & (PAGE_CACHE_SIZE - 1);
 	len = bh->b_size;
 	data = bh->b_data;
 	while (len > 0) {
 		int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize;
+		int transfer_result;
+
 		size = PAGE_CACHE_SIZE - offset;
 		if (size > len)
 			size = len;
@@ -197,30 +200,35 @@
 			goto unlock;
 		kaddr = page_address(page);
 		flush_dcache_page(page);
-		if (lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV))
-			goto write_fail;
+		transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV);
+		if (transfer_result) {
+			/*
+			 * The transfer failed, but we still write the data to
+			 * keep prepare/commit calls balanced.
+			 */
+			printk(KERN_ERR "loop: transfer error block %ld\n", index);
+			memset(kaddr + offset, 0, size);
+		}
 		if (aops->commit_write(file, page, offset, offset+size))
 			goto unlock;
+		if (transfer_result)
+			goto unlock;
 		data += size;
 		len -= size;
 		offset = 0;
 		index++;
 		pos += size;
 		UnlockPage(page);
-		deactivate_page(page);
 		page_cache_release(page);
 	}
+	up(&mapping->host->i_sem);
 	return 0;
 
-write_fail:
-	printk(KERN_ERR "loop: transfer error block %ld\n", index);
-	ClearPageUptodate(page);
-	kunmap(page);
 unlock:
 	UnlockPage(page);
-	deactivate_page(page);
 	page_cache_release(page);
 fail:
+	up(&mapping->host->i_sem);
 	return -1;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)