diff -ur -b linux/fs/buffer.c linux_brw/fs/buffer.c --- linux/fs/buffer.c Mon Feb 19 17:36:43 2001 +++ linux_brw/fs/buffer.c Mon Feb 19 17:29:30 2001 @@ -1293,7 +1293,6 @@ iosize = 0; } - put_unused_buffer_head(tmp); iosize += size; } wake_up(&buffer_wait); @@ -1316,8 +1315,9 @@ * It is up to the caller to make sure that there are enough blocks * passed in to completely map the iobufs to disk. */ -int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], - kdev_t dev, unsigned long b[], int size, int bmap) +int brw_kiovec_bh(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size, int bmap, + struct buffer_head *bh[], int nbh) { int err; int length; @@ -1331,11 +1331,20 @@ struct kiobuf * iobuf = NULL; unsigned long page; struct page * map; - struct buffer_head *tmp, *bh[KIO_MAX_SECTORS]; + struct buffer_head *tmp; /* * First, do some alignment and validity checks */ + if(!bh) + panic("brw_kiovec_bh: bh == NULL\n"); + + for (i = 0; i < nbh; i++) { + if(!bh[i]) + panic("brw_kiovec_bh: bh[%d] == NULL\n", i); + memset(bh[i], 0, sizeof(**bh)); + } + for (i = 0; i < nr; i++) { iobuf = iovec[i]; if ((iobuf->offset & (size-1)) || @@ -1367,7 +1376,7 @@ while (length > 0) { blocknr = b[bufind++]; - tmp = get_unused_buffer_head(0); + tmp = bh[bhind]; if (!tmp) { err = -ENOMEM; goto error; @@ -1387,7 +1396,7 @@ dprintk ("buffer %d (%d) at %p\n", bhind, tmp->b_blocknr, tmp->b_data); - bh[bhind++] = tmp; + bhind++; length -= size; offset += size; @@ -1395,7 +1404,7 @@ * Start the IO if we have got too much or if * this is the end of the last iobuf */ - if (bhind >= KIO_MAX_SECTORS) { + if (bhind >= nbh) { err = do_kio(rw, bhind, bh, size); if (err >= 0) transferred += err; @@ -1430,11 +1439,29 @@ error: /* We got an error allocation the bh'es. Just free the current buffer_heads and exit. */ - for (i = 0; i < bhind; i++) - put_unused_buffer_head(bh[i]); wake_up(&buffer_wait); goto finished; } + +int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size, int bmap) { + int i, ret, nbh; + struct buffer_head *bh[KIO_MAX_SECTORS]; + + nbh = (nr > KIO_MAX_SECTORS) ? KIO_MAX_SECTORS : nr; + for(i = 0; i < nbh; i++) + if(!(bh[i] = get_unused_buffer_head(0))) { + ret = -ENOMEM; + goto out; + } + + ret = brw_kiovec_bh(rw, nr, iovec, dev, b, size, bmap, bh, nbh); + + out: + while(i) put_unused_buffer_head(bh[--i]); + return ret; +} + /* * Start I/O on a page. diff -ur -b linux/include/linux/iobuf.h linux_brw/include/linux/iobuf.h --- linux/include/linux/iobuf.h Mon Feb 19 17:36:43 2001 +++ linux_brw/include/linux/iobuf.h Mon Feb 19 17:31:17 2001 @@ -64,6 +64,10 @@ /* fs/buffer.c */ +int brw_kiovec_bh(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size, int bmap, + struct buffer_head *bh[], int nbh); + int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], kdev_t dev, unsigned long b[], int size, int bmap); diff -ur -b linux/kernel/ksyms.c linux_brw/kernel/ksyms.c --- linux/kernel/ksyms.c Mon Feb 19 17:36:43 2001 +++ linux_brw/kernel/ksyms.c Mon Feb 19 17:24:49 2001 @@ -260,6 +260,7 @@ EXPORT_SYMBOL(alloc_kiovec); EXPORT_SYMBOL(free_kiovec); EXPORT_SYMBOL(expand_kiobuf); +EXPORT_SYMBOL(brw_kiovec_bh); EXPORT_SYMBOL(brw_kiovec); /* tty routines */