Commit cbf5d468 authored by Linus Torvalds's avatar Linus Torvalds

Linux-2.3.7.. Let's be careful out there..

The new and much improved fully page-cache based filesystem code is now
apparently stable, and works wonderfully well performancewise. We fixed
all known issues with the IO subsystem: it scales well in SMP, and it
avoids unnecessary copies and unnecessary temporary buffers for write-out.

The shared mapping code in particular is much cleaner and also a _lot_
faster.

In short, it's perfect. And we want as many people as possible out there
testing out the new cool code, and bask in the success stories..
HOWEVER. _Just_ in case something goes wrong [ extremely unlikely of
course. Sure. Sue me ], we want to indeminfy ourselves. There just might
be a bug hiding there somewhere, and it might eat your filesystem while
laughing in glee over you being naive and testing new code. So you have
been warned.

In particular, there's some indication that it might have problems on
sparc still (and/or other architectures), possibly due to the ext2fs byte
order cleanups that have also been done in order to reach the
afore-mentioned state of perfection.
I'd be especially interested in people running databases on top of Linux:
Solid server in particular is very fsync-happy, and that's one of the
operations that have been speeded up by orders of magnitude.

                        Linus
parent ee5028bb
......@@ -148,7 +148,6 @@ static struct inode_operations proc_mca_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
#endif
......
......@@ -47,13 +47,23 @@ pci_find_slot(unsigned int bus, unsigned int devfn)
struct pci_dev *
pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
{
if (!from)
from = pci_devices;
else
from = from->next;
while (from && (from->vendor != vendor && vendor != PCI_ANY_ID || from->device != device && device != PCI_ANY_ID))
from = from->next;
return from;
struct pci_dev *next;
next = pci_devices;
if (from)
next = from->next;
while (next) {
struct pci_dev *dev = next;
next = next->next;
if (vendor != PCI_ANY_ID && dev->vendor != vendor)
continue;
if (device != PCI_ANY_ID && dev->device != device)
continue;
return dev;
}
return NULL;
}
......
......@@ -50,7 +50,7 @@ static struct acm_state static_acm_state;
spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED;
static int acm_irq(int state, void *__buffer, void *dev_id)
static int acm_irq(int state, void *__buffer, int len, void *dev_id)
{
// unsigned char *data = __buffer;
struct acm_state *acm = &static_acm_state;
......
......@@ -27,7 +27,7 @@ static struct usb_driver usb_audio_driver =
};
static int usb_audio_irq(int state, void *buffer, void *dev_id)
static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
{
struct usb_audio *aud = (struct usb_audio*) dev_id;
return 1;
......
......@@ -451,7 +451,7 @@ printk("copying\n");
}
}
static int cpia_isoc_irq(int status, void *__buffer, void *dev_id)
static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id)
{
struct usb_cpia *cpia = dev_id;
struct usb_device *dev = cpia->dev;
......
......@@ -33,7 +33,7 @@ static int khubd_pid = 0;
* the low-level driver that it wants to be re-activated,
* or zero to say "I'm done".
*/
static int hub_irq(int status, void *__buffer, void *dev_id)
static int hub_irq(int status, void *__buffer, int len, void *dev_id)
{
struct usb_hub *hub = dev_id;
unsigned long flags;
......
......@@ -92,7 +92,7 @@ usb_kbd_repeat(unsigned long dev_id)
}
static int
usb_kbd_irq(int state, void *buffer, void *dev_id)
usb_kbd_irq(int state, void *buffer, int len, void *dev_id)
{
struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
unsigned long *down = (unsigned long*) buffer;
......
......@@ -60,7 +60,7 @@ static struct mouse_state static_mouse_state;
spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
static int mouse_irq(int state, void *__buffer, void *dev_id)
static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
{
signed char *data = __buffer;
/* finding the mouse is easy when there's only one */
......
......@@ -102,7 +102,7 @@ static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len,
OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
OHCI_DEBUG( printk(" ret_status: %x\n", status); })
ret = handler(cc_to_status[status & 0xf], data, dev_id);
ret = handler(cc_to_status[status & 0xf], data, data_len, dev_id);
if(ret == 0) return 0; /* 0 .. do not requeue */
if(status > 0) return -1; /* error occured do not requeue ? */
ohci_trans_req(ohci, ep_addr, 0, NULL, data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); /* requeue int request */
......
......@@ -777,7 +777,7 @@ static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
*
* This function is called from the interrupt handler.
*/
static int ohci_control_completed(int stats, void *buffer, void *dev_id)
static int ohci_control_completed(int stats, void *buffer, int len, void *dev_id)
{
/* pass the TDs completion status back to control_msg */
if (dev_id) {
......@@ -1456,7 +1456,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
/* Check if TD should be re-queued */
if ((td->completed != NULL) &&
(td->completed(cc, td->data, td->dev_id))) {
(td->completed(cc, td->data, -1 /* XXX */, td->dev_id))) {
/* Mark the TD as active again:
* Set the not accessed condition code
* Reset the Error count
......
......@@ -131,7 +131,7 @@ void show_queue(struct uhci_qh *qh)
#if 0
printk(" link = %p, element = %p\n", qh->link, qh->element);
#endif
if(!qh->element) {
if(!(qh->element & ~0xF)) {
printk(" td 0 = NULL\n");
return;
}
......
......@@ -126,7 +126,7 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
tmp = td->first;
printk("uhci_td_result() failed with status %x\n", status);
show_status(dev->uhci);
//show_status(dev->uhci);
do {
show_td(tmp);
if ((tmp->link & 1) || (tmp->link & 2))
......@@ -422,7 +422,7 @@ static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_de
/* notify removal */
td->completed(USB_ST_REMOVED, NULL, td->dev_id);
td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
/* this is DANGEROUS - not sure whether this is right */
......@@ -645,7 +645,7 @@ void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc)
*/
static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
static int uhci_control_completed(int status, void *buffer, void *dev_id)
static int uhci_control_completed(int status, void *buffer, int len, void *dev_id)
{
wake_up(&control_wakeup);
return 0; /* Don't re-instate */
......@@ -692,7 +692,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
// show_status(dev->uhci);
// show_queues(dev->uhci);
schedule_timeout(HZ/10);
schedule_timeout(HZ*5);
// control should be empty here...
// show_status(dev->uhci);
......@@ -736,8 +736,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
* information, that's just ridiculously high. Most
* control messages have just a few bytes of data.
*/
static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
devrequest *cmd, void *data, int len)
static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *first, *td, *prevtd;
......@@ -805,17 +804,18 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
}
/*
* Build the final TD for control status
* Build the final TD for control status
*/
destination ^= (0xE1 ^ 0x69); /* OUT -> IN */
destination |= 1 << 19; /* End in Data1 */
td->link = 1; /* Terminate */
td->status = status | (1 << 24); /* IOC */
td->backptr = &prevtd->link;
td->status = (status /* & ~(3 << 27) */) | (1 << 24); /* no limit on final packet */
td->info = destination | (0x7ff << 21); /* 0 bytes of data */
td->buffer = 0;
td->first = first;
td->backptr = &prevtd->link;
td->link = 1; /* Terminate */
/* Start it up.. */
ret = uhci_run_control(dev, first, td);
......@@ -841,7 +841,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
}
if (uhci_debug && ret) {
__u8 *p = (__u8 *) cmd;
__u8 *p = cmd;
printk("Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
......@@ -860,7 +860,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
*/
static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
static int uhci_bulk_completed(int status, void *buffer, void *dev_id)
static int uhci_bulk_completed(int status, void *buffer, int len, void *dev_id)
{
wake_up(&bulk_wakeup);
return 0; /* Don't re-instate */
......@@ -908,10 +908,11 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
// show_status(dev->uhci);
// show_queues(dev->uhci);
schedule_timeout(HZ/10);
schedule_timeout(HZ*5);
// show_status(dev->uhci);
// show_queues(dev->uhci);
//show_queue(first->qh);
remove_wait_queue(&bulk_wakeup, &wait);
/* Clean up in case it failed.. */
......@@ -1243,6 +1244,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
{
struct list_head *head = &uhci->interrupt_list;
struct list_head *tmp;
int status;
spin_lock(&irqlist_lock);
tmp = head->next;
......@@ -1252,12 +1254,14 @@ static void uhci_interrupt_notify(struct uhci *uhci)
next = tmp->next;
if (!(td->status & (1 << 23))) { /* No longer active? */
if (!((status = td->status) & (1 << 23)) || /* No longer active? */
((td->qh->element & ~15) &&
!((status = uhci_link_to_td(td->qh->element)->status) & (1 <<23)) &&
(status & 0x760000) /* is in error state (Stall, db, babble, timeout, bitstuff) */)) {
/* remove from IRQ list */
__list_del(tmp->prev, next);
INIT_LIST_HEAD(tmp);
if (td->completed(uhci_map_status((td->status & 0xff)>> 16, 0),
bus_to_virt(td->buffer), td->dev_id)) {
if (td->completed(uhci_map_status(status, 0), bus_to_virt(td->buffer), -1, td->dev_id)) {
list_add(&td->irq_list, &uhci->interrupt_list);
if (!(td->status & (1 << 25))) {
......@@ -1284,7 +1288,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
/* If completed wants to not reactivate, then it's */
/* responsible for free'ing the TD's and QH's */
/* or another function (such as run_control) */
}
}
tmp = next;
}
spin_unlock(&irqlist_lock);
......@@ -1564,6 +1568,7 @@ static int uhci_control_thread(void * __uhci)
{
struct uhci *uhci = (struct uhci *)__uhci;
struct uhci_device * root_hub =usb_to_uhci(uhci->bus->root_hub);
lock_kernel();
request_region(uhci->io_addr, 32, "usb-uhci");
......
......@@ -242,10 +242,12 @@ struct usb_driver {
* until we come up with a common meaning.
* void *buffer - This is a pointer to the data used in this
* USB transfer.
* int length - This is the number of bytes transferred in or out
* of the buffer by this transfer. (-1 = unknown/unsupported)
* void *dev_id - This is a user defined pointer set when the IRQ
* is requested that is passed back.
*/
typedef int (*usb_device_irq)(int, void *, void *);
typedef int (*usb_device_irq)(int, void *, int, void *);
struct usb_operations {
struct usb_device *(*allocate)(struct usb_device *);
......
This diff is collapsed.
......@@ -95,7 +95,7 @@ void us_show_command(Scsi_Cmnd *srb)
case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
default: what = "??"; break;
default: break;
}
printk(KERN_DEBUG USB_SCSI "Command %s (%d bytes)\n", what, srb->cmd_len);
printk(KERN_DEBUG USB_SCSI " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
......
......@@ -63,7 +63,6 @@ struct inode_operations affs_dir_inode_operations = {
NULL, /* truncate */
NULL, /* permissions */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......
......@@ -80,7 +80,6 @@ struct inode_operations affs_file_inode_operations = {
affs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......@@ -121,7 +120,6 @@ struct inode_operations affs_file_inode_operations_ofs = {
affs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......
......@@ -79,7 +79,6 @@ struct inode_operations autofs_dir_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......@@ -60,7 +60,6 @@ struct inode_operations autofs_root_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......
......@@ -55,6 +55,5 @@ struct inode_operations autofs_symlink_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......@@ -60,13 +60,13 @@ struct inode_operations bad_inode_ops =
EIO_ERROR, /* rename */
EIO_ERROR, /* readlink */
bad_follow_link, /* follow_link */
EIO_ERROR, /* bmap */
EIO_ERROR, /* readpage */
EIO_ERROR, /* writepage */
EIO_ERROR, /* bmap */
EIO_ERROR, /* flushpage */
EIO_ERROR, /* truncate */
EIO_ERROR, /* permission */
EIO_ERROR, /* smap */
EIO_ERROR, /* update_page */
EIO_ERROR /* revalidate */
};
......
......@@ -124,6 +124,7 @@ ssize_t block_write(struct file * filp, const char * buf,
}
buffercount=0;
}
balance_dirty(dev);
if(write_error)
break;
}
......
This diff is collapsed.
......@@ -277,11 +277,14 @@ struct inode_operations blkdev_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
/*
......
......@@ -57,7 +57,6 @@ struct inode_operations devpts_root_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......
......@@ -67,12 +67,14 @@ struct inode_operations ext2_dir_inode_operations = {
ext2_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
ext2_permission, /* permission */
NULL /* smap */
NULL, /* smap */
NULL /* revalidate */
};
int ext2_check_dir_entry (const char * function, struct inode * dir,
......
......@@ -113,7 +113,7 @@ static int ext2_writepage (struct file * file, struct page * page)
static long ext2_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
return block_write_one_page(file, page, offset, bytes, buf, ext2_getblk_block);
return block_write_partial_page(file, page, offset, bytes, buf, ext2_getblk_block);
}
/*
......@@ -122,7 +122,14 @@ static long ext2_write_one_page (struct file *file, struct page *page, unsigned
static ssize_t
ext2_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
return generic_file_write(file, buf, count, ppos, ext2_write_one_page);
ssize_t retval = generic_file_write(file, buf, count, ppos, ext2_write_one_page);
if (retval > 0) {
struct inode *inode = file->f_dentry->d_inode;
remove_suid(inode);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
}
return retval;
}
/*
......@@ -188,13 +195,12 @@ struct inode_operations ext2_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
ext2_writepage, /* writepage */
ext2_bmap, /* bmap */
block_read_full_page, /* readpage */
ext2_writepage, /* writepage */
block_flushpage, /* flushpage */
ext2_truncate, /* truncate */
ext2_permission, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage,/* flushpage */
};
......@@ -31,6 +31,7 @@
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
static int ext2_update_inode(struct inode * inode, int do_sync);
......@@ -131,58 +132,66 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
int ext2_bmap (struct inode * inode, int block)
{
int i;
int i, ret;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
ret = 0;
lock_kernel();
if (block < 0) {
ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
return 0;
goto out;
}
if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
(1 << (addr_per_block_bits * 2)) +
((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
return 0;
goto out;
}
if (block < EXT2_NDIR_BLOCKS) {
ret = inode_bmap (inode, block);
goto out;
}
if (block < EXT2_NDIR_BLOCKS)
return inode_bmap (inode, block);
block -= EXT2_NDIR_BLOCKS;
if (block < addr_per_block) {
i = inode_bmap (inode, EXT2_IND_BLOCK);
if (!i)
return 0;
return block_bmap (bread (inode->i_dev, i,
goto out;
ret = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize), block);
goto out;
}
block -= addr_per_block;
if (block < (1 << (addr_per_block_bits * 2))) {
i = inode_bmap (inode, EXT2_DIND_BLOCK);
if (!i)
return 0;
goto out;
i = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
block >> addr_per_block_bits);
if (!i)
return 0;
return block_bmap (bread (inode->i_dev, i,
goto out;
ret = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
block & (addr_per_block - 1));
block & (addr_per_block - 1));
}
block -= (1 << (addr_per_block_bits * 2));
i = inode_bmap (inode, EXT2_TIND_BLOCK);
if (!i)
return 0;
goto out;
i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
block >> (addr_per_block_bits * 2));
if (!i)
return 0;
goto out;
i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
(block >> addr_per_block_bits) & (addr_per_block - 1));
if (!i)
return 0;
return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
goto out;
ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
block & (addr_per_block - 1));
out:
unlock_kernel();
return ret;
}
int ext2_bmap_create (struct inode * inode, int block)
......@@ -461,18 +470,20 @@ int ext2_getblk_block (struct inode * inode, long block,
unsigned long b;
unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
int phys_block;
int phys_block, ret;
lock_kernel();
ret = 0;
*err = -EIO;
if (block < 0) {
ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
return 0;
goto abort;
}
if (block > EXT2_NDIR_BLOCKS + addr_per_block +
(1 << (addr_per_block_bits * 2)) +
((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
return 0;
goto abort;
}
/*
* If this is a sequential block allocation, set the next_alloc_block
......@@ -527,13 +538,14 @@ int ext2_getblk_block (struct inode * inode, long block,
inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
out:
if (!phys_block) {
return 0;
}
if (*err) {
return 0;
}
return phys_block;
if (!phys_block)
goto abort;
if (*err)
goto abort;
ret = phys_block;
abort:
unlock_kernel();
return ret;
}
struct buffer_head * ext2_getblk (struct inode * inode, long block,
......
......@@ -43,12 +43,14 @@ struct inode_operations ext2_symlink_inode_operations = {
NULL, /* rename */
ext2_readlink, /* readlink */
ext2_follow_link, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL /* smap */
NULL, /* smap */
NULL /* revalidate */
};
static struct dentry * ext2_follow_link(struct dentry * dentry,
......
......@@ -179,11 +179,14 @@ struct inode_operations fifo_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
......
......@@ -99,7 +99,6 @@ struct inode_operations hfs_nat_ndir_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......@@ -122,7 +121,6 @@ struct inode_operations hfs_nat_hdir_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......
......@@ -69,7 +69,6 @@ struct inode_operations hfs_file_inode_operations = {
hfs_file_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......
......@@ -83,7 +83,6 @@ struct inode_operations hfs_cap_info_inode_operations = {
cap_info_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidata */
};
......
......@@ -85,7 +85,6 @@ struct inode_operations hfs_hdr_inode_operations = {
hdr_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......
......@@ -48,7 +48,6 @@ static const struct inode_operations hpfs_file_iops =
&hpfs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......@@ -91,7 +90,6 @@ static const struct inode_operations hpfs_dir_iops =
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......@@ -115,7 +113,6 @@ const struct inode_operations hpfs_symlink_iops =
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......
......@@ -48,9 +48,10 @@ struct inode_operations isofs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
isofs_bmap, /* bmap */
block_read_full_page, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
};
......@@ -26,6 +26,7 @@
#include <linux/init.h>
#include <linux/nls.h>
#include <linux/ctype.h>
#include <linux/smp_lock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
......@@ -909,7 +910,7 @@ int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
int isofs_bmap(struct inode * inode,int block)
static int do_isofs_bmap(struct inode * inode,int block)
{
off_t b_off, offset, size;
struct inode *ino;
......@@ -991,6 +992,15 @@ int isofs_bmap(struct inode * inode,int block)
return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
}
int isofs_bmap(struct inode * inode,int block)
{
int retval;
lock_kernel();
retval = do_isofs_bmap(inode, block);
unlock_kernel();
return retval;
}
static void test_and_set_uid(uid_t *p, uid_t value)
{
......
......@@ -110,7 +110,6 @@ struct inode_operations minix_file_inode_operations = {
minix_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage,/* flushpage */
block_flushpage, /* flushpage */
};
......@@ -633,7 +633,6 @@ struct inode_operations msdos_dir_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......
......@@ -98,7 +98,6 @@ struct inode_operations ncp_dir_inode_operations =
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......
......@@ -78,13 +78,13 @@ struct inode_operations nfs_dir_inode_operations = {
nfs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
nfs_revalidate, /* revalidate */
};
......
......@@ -71,15 +71,14 @@ struct inode_operations nfs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
nfs_readpage, /* readpage */
nfs_writepage, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
nfs_revalidate, /* revalidate */
NULL, /* flushpage */
};
/* Hack for future NFS swap support */
......
......@@ -26,6 +26,7 @@
#include <linux/pagemap.h>
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <asm/system.h>
......@@ -222,6 +223,7 @@ nfs_readpage(struct file *file, struct page *page)
struct inode *inode = dentry->d_inode;
int error;
lock_kernel();
dprintk("NFS: nfs_readpage (%p %ld@%ld)\n",
page, PAGE_SIZE, page->offset);
get_page(page);
......@@ -254,5 +256,6 @@ nfs_readpage(struct file *file, struct page *page)
out_free:
free_page(page_address(page));
out:
unlock_kernel();
return error;
}
......@@ -43,11 +43,14 @@ struct inode_operations nfs_symlink_inode_operations = {
NULL, /* rename */
nfs_readlink, /* readlink */
nfs_follow_link, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
/* Symlink caching in the page cache is even more simplistic
......
......@@ -55,6 +55,7 @@
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
#include <asm/uaccess.h>
#include <linux/smp_lock.h>
#define NFS_PARANOIA 1
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
......@@ -93,6 +94,7 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
u8 *buffer;
struct nfs_fattr fattr;
lock_kernel();
dprintk("NFS: nfs_writepage_sync(%s/%s %d@%ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
count, page->offset + offset);
......@@ -153,6 +155,7 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
inode->i_ino, fattr.fileid);
}
unlock_kernel();
return written? written : result;
}
......
......@@ -445,7 +445,6 @@ static struct inode_operations ntfs_inode_operations_nobmap = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......@@ -628,7 +627,6 @@ static struct inode_operations ntfs_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......@@ -677,7 +675,6 @@ static struct inode_operations ntfs_dir_inode_operations = {
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......
......@@ -461,11 +461,14 @@ struct inode_operations pipe_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
int do_pipe(int *fd)
......
......@@ -1519,11 +1519,14 @@ struct inode_operations proc_array_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
static ssize_t arraylong_read(struct file * file, char * buf,
......@@ -1567,9 +1570,12 @@ struct inode_operations proc_arraylong_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
......@@ -45,11 +45,14 @@ static struct inode_operations proc_base_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
/*
......
......@@ -51,11 +51,14 @@ struct inode_operations proc_fd_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
proc_permission /* permission */
proc_permission, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
/*
......
......@@ -51,20 +51,23 @@ struct inode_operations proc_file_inode_operations = {
&proc_file_operations, /* default proc file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
/*
......@@ -83,11 +86,14 @@ struct inode_operations proc_net_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
......
......@@ -72,9 +72,12 @@ struct inode_operations proc_kmsg_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
......@@ -49,11 +49,14 @@ struct inode_operations proc_link_inode_operations = {
NULL, /* rename */
proc_readlink, /* readlink */
proc_follow_link, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
proc_permission /* permission */
proc_permission, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
static struct dentry * proc_follow_link(struct dentry *dentry,
......
......@@ -336,9 +336,12 @@ struct inode_operations proc_mem_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
proc_permission /* permission */
proc_permission, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
......@@ -113,9 +113,12 @@ struct inode_operations proc_net_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
......@@ -277,22 +277,24 @@ static struct file_operations omirr_operations = {
};
struct inode_operations proc_omirr_inode_operations = {
&omirr_operations,
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL, /* permission */
NULL /* smap */
&omirr_operations,
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
......@@ -57,12 +57,14 @@ struct inode_operations devtree_symlink_inode_operations = {
NULL, /* rename */
devtree_readlink, /* readlink */
devtree_follow_link, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL /* smap */
NULL, /* smap */
NULL /* revalidate */
};
static struct dentry *devtree_follow_link(struct dentry *dentry,
......
......@@ -71,11 +71,14 @@ struct inode_operations proc_dir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
/*
......@@ -94,11 +97,14 @@ struct inode_operations proc_dyna_dir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
/*
......@@ -136,11 +142,14 @@ static struct inode_operations proc_root_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
/*
......@@ -293,11 +302,14 @@ struct inode_operations proc_openprom_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
struct proc_dir_entry proc_openprom = {
......@@ -478,11 +490,14 @@ static struct inode_operations proc_self_inode_operations = {
NULL, /* rename */
proc_self_readlink, /* readlink */
proc_self_follow_link, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
static struct inode_operations proc_link_inode_operations = {
......@@ -498,11 +513,14 @@ static struct inode_operations proc_link_inode_operations = {
NULL, /* rename */
proc_readlink, /* readlink */
proc_follow_link, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
static struct proc_dir_entry proc_root_loadavg = {
......
......@@ -59,23 +59,26 @@ static struct file_operations proc_scsi_operations = {
* proc directories can do almost nothing..
*/
struct inode_operations proc_scsi_inode_operations = {
&proc_scsi_operations, /* default scsi directory file-ops */
NULL, /* create */
proc_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
&proc_scsi_operations, /* default scsi directory file-ops */
NULL, /* create */
proc_lookup, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
int get_not_present_info(char *buffer, char **start, off_t offset, int length)
......
......@@ -118,21 +118,24 @@ static struct file_operations proc_sysvipc_operations = {
* proc directories can do almost nothing..
*/
struct inode_operations proc_sysvipc_inode_operations = {
&proc_sysvipc_operations, /* default net file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
&proc_sysvipc_operations, /* default net file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
......@@ -65,7 +65,6 @@ struct inode_operations smb_dir_inode_operations =
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
smb_revalidate_inode, /* revalidate */
};
......
......@@ -410,6 +410,5 @@ struct inode_operations smb_file_inode_operations =
NULL, /* truncate */
smb_file_permission, /* permission */
NULL, /* smap */
NULL, /* updatepage */
smb_revalidate_inode, /* revalidate */
};
......@@ -119,7 +119,6 @@ struct inode_operations sysv_file_inode_operations = {
sysv_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage,/* flushpage */
block_flushpage, /* flushpage */
};
......@@ -182,7 +182,6 @@ struct inode_operations ufs_file_inode_operations = {
ufs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage,/* flushpage */
block_flushpage, /* flushpage */
};
......@@ -838,6 +838,5 @@ struct inode_operations umsdos_dir_inode_operations =
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......@@ -253,6 +253,5 @@ struct inode_operations umsdos_rdir_inode_operations =
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
};
......@@ -141,7 +141,6 @@ struct inode_operations umsdos_symlink_inode_operations =
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL /* revalidate */
};
......@@ -596,15 +596,23 @@ struct inode_operations {
struct inode *, struct dentry *);
int (*readlink) (struct dentry *, char *,int);
struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int);
/*
* the order of these functions within the VFS template has been
* changed because SMP locking has changed: from now on all bmap,
* readpage, writepage and flushpage functions are supposed to do
* whatever locking they need to get proper SMP operation - for
* now in most cases this means a lock/unlock_kernel at entry/exit.
* [The new order is also slightly more logical :)]
*/
int (*bmap) (struct inode *,int);
int (*readpage) (struct file *, struct page *);
int (*writepage) (struct file *, struct page *);
int (*bmap) (struct inode *,int);
int (*flushpage) (struct inode *, struct page *, unsigned long);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int);
int (*smap) (struct inode *,int);
int (*updatepage) (struct file *, struct page *, unsigned long, unsigned int);
int (*revalidate) (struct dentry *);
int (*flushpage) (struct inode *, struct page *, unsigned long);
};
struct super_operations {
......@@ -745,21 +753,36 @@ void mark_buffer_uptodate(struct buffer_head *, int);
extern inline void mark_buffer_clean(struct buffer_head * bh)
{
if (test_and_clear_bit(BH_Dirty, &bh->b_state)) {
if (bh->b_list == BUF_DIRTY)
refile_buffer(bh);
}
if (test_and_clear_bit(BH_Dirty, &bh->b_state))
refile_buffer(bh);
}
extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh, int flag));
extern void FASTCALL(__atomic_mark_buffer_dirty(struct buffer_head *bh, int flag));
#define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag)
{
if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
set_writetime(bh, flag);
if (bh->b_list != BUF_DIRTY)
refile_buffer(bh);
}
if (!atomic_set_buffer_dirty(bh))
__mark_buffer_dirty(bh, flag);
}
/*
* SMP-safe version of the above - does synchronization with
* other users of buffer-cache data structures.
*
* since we test-set the dirty bit in a CPU-atomic way we also
* have optimized the common 'redirtying' case away completely.
*/
extern inline void atomic_mark_buffer_dirty(struct buffer_head * bh, int flag)
{
if (!atomic_set_buffer_dirty(bh))
__atomic_mark_buffer_dirty(bh, flag);
}
extern void balance_dirty(kdev_t);
extern int check_disk_change(kdev_t);
extern int invalidate_inodes(struct super_block *);
extern void invalidate_inode_pages(struct inode *);
......@@ -850,14 +873,15 @@ extern int brw_page(int, struct page *, kdev_t, int [], int, int);
typedef long (*writepage_t)(struct file *, struct page *, unsigned long, unsigned long, const char *);
typedef int (*fs_getblock_t)(struct inode *, long, int, int *, int *);
/* Generic buffer handling for block filesystems.. */
extern int block_read_full_page(struct file *, struct page *);
extern int block_write_full_page (struct file *, struct page *, fs_getblock_t);
extern int block_write_partial_page (struct file *, struct page *, unsigned long, unsigned long, const char *, fs_getblock_t);
extern int block_flushpage(struct inode *, struct page *, unsigned long);
extern int generic_readpage(struct file *, struct page *);
extern int generic_file_mmap(struct file *, struct vm_area_struct *);
extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *, writepage_t);
extern int generic_block_flushpage(struct inode *, struct page *, unsigned long);
extern int block_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf, fs_getblock_t fs_get_block);
extern int block_write_full_page (struct file *file, struct page *page, fs_getblock_t fs_get_block);
extern struct super_block *get_super(kdev_t);
......
......@@ -107,6 +107,7 @@ extern int FASTCALL(swap_count(unsigned long));
/*
* Make these inline later once they are working properly.
*/
extern void __delete_from_swap_cache(struct page *page);
extern void delete_from_swap_cache(struct page *page);
extern void free_page_and_swap_cache(unsigned long addr);
......
......@@ -167,7 +167,6 @@ EXPORT_SYMBOL(add_blkdev_randomness);
EXPORT_SYMBOL(generic_file_read);
EXPORT_SYMBOL(generic_file_write);
EXPORT_SYMBOL(generic_file_mmap);
EXPORT_SYMBOL(generic_readpage);
EXPORT_SYMBOL(file_lock_table);
EXPORT_SYMBOL(posix_lock_file);
EXPORT_SYMBOL(posix_test_lock);
......
......@@ -121,11 +121,14 @@ struct inode_operations proc_sys_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* flushpage */
NULL, /* truncate */
proc_sys_permission
proc_sys_permission, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
extern struct proc_dir_entry proc_sys_root;
......
......@@ -228,12 +228,14 @@ void truncate_inode_pages(struct inode * inode, unsigned long start)
spin_unlock(&pagecache_lock);
}
extern atomic_t too_many_dirty_buffers;
int shrink_mmap(int priority, int gfp_mask)
{
static unsigned long clock = 0;
unsigned long limit = num_physpages;
struct page * page;
int count, err;
int count, users;
count = limit >> priority;
......@@ -262,24 +264,64 @@ int shrink_mmap(int priority, int gfp_mask)
if ((gfp_mask & __GFP_DMA) && !PageDMA(page))
continue;
if (PageLocked(page))
/*
* Some common cases that we just short-circuit without
* getting the locks - we need to re-check this once we
* have the lock, but that's fine.
*/
users = page_count(page);
if (!users)
continue;
if (!page->buffers) {
if (!page->inode)
continue;
if (users > 1)
continue;
}
/*
* ok, now the page looks interesting. Re-check things
* and keep the lock.
*/
spin_lock(&pagecache_lock);
if (!page->inode && !page->buffers) {
spin_unlock(&pagecache_lock);
continue;
}
if (!page_count(page)) {
// BUG();
spin_unlock(&pagecache_lock);
continue;
}
get_page(page);
if (TryLockPage(page)) {
spin_unlock(&pagecache_lock);
goto put_continue;
}
/*
* we keep pagecache_lock locked and unlock it in
* each branch, so that the page->inode case doesnt
* have to re-grab it. Here comes the 'real' logic
* to free memory:
*/
/* Is it a buffer page? */
if (page->buffers) {
if (TryLockPage(page))
continue;
err = try_to_free_buffers(page);
UnlockPage(page);
if (!err)
continue;
goto out;
kdev_t dev = page->buffers->b_dev;
spin_unlock(&pagecache_lock);
if (try_to_free_buffers(page))
goto made_progress;
if (!atomic_read(&too_many_dirty_buffers)) {
atomic_set(&too_many_dirty_buffers, 1);
balance_dirty(dev);
}
goto unlock_continue;
}
/* We can't free pages unless there's just one user */
if (page_count(page) != 1)
continue;
if (page_count(page) != 2)
goto spin_unlock_continue;
count--;
......@@ -289,44 +331,36 @@ int shrink_mmap(int priority, int gfp_mask)
* were to be marked referenced..
*/
if (PageSwapCache(page)) {
if (referenced && swap_count(page->offset) != 1)
continue;
delete_from_swap_cache(page);
err = 1;
goto out;
spin_unlock(&pagecache_lock);
if (referenced && swap_count(page->offset) != 2)
goto unlock_continue;
__delete_from_swap_cache(page);
page_cache_release(page);
goto made_progress;
}
if (referenced)
continue;
/* is it a page-cache page? */
spin_lock(&pagecache_lock);
if (page->inode) {
if (pgcache_under_min())
goto unlock_continue;
if (TryLockPage(page))
goto unlock_continue;
if (page_count(page) == 1) {
remove_page_from_inode_queue(page);
remove_page_from_hash_queue(page);
page->inode = NULL;
}
if (!referenced && page->inode && !pgcache_under_min()) {
remove_page_from_inode_queue(page);
remove_page_from_hash_queue(page);
page->inode = NULL;
spin_unlock(&pagecache_lock);
UnlockPage(page);
page_cache_release(page);
err = 1;
goto out;
unlock_continue:
spin_unlock(&pagecache_lock);
continue;
goto made_progress;
}
spin_unlock_continue:
spin_unlock(&pagecache_lock);
unlock_continue:
UnlockPage(page);
put_continue:
put_page(page);
} while (count > 0);
err = 0;
out:
return err;
return 0;
made_progress:
UnlockPage(page);
put_page(page);
return 1;
}
static inline struct page * __find_page_nolock(struct inode * inode, unsigned long offset, struct page *page)
......@@ -499,9 +533,7 @@ static unsigned long try_to_read_ahead(struct file * file,
* We do not have to check the return value here
* because it's a readahead.
*/
lock_kernel();
inode->i_op->readpage(file, page);
unlock_kernel();
page_cache = 0;
page_cache_release(page);
}
......@@ -522,15 +554,13 @@ void ___wait_on_page(struct page *page)
DECLARE_WAITQUEUE(wait, tsk);
add_wait_queue(&page->wait, &wait);
tsk->state = TASK_UNINTERRUPTIBLE;
run_task_queue(&tq_disk);
if (PageLocked(page)) {
do {
tsk->state = TASK_UNINTERRUPTIBLE;
run_task_queue(&tq_disk);
schedule();
} while (PageLocked(page));
}
do {
tsk->state = TASK_UNINTERRUPTIBLE;
run_task_queue(&tq_disk);
if (!PageLocked(page))
break;
schedule();
} while (PageLocked(page));
tsk->state = TASK_RUNNING;
remove_wait_queue(&page->wait, &wait);
}
......@@ -1039,11 +1069,9 @@ static void do_generic_file_read(struct file * filp, loff_t *ppos, read_descript
goto page_ok;
}
read_page:
readpage:
/* ... and start the actual read. The read will unlock the page. */
lock_kernel();
error = inode->i_op->readpage(filp, page);
unlock_kernel();
if (!error) {
if (Page_Uptodate(page))
......@@ -1095,7 +1123,7 @@ static void do_generic_file_read(struct file * filp, loff_t *ppos, read_descript
spin_unlock(&pagecache_lock);
page_cache = 0;
goto read_page;
goto readpage;
}
*ppos = pos;
......@@ -1221,6 +1249,7 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou
if (retval)
goto fput_out;
unlock_kernel();
retval = 0;
if (count) {
read_descriptor_t desc;
......@@ -1230,7 +1259,7 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou
ppos = &in_file->f_pos;
if (offset) {
if (get_user(pos, offset))
goto fput_out;
goto fput_out_lock;
ppos = &pos;
}
......@@ -1247,7 +1276,8 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou
put_user(pos, offset);
}
fput_out_lock:
lock_kernel();
fput_out:
fput(out_file);
fput_in:
......@@ -1283,6 +1313,7 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
offset = (address & PAGE_MASK) - area->vm_start + area->vm_offset;
if (offset >= inode->i_size && (area->vm_flags & VM_SHARED) && area->vm_mm == current->mm)
goto no_page_nolock;
unlock_kernel();
/*
......@@ -1306,10 +1337,12 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
goto failure;
}
wait_on_page(page);
if (!Page_Uptodate(page))
PAGE_BUG(page);
if (!Page_Uptodate(page)) {
lock_page(page);
if (!Page_Uptodate(page))
goto page_not_uptodate;
UnlockPage(page);
}
success:
/*
......@@ -1377,9 +1410,8 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
*/
new_page = 0;
lock_kernel();
page_not_uptodate:
error = inode->i_op->readpage(file, page);
unlock_kernel();
if (!error) {
wait_on_page(page);
......@@ -1398,9 +1430,7 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
if (!PageLocked(page))
PAGE_BUG(page);
ClearPageError(page);
lock_kernel();
error = inode->i_op->readpage(file, page);
unlock_kernel();
if (error)
goto failure;
wait_on_page(page);
......
......@@ -39,15 +39,14 @@ static struct inode_operations swapper_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* bmap */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
block_flushpage, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage, /* flushpage */
NULL /* revalidate */
};
struct inode swapper_inode = { i_op: &swapper_inode_operations };
......@@ -221,17 +220,14 @@ static inline void remove_from_swap_cache(struct page *page)
remove_inode_page(page);
}
/*
* This must be called only on pages that have
* been verified to be in the swap cache.
*/
void delete_from_swap_cache(struct page *page)
void __delete_from_swap_cache(struct page *page)
{
long entry = page->offset;
lock_page(page);
#ifdef SWAP_CACHE_INFO
swap_cache_del_total++;
#endif
......@@ -241,9 +237,21 @@ void delete_from_swap_cache(struct page *page)
page_address(page), page_count(page), entry);
#endif
remove_from_swap_cache (page);
swap_free (entry);
}
/*
* This must be called only on pages that have
* been verified to be in the swap cache.
*/
void delete_from_swap_cache(struct page *page)
{
lock_page(page);
__delete_from_swap_cache(page);
UnlockPage(page);
page_cache_release(page);
swap_free (entry);
}
/*
......@@ -258,9 +266,8 @@ void free_page_and_swap_cache(unsigned long addr)
/*
* If we are the only user, then free up the swap cache.
*/
if (PageSwapCache(page) && !is_page_shared(page)) {
if (PageSwapCache(page) && !is_page_shared(page))
delete_from_swap_cache(page);
}
__free_page(page);
}
......
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