lkml.org 
[lkml]   [2001]   [Jun]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: patch: highmem zero-bounce
On Wed, Jun 27 2001, Jens Axboe wrote:
> > I can see one mm corruption race condition in the patch, you missed
> > nested irq in the for kmap_irq_bh (PIO). You must _always_
> > __cli/__save_flags before accessing the KMAP_IRQ_BH slot, in case the
> > remapping is required (so _only_ when the page is in the highmem zone).
> > Otherwise memory corruption will happen when the race triggers (for
> > example two ide disks in PIO mode doing I/O at the same time connected
> > to different irq sources).
>
> Ah yes, my bad. This requires some moving around, I'll post an updated
> patch later tonight. Thanks!

A prelim and untested fix just whipped up

--
Jens Axboe

--- include/linux/highmem.h~ Wed Jun 27 18:24:13 2001
+++ include/linux/highmem.h Wed Jun 27 18:41:55 2001
@@ -26,7 +26,9 @@
}

/*
- * remember to add offset!
+ * remember to add offset! caller must also rememer to have done __save_flags
+ * and __cli prior to calling bh_kmap_irq, and __restore_flags after calling
+ * bh_kunmap_irq
*/
static inline char *bh_kmap_irq(struct buffer_head *bh)
{
@@ -44,6 +46,37 @@

kunmap_atomic((void *) ptr, KM_BH_IRQ);
}
+
+static inline void bh_cpy_to_buf(char *buf, struct buffer_head *bh, int len)
+{
+ unsigned long flags;
+ char *bh_buf;
+
+ __save_flags(flags);
+ __cli();
+
+ bh_buf = bh_kmap_irq(bh);
+ memcpy(buf, bh_buf, len);
+ bh_kunmap_irq(bh_buf);
+
+ __restore_flags(flags);
+}
+
+static inline void bh_cpy_from_buf(struct buffer_head *bh, char *buf, int len)
+{
+ unsigned long flags;
+ char *bh_buf;
+
+ __save_flags(flags);
+ __cli();
+
+ bh_buf = bh_kmap_irq(bh);
+ memcpy(bh_buf, buf, len);
+ bh_kunmap_irq(bh_buf);
+
+ __restore_flags(flags);
+}
+

#else /* CONFIG_HIGHMEM */

--- include/linux/ide.h~ Wed Jun 27 18:43:46 2001
+++ include/linux/ide.h Wed Jun 27 18:44:18 2001
@@ -759,14 +759,17 @@
*/
#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)

-extern inline void *ide_map_buffer(struct request *rq)
+extern inline void *ide_map_buffer(struct request *rq, unsigned long flags);
{
+ __save_flags(flags);
+ __cli();
return bh_kmap_irq(rq->bh) + ide_rq_offset(rq);
}

-extern inline void ide_unmap_buffer(char *buffer)
+extern inline void ide_unmap_buffer(char *buffer, unsigned long flags)
{
bh_kunmap_irq(buffer);
+ __restore_flags(flags);
}

/*
--- drivers/scsi/scsi_lib.c~ Wed Jun 27 18:32:58 2001
+++ drivers/scsi/scsi_lib.c Wed Jun 27 18:40:57 2001
@@ -566,11 +566,8 @@
scsi_free(SCpnt->buffer, SCpnt->sglist_len);
} else {
if (SCpnt->buffer != req->buffer) {
- if (req->cmd == READ) {
- char *to = bh_kmap_irq(req->bh);
- memcpy(to, SCpnt->buffer, SCpnt->bufflen);
- bh_kunmap_irq(to);
- }
+ if (req->cmd == READ)
+ bh_cpy_from_buf(req->bh, SCpnt->buffer, SCpnt->bufflen);
scsi_free(SCpnt->buffer, SCpnt->bufflen);
}
}
--- drivers/scsi/scsi_merge.c~ Wed Jun 27 18:34:15 2001
+++ drivers/scsi/scsi_merge.c Wed Jun 27 18:38:01 2001
@@ -1022,11 +1022,8 @@
dma_exhausted(SCpnt, 0);
}
}
- if (req->cmd == WRITE) {
- char *buf = bh_kmap_irq(bh);
- memcpy(buff, buf, this_count << 9);
- bh_kunmap_irq(buf);
- }
+ if (req->cmd == WRITE)
+ bh_cpy_buf_high(buff, bh, this_count << 9);
}
}
SCpnt->request_bufflen = this_count << 9;
--- drivers/ide/ide-disk.c~ Wed Jun 27 18:42:35 2001
+++ drivers/ide/ide-disk.c Wed Jun 27 18:43:40 2001
@@ -140,6 +140,7 @@
byte stat;
int i;
unsigned int msect, nsect;
+ unsigned long flags;
struct request *rq;
char *to;

@@ -162,14 +163,14 @@
msect -= nsect;
} else
nsect = 1;
- to = ide_map_buffer(rq);
+ to = ide_map_buffer(rq, flags);
idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
#ifdef DEBUG
printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
drive->name, rq->sector, rq->sector+nsect-1,
(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
#endif
- ide_unmap_buffer(to);
+ ide_unmap_buffer(to, flags);
rq->sector += nsect;
rq->errors = 0;
i = (rq->nr_sectors -= nsect);
@@ -193,6 +194,7 @@
int i;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
struct request *rq = hwgroup->rq;
+ unsigned long flags;

if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
@@ -210,9 +212,9 @@
if (((long)rq->current_nr_sectors) <= 0)
ide_end_request(1, hwgroup);
if (i > 0) {
- char *to = ide_map_buffer(rq);
+ char *to = ide_map_buffer(rq, flags);
idedisk_output_data (drive, to, SECTOR_WORDS);
- ide_unmap_buffer(to);
+ ide_unmap_buffer(to, flags);
ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
return ide_started;
}
@@ -242,12 +244,13 @@
do {
char *buffer;
int nsect = rq->current_nr_sectors;
+ unsigned long flags;

if (nsect > mcount)
nsect = mcount;
mcount -= nsect;

- buffer = ide_map_buffer(rq);
+ buffer = ide_map_buffer(rq, flags);
rq->sector += nsect;
rq->nr_sectors -= nsect;
rq->current_nr_sectors -= nsect;
@@ -271,7 +274,7 @@
* re-entering us on the last transfer.
*/
idedisk_output_data(drive, buffer, nsect<<7);
- ide_unmap_buffer(buffer);
+ ide_unmap_buffer(buffer, flags);
} while (mcount);

return 0;
@@ -455,10 +458,12 @@
return ide_stopped;
}
} else {
- char *buffer = ide_map_buffer(rq);
+ unsigned long flags;
+ char *buffer = ide_map_buffer(rq, flags);
+
ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
idedisk_output_data(drive, buffer, SECTOR_WORDS);
- ide_unmap_buffer(buffer);
+ ide_unmap_buffer(buffer, flags);
}
return ide_started;
}
\
 
 \ /
  Last update: 2005-03-22 13:17    [W:0.149 / U:0.272 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site