Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 323

kernel-2.6.18-238.el5.src.rpm

From: Tomas Henzl <thenzl@redhat.com>
Date: Sun, 29 Aug 2010 15:49:13 -0400
Subject: [block] cciss: fix problem with SG_IO completions
Message-id: <1283097002-3341-15-git-send-email-thenzl@redhat.com>
Patchwork-id: 27861
O-Subject: [RHEL6 PATCH 14/63] cciss: fix problem with SG_IO completions
Bugzilla: 568830
RH-Acked-by: Neil Horman <nhorman@redhat.com>

ix problem with SG_IO completions
Fix the problem with the main i/o path and SG_IO.  For block_fs_requests,
we now call complete_fs_buffers, which does thing more or less as before.
For block_pc_requests, loop through the bios, completing requests up to
nr_bytes (as computed by blk_rq_bytes()).

diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 0592519..8aa237d 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1485,15 +1485,33 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 	}
 }
 
-static inline void complete_buffers(struct bio *bio, int status)
+static inline void complete_pc_buffers(struct bio *bio, unsigned int nr_bytes, int status)
 {
+	unsigned int bytes_remaining = nr_bytes;
+
 	while (bio) {
 		struct bio *xbh = bio->bi_next;
-		int nr_sectors = bio_sectors(bio);
+		unsigned int bytes_in_this_bio = bio_sectors(bio) << 9;
+
+		if (bytes_in_this_bio > bytes_remaining)
+			bytes_in_this_bio = bytes_remaining;
 
 		bio->bi_next = NULL;
-		blk_finished_io(len);
-		bio_endio(bio, nr_sectors << 9, status);
+		bio_endio(bio, bytes_in_this_bio, status ? 0 : -EIO);
+		bio = xbh;
+
+		bytes_remaining -= bytes_in_this_bio;
+	}
+}
+
+static inline void complete_fs_buffers(struct bio *bio, int status)
+{
+	while (bio) {
+		struct bio *xbh = bio->bi_next;
+		unsigned int nr_bytes = bio_sectors(bio) << 9;
+ 
+		bio->bi_next = NULL;
+		bio_endio(bio, nr_bytes, status ? 0 : -EIO);
 		bio = xbh;
 	}
 }
@@ -1545,10 +1563,28 @@ static void cciss_check_queues(ctlr_info_t *h)
 	}
 }
 
+/**
+ * blk_rq_bytes - Returns bytes left to complete in the entire request
+ * @rq: the request being processed
+ * this function is copied from later kernels (2.6.29-ish), where it is
+ * normally defined in blk/blk-core.c
+ * Slightly modified for older kernels.
+ **/
+static unsigned int blk_rq_bytes(struct request *rq)
+{
+	int nr_sectors = bio_sectors(rq->bio);
+
+	if (blk_fs_request(rq))
+		return nr_sectors << 9;
+
+	return rq->data_len;
+}
+
 static void cciss_softirq_done(struct request *rq)
 {
 	CommandList_struct *cmd = rq->completion_data;
 	ctlr_info_t *h = hba[cmd->ctlr];
+	unsigned int nr_bytes;
 	unsigned long flags;
 	u64bit temp64;
 	int i, ddir;
@@ -1565,12 +1601,13 @@ static void cciss_softirq_done(struct request *rq)
 		temp64.val32.upper = cmd->SG[i].Addr.upper;
 		pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
 	}
-
-	complete_buffers(rq->bio, rq->errors);
-
-	if (blk_fs_request(rq)) {
+	if (blk_pc_request(rq)) {
+		nr_bytes = blk_rq_bytes(rq);
+		complete_pc_buffers(rq->bio, nr_bytes, rq->errors);
+		rq->data_len = cmd->err_info->ResidualCnt;
+	} else {
 		const int rw = rq_data_dir(rq);
-
+		complete_fs_buffers(rq->bio, (rq->errors == 0));
 		all_stat_add(rq->rq_disk, sectors[rw],
 			     rq->nr_sectors, rq->sector);
 	}