Commit fbc139f5 authored by Linus Torvalds's avatar Linus Torvalds

v2.4.10.0.2 -> v2.4.10.0.3

  - more buffers-in-pagecache coherency
parent d51c905a
...@@ -719,7 +719,7 @@ static int loop_init_xfer(struct loop_device *lo, int type,struct loop_info *i) ...@@ -719,7 +719,7 @@ static int loop_init_xfer(struct loop_device *lo, int type,struct loop_info *i)
return err; return err;
} }
static int loop_clr_fd(struct loop_device *lo, kdev_t dev) static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
{ {
struct file *filp = lo->lo_backing_file; struct file *filp = lo->lo_backing_file;
int gfp = lo->old_gfp_mask; int gfp = lo->old_gfp_mask;
...@@ -752,7 +752,7 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev) ...@@ -752,7 +752,7 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_name, 0, LO_NAME_SIZE); memset(lo->lo_name, 0, LO_NAME_SIZE);
loop_sizes[lo->lo_number] = 0; loop_sizes[lo->lo_number] = 0;
invalidate_buffers(dev); invalidate_bdev(bdev, 0);
filp->f_dentry->d_inode->i_mapping->gfp_mask = gfp; filp->f_dentry->d_inode->i_mapping->gfp_mask = gfp;
lo->lo_state = Lo_unbound; lo->lo_state = Lo_unbound;
fput(filp); fput(filp);
...@@ -852,7 +852,7 @@ static int lo_ioctl(struct inode * inode, struct file * file, ...@@ -852,7 +852,7 @@ static int lo_ioctl(struct inode * inode, struct file * file,
err = loop_set_fd(lo, file, inode->i_rdev, arg); err = loop_set_fd(lo, file, inode->i_rdev, arg);
break; break;
case LOOP_CLR_FD: case LOOP_CLR_FD:
err = loop_clr_fd(lo, inode->i_rdev); err = loop_clr_fd(lo, inode->i_bdev);
break; break;
case LOOP_SET_STATUS: case LOOP_SET_STATUS:
err = loop_set_status(lo, (struct loop_info *) arg); err = loop_set_status(lo, (struct loop_info *) arg);
......
...@@ -481,7 +481,7 @@ static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *dr ...@@ -481,7 +481,7 @@ static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *dr
static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive) static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
{ {
if (drive->removable && !drive->usage) { if (drive->removable && !drive->usage) {
invalidate_buffers(inode->i_rdev); invalidate_bdev(inode->i_bdev, 0);
if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL)) if (drive->doorlocking && ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL))
drive->doorlocking = 0; drive->doorlocking = 0;
} }
......
...@@ -1750,7 +1750,7 @@ static void idefloppy_release (struct inode *inode, struct file *filp, ide_drive ...@@ -1750,7 +1750,7 @@ static void idefloppy_release (struct inode *inode, struct file *filp, ide_drive
if (!drive->usage) { if (!drive->usage) {
idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_floppy_t *floppy = drive->driver_data;
invalidate_buffers (inode->i_rdev); invalidate_bdev (inode->i_bdev, 0);
/* IOMEGA Clik! drives do not support lock/unlock commands */ /* IOMEGA Clik! drives do not support lock/unlock commands */
if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
......
...@@ -79,6 +79,45 @@ static loff_t blkdev_size(kdev_t dev) ...@@ -79,6 +79,45 @@ static loff_t blkdev_size(kdev_t dev)
return (loff_t) blocks << BLOCK_SIZE_BITS; return (loff_t) blocks << BLOCK_SIZE_BITS;
} }
/* Kill _all_ buffers, dirty or not.. */
static void kill_bdev(struct block_device *bdev)
{
invalidate_bdev(bdev, 1);
truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
}
static inline void kill_buffers(kdev_t dev)
{
struct block_device *bdev = bdget(dev);
if (bdev) {
kill_bdev(bdev);
bdput(bdev);
}
}
void set_blocksize(kdev_t dev, int size)
{
extern int *blksize_size[];
if (!blksize_size[MAJOR(dev)])
return;
/* Size must be a power of two, and between 512 and PAGE_SIZE */
if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
panic("Invalid blocksize passed to set_blocksize");
if (blksize_size[MAJOR(dev)][MINOR(dev)] == 0 && size == BLOCK_SIZE) {
blksize_size[MAJOR(dev)][MINOR(dev)] = size;
return;
}
if (blksize_size[MAJOR(dev)][MINOR(dev)] == size)
return;
sync_buffers(dev, 2);
blksize_size[MAJOR(dev)][MINOR(dev)] = size;
kill_buffers(dev);
}
static inline int blkdev_get_block(struct inode * inode, long iblock, struct buffer_head * bh_result) static inline int blkdev_get_block(struct inode * inode, long iblock, struct buffer_head * bh_result)
{ {
int err; int err;
...@@ -352,21 +391,19 @@ static int blkdev_commit_write(struct file *file, struct page *page, ...@@ -352,21 +391,19 @@ static int blkdev_commit_write(struct file *file, struct page *page,
*/ */
static loff_t block_llseek(struct file *file, loff_t offset, int origin) static loff_t block_llseek(struct file *file, loff_t offset, int origin)
{ {
long long retval; /* ewww */
kdev_t dev; loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size;
loff_t retval;
switch (origin) { switch (origin) {
case 2: case 2:
dev = file->f_dentry->d_inode->i_rdev; offset += size;
if (blk_size[MAJOR(dev)])
offset += (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
/* else? return -EINVAL? */
break; break;
case 1: case 1:
offset += file->f_pos; offset += file->f_pos;
} }
retval = -EINVAL; retval = -EINVAL;
if (offset >= 0) { if (offset >= 0 && offset <= size) {
if (offset != file->f_pos) { if (offset != file->f_pos) {
file->f_pos = offset; file->f_pos = offset;
file->f_reada = 0; file->f_reada = 0;
...@@ -532,7 +569,6 @@ struct block_device *bdget(dev_t dev) ...@@ -532,7 +569,6 @@ struct block_device *bdget(dev_t dev)
new_bdev->bd_dev = dev; new_bdev->bd_dev = dev;
new_bdev->bd_op = NULL; new_bdev->bd_op = NULL;
new_bdev->bd_inode = inode; new_bdev->bd_inode = inode;
inode->i_size = blkdev_size(dev);
inode->i_rdev = to_kdev_t(dev); inode->i_rdev = to_kdev_t(dev);
inode->i_bdev = new_bdev; inode->i_bdev = new_bdev;
inode->i_data.a_ops = &def_blk_aops; inode->i_data.a_ops = &def_blk_aops;
...@@ -767,6 +803,7 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind) ...@@ -767,6 +803,7 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind)
ret = bdev->bd_op->open(bdev->bd_inode, &fake_file); ret = bdev->bd_op->open(bdev->bd_inode, &fake_file);
if (!ret) { if (!ret) {
bdev->bd_openers++; bdev->bd_openers++;
bdev->bd_inode->i_size = blkdev_size(rdev);
} else if (!bdev->bd_openers) } else if (!bdev->bd_openers)
bdev->bd_op = NULL; bdev->bd_op = NULL;
} }
...@@ -798,15 +835,18 @@ int blkdev_open(struct inode * inode, struct file * filp) ...@@ -798,15 +835,18 @@ int blkdev_open(struct inode * inode, struct file * filp)
lock_kernel(); lock_kernel();
if (!bdev->bd_op) if (!bdev->bd_op)
bdev->bd_op = get_blkfops(MAJOR(inode->i_rdev)); bdev->bd_op = get_blkfops(MAJOR(inode->i_rdev));
if (bdev->bd_op) { if (bdev->bd_op) {
ret = 0; ret = 0;
if (bdev->bd_op->open) if (bdev->bd_op->open)
ret = bdev->bd_op->open(inode,filp); ret = bdev->bd_op->open(inode,filp);
if (!ret) if (!ret) {
bdev->bd_openers++; bdev->bd_openers++;
else if (!bdev->bd_openers) bdev->bd_inode->i_size = blkdev_size(inode->i_rdev);
} else if (!bdev->bd_openers)
bdev->bd_op = NULL; bdev->bd_op = NULL;
} }
unlock_kernel(); unlock_kernel();
up(&bdev->bd_sem); up(&bdev->bd_sem);
if (ret) if (ret)
...@@ -822,14 +862,12 @@ int blkdev_put(struct block_device *bdev, int kind) ...@@ -822,14 +862,12 @@ int blkdev_put(struct block_device *bdev, int kind)
down(&bdev->bd_sem); down(&bdev->bd_sem);
lock_kernel(); lock_kernel();
if (kind == BDEV_FILE) { if (kind == BDEV_FILE)
__block_fsync(bd_inode); __block_fsync(bd_inode);
} else if (kind == BDEV_FS) else if (kind == BDEV_FS)
fsync_no_super(rdev); fsync_no_super(rdev);
if (!--bdev->bd_openers) { if (!--bdev->bd_openers)
truncate_inode_pages(bd_inode->i_mapping, 0); kill_bdev(bdev);
invalidate_buffers(rdev);
}
if (bdev->bd_op->release) if (bdev->bd_op->release)
ret = bdev->bd_op->release(bd_inode, NULL); ret = bdev->bd_op->release(bd_inode, NULL);
if (!bdev->bd_openers) if (!bdev->bd_openers)
......
...@@ -86,7 +86,6 @@ static int nr_unused_buffer_heads; ...@@ -86,7 +86,6 @@ static int nr_unused_buffer_heads;
static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED; static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait); static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
static void truncate_buffers(kdev_t dev);
static int grow_buffers(kdev_t dev, unsigned long block, int size); static int grow_buffers(kdev_t dev, unsigned long block, int size);
static void __refile_buffer(struct buffer_head *); static void __refile_buffer(struct buffer_head *);
...@@ -633,10 +632,11 @@ int inode_has_buffers(struct inode *inode) ...@@ -633,10 +632,11 @@ int inode_has_buffers(struct inode *inode)
we think the disk contains more recent information than the buffercache. we think the disk contains more recent information than the buffercache.
The update == 1 pass marks the buffers we need to update, the update == 2 The update == 1 pass marks the buffers we need to update, the update == 2
pass does the actual I/O. */ pass does the actual I/O. */
void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers) void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers)
{ {
int i, nlist, slept; int i, nlist, slept;
struct buffer_head * bh, * bh_next; struct buffer_head * bh, * bh_next;
kdev_t dev = to_kdev_t(bdev->bd_dev); /* will become bdev */
retry: retry:
slept = 0; slept = 0;
...@@ -691,30 +691,16 @@ void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers) ...@@ -691,30 +691,16 @@ void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
goto retry; goto retry;
/* Get rid of the page cache */ /* Get rid of the page cache */
truncate_buffers(dev); invalidate_inode_pages(bdev->bd_inode);
} }
void set_blocksize(kdev_t dev, int size) void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
{ {
extern int *blksize_size[]; struct block_device *bdev = bdget(dev);
if (bdev) {
if (!blksize_size[MAJOR(dev)]) invalidate_bdev(bdev, destroy_dirty_buffers);
return; bdput(bdev);
/* Size must be a power of two, and between 512 and PAGE_SIZE */
if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
panic("Invalid blocksize passed to set_blocksize");
if (blksize_size[MAJOR(dev)][MINOR(dev)] == 0 && size == BLOCK_SIZE) {
blksize_size[MAJOR(dev)][MINOR(dev)] = size;
return;
} }
if (blksize_size[MAJOR(dev)][MINOR(dev)] == size)
return;
sync_buffers(dev, 2);
blksize_size[MAJOR(dev)][MINOR(dev)] = size;
invalidate_buffers(dev);
} }
static void free_more_memory(void) static void free_more_memory(void)
...@@ -2345,13 +2331,6 @@ static int grow_buffers(kdev_t dev, unsigned long block, int size) ...@@ -2345,13 +2331,6 @@ static int grow_buffers(kdev_t dev, unsigned long block, int size)
return 1; return 1;
} }
static void truncate_buffers(kdev_t dev)
{
struct block_device *bdev = bdget(kdev_t_to_nr(dev));
truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
atomic_dec(&bdev->bd_count);
}
static int sync_page_buffers(struct buffer_head *bh, unsigned int gfp_mask) static int sync_page_buffers(struct buffer_head *bh, unsigned int gfp_mask)
{ {
struct buffer_head * p = bh; struct buffer_head * p = bh;
......
...@@ -1167,6 +1167,7 @@ extern void invalidate_inode_pages2(struct address_space *); ...@@ -1167,6 +1167,7 @@ extern void invalidate_inode_pages2(struct address_space *);
extern void invalidate_inode_buffers(struct inode *); extern void invalidate_inode_buffers(struct inode *);
#define invalidate_buffers(dev) __invalidate_buffers((dev), 0) #define invalidate_buffers(dev) __invalidate_buffers((dev), 0)
#define destroy_buffers(dev) __invalidate_buffers((dev), 1) #define destroy_buffers(dev) __invalidate_buffers((dev), 1)
extern void invalidate_bdev(struct block_device *, int);
extern void __invalidate_buffers(kdev_t dev, int); extern void __invalidate_buffers(kdev_t dev, int);
extern void sync_inodes(kdev_t); extern void sync_inodes(kdev_t);
extern void sync_unlocked_inodes(void); extern void sync_unlocked_inodes(void);
......
...@@ -172,6 +172,7 @@ EXPORT_SYMBOL(put_filp); ...@@ -172,6 +172,7 @@ EXPORT_SYMBOL(put_filp);
EXPORT_SYMBOL(files_lock); EXPORT_SYMBOL(files_lock);
EXPORT_SYMBOL(check_disk_change); EXPORT_SYMBOL(check_disk_change);
EXPORT_SYMBOL(__invalidate_buffers); EXPORT_SYMBOL(__invalidate_buffers);
EXPORT_SYMBOL(invalidate_bdev);
EXPORT_SYMBOL(invalidate_inodes); EXPORT_SYMBOL(invalidate_inodes);
EXPORT_SYMBOL(invalidate_device); EXPORT_SYMBOL(invalidate_device);
EXPORT_SYMBOL(invalidate_inode_pages); EXPORT_SYMBOL(invalidate_inode_pages);
......
...@@ -172,11 +172,7 @@ void invalidate_inode_pages(struct inode * inode) ...@@ -172,11 +172,7 @@ void invalidate_inode_pages(struct inode * inode)
page = list_entry(curr, struct page, list); page = list_entry(curr, struct page, list);
curr = curr->next; curr = curr->next;
/* We cannot invalidate something in use.. */ /* We cannot invalidate something in dirty.. */
if (page_count(page) != 1)
continue;
/* ..or dirty.. */
if (PageDirty(page)) if (PageDirty(page))
continue; continue;
...@@ -184,10 +180,20 @@ void invalidate_inode_pages(struct inode * inode) ...@@ -184,10 +180,20 @@ void invalidate_inode_pages(struct inode * inode)
if (TryLockPage(page)) if (TryLockPage(page))
continue; continue;
if (page->buffers && !try_to_free_buffers(page, 0))
goto unlock;
if (page_count(page) != 1)
goto unlock;
__lru_cache_del(page); __lru_cache_del(page);
__remove_inode_page(page); __remove_inode_page(page);
UnlockPage(page); UnlockPage(page);
page_cache_release(page); page_cache_release(page);
continue;
unlock:
UnlockPage(page);
continue;
} }
spin_unlock(&pagemap_lru_lock); spin_unlock(&pagemap_lru_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment