Commit 344971f8 authored by Linus Torvalds's avatar Linus Torvalds

Linux 2.3.7pre1

I'd like to point out that the current pre-2.3.7 series is fairly
experimental. As amply demonstrated by the filename (the "dangerous" part
in the filename hopefully made some people go "Hmm..").

We're working on re-architecting (or rather, cleaning up so that it works
like it really was supposed to) the page cache writing, and as a result a
number of filesystems are probably going to be broken for a while unless
we get people jumping in to help.

Right now 2.3.7-1 (aka "dangerous") is not stable even with ext2, in that
swapping doesn't work. Ingo just sent me patches to fix that, and I'm
hoping to remove the "dangerous" part from 2.3.7-2, but even then a number
of filesystems will be broken.

We _may_ end up just re-introducing the "update_vm_cache()" code for
filesystems that really don't need the added performance, but it would
actually be preferable if people really wanted to make them perform well
with the new direct write-through cache code.

                Linus
parent 3820a431
......@@ -624,6 +624,13 @@ S: 1123 North Oak Park Avenue
S: Oak Park, Illinois 60302
S: USA
N: Daniel J. Frasnelli
E: dfrasnel@alphalinux.org
W: http://www.alphalinux.org/
P: 1024/3EF87611 B9 F1 44 50 D3 E8 C2 80 DA E5 55 AA 56 7C 42 DA
D: DEC Alpha hacker
D: Miscellaneous bug squisher
N: Jim Freeman
E: jfree@sovereign.org
W: http://www.sovereign.org/
......
VERSION = 2
PATCHLEVEL = 3
SUBLEVEL = 6
SUBLEVEL = 7
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
......
......@@ -159,10 +159,10 @@ void show_mem(void)
reserved++;
else if (PageSwapCache(mem_map+i))
cached++;
else if (!atomic_read(&mem_map[i].count))
else if (!page_count(mem_map+i))
free++;
else
shared += atomic_read(&mem_map[i].count) - 1;
shared += page_count(mem_map+i) - 1;
}
printk("%d pages of RAM\n",total);
printk("%d reserved pages\n",reserved);
......@@ -449,7 +449,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
reservedpages++;
continue;
}
atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
set_page_count(mem_map+MAP_NR(tmp), 1);
#ifdef CONFIG_BLK_DEV_INITRD
if (!initrd_start || (tmp < initrd_start || tmp >=
initrd_end))
......@@ -475,7 +475,7 @@ void free_initmem(void)
addr = (unsigned long)(&__init_begin);
for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
atomic_set(&mem_map[MAP_NR(addr)].count, 1);
set_page_count(mem_map+MAP_NR(addr), 1);
free_page(addr);
}
printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
......@@ -494,9 +494,9 @@ void si_meminfo(struct sysinfo *val)
if (PageReserved(mem_map+i))
continue;
val->totalram++;
if (!atomic_read(&mem_map[i].count))
if (!page_count(mem_map+i))
continue;
val->sharedram += atomic_read(&mem_map[i].count) - 1;
val->sharedram += page_count(mem_map+i) - 1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
......
......@@ -603,7 +603,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
/* Verify requested block sizes. */
for (i = 0; i < nr; i++) {
if (bh[i] && bh[i]->b_size != correct_size) {
if (bh[i]->b_size != correct_size) {
printk(KERN_NOTICE "ll_rw_block: device %s: "
"only %d-char blocks implemented (%lu)\n",
kdevname(bh[0]->b_dev),
......
......@@ -9,6 +9,7 @@
* Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
* Original release 01/11/99
* ==FILEDATE 19990524==
*
* This code is released under the GNU General Public License (GPL)
*
......@@ -72,7 +73,7 @@
*/
#define HDLC_MAGIC 0x239e
#define HDLC_VERSION "1.0"
#define HDLC_VERSION "1.2"
#include <linux/version.h>
#include <linux/config.h>
......@@ -813,6 +814,8 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
{
struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
int error = 0;
int count;
unsigned long flags;
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
......@@ -824,21 +827,29 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
switch (cmd) {
case FIONREAD:
{
/* report count of read data available */
/* in next available frame (if any) */
int count;
unsigned long flags;
spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
if (n_hdlc->rx_buf_list.head)
count = n_hdlc->rx_buf_list.head->count;
else
count = 0;
spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
PUT_USER (error, count, (int *) arg);
}
/* report count of read data available */
/* in next available frame (if any) */
spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
if (n_hdlc->rx_buf_list.head)
count = n_hdlc->rx_buf_list.head->count;
else
count = 0;
spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
PUT_USER (error, count, (int *) arg);
break;
case TIOCOUTQ:
/* get the pending tx byte count in the driver */
count = tty->driver.chars_in_buffer ?
tty->driver.chars_in_buffer(tty) : 0;
/* add size of next output frame in queue */
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
if (n_hdlc->tx_buf_list.head)
count += n_hdlc->tx_buf_list.head->count;
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
PUT_USER (error, count, (int*)arg);
break;
default:
error = n_tty_ioctl (tty, file, cmd, arg);
break;
......
This diff is collapsed.
......@@ -53,7 +53,7 @@ int usb_init(void)
usb_acm_init();
# endif
# ifdef CONFIG_USB_PRINTER
usb_print_init();
usb_printer_init();
# endif
# ifdef CONFIG_USB_CPIA
usb_cpia_init();
......
......@@ -135,9 +135,17 @@ void no_scroll(char *str, int *ints)
*/
static inline void write_vga(unsigned char reg, unsigned int val)
{
#ifndef SLOW_VGA
unsigned int v1, v2;
unsigned long flags;
/*
* ddprintk might set the console position from interrupt
* handlers, thus the write has to be IRQ-atomic.
*/
save_flags(flags);
cli();
#ifndef SLOW_VGA
v1 = reg + (val & 0xff00);
v2 = reg + 1 + ((val << 8) & 0xff00);
outw(v1, vga_video_port_reg);
......@@ -148,6 +156,7 @@ static inline void write_vga(unsigned char reg, unsigned int val)
outb_p(reg+1, vga_video_port_reg);
outb_p(val & 0xff, vga_video_port_val);
#endif
restore_flags(flags);
}
__initfunc(static const char *vgacon_startup(void))
......
This diff is collapsed.
......@@ -358,7 +358,7 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block,
* bitmap, and then for any free bit if that fails.
*/
int ext2_new_block (const struct inode * inode, unsigned long goal,
u32 * prealloc_count, u32 * prealloc_block, int * err)
u32 * prealloc_count, u32 * prealloc_block, int * err)
{
struct buffer_head * bh;
struct buffer_head * bh2;
......@@ -594,20 +594,12 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
if (j >= le32_to_cpu(es->s_blocks_count)) {
ext2_error (sb, "ext2_new_block",
"block >= blocks count - "
"block_group = %d, block=%d", i, j);
"block(%d) >= blocks count(%d) - "
"block_group = %d, es == %p ",j,
le32_to_cpu(es->s_blocks_count), i, es);
unlock_super (sb);
return 0;
}
if (!(bh = getblk (sb->s_dev, j, sb->s_blocksize))) {
ext2_error (sb, "ext2_new_block", "cannot get block %d", j);
unlock_super (sb);
return 0;
}
memset(bh->b_data, 0, sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 1);
brelse (bh);
ext2_debug ("allocating block %d. "
"Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
......
......@@ -30,15 +30,15 @@
#include <linux/locks.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/smp_lock.h>
#define NBUF 32
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
static int ext2_writepage (struct file * file, struct page * page);
static long long ext2_file_lseek(struct file *, long long, int);
static ssize_t ext2_file_write (struct file *, const char *, size_t, loff_t *);
static int ext2_release_file (struct inode *, struct file *);
#if BITS_PER_LONG < 64
static int ext2_open_file (struct inode *, struct file *);
......@@ -57,51 +57,6 @@ EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13)
#endif
/*
* We have mostly NULL's here: the current defaults are ok for
* the ext2 filesystem.
*/
static struct file_operations ext2_file_operations = {
ext2_file_lseek, /* lseek */
generic_file_read, /* read */
ext2_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* poll - default */
ext2_ioctl, /* ioctl */
generic_file_mmap, /* mmap */
#if BITS_PER_LONG == 64
NULL, /* no special open is needed */
#else
ext2_open_file,
#endif
NULL, /* flush */
ext2_release_file, /* release */
ext2_sync_file, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
NULL /* revalidate */
};
struct inode_operations ext2_file_inode_operations = {
&ext2_file_operations,/* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
ext2_bmap, /* bmap */
ext2_truncate, /* truncate */
ext2_permission, /* permission */
NULL /* smap */
};
/*
* Make sure the offset never goes beyond the 32-bit mark..
......@@ -151,164 +106,50 @@ static inline void remove_suid(struct inode *inode)
}
}
static ssize_t ext2_file_write (struct file * filp, const char * buf,
size_t count, loff_t *ppos)
static int ext2_writepage (struct file * file, struct page * page)
{
struct inode * inode = filp->f_dentry->d_inode;
off_t pos;
long block;
int offset;
int written, c;
struct buffer_head * bh, *bufferlist[NBUF];
struct super_block * sb;
int err;
int i,buffercount,write_error;
/* POSIX: mtime/ctime may not change for 0 count */
if (!count)
return 0;
write_error = buffercount = 0;
if (!inode) {
printk("ext2_file_write: inode = NULL\n");
return -EINVAL;
}
sb = inode->i_sb;
if (sb->s_flags & MS_RDONLY)
/*
* This fs has been automatically remounted ro because of errors
*/
return -ENOSPC;
if (!S_ISREG(inode->i_mode)) {
ext2_warning (sb, "ext2_file_write", "mode = %07o",
inode->i_mode);
return -EINVAL;
}
remove_suid(inode);
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else {
pos = *ppos;
if (pos != *ppos)
return -EINVAL;
#if BITS_PER_LONG >= 64
if (pos > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)])
return -EINVAL;
#endif
}
/* Check for overflow.. */
#if BITS_PER_LONG < 64
if (pos > (__u32) (pos + count)) {
count = ~pos; /* == 0xFFFFFFFF - pos */
if (!count)
return -EFBIG;
}
#else
{
off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)];
if (pos + count > max) {
count = max - pos;
if (!count)
return -EFBIG;
}
if (((pos + count) >> 32) &&
!(sb->u.ext2_sb.s_es->s_feature_ro_compat &
cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) {
/* If this is the first large file created, add a flag
to the superblock */
sb->u.ext2_sb.s_es->s_feature_ro_compat |=
cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
}
}
#endif
/*
* If a file has been opened in synchronous mode, we have to ensure
* that meta-data will also be written synchronously. Thus, we
* set the i_osync field. This field is tested by the allocation
* routines.
*/
if (filp->f_flags & O_SYNC)
inode->u.ext2_i.i_osync++;
block = pos >> EXT2_BLOCK_SIZE_BITS(sb);
offset = pos & (sb->s_blocksize - 1);
c = sb->s_blocksize - offset;
written = 0;
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
unsigned long block;
int *p, nr[PAGE_SIZE/512];
int i, err, created;
struct buffer_head *bh;
i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
block = page->offset >> inode->i_sb->s_blocksize_bits;
p = nr;
bh = page->buffers;
do {
bh = ext2_getblk (inode, block, 1, &err);
if (!bh) {
if (!written)
written = err;
break;
}
if (c > count)
c = count;
if (c != sb->s_blocksize && !buffer_uptodate(bh)) {
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
if (!buffer_uptodate(bh)) {
brelse (bh);
if (!written)
written = -EIO;
break;
}
}
c -= copy_from_user (bh->b_data + offset, buf, c);
if (!c) {
brelse(bh);
if (!written)
written = -EFAULT;
break;
}
update_vm_cache(inode, pos, bh->b_data + offset, c);
pos += c;
written += c;
buf += c;
count -= c;
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 0);
if (filp->f_flags & O_SYNC)
bufferlist[buffercount++] = bh;
if (bh && bh->b_blocknr)
*p = bh->b_blocknr;
else
brelse(bh);
if (buffercount == NBUF){
ll_rw_block(WRITE, buffercount, bufferlist);
for(i=0; i<buffercount; i++){
wait_on_buffer(bufferlist[i]);
if (!buffer_uptodate(bufferlist[i]))
write_error=1;
brelse(bufferlist[i]);
}
buffercount=0;
}
if(write_error)
break;
*p = ext2_getblk_block (inode, block, 1, &err, &created);
if (!*p)
return -EIO;
i--;
block++;
offset = 0;
c = sb->s_blocksize;
} while (count);
if ( buffercount ){
ll_rw_block(WRITE, buffercount, bufferlist);
for(i=0; i<buffercount; i++){
wait_on_buffer(bufferlist[i]);
if (!buffer_uptodate(bufferlist[i]))
write_error=1;
brelse(bufferlist[i]);
}
}
if (pos > inode->i_size)
inode->i_size = pos;
if (filp->f_flags & O_SYNC)
inode->u.ext2_i.i_osync--;
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
*ppos = pos;
mark_inode_dirty(inode);
return written;
p++;
if (bh)
bh = bh->b_this_page;
} while (i > 0);
/* IO start */
brw_page(WRITE, page, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
return 0;
}
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);
}
/*
* Write to a file (through the page cache).
*/
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);
}
/*
......@@ -335,3 +176,52 @@ static int ext2_open_file (struct inode * inode, struct file * filp)
return 0;
}
#endif
/*
* We have mostly NULL's here: the current defaults are ok for
* the ext2 filesystem.
*/
static struct file_operations ext2_file_operations = {
ext2_file_lseek, /* lseek */
generic_file_read, /* read */
ext2_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* poll - default */
ext2_ioctl, /* ioctl */
generic_file_mmap, /* mmap */
#if BITS_PER_LONG == 64
NULL, /* no special open is needed */
#else
ext2_open_file,
#endif
NULL, /* flush */
ext2_release_file, /* release */
ext2_sync_file, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
NULL /* revalidate */
};
struct inode_operations ext2_file_inode_operations = {
&ext2_file_operations,/* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
ext2_writepage, /* writepage */
ext2_bmap, /* bmap */
ext2_truncate, /* truncate */
ext2_permission, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage,/* flushpage */
};
This diff is collapsed.
......@@ -160,6 +160,9 @@ static int check_block_empty(struct inode *inode, struct buffer_head *bh,
return retry;
}
#define DATA_BUFFER_USED(bh) \
((bh->b_count > 1) || buffer_locked(bh))
static int trunc_direct (struct inode * inode)
{
struct buffer_head * bh;
......@@ -178,7 +181,7 @@ static int trunc_direct (struct inode * inode)
bh = find_buffer(inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (bh) {
bh->b_count++;
if(bh->b_count != 1 || buffer_locked(bh)) {
if (DATA_BUFFER_USED(bh)) {
brelse(bh);
retry = 1;
continue;
......@@ -255,8 +258,8 @@ static int trunc_indirect (struct inode * inode, int offset, u32 * p,
bh = find_buffer(inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (bh) {
bh->b_count++;
if (bh->b_count != 1 || buffer_locked(bh)) {
brelse (bh);
if (DATA_BUFFER_USED(bh)) {
brelse(bh);
retry = 1;
continue;
}
......@@ -384,8 +387,6 @@ static int trunc_tindirect (struct inode * inode)
void ext2_truncate (struct inode * inode)
{
int err, offset;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
......@@ -411,25 +412,6 @@ void ext2_truncate (struct inode * inode)
current->policy |= SCHED_YIELD;
schedule();
}
/*
* If the file is not being truncated to a block boundary, the
* contents of the partial block following the end of the file
* must be zeroed in case it ever becomes accessible again due
* to subsequent file growth.
*/
offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
if (offset) {
struct buffer_head * bh;
bh = ext2_bread (inode,
inode->i_size >> EXT2_BLOCK_SIZE_BITS(inode->i_sb),
0, &err);
if (bh) {
memset (bh->b_data + offset, 0,
inode->i_sb->s_blocksize - offset);
mark_buffer_dirty (bh, 0);
brelse (bh);
}
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
}
......@@ -2,14 +2,45 @@
* linux/fs/fifo.c
*
* written by Paul H. Hargrove
*
* Fixes:
* 10-06-1999, AV: fixed OOM handling in fifo_open(), moved
* initialization there, switched to external
* allocation of pipe_inode_info.
*/
#include <linux/mm.h>
#include <linux/malloc.h>
static int fifo_open(struct inode * inode,struct file * filp)
{
int retval = 0;
unsigned long page;
unsigned long page = 0;
struct pipe_inode_info *info, *tmp = NULL;
if (inode->i_pipe)
goto got_it;
tmp = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL);
if (inode->i_pipe)
goto got_it;
if (!tmp)
goto oom;
page = __get_free_page(GFP_KERNEL);
if (inode->i_pipe)
goto got_it;
if (!page)
goto oom;
inode->i_pipe = tmp;
PIPE_LOCK(*inode) = 0;
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
PIPE_BASE(*inode) = (char *) page;
PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
init_waitqueue_head(&PIPE_WAIT(*inode));
tmp = NULL; /* no need to free it */
page = 0;
got_it:
switch( filp->f_mode ) {
......@@ -94,19 +125,26 @@ static int fifo_open(struct inode * inode,struct file * filp)
default:
retval = -EINVAL;
}
if (retval || PIPE_BASE(*inode))
return retval;
page = __get_free_page(GFP_KERNEL);
if (PIPE_BASE(*inode)) {
if (retval)
goto cleanup;
out:
if (tmp)
kfree(tmp);
if (page)
free_page(page);
return 0;
return retval;
cleanup:
if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
info = inode->i_pipe;
inode->i_pipe = NULL;
free_page((unsigned long)info->base);
kfree(info);
}
if (!page)
return -ENOMEM;
PIPE_LOCK(*inode) = 0;
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
PIPE_BASE(*inode) = (char *) page;
return 0;
goto out;
oom:
retval = -ENOMEM;
goto out;
}
/*
......@@ -148,13 +186,10 @@ struct inode_operations fifo_inode_operations = {
NULL /* permission */
};
/* Goner. Filesystems do not use it anymore. */
void init_fifo(struct inode * inode)
{
inode->i_op = &fifo_inode_operations;
PIPE_LOCK(*inode) = 0;
PIPE_BASE(*inode) = NULL;
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
init_waitqueue_head(&PIPE_WAIT(*inode));
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
}
......@@ -527,6 +527,7 @@ void clean_inode(struct inode *inode)
inode->i_generation = 0;
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
sema_init(&inode->i_sem, 1);
inode->i_pipe = NULL;
}
/*
......
......@@ -221,35 +221,36 @@ static struct page *try_to_get_dirent_page(struct file *, unsigned long, int);
*/
static int refetch_to_readdir_off(struct file *file, struct inode *inode, u32 off)
{
struct page *page;
u32 cur_off, goal_off = off & PAGE_MASK;
again:
cur_off = 0;
while (cur_off < goal_off) {
struct page *page;
page = find_page(inode, cur_off);
page = find_get_page(inode, cur_off);
if (page) {
if (PageLocked(page))
__wait_on_page(page);
if (!PageUptodate(page))
return -1;
if (!Page_Uptodate(page))
goto out_error;
} else {
page = try_to_get_dirent_page(file, cur_off, 0);
if (!page) {
if (!cur_off)
return -1;
goto out_error;
/* Someone touched the dir on us. */
goto again;
}
page_cache_release(page);
}
page_cache_release(page);
cur_off += PAGE_SIZE;
}
return 0;
out_error:
if (page)
page_cache_release(page);
return -1;
}
static struct page *try_to_get_dirent_page(struct file *file, unsigned long offset, int refetch_ok)
......@@ -274,20 +275,18 @@ static struct page *try_to_get_dirent_page(struct file *file, unsigned long offs
}
hash = page_hash(inode, offset);
page = __find_page(inode, offset, *hash);
repeat:
page = __find_lock_page(inode, offset, *hash);
if (page) {
page_cache_free(page_cache);
goto out;
goto unlock_out;
}
page = page_cache_entry(page_cache);
atomic_inc(&page->count);
page->flags = ((page->flags &
~((1 << PG_uptodate) | (1 << PG_error))) |
((1 << PG_referenced) | (1 << PG_locked)));
page->offset = offset;
add_page_to_inode_queue(inode, page);
__add_page_to_hash_queue(page, hash);
if (add_to_page_cache_unique(page, inode, offset, hash)) {
page_cache_release(page);
goto repeat;
}
rd_args.fh = NFS_FH(dentry);
rd_res.buffer = (char *)page_cache;
......@@ -308,15 +307,14 @@ static struct page *try_to_get_dirent_page(struct file *file, unsigned long offs
else if (create_cookie(rd_res.cookie, offset, inode))
goto error;
set_bit(PG_uptodate, &page->flags);
SetPageUptodate(page);
unlock_out:
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
UnlockPage(page);
out:
return page;
error:
set_bit(PG_error, &page->flags);
SetPageError(page);
goto unlock_out;
}
......@@ -371,12 +369,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
offset = filp->f_pos >> PAGE_CACHE_SHIFT;
hash = page_hash(inode, offset);
page = __find_page(inode, offset, *hash);
page = __find_get_page(inode, offset, *hash);
if (!page)
goto no_dirent_page;
if (PageLocked(page))
goto dirent_locked_wait;
if (!PageUptodate(page))
if (!Page_Uptodate(page))
goto dirent_read_error;
success:
filp->f_pos = nfs_do_filldir((__u32 *) page_address(page),
......@@ -389,9 +385,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (!page)
goto no_page;
dirent_locked_wait:
wait_on_page(page);
if (PageUptodate(page))
if (Page_Uptodate(page))
goto success;
dirent_read_error:
page_cache_release(page);
......
......@@ -26,6 +26,7 @@
#include <linux/malloc.h>
#include <linux/pagemap.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/segment.h>
......@@ -78,6 +79,7 @@ struct inode_operations nfs_file_inode_operations = {
NULL, /* smap */
NULL, /* updatepage */
nfs_revalidate, /* revalidate */
NULL, /* flushpage */
};
/* Hack for future NFS swap support */
......@@ -172,8 +174,11 @@ static long nfs_write_one_page(struct file *file, struct page *page, unsigned lo
bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
status = -EFAULT;
if (bytes)
if (bytes) {
lock_kernel();
status = nfs_updatepage(file, page, offset, bytes);
unlock_kernel();
}
return status;
}
......
......@@ -77,7 +77,6 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
int flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
dprintk("NFS: nfs_readpage_sync(%p)\n", page);
clear_bit(PG_error, &page->flags);
do {
if (count < rsize)
......@@ -111,16 +110,14 @@ nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
} while (count);
memset(buffer, 0, count);
set_bit(PG_uptodate, &page->flags);
SetPageUptodate(page);
result = 0;
io_error:
UnlockPage(page);
/* Note: we don't refresh if the call returned error */
if (refresh && result >= 0)
nfs_refresh_inode(inode, &rqst.ra_fattr);
/* N.B. Use nfs_unlock_page here? */
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
return result;
}
......@@ -146,17 +143,15 @@ nfs_readpage_result(struct rpc_task *task)
memset((char *) address + result, 0, PAGE_SIZE - result);
}
nfs_refresh_inode(req->ra_inode, &req->ra_fattr);
set_bit(PG_uptodate, &page->flags);
SetPageUptodate(page);
succ++;
} else {
set_bit(PG_error, &page->flags);
SetPageError(page);
fail++;
dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
}
/* N.B. Use nfs_unlock_page here? */
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
page->owner = (int)current; // HACK, FIXME, will go away.
UnlockPage(page);
free_page(address);
rpc_release_task(task);
......@@ -229,8 +224,7 @@ nfs_readpage(struct file *file, struct page *page)
dprintk("NFS: nfs_readpage (%p %ld@%ld)\n",
page, PAGE_SIZE, page->offset);
atomic_inc(&page->count);
set_bit(PG_locked, &page->flags);
get_page(page);
/*
* Try to flush any pending writes to the file..
......@@ -256,8 +250,7 @@ nfs_readpage(struct file *file, struct page *page)
goto out_free;
out_error:
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
UnlockPage(page);
out_free:
free_page(page_address(page));
out:
......
......@@ -65,20 +65,18 @@ static struct page *try_to_get_symlink_page(struct dentry *dentry, struct inode
goto out;
hash = page_hash(inode, 0);
page = __find_page(inode, 0, *hash);
repeat:
page = __find_lock_page(inode, 0, *hash);
if (page) {
page_cache_free(page_cache);
goto out;
goto unlock_out;
}
page = page_cache_entry(page_cache);
atomic_inc(&page->count);
page->flags = ((page->flags &
~((1 << PG_uptodate) | (1 << PG_error))) |
((1 << PG_referenced) | (1 << PG_locked)));
page->offset = 0;
add_page_to_inode_queue(inode, page);
__add_page_to_hash_queue(page, hash);
if (add_to_page_cache_unique(page, inode, 0, hash)) {
page_cache_release(page);
goto repeat;
}
/* We place the length at the beginning of the page,
* in host byte order, followed by the string. The
......@@ -89,32 +87,28 @@ static struct page *try_to_get_symlink_page(struct dentry *dentry, struct inode
if (rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
&rl_args, NULL, 0) < 0)
goto error;
set_bit(PG_uptodate, &page->flags);
SetPageUptodate(page);
unlock_out:
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
UnlockPage(page);
out:
return page;
error:
set_bit(PG_error, &page->flags);
SetPageError(page);
goto unlock_out;
}
static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
struct inode *inode = dentry->d_inode;
struct page *page, **hash;
struct page *page;
u32 *p, len;
/* Caller revalidated the directory inode already. */
hash = page_hash(inode, 0);
page = __find_page(inode, 0, *hash);
page = find_get_page(inode, 0);
if (!page)
goto no_readlink_page;
if (PageLocked(page))
goto readlink_locked_wait;
if (!PageUptodate(page))
if (!Page_Uptodate(page))
goto readlink_read_error;
success:
p = (u32 *) page_address(page);
......@@ -129,9 +123,7 @@ static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
page = try_to_get_symlink_page(dentry, inode);
if (!page)
goto no_page;
readlink_locked_wait:
wait_on_page(page);
if (PageUptodate(page))
if (Page_Uptodate(page))
goto success;
readlink_read_error:
page_cache_release(page);
......@@ -144,17 +136,14 @@ nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
{
struct dentry *result;
struct inode *inode = dentry->d_inode;
struct page *page, **hash;
struct page *page;
u32 *p;
/* Caller revalidated the directory inode already. */
hash = page_hash(inode, 0);
page = __find_page(inode, 0, *hash);
page = find_get_page(inode, 0);
if (!page)
goto no_followlink_page;
if (PageLocked(page))
goto followlink_locked_wait;
if (!PageUptodate(page))
if (!Page_Uptodate(page))
goto followlink_read_error;
success:
p = (u32 *) page_address(page);
......@@ -166,9 +155,7 @@ nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
page = try_to_get_symlink_page(dentry, inode);
if (!page)
goto no_page;
followlink_locked_wait:
wait_on_page(page);
if (PageUptodate(page))
if (Page_Uptodate(page))
goto success;
followlink_read_error:
page_cache_release(page);
......
......@@ -110,7 +110,7 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
if (result < 0) {
/* Must mark the page invalid after I/O error */
clear_bit(PG_uptodate, &page->flags);
ClearPageUptodate(page);
goto io_error;
}
if (result != wsize)
......@@ -463,7 +463,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
* Ok, there's another user of this page with the new request..
* The IO completion will then free the page and the dentry.
*/
atomic_inc(&page->count);
get_page(page);
file->f_count++;
/* Schedule request */
......@@ -471,7 +471,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
updated:
if (req->wb_bytes == PAGE_SIZE)
set_bit(PG_uptodate, &page->flags);
SetPageUptodate(page);
retval = count;
if (synchronous) {
......@@ -486,7 +486,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
}
if (retval < 0)
clear_bit(PG_uptodate, &page->flags);
ClearPageUptodate(page);
}
free_write_request(req);
......@@ -682,7 +682,7 @@ nfs_wback_result(struct rpc_task *task)
rpc_release_task(task);
if (WB_INVALIDATE(req))
clear_bit(PG_uptodate, &page->flags);
ClearPageUptodate(page);
__free_page(page);
remove_write_request(&NFS_WRITEBACK(inode), req);
......
......@@ -7,6 +7,7 @@
#include <linux/mm.h>
#include <linux/file.h>
#include <linux/poll.h>
#include <linux/malloc.h>
#include <asm/uaccess.h>
......@@ -249,8 +250,10 @@ static unsigned int connect_poll(struct file * filp, poll_table * wait)
static int pipe_release(struct inode * inode)
{
if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
free_page((unsigned long) PIPE_BASE(*inode));
PIPE_BASE(*inode) = NULL;
struct pipe_inode_info *info = inode->i_pipe;
inode->i_pipe = NULL;
free_page((unsigned long) info->base);
kfree(info);
}
wake_up_interruptible(&PIPE_WAIT(*inode));
return 0;
......@@ -404,36 +407,48 @@ static struct inode * get_pipe_inode(void)
{
extern struct inode_operations pipe_inode_operations;
struct inode *inode = get_empty_inode();
unsigned long page;
if (inode) {
unsigned long page = __get_free_page(GFP_USER);
if (!page) {
iput(inode);
inode = NULL;
} else {
PIPE_BASE(*inode) = (char *) page;
inode->i_op = &pipe_inode_operations;
init_waitqueue_head(&PIPE_WAIT(*inode));
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
PIPE_LOCK(*inode) = 0;
/*
* Mark the inode dirty from the very beginning,
* that way it will never be moved to the dirty
* list because "mark_inode_dirty()" will think
* that it already _is_ on the dirty list.
*/
inode->i_state = I_DIRTY;
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_blksize = PAGE_SIZE;
}
}
if (!inode)
goto fail_inode;
page = __get_free_page(GFP_USER);
if (!page)
goto fail_iput;
/* XXX */
inode->i_pipe = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
if (!inode->i_pipe)
goto fail_page;
PIPE_BASE(*inode) = (char *) page;
inode->i_op = &pipe_inode_operations;
init_waitqueue_head(&PIPE_WAIT(*inode));
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
PIPE_LOCK(*inode) = 0;
/*
* Mark the inode dirty from the very beginning,
* that way it will never be moved to the dirty
* list because "mark_inode_dirty()" will think
* that it already _is_ on the dirty list.
*/
inode->i_state = I_DIRTY;
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_blksize = PAGE_SIZE;
return inode;
fail_page:
free_page(page);
fail_iput:
iput(inode);
fail_inode:
return NULL;
}
struct inode_operations pipe_inode_operations = {
......@@ -513,6 +528,8 @@ int do_pipe(int *fd)
put_unused_fd(i);
close_f12_inode:
free_page((unsigned long) PIPE_BASE(*inode));
kfree(inode->i_pipe);
inode->i_pipe = NULL;
iput(inode);
close_f12:
put_filp(f2);
......
......@@ -348,7 +348,7 @@ static int get_meminfo(char * buffer)
len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n"
"Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n"
"Swap: %8lu %8lu %8lu\n",
i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, page_cache_size*PAGE_SIZE,
i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, atomic_read(&page_cache_size)*PAGE_SIZE,
i.totalswap, i.totalswap-i.freeswap, i.freeswap);
/*
* Tagged format, for easy grepping and expansion. The above will go away
......@@ -359,14 +359,14 @@ static int get_meminfo(char * buffer)
"MemFree: %8lu kB\n"
"MemShared: %8lu kB\n"
"Buffers: %8lu kB\n"
"Cached: %8lu kB\n"
"Cached: %8u kB\n"
"SwapTotal: %8lu kB\n"
"SwapFree: %8lu kB\n",
i.totalram >> 10,
i.freeram >> 10,
i.sharedram >> 10,
i.bufferram >> 10,
page_cache_size << (PAGE_SHIFT - 10),
atomic_read(&page_cache_size) << (PAGE_SHIFT - 10),
i.totalswap >> 10,
i.freeswap >> 10);
}
......@@ -975,7 +975,7 @@ static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned
++*dirty;
if (MAP_NR(pte_page(page)) >= max_mapnr)
continue;
if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1)
if (page_count(mem_map + MAP_NR(pte_page(page))) > 1)
++*shared;
} while (address < end);
}
......
......@@ -298,7 +298,7 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma)
set_pte(dest_table, *src_table);
mapnr = MAP_NR(pte_page(*src_table));
if (mapnr < max_mapnr)
atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count);
get_page(mem_map + MAP_NR(pte_page(*src_table)));
stmp += PAGE_SIZE;
dtmp += PAGE_SIZE;
......
......@@ -14,6 +14,7 @@
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/pagemap.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/system.h>
......@@ -271,8 +272,11 @@ static long smb_write_one_page(struct file *file, struct page *page, unsigned lo
bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
status = -EFAULT;
if (bytes)
if (bytes) {
lock_kernel();
status = smb_updatepage(file, page, offset, bytes);
unlock_kernel();
}
return status;
}
......
......@@ -84,6 +84,14 @@ typedef unsigned long pgprot_t;
#define __PAGE_OFFSET (PAGE_OFFSET_RAW)
#ifndef __ASSEMBLY__
#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
#define PAGE_BUG(page) do { \
BUG(); } while (0)
#endif /* __ASSEMBLY__ */
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
......
......@@ -556,6 +556,7 @@ extern void ext2_check_inodes_bitmap (struct super_block *);
extern int ext2_bmap (struct inode *, int);
extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
extern int ext2_getblk_block (struct inode *, long, int, int *, int *);
extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
extern int ext2_getcluster (struct inode * inode, long block);
......
......@@ -74,11 +74,11 @@ extern int max_super_blocks, nr_super_blocks;
/* public flags for file_system_type */
#define FS_REQUIRES_DEV 1
#define FS_NO_DCACHE 2 /* Only dcache the necessary things. */
#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if
#define FS_NO_DCACHE 2 /* Only dcache the necessary things. */
#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if
* FS_NO_DCACHE is not set.
*/
#define FS_IBASKET 8 /* FS does callback to free_ibasket() if space gets low. */
#define FS_IBASKET 8 /* FS does callback to free_ibasket() if space gets low. */
/*
* These are the fs-independent mount-flags: up to 16 flags are supported
......@@ -94,9 +94,9 @@ extern int max_super_blocks, nr_super_blocks;
#define S_APPEND 256 /* Append-only file */
#define S_IMMUTABLE 512 /* Immutable file */
#define MS_NOATIME 1024 /* Do not update access times. */
#define MS_NODIRATIME 2048 /* Do not update directory access times */
#define MS_NODIRATIME 2048 /* Do not update directory access times */
#define MS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon
#define MS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon
* as nfs_rename() will be cleaned up
*/
......@@ -189,7 +189,6 @@ typedef char buffer_block[BLOCK_SIZE];
#define BH_Lock 2 /* 1 if the buffer is locked */
#define BH_Req 3 /* 0 if the buffer has been invalidated */
#define BH_Protected 6 /* 1 if the buffer is protected */
/*
* Try to keep the most commonly used fields in single cache lines (16
* bytes) to improve performance. This ordering should be
......@@ -218,7 +217,7 @@ struct buffer_head {
/* Non-performance-critical data follows. */
char * b_data; /* pointer to data block (1024 bytes) */
unsigned int b_list; /* List that this buffer appears */
unsigned long b_flushtime; /* Time when this (dirty) buffer
unsigned long b_flushtime; /* Time when this (dirty) buffer
* should be written */
wait_queue_head_t b_wait;
struct buffer_head ** b_pprev; /* doubly linked list of hash-queue */
......@@ -365,22 +364,21 @@ struct inode {
struct vm_area_struct *i_mmap;
struct page *i_pages;
struct dquot *i_dquot[MAXQUOTAS];
struct pipe_inode_info *i_pipe;
unsigned long i_state;
unsigned int i_flags;
unsigned char i_pipe;
unsigned char i_sock;
int i_writecount;
unsigned int i_attr_flags;
__u32 i_generation;
union {
struct pipe_inode_info pipe_i;
struct minix_inode_info minix_i;
struct ext2_inode_info ext2_i;
struct hpfs_inode_info hpfs_i;
struct ntfs_inode_info ntfs_i;
struct ntfs_inode_info ntfs_i;
struct msdos_inode_info msdos_i;
struct umsdos_inode_info umsdos_i;
struct iso_inode_info isofs_i;
......@@ -388,13 +386,13 @@ struct inode {
struct sysv_inode_info sysv_i;
struct affs_inode_info affs_i;
struct ufs_inode_info ufs_i;
struct efs_inode_info efs_i;
struct efs_inode_info efs_i;
struct romfs_inode_info romfs_i;
struct coda_inode_info coda_i;
struct smb_inode_info smbfs_i;
struct hfs_inode_info hfs_i;
struct adfs_inode_info adfs_i;
struct qnx4_inode_info qnx4_i;
struct qnx4_inode_info qnx4_i;
struct socket socket_i;
void *generic_ip;
} u;
......@@ -491,10 +489,10 @@ extern void posix_block_lock(struct file_lock *, struct file_lock *);
extern void posix_unblock_lock(struct file_lock *);
struct fasync_struct {
int magic;
int fa_fd;
struct fasync_struct *fa_next; /* singly linked list */
struct file *fa_file;
int magic;
int fa_fd;
struct fasync_struct *fa_next; /* singly linked list */
struct file *fa_file;
};
#define FASYNC_MAGIC 0x4601
......@@ -547,19 +545,19 @@ struct super_block {
struct minix_sb_info minix_sb;
struct ext2_sb_info ext2_sb;
struct hpfs_sb_info hpfs_sb;
struct ntfs_sb_info ntfs_sb;
struct ntfs_sb_info ntfs_sb;
struct msdos_sb_info msdos_sb;
struct isofs_sb_info isofs_sb;
struct nfs_sb_info nfs_sb;
struct sysv_sb_info sysv_sb;
struct affs_sb_info affs_sb;
struct ufs_sb_info ufs_sb;
struct efs_sb_info efs_sb;
struct efs_sb_info efs_sb;
struct romfs_sb_info romfs_sb;
struct smb_sb_info smbfs_sb;
struct hfs_sb_info hfs_sb;
struct adfs_sb_info adfs_sb;
struct qnx4_sb_info qnx4_sb;
struct qnx4_sb_info qnx4_sb;
void *generic_sbp;
} u;
/*
......@@ -624,6 +622,7 @@ struct inode_operations {
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 *, int);
};
struct super_operations {
......@@ -749,13 +748,19 @@ extern int fs_may_mount(kdev_t);
extern struct file *inuse_filps;
extern void refile_buffer(struct buffer_head *);
extern void set_writetime(struct buffer_head *, int);
extern int try_to_free_buffers(struct page *);
extern void __refile_buffer(struct buffer_head * buf);
extern inline void refile_buffer(struct buffer_head * buf)
{
/*
* Subtle, we do not want to refile not hashed buffers ...
*/
if (buf->b_pprev)
__refile_buffer(buf);
}
extern int nr_buffers;
extern int buffermem;
extern int nr_buffer_heads;
#define BUF_CLEAN 0
#define BUF_LOCKED 1 /* Buffers scheduled for write */
......@@ -869,11 +874,15 @@ extern struct buffer_head * breada(kdev_t, int, int, unsigned int, unsigned int)
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 *);
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 *, int);
extern long 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 struct super_block *get_super(kdev_t);
extern void put_super(kdev_t);
......
#ifndef _HPFS_FS_I
#define _HPFS_FS_I
#if ANALWARNINGS
#warning Fix the FIFO stuff!
#warning Fix the FIFO stuff!
#warning Fix the FIFO stuff!
#endif
struct hpfs_inode_info {
union { /* Linux sometimes destroys this structure */
struct pipe_inode_info bla; /* due to a bug. Linus doesn't want to fix */
struct socket ble; /* it so I had to write this workaround :-) */
} dummy;
ino_t i_parent_dir; /* (directories) gives fnode of parent dir */
unsigned i_dno; /* (directories) root dnode */
unsigned i_dpos; /* (directories) temp for readdir */
......
......@@ -129,29 +129,56 @@ typedef struct page {
wait_queue_head_t wait;
struct page **pprev_hash;
struct buffer_head * buffers;
int owner; /* temporary debugging check */
} mem_map_t;
#define get_page(p) do { atomic_inc(&(p)->count); \
} while (0)
#define put_page(p) __free_page(p)
#define put_page_testzero(p) ({ int __ret = atomic_dec_and_test(&(p)->count);\
__ret; })
#define page_count(p) atomic_read(&(p)->count)
#define set_page_count(p,v) do { atomic_set(&(p)->count, v); \
} while (0)
/* Page flag bit values */
#define PG_locked 0
#define PG_error 1
#define PG_referenced 2
#define PG_dirty 3
#define PG_uptodate 4
#define PG_free_after 5
#define PG_decr_after 6
#define PG_swap_unlock_after 7
#define PG_DMA 8
#define PG_Slab 9
#define PG_swap_cache 10
#define PG_skip 11
#define PG_uptodate 3
#define PG_free_after 4
#define PG_decr_after 5
#define PG_swap_unlock_after 6
#define PG_DMA 7
#define PG_Slab 8
#define PG_swap_cache 9
#define PG_skip 10
/* bits 21-30 unused */
#define PG_reserved 31
/* Make it prettier to test the above... */
#define Page_Uptodate(page) (test_bit(PG_uptodate, &(page)->flags))
#define SetPageUptodate(page) do { set_bit(PG_uptodate, &(page)->flags); \
} while (0)
#define ClearPageUptodate(page) do { clear_bit(PG_uptodate, &(page)->flags); \
} while (0)
#define PageLocked(page) (test_bit(PG_locked, &(page)->flags))
#define LockPage(page) \
do { int _ret = test_and_set_bit(PG_locked, &(page)->flags); \
if (_ret) PAGE_BUG(page); \
page->owner = (int)current; } while (0)
#define TryLockPage(page) ({ int _ret = test_and_set_bit(PG_locked, &(page)->flags); \
if (!_ret) page->owner = (int)current; _ret; })
#define UnlockPage(page) do { \
if (page->owner != (int)current) { \
BUG(); } page->owner = 0; \
if (!test_and_clear_bit(PG_locked, &(page)->flags)) { \
BUG(); } wake_up(&page->wait); } while (0)
#define PageError(page) (test_bit(PG_error, &(page)->flags))
#define SetPageError(page) ({ int _ret = test_and_set_bit(PG_error, &(page)->flags); _ret; })
#define ClearPageError(page) do { if (!test_and_clear_bit(PG_error, &(page)->flags)) BUG(); } while (0)
#define PageReferenced(page) (test_bit(PG_referenced, &(page)->flags))
#define PageDirty(page) (test_bit(PG_dirty, &(page)->flags))
#define PageUptodate(page) (test_bit(PG_uptodate, &(page)->flags))
#define PageFreeAfter(page) (test_bit(PG_free_after, &(page)->flags))
#define PageDecrAfter(page) (test_bit(PG_decr_after, &(page)->flags))
#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
......@@ -163,16 +190,12 @@ typedef struct page {
#define PageSetSlab(page) (set_bit(PG_Slab, &(page)->flags))
#define PageSetSwapCache(page) (set_bit(PG_swap_cache, &(page)->flags))
#define PageTestandSetDirty(page) \
(test_and_set_bit(PG_dirty, &(page)->flags))
#define PageTestandSetSwapCache(page) \
(test_and_set_bit(PG_swap_cache, &(page)->flags))
#define PageClearSlab(page) (clear_bit(PG_Slab, &(page)->flags))
#define PageClearSwapCache(page)(clear_bit(PG_swap_cache, &(page)->flags))
#define PageTestandClearDirty(page) \
(test_and_clear_bit(PG_dirty, &(page)->flags))
#define PageTestandClearSwapCache(page) \
(test_and_clear_bit(PG_swap_cache, &(page)->flags))
......@@ -387,7 +410,7 @@ extern struct vm_area_struct *find_extend_vma(struct task_struct *tsk, unsigned
#define buffer_under_min() ((buffermem >> PAGE_SHIFT) * 100 < \
buffer_mem.min_percent * num_physpages)
#define pgcache_under_min() (page_cache_size * 100 < \
#define pgcache_under_min() (atomic_read(&page_cache_size) * 100 < \
page_cache.min_percent * num_physpages)
#endif /* __KERNEL__ */
......
#ifndef _MSDOS_FS_I
#define _MSDOS_FS_I
#ifndef _LINUX_PIPE_FS_I_H
#include <linux/pipe_fs_i.h>
#endif
/*
* MS-DOS file system inode data in memory
*/
struct msdos_inode_info {
/*
UMSDOS manage special file and fifo as normal empty
msdos file. fifo inode processing conflict with msdos
processing. So I insert the pipe_inode_info so the
information does not overlap. This increases the size of
the msdos_inode_info, but the clear winner here is
the ext2_inode_info. So it does not change anything to
the total size of a struct inode.
I have not put it conditional. With the advent of loadable
file system drivers, it would be very easy to compile
a MS-DOS FS driver unaware of UMSDOS and then later to
load a (then incompatible) UMSDOS FS driver.
*/
struct pipe_inode_info reserved;
int i_start; /* first cluster or 0 */
int i_logstart; /* logical first cluster */
int i_attrs; /* unused attribute bits */
......
......@@ -8,13 +8,6 @@
* nfs fs inode data in memory
*/
struct nfs_inode_info {
/*
* This is a place holder so named pipes on NFS filesystems
* work (more or less correctly). This must be first in the
* struct because the data is really accessed via inode->u.pipe_i.
*/
struct pipe_inode_info pipeinfo;
/*
* Various flags
*/
......
......@@ -39,10 +39,10 @@ static inline unsigned long page_address(struct page * page)
*/
#define page_cache_entry(x) (mem_map + MAP_NR(x))
#define PAGE_HASH_BITS 12
#define PAGE_HASH_BITS 16
#define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)
extern unsigned long page_cache_size; /* # of pages currently in the hash table */
extern atomic_t page_cache_size; /* # of pages currently in the hash table */
extern struct page * page_hash_table[PAGE_HASH_SIZE];
/*
......@@ -64,50 +64,18 @@ static inline unsigned long _page_hashfn(struct inode * inode, unsigned long off
#define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset))
static inline struct page * __find_page(struct inode * inode, unsigned long offset, struct page *page)
{
goto inside;
for (;;) {
page = page->next_hash;
inside:
if (!page)
goto not_found;
if (page->inode != inode)
continue;
if (page->offset == offset)
break;
}
/* Found the page. */
atomic_inc(&page->count);
set_bit(PG_referenced, &page->flags);
not_found:
return page;
}
static inline struct page *find_page(struct inode * inode, unsigned long offset)
{
return __find_page(inode, offset, *page_hash(inode, offset));
}
extern struct page * __find_get_page (struct inode * inode,
unsigned long offset, struct page *page);
#define find_get_page(inode, offset) \
__find_get_page(inode, offset, *page_hash(inode, offset))
extern struct page * __find_lock_page (struct inode * inode,
unsigned long offset, struct page *page);
#define find_lock_page(inode, offset) \
__find_lock_page(inode, offset, *page_hash(inode, offset))
static inline void remove_page_from_hash_queue(struct page * page)
{
if(page->pprev_hash) {
if(page->next_hash)
page->next_hash->pprev_hash = page->pprev_hash;
*page->pprev_hash = page->next_hash;
page->pprev_hash = NULL;
}
page_cache_size--;
}
extern void __add_page_to_hash_queue(struct page * page, struct page **p);
static inline void __add_page_to_hash_queue(struct page * page, struct page **p)
{
page_cache_size++;
if((page->next_hash = *p) != NULL)
(*p)->pprev_hash = &page->next_hash;
*p = page;
page->pprev_hash = p;
}
extern int add_to_page_cache_unique(struct page * page, struct inode * inode, unsigned long offset, struct page **hash);
static inline void add_page_to_hash_queue(struct page * page, struct inode * inode, unsigned long offset)
{
......@@ -118,7 +86,6 @@ static inline void remove_page_from_inode_queue(struct page * page)
{
struct inode * inode = page->inode;
page->inode = NULL;
inode->i_nrpages--;
if (inode->i_pages == page)
inode->i_pages = page->next;
......@@ -142,11 +109,13 @@ static inline void add_page_to_inode_queue(struct inode * inode, struct page * p
*p = page;
}
extern void __wait_on_page(struct page *);
extern void ___wait_on_page(struct page *);
static inline void wait_on_page(struct page * page)
{
if (PageLocked(page))
__wait_on_page(page);
___wait_on_page(page);
}
extern void update_vm_cache(struct inode *, unsigned long, const char *, int);
......
......@@ -12,15 +12,15 @@ struct pipe_inode_info {
unsigned int writers;
};
#define PIPE_WAIT(inode) ((inode).u.pipe_i.wait)
#define PIPE_BASE(inode) ((inode).u.pipe_i.base)
#define PIPE_START(inode) ((inode).u.pipe_i.start)
#define PIPE_WAIT(inode) ((inode).i_pipe->wait)
#define PIPE_BASE(inode) ((inode).i_pipe->base)
#define PIPE_START(inode) ((inode).i_pipe->start)
#define PIPE_LEN(inode) ((inode).i_size)
#define PIPE_RD_OPENERS(inode) ((inode).u.pipe_i.rd_openers)
#define PIPE_WR_OPENERS(inode) ((inode).u.pipe_i.wr_openers)
#define PIPE_READERS(inode) ((inode).u.pipe_i.readers)
#define PIPE_WRITERS(inode) ((inode).u.pipe_i.writers)
#define PIPE_LOCK(inode) ((inode).u.pipe_i.lock)
#define PIPE_RD_OPENERS(inode) ((inode).i_pipe->rd_openers)
#define PIPE_WR_OPENERS(inode) ((inode).i_pipe->wr_openers)
#define PIPE_READERS(inode) ((inode).i_pipe->readers)
#define PIPE_WRITERS(inode) ((inode).i_pipe->writers)
#define PIPE_LOCK(inode) ((inode).i_pipe->lock)
#define PIPE_SIZE(inode) PIPE_LEN(inode)
#define PIPE_EMPTY(inode) (PIPE_SIZE(inode)==0)
......
......@@ -286,7 +286,7 @@ struct task_struct {
gid_t gid,egid,sgid,fsgid;
int ngroups;
gid_t groups[NGROUPS];
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
struct user_struct *user;
/* limits */
struct rlimit rlim[RLIM_NLIMITS];
......@@ -601,7 +601,7 @@ extern inline int capable(int cap)
#else
if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0)
#endif
{
{
current->flags |= PF_SUPERPRIV;
return 1;
}
......
......@@ -67,7 +67,7 @@ extern int nr_swap_pages;
extern int nr_free_pages;
extern atomic_t nr_async_pages;
extern struct inode swapper_inode;
extern unsigned long page_cache_size;
extern atomic_t page_cache_size;
extern int buffermem;
/* Incomplete types for prototype declarations: */
......@@ -163,7 +163,7 @@ static inline int is_page_shared(struct page *page)
unsigned int count;
if (PageReserved(page))
return 1;
count = atomic_read(&page->count);
count = page_count(page);
if (PageSwapCache(page))
count += swap_count(page->offset) - 2;
if (PageFreeAfter(page))
......
/*
* SyncLink Multiprotocol Serial Adapter Driver
*
* ==FILEDATE 19990523==
*
* Copyright (C) 1998 by Microgate Corporation
*
* Redistribution of this file is permitted under
......@@ -66,11 +68,16 @@
#define HDLC_FLAG_AUTO_RTS 0x0080
#define HDLC_FLAG_RXC_DPLL 0x0100
#define HDLC_FLAG_RXC_BRG 0x0200
#define HDLC_FLAG_RXC_TXCPIN 0x8000
#define HDLC_FLAG_RXC_RXCPIN 0x0000
#define HDLC_FLAG_TXC_DPLL 0x0400
#define HDLC_FLAG_TXC_BRG 0x0800
#define HDLC_FLAG_TXC_TXCPIN 0x0000
#define HDLC_FLAG_TXC_RXCPIN 0x0008
#define HDLC_FLAG_DPLL_DIV8 0x1000
#define HDLC_FLAG_DPLL_DIV16 0x2000
#define HDLC_FLAG_DPLL_DIV32 0x0000
#define HDLC_FLAG_HDLC_LOOPMODE 0x4000
#define HDLC_CRC_NONE 0
#define HDLC_CRC_16_CCITT 1
......@@ -87,6 +94,7 @@
#define HDLC_ENCODING_NRZB 1
#define HDLC_ENCODING_NRZI_MARK 2
#define HDLC_ENCODING_NRZI_SPACE 3
#define HDLC_ENCODING_NRZI HDLC_ENCODING_NRZI_SPACE
#define HDLC_ENCODING_BIPHASE_MARK 4
#define HDLC_ENCODING_BIPHASE_SPACE 5
#define HDLC_ENCODING_BIPHASE_LEVEL 6
......@@ -227,17 +235,19 @@ struct mgsl_icount {
* MGSL_IOCTXABORT abort transmitting frame (HDLC)
* MGSL_IOCGSTATS return current statistics
* MGSL_IOCWAITEVENT wait for specified event to occur
* MGSL_LOOPTXDONE transmit in HDLC LoopMode done
*/
#define MGSL_MAGIC_IOC 'm'
#define MGSL_IOCSPARAMS _IOW(MGSL_MAGIC_IOC,0,sizeof(MGSL_PARAMS))
#define MGSL_IOCGPARAMS _IOR(MGSL_MAGIC_IOC,1,sizeof(MGSL_PARAMS))
#define MGSL_IOCSPARAMS _IOW(MGSL_MAGIC_IOC,0,struct _MGSL_PARAMS)
#define MGSL_IOCGPARAMS _IOR(MGSL_MAGIC_IOC,1,struct _MGSL_PARAMS)
#define MGSL_IOCSTXIDLE _IO(MGSL_MAGIC_IOC,2)
#define MGSL_IOCGTXIDLE _IO(MGSL_MAGIC_IOC,3)
#define MGSL_IOCTXENABLE _IO(MGSL_MAGIC_IOC,4)
#define MGSL_IOCRXENABLE _IO(MGSL_MAGIC_IOC,5)
#define MGSL_IOCTXABORT _IO(MGSL_MAGIC_IOC,6)
#define MGSL_IOCGSTATS _IO(MGSL_MAGIC_IOC,7)
#define MGSL_IOCWAITEVENT _IO(MGSL_MAGIC_IOC,8)
#define MGSL_IOCWAITEVENT _IOWR(MGSL_MAGIC_IOC,8,int)
#define MGSL_IOCCLRMODCOUNT _IO(MGSL_MAGIC_IOC,15)
#define MGSL_IOCLOOPTXDONE _IO(MGSL_MAGIC_IOC,9)
#endif /* _SYNCLINK_H_ */
......@@ -28,9 +28,8 @@
*
* For directory, we also have a reference to the inode of its
* own EMD file. Also, we have dir_locking_info to help synchronise
* file creation and file lookup. This data is sharing space with
* the pipe_inode_info not used by directory. See also msdos_fs_i.h
* for more information about pipe_inode_info and msdos_inode_info.
* file creation and file lookup. See also msdos_fs_i.h for more
* information about msdos_inode_info.
*
* Special file and fifo do have an inode which correspond to an
* empty MSDOS file.
......@@ -38,11 +37,6 @@
* symlink are processed mostly like regular file. The content is the
* link.
*
* fifos add there own extension to the inode. I have reserved some
* space for fifos side by side with msdos_inode_info. This is just
* to for the show, because msdos_inode_info already include the
* pipe_inode_info.
*
* The UMSDOS specific extension is placed after the union.
*/
......@@ -60,7 +54,6 @@ struct dir_locking_info {
struct umsdos_inode_info {
union {
struct msdos_inode_info msdos_info;
struct pipe_inode_info pipe_info;
struct dir_locking_info dir_info;
} u;
int i_patched; /* Inode has been patched */
......
......@@ -675,7 +675,7 @@ static unsigned long shm_nopage(struct vm_area_struct * shmd, unsigned long addr
done: /* pte_val(pte) == shp->shm_pages[idx] */
current->min_flt++;
atomic_inc(&mem_map[MAP_NR(pte_page(pte))].count);
get_page(mem_map + MAP_NR(pte_page(pte)));
return pte_page(pte);
}
......@@ -730,7 +730,7 @@ int shm_swap (int prio, int gfp_mask)
swap_free (swap_nr);
return 0;
}
if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) != 1)
if (page_count(mem_map + MAP_NR(pte_page(page))) != 1)
goto check_table;
shp->shm_pages[idx] = swap_nr;
rw_swap_page_nocache (WRITE, swap_nr, (char *) pte_page(page));
......@@ -751,7 +751,7 @@ static void shm_unuse_page(struct shmid_kernel *shp, unsigned long idx,
pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
shp->shm_pages[idx] = pte_val(pte);
atomic_inc(&mem_map[MAP_NR(page)].count);
get_page(mem_map + MAP_NR(page));
shm_rss++;
swap_free(entry);
......
......@@ -106,7 +106,6 @@ EXPORT_SYMBOL(mem_map);
EXPORT_SYMBOL(remap_page_range);
EXPORT_SYMBOL(max_mapnr);
EXPORT_SYMBOL(high_memory);
EXPORT_SYMBOL(update_vm_cache);
EXPORT_SYMBOL(vmtruncate);
EXPORT_SYMBOL(find_vma);
EXPORT_SYMBOL(get_unmapped_area);
......@@ -175,7 +174,6 @@ EXPORT_SYMBOL(posix_test_lock);
EXPORT_SYMBOL(posix_block_lock);
EXPORT_SYMBOL(posix_unblock_lock);
EXPORT_SYMBOL(dput);
EXPORT_SYMBOL(get_cached_page);
EXPORT_SYMBOL(put_cached_page);
EXPORT_SYMBOL(is_root_busy);
EXPORT_SYMBOL(prune_dcache);
......@@ -361,7 +359,6 @@ EXPORT_SYMBOL(sys_tz);
EXPORT_SYMBOL(__wait_on_super);
EXPORT_SYMBOL(file_fsync);
EXPORT_SYMBOL(clear_inode);
EXPORT_SYMBOL(refile_buffer);
EXPORT_SYMBOL(nr_async_pages);
EXPORT_SYMBOL(___strtok);
EXPORT_SYMBOL(init_special_inode);
......
This diff is collapsed.
This diff is collapsed.
......@@ -63,7 +63,7 @@ int vm_enough_memory(long pages)
return 1;
free = buffermem >> PAGE_SHIFT;
free += page_cache_size;
free += atomic_read(&page_cache_size);
free += nr_free_pages;
free += nr_swap_pages;
free -= (page_cache.min_percent + buffer_mem.min_percent + 2)*num_physpages/100;
......@@ -728,6 +728,10 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
struct vm_area_struct * vma;
unsigned long flags, retval;
len = PAGE_ALIGN(len);
if (!len)
return addr;
/*
* mlock MCL_FUTURE?
*/
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -192,7 +192,7 @@ static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,
return;
set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
swap_free(entry);
atomic_inc(&mem_map[MAP_NR(page)].count);
get_page(mem_map + MAP_NR(page));
++vma->vm_mm->rss;
}
......
......@@ -157,7 +157,7 @@ static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
add_to_swap_cache(page_map, entry);
/* We checked we were unlocked way up above, and we
have been careful not to stall until here */
set_bit(PG_locked, &page_map->flags);
LockPage(page_map);
/* OK, do a physical asynchronous write to swap. */
rw_swap_page(WRITE, entry, (char *) page, 0);
......
This diff is collapsed.
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