Messages in this thread Patch in this message | | | Date | Tue, 29 Jun 1999 11:17:09 +0200 (CEST) | From | Ingo Molnar <> | Subject | [fixpatch] 2.3.9-pre7, DANGER |
| |
2.3.9-pre7 can rather badly damage filesystems, because block_dev.c does buffer-cache access without the kernel lock held.
i suspect that this patch will clash with David's cool buffer-cache patches - but i've just trashed one of my filesystems so i suppose people want to apply it ... Maybe we want to add the -DANGEROUS flag again? :)
-- mingo --- linux/fs/block_dev.c.orig Tue Jun 29 11:29:41 1999 +++ linux/fs/block_dev.c Tue Jun 29 12:04:17 1999 @@ -7,6 +7,7 @@ #include <linux/mm.h> #include <linux/locks.h> #include <linux/fcntl.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -30,11 +31,14 @@ kdev_t dev; struct buffer_head * bh, *bufferlist[NBUF]; register char * p; + int err; + lock_kernel(); write_error = buffercount = 0; dev = inode->i_rdev; + err = -EPERM; if ( is_read_only( inode->i_rdev )) - return -EPERM; + goto out; blocksize = BLOCK_SIZE; if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]) blocksize = blksize_size[MAJOR(dev)][MINOR(dev)]; @@ -54,8 +58,10 @@ else size = INT_MAX; while (count>0) { - if (block >= size) - return written ? written : -ENOSPC; + if (block >= size) { + err = written ? written : -ENOSPC; + goto out; + } chars = blocksize - offset; if (chars > count) chars=count; @@ -87,7 +93,8 @@ bhlist[i] = getblk (dev, block+i, blocksize); if(!bhlist[i]){ while(i >= 0) brelse(bhlist[i--]); - return written ? written : -EIO; + err = written ? written : -EIO; + goto out; }; }; ll_rw_block(READ, blocks, bhlist); @@ -98,8 +105,10 @@ }; #endif block++; - if (!bh) - return written ? written : -EIO; + if (!bh) { + err = written ? written : -EIO; + goto out; + } p = offset + bh->b_data; offset = 0; *ppos += chars; @@ -138,9 +147,12 @@ } } filp->f_reada = 1; + err = written; if(write_error) - return -EIO; - return written; + err = -EIO; +out: + unlock_kernel(); + return err; } ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos) @@ -151,7 +163,7 @@ ssize_t blocksize; ssize_t blocksize_bits, i; size_t blocks, rblocks, left; - int bhrequest, uptodate; + int bhrequest, uptodate, err; struct buffer_head ** bhb, ** bhe; struct buffer_head * buflist[NBUF]; struct buffer_head * bhreq[NBUF]; @@ -160,6 +172,7 @@ kdev_t dev; ssize_t read; + lock_kernel(); dev = inode->i_rdev; blocksize = BLOCK_SIZE; if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]) @@ -186,8 +199,10 @@ left = size - offset; if (left > count) left = count; - if (left <= 0) - return 0; + if (left <= 0) { + err = 0; + goto out; + } read = 0; block = offset >> blocksize_bits; offset &= blocksize-1; @@ -203,8 +218,10 @@ } if (block + blocks > size) { blocks = size - block; - if (blocks == 0) - return 0; + if (blocks == 0) { + err = 0; + goto out; + } } /* We do this in a two stage process. We first try to request @@ -284,10 +301,15 @@ if (++bhe == &buflist[NBUF]) bhe = buflist; }; - if (!read) - return -EIO; - filp->f_reada = 1; - return read; + if (!read) { + err = -EIO; + } else { + err = read; + filp->f_reada = 1; + } +out: + unlock_kernel(); + return err; } /*
| |