Commit f6506d68 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.7pre3

parent 2fcc8e43
......@@ -651,9 +651,7 @@ static inline ssize_t do_tty_write(
ssize_t ret = 0, written = 0;
struct inode *inode = file->f_dentry->d_inode;
up(&inode->i_sem);
if (down_interruptible(&inode->i_atomic_write)) {
down(&inode->i_sem);
if (down_interruptible(&inode->i_sem)) {
return -ERESTARTSYS;
}
for (;;) {
......@@ -678,8 +676,7 @@ static inline ssize_t do_tty_write(
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
ret = written;
}
up(&inode->i_atomic_write);
down(&inode->i_sem);
up(&inode->i_sem);
return ret;
}
......
......@@ -1264,7 +1264,8 @@ static void uhci_interrupt_notify(struct uhci *uhci)
struct uhci_qh *interrupt_qh = td->qh;
usb_dotoggle(td->dev, usb_pipeendpoint(td->info));
td->info |= 1 << 19; /* toggle between data0 and data1 */
td->info &= ~(1 << 19); /* clear data toggle */
td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info)) << 19; /* toggle between data0 and data1 */
td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */
/* Remove then readd? Is that necessary */
......
This diff is collapsed.
......@@ -108,34 +108,7 @@ static inline void remove_suid(struct inode *inode)
static int ext2_writepage (struct file * file, struct page * page)
{
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 {
if (bh && bh->b_blocknr)
*p = bh->b_blocknr;
else
*p = ext2_getblk_block (inode, block, 1, &err, &created);
if (!*p)
return -EIO;
i--;
block++;
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;
return block_write_full_page(file, page, ext2_getblk_block);
}
static long ext2_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
......
......@@ -130,7 +130,6 @@ static inline void init_once(struct inode * inode)
INIT_LIST_HEAD(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_dentry);
sema_init(&inode->i_sem, 1);
sema_init(&inode->i_atomic_write, 1);
}
static inline void write_inode(struct inode *inode)
......@@ -767,9 +766,6 @@ kdevname(inode->i_dev), inode->i_ino, inode->i_count);
if (atomic_read(&inode->i_sem.count) != 1)
printk(KERN_ERR "iput: Aieee, semaphore in use inode %s/%ld, count=%d\n",
kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count));
if (atomic_read(&inode->i_atomic_write.count) != 1)
printk(KERN_ERR "iput: Aieee, atomic write semaphore in use inode %s/%ld, count=%d\n",
kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count));
#endif
}
if (inode->i_count > (1<<31)) {
......
......@@ -112,14 +112,6 @@ int minix_new_block(struct super_block * sb)
if (j < sb->u.minix_sb.s_firstdatazone ||
j >= sb->u.minix_sb.s_nzones)
return 0;
if (!(bh = getblk(sb->s_dev,j,BLOCK_SIZE))) {
printk("new_block: cannot get block");
return 0;
}
memset(bh->b_data, 0, BLOCK_SIZE);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 1);
brelse(bh);
return j;
}
......
......@@ -27,7 +27,51 @@
#include <linux/fs.h>
#include <linux/minix_fs.h>
static ssize_t minix_file_write(struct file *, const char *, size_t, loff_t *);
static int minix_writepage(struct file *file, struct page *page)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
unsigned long block;
int *p, nr[PAGE_SIZE/BLOCK_SIZE];
int i, err, created;
struct buffer_head *bh;
i = PAGE_SIZE / BLOCK_SIZE;
block = page->offset / BLOCK_SIZE;
p = nr;
bh = page->buffers;
do {
if (bh && bh->b_blocknr)
*p = bh->b_blocknr;
else
*p = minix_getblk_block(inode, block, 1, &err, &created);
if (!*p)
return -EIO;
i--;
block++;
p++;
if (bh)
bh = bh->b_this_page;
} while(i > 0);
/* IO start */
brw_page(WRITE, page, inode->i_dev, nr, BLOCK_SIZE, 1);
return 0;
}
static long minix_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, minix_getblk_block);
}
/*
* Write to a file (through the page cache).
*/
static ssize_t
minix_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
return generic_file_write(file, buf, count, ppos, minix_write_one_page);
}
/*
* We have mostly NULLs here: the current defaults are OK for
......@@ -61,74 +105,12 @@ struct inode_operations minix_file_inode_operations = {
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
minix_writepage, /* writepage */
minix_bmap, /* bmap */
minix_truncate, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage,/* flushpage */
};
static ssize_t minix_file_write(struct file * filp, const char * buf,
size_t count, loff_t *ppos)
{
struct inode * inode = filp->f_dentry->d_inode;
off_t pos;
ssize_t written, c;
struct buffer_head * bh;
char * p;
if (!inode) {
printk("minix_file_write: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
printk("minix_file_write: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
pos = *ppos;
written = 0;
while (written < count) {
bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
if (!bh) {
if (!written)
written = -ENOSPC;
break;
}
c = BLOCK_SIZE - (pos % BLOCK_SIZE);
if (c > count-written)
c = count-written;
if (c != BLOCK_SIZE && !buffer_uptodate(bh)) {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
brelse(bh);
if (!written)
written = -EIO;
break;
}
}
p = (pos % BLOCK_SIZE) + bh->b_data;
c -= copy_from_user(p,buf,c);
if (!c) {
brelse(bh);
if (!written)
written = -EFAULT;
break;
}
update_vm_cache(inode, pos, p, c);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 0);
brelse(bh);
pos += c;
written += c;
buf += c;
}
if (pos > inode->i_size)
inode->i_size = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
*ppos = pos;
mark_inode_dirty(inode);
return written;
}
This diff is collapsed.
......@@ -32,6 +32,9 @@
* general case (size = XXX). I hope.
*/
#define DATA_BUFFER_USED(bh) \
((bh->b_count > 1) || buffer_locked(bh))
/*
* The functions for minix V1 fs truncation.
*/
......@@ -52,7 +55,7 @@ static int V1_trunc_direct(struct inode * inode)
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *p) {
if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) {
retry = 1;
brelse(bh);
continue;
......@@ -103,7 +106,7 @@ static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short *
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *ind) {
if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) {
retry = 1;
brelse(bh);
continue;
......@@ -216,7 +219,7 @@ static int V2_trunc_direct(struct inode * inode)
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *p) {
if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) {
retry = 1;
brelse(bh);
continue;
......@@ -267,7 +270,7 @@ static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *ind) {
if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) {
retry = 1;
brelse(bh);
continue;
......
This diff is collapsed.
......@@ -99,23 +99,28 @@ nfs_delete_inode(struct inode * inode)
int failed;
dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
/*
* Flush out any pending write requests ...
*/
if (NFS_WRITEBACK(inode) != NULL) {
unsigned long timeout = jiffies + 5*HZ;
if (S_ISDIR(inode->i_mode)) {
nfs_free_dircache(inode);
} else {
/*
* Flush out any pending write requests ...
*/
if (NFS_WRITEBACK(inode) != NULL) {
unsigned long timeout = jiffies + 5*HZ;
#ifdef NFS_DEBUG_VERBOSE
printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
#endif
nfs_inval(inode);
while (NFS_WRITEBACK(inode) != NULL &&
time_before(jiffies, timeout)) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ/10);
nfs_inval(inode);
while (NFS_WRITEBACK(inode) != NULL &&
time_before(jiffies, timeout)) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ/10);
}
current->state = TASK_RUNNING;
if (NFS_WRITEBACK(inode) != NULL)
printk("NFS: Arghhh, stuck RPC requests!\n");
}
current->state = TASK_RUNNING;
if (NFS_WRITEBACK(inode) != NULL)
printk("NFS: Arghhh, stuck RPC requests!\n");
}
failed = nfs_check_failed_request(inode);
......@@ -433,7 +438,7 @@ nfs_zap_caches(struct inode *inode)
invalidate_inode_pages(inode);
if (S_ISDIR(inode->i_mode))
nfs_invalidate_dircache(inode);
nfs_flush_dircache(inode);
}
/*
......@@ -477,8 +482,6 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_size = fattr->size;
inode->i_mtime = fattr->mtime.seconds;
NFS_OLDMTIME(inode) = fattr->mtime.seconds;
NFS_COOKIES(inode) = NULL;
NFS_WRITEBACK(inode) = NULL;
}
nfs_refresh_inode(inode, fattr);
}
......
......@@ -102,9 +102,7 @@ static ssize_t pipe_write(struct file * filp, const char * buf,
free = count;
else
free = 1; /* can't do it atomically, wait for any free space */
up(&inode->i_sem);
if (down_interruptible(&inode->i_atomic_write)) {
down(&inode->i_sem);
if (down_interruptible(&inode->i_sem)) {
return -ERESTARTSYS;
}
while (count>0) {
......@@ -145,8 +143,7 @@ static ssize_t pipe_write(struct file * filp, const char * buf,
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
errout:
up(&inode->i_atomic_write);
down(&inode->i_sem);
up(&inode->i_sem);
return written ? written : err;
}
......@@ -254,6 +251,7 @@ static int pipe_release(struct inode * inode)
inode->i_pipe = NULL;
free_page((unsigned long) info->base);
kfree(info);
return 0;
}
wake_up_interruptible(&PIPE_WAIT(*inode));
return 0;
......
......@@ -166,9 +166,7 @@ asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
if (!file->f_op || !(write = file->f_op->write))
goto out;
down(&inode->i_sem);
ret = write(file, buf, count, &file->f_pos);
up(&inode->i_sem);
out:
fput(file);
bad_file:
......@@ -304,9 +302,7 @@ asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
if (!file)
goto bad_file;
if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
down(&file->f_dentry->d_inode->i_sem);
ret = do_readv_writev(VERIFY_READ, file, vector, count);
up(&file->f_dentry->d_inode->i_sem);
}
fput(file);
......@@ -376,10 +372,7 @@ asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
if (pos < 0)
goto out;
down(&file->f_dentry->d_inode->i_sem);
ret = write(file, buf, count, &pos);
up(&file->f_dentry->d_inode->i_sem);
out:
fput(file);
bad_file:
......
......@@ -33,7 +33,51 @@
#include <linux/fs.h>
#include <linux/sysv_fs.h>
static ssize_t sysv_file_write(struct file *, const char *, size_t, loff_t *);
static int sysv_writepage (struct file * file, struct page * page)
{
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->sv_block_size_bits;
block = page->offset >> inode->i_sb->sv_block_size_bits;
p = nr;
bh = page->buffers;
do {
if (bh && bh->b_blocknr)
*p = bh->b_blocknr;
else
*p = sysv_getblk_block (inode, block, 1, &err, &created);
if (!*p)
return -EIO;
i--;
block++;
p++;
if (bh)
bh = bh->b_this_page;
} while (i > 0);
/* IO start */
brw_page(WRITE, page, inode->i_dev, nr, inode->i_sb->sv_block_size, 1);
return 0;
}
static long sysv_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, sysv_getblk_block);
}
/*
* Write to a file (through the page cache).
*/
static ssize_t
sysv_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
return generic_file_write(file, buf, count, ppos, sysv_write_one_page);
}
/*
* We have mostly NULLs here: the current defaults are OK for
......@@ -41,7 +85,7 @@ static ssize_t sysv_file_write(struct file *, const char *, size_t, loff_t *);
*/
static struct file_operations sysv_file_operations = {
NULL, /* lseek - default */
sysv_file_read, /* read */
generic_file_read, /* read */
sysv_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* poll - default */
......@@ -50,7 +94,10 @@ static struct file_operations sysv_file_operations = {
NULL, /* no special open is needed */
NULL, /* flush */
NULL, /* release */
sysv_sync_file /* fsync */
sysv_sync_file, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
NULL /* revalidate */
};
struct inode_operations sysv_file_inode_operations = {
......@@ -67,208 +114,12 @@ struct inode_operations sysv_file_inode_operations = {
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
sysv_writepage, /* writepage */
sysv_bmap, /* bmap */
sysv_truncate, /* truncate */
NULL /* permission */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage,/* flushpage */
};
ssize_t sysv_file_read(struct file * filp, char * buf,
size_t count, loff_t *ppos)
{
struct inode * inode = filp->f_dentry->d_inode;
struct super_block * sb = inode->i_sb;
ssize_t read,left,chars;
size_t block;
ssize_t blocks, offset;
int bhrequest, uptodate;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * bhreq[NBUF];
struct buffer_head * buflist[NBUF];
size_t size;
if (!inode) {
printk("sysv_file_read: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
printk("sysv_file_read: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
offset = *ppos;
size = inode->i_size;
if (offset > size)
left = 0;
else
left = size - offset;
if (left > count)
left = count;
if (left <= 0)
return 0;
read = 0;
block = offset >> sb->sv_block_size_bits;
offset &= sb->sv_block_size_1;
size = (size + sb->sv_block_size_1) >> sb->sv_block_size_bits;
blocks = (left + offset + sb->sv_block_size_1) >> sb->sv_block_size_bits;
bhb = bhe = buflist;
if (filp->f_reada) {
blocks += read_ahead[MAJOR(inode->i_dev)] >> (sb->sv_block_size_bits - 9);
if (block + blocks > size)
blocks = size - block;
}
/* We do this in a two stage process. We first try to request
as many blocks as we can, then we wait for the first one to
complete, and then we try to wrap up as many as are actually
done. This routine is rather generic, in that it can be used
in a filesystem by substituting the appropriate function in
for getblk.
This routine is optimized to make maximum use of the various
buffers and caches.
*/
do {
bhrequest = 0;
uptodate = 1;
while (blocks) {
--blocks;
*bhb = sysv_getblk(inode, block++, 0);
if (*bhb && !buffer_uptodate(*bhb)) {
uptodate = 0;
bhreq[bhrequest++] = *bhb;
}
if (++bhb == &buflist[NBUF])
bhb = buflist;
/* If the block we have on hand is uptodate, go ahead
and complete processing. */
if (uptodate)
break;
if (bhb == bhe)
break;
}
/* Now request them all */
if (bhrequest)
ll_rw_block(READ, bhrequest, bhreq);
do { /* Finish off all I/O that has actually completed */
if (*bhe) {
wait_on_buffer(*bhe);
if (!buffer_uptodate(*bhe)) { /* read error? */
brelse(*bhe);
if (++bhe == &buflist[NBUF])
bhe = buflist;
left = 0;
break;
}
}
if (left < sb->sv_block_size - offset)
chars = left;
else
chars = sb->sv_block_size - offset;
*ppos += chars;
left -= chars;
read += chars;
if (*bhe) {
copy_to_user(buf,offset+(*bhe)->b_data,chars);
brelse(*bhe);
buf += chars;
} else {
while (chars-- > 0)
put_user(0,buf++);
}
offset = 0;
if (++bhe == &buflist[NBUF])
bhe = buflist;
} while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
} while (left > 0);
/* Release the read-ahead blocks */
while (bhe != bhb) {
brelse(*bhe);
if (++bhe == &buflist[NBUF])
bhe = buflist;
};
if (!read)
return -EIO;
filp->f_reada = 1;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
mark_inode_dirty(inode);
}
return read;
}
static ssize_t sysv_file_write(struct file * filp, const char * buf,
size_t count, loff_t *ppos)
{
struct inode * inode = filp->f_dentry->d_inode;
struct super_block * sb = inode->i_sb;
off_t pos;
ssize_t written, c;
struct buffer_head * bh;
char * p;
if (!inode) {
printk("sysv_file_write: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
printk("sysv_file_write: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
/*
* OK, append may not work when many processes are writing at the same time
* but so what. That way leads to madness anyway.
* But we need to protect against simultaneous truncate as we may end up
* writing our data into blocks that have meanwhile been incorporated into
* the freelist, thereby trashing the freelist.
*/
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
pos = *ppos;
written = 0;
while (written<count) {
bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
if (!bh) {
if (!written)
written = -ENOSPC;
break;
}
c = sb->sv_block_size - (pos & sb->sv_block_size_1);
if (c > count-written)
c = count-written;
if (c != sb->sv_block_size && !buffer_uptodate(bh)) {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
brelse(bh);
if (!written)
written = -EIO;
break;
}
}
/* now either c==sb->sv_block_size or buffer_uptodate(bh) */
p = (pos & sb->sv_block_size_1) + bh->b_data;
copy_from_user(p, buf, c);
update_vm_cache(inode, pos, p, c);
pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
mark_inode_dirty(inode);
}
written += c;
buf += c;
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 0);
brelse(bh);
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
*ppos = pos;
mark_inode_dirty(inode);
return written;
}
......@@ -657,7 +657,8 @@ int sysv_bmap(struct inode * inode,int block_nr)
/* Access selected blocks of regular files (or directories) */
static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create)
static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create,
int metadata, int *phys_block, int *created)
{
struct super_block *sb;
u32 tmp;
......@@ -669,31 +670,48 @@ static struct buffer_head * inode_getblk(struct inode * inode, int nr, int creat
repeat:
tmp = *p;
if (tmp) {
result = sv_getblk(sb, inode->i_dev, tmp);
if (tmp == *p)
return result;
brelse(result);
goto repeat;
if (metadata) {
result = sv_getblk(sb, inode->i_dev, tmp);
if (tmp == *p)
return result;
brelse(result);
goto repeat;
} else {
*phys_block = tmp;
return NULL;
}
}
if (!create)
return NULL;
tmp = sysv_new_block(sb);
if (!tmp)
return NULL;
result = sv_getblk(sb, inode->i_dev, tmp);
if (*p) {
sysv_free_block(sb,tmp);
brelse(result);
goto repeat;
if (metadata) {
result = sv_getblk(sb, inode->i_dev, tmp);
if (*p) {
sysv_free_block(sb, tmp);
brelse(result);
goto repeat;
}
} else {
if (*p) {
sysv_free_block(sb, tmp);
goto repeat;
}
*phys_block = tmp;
result = NULL;
*created = 1;
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
return result;
}
static struct buffer_head * block_getblk(struct inode * inode,
struct buffer_head * bh, int nr, int create)
struct buffer_head * bh, int nr, int create,
int metadata, int *phys_block, int *created)
{
struct super_block *sb;
u32 tmp, block;
......@@ -717,13 +735,19 @@ static struct buffer_head * block_getblk(struct inode * inode,
if (sb->sv_convert)
block = from_coh_ulong(block);
if (tmp) {
result = sv_getblk(sb, bh->b_dev, block);
if (tmp == *p) {
if (metadata) {
result = sv_getblk(sb, bh->b_dev, block);
if (tmp == *p) {
brelse(bh);
return result;
}
brelse(result);
goto repeat;
} else {
*phys_block = tmp;
brelse(bh);
return result;
return NULL;
}
brelse(result);
goto repeat;
}
if (!create) {
brelse(bh);
......@@ -734,11 +758,17 @@ static struct buffer_head * block_getblk(struct inode * inode,
brelse(bh);
return NULL;
}
result = sv_getblk(sb, bh->b_dev, block);
if (*p) {
sysv_free_block(sb,block);
brelse(result);
goto repeat;
if (metadata) {
result = sv_getblk(sb, bh->b_dev, block);
if (*p) {
sysv_free_block(sb,block);
brelse(result);
goto repeat;
}
} else {
*phys_block = tmp;
result = NULL;
*created = 1;
}
*p = (sb->sv_convert ? to_coh_ulong(block) : block);
mark_buffer_dirty(bh, 1);
......@@ -746,37 +776,74 @@ static struct buffer_head * block_getblk(struct inode * inode,
return result;
}
struct buffer_head * sysv_getblk(struct inode * inode, unsigned int block, int create)
int sysv_getblk_block(struct inode *inode, long block, int create,
int *err, int *created)
{
struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
struct super_block *sb = inode->i_sb;
struct buffer_head *bh, *tmp;
int phys_block;
if (block < 10)
return inode_getblk(inode,block,create);
*err = -EIO;
if (block < 0) {
printk("sysv_getblk: block<0");
return 0;
}
if (block > sb->sv_ind_per_block_3) {
printk("sysv_getblk: block>big");
return 0;
}
if (block < 10) {
tmp = inode_getblk(inode, block, create,
0, &phys_block, created);
goto out;
}
block -= 10;
if (block < sb->sv_ind_per_block) {
bh = inode_getblk(inode,10,create);
return block_getblk(inode, bh, block, create);
bh = inode_getblk(inode, 10, create, 1, NULL, NULL);
tmp = block_getblk(inode, bh, block, create,
0, &phys_block, created);
goto out;
}
block -= sb->sv_ind_per_block;
if (block < sb->sv_ind_per_block_2) {
bh = inode_getblk(inode,11,create);
bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_bits, create);
return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create);
bh = inode_getblk(inode, 11, create, 1, NULL, NULL);
bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_bits, create,
1, NULL, NULL);
tmp = block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create,
0, &phys_block, created);
goto out;
}
block -= sb->sv_ind_per_block_2;
if (block < sb->sv_ind_per_block_3) {
bh = inode_getblk(inode,12,create);
bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_2_bits, create);
bh = block_getblk(inode, bh, (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1, create);
return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create);
}
if ((int)block<0) {
printk("sysv_getblk: block<0");
return NULL;
bh = inode_getblk(inode, 12, create, 1, NULL, NULL);
bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_2_bits, create,
1, NULL, NULL);
bh = block_getblk(inode, bh,
(block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1,
create, 1, NULL, NULL);
tmp = block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create,
0, &phys_block, created);
out:
*err = 0;
return phys_block;
}
struct buffer_head *sysv_getblk (struct inode *inode, unsigned int block, int create)
{
struct buffer_head *tmp = NULL;
int phys_block;
int err, created;
phys_block = sysv_getblk_block(inode, block, create, &err, &created);
if (phys_block) {
tmp = getblk(inode->i_dev, phys_block, BLOCK_SIZE);
if (created) {
memset(tmp->b_data, 0, BLOCK_SIZE);
mark_buffer_uptodate(tmp, 1);
mark_buffer_dirty(tmp, 1);
}
}
printk("sysv_getblk: block>big");
return NULL;
return tmp;
}
struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create)
......
......@@ -35,6 +35,9 @@
* general case (size = XXX). I hope.
*/
#define DATA_BUFFER_USED(bh) \
((bh->b_count > 1) || buffer_locked(bh))
/* We throw away any data beyond inode->i_size. */
static int trunc_direct(struct inode * inode)
......@@ -58,7 +61,7 @@ static int trunc_direct(struct inode * inode)
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || (block != *p)) {
if ((bh && DATA_BUFFER_USED(bh)) || (block != *p)) {
retry = 1;
brelse(bh);
continue;
......@@ -115,7 +118,7 @@ static int trunc_indirect(struct inode * inode, unsigned long offset, sysv_zone_
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || (tmp != *ind)) {
if ((bh && DATA_BUFFER_USED(bh)) || (tmp != *ind)) {
retry = 1;
brelse(bh);
continue;
......@@ -128,7 +131,7 @@ static int trunc_indirect(struct inode * inode, unsigned long offset, sysv_zone_
for (i = 0; i < sb->sv_ind_per_block; i++)
if (((sysv_zone_t *) indbh->b_data)[i])
goto done;
if ((indbh->b_count != 1) || (indtmp != *p)) {
if (DATA_BUFFER_USED(indbh) || (indtmp != *p)) {
brelse(indbh);
return 1;
}
......@@ -185,7 +188,7 @@ static int trunc_dindirect(struct inode * inode, unsigned long offset, sysv_zone
for (i = 0; i < sb->sv_ind_per_block; i++)
if (((sysv_zone_t *) indbh->b_data)[i])
goto done;
if ((indbh->b_count != 1) || (indtmp != *p)) {
if (DATA_BUFFER_USED(indbh) || (indtmp != *p)) {
brelse(indbh);
return 1;
}
......@@ -242,7 +245,7 @@ static int trunc_tindirect(struct inode * inode, unsigned long offset, sysv_zone
for (i = 0; i < sb->sv_ind_per_block; i++)
if (((sysv_zone_t *) indbh->b_data)[i])
goto done;
if ((indbh->b_count != 1) || (indtmp != *p)) {
if (DATA_BUFFER_USED(indbh) || (indtmp != *p)) {
brelse(indbh);
return 1;
}
......
......@@ -41,52 +41,6 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
static long long ufs_file_lseek(struct file *, long long, int);
static ssize_t ufs_file_write (struct file *, const char *, size_t, loff_t *);
static int ufs_release_file (struct inode *, struct file *);
/*
* We have mostly NULL's here: the current defaults are ok for
* the ufs filesystem.
*/
static struct file_operations ufs_file_operations = {
ufs_file_lseek, /* lseek */
generic_file_read, /* read */
ufs_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* poll - default */
NULL, /* ioctl */
generic_file_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* flush */
ufs_release_file, /* release */
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
NULL /* revalidate */
};
struct inode_operations ufs_file_inode_operations = {
&ufs_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 */
ufs_bmap, /* bmap */
ufs_truncate, /* truncate */
NULL, /* permission */
NULL /* smap */
};
/*
* Make sure the offset never goes beyond the 32-bit mark..
*/
......@@ -133,139 +87,49 @@ static inline void remove_suid(struct inode *inode)
}
}
static ssize_t ufs_file_write (
struct file * filp,
const char * buf,
size_t count,
loff_t *ppos )
static int ufs_writepage (struct file *file, struct page *page)
{
struct inode * inode = filp->f_dentry->d_inode;
__u32 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)
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)) {
ufs_warning (sb, "ufs_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;
}
/* Check for overflow.. */
if (pos > (__u32) (pos + count)) {
count = ~pos; /* == 0xFFFFFFFF - pos */
if (!count)
return -EFBIG;
}
/*
* 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.ufs_i.i_osync++;
block = pos >> sb->s_blocksize_bits;
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 = ufs_getfrag (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 = ufs_getfrag_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.ufs_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);
brw_page(WRITE, page, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
return 0;
}
static long ufs_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, ufs_getfrag_block);
}
/*
* Write to a file (through the page cache).
*/
static ssize_t
ufs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
return generic_file_write(file, buf, count, ppos, ufs_write_one_page);
}
/*
......@@ -277,3 +141,48 @@ static int ufs_release_file (struct inode * inode, struct file * filp)
{
return 0;
}
/*
* We have mostly NULL's here: the current defaults are ok for
* the ufs filesystem.
*/
static struct file_operations ufs_file_operations = {
ufs_file_lseek, /* lseek */
generic_file_read, /* read */
ufs_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* poll - default */
NULL, /* ioctl */
generic_file_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* flush */
ufs_release_file, /* release */
NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
NULL /* revalidate */
};
struct inode_operations ufs_file_inode_operations = {
&ufs_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 */
ufs_writepage, /* writepage */
ufs_bmap, /* bmap */
ufs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* updatepage */
NULL, /* revalidate */
generic_block_flushpage,/* flushpage */
};
......@@ -175,7 +175,7 @@ int ufs_bmap (struct inode * inode, int fragment)
static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
unsigned fragment, unsigned new_fragment, int create,
unsigned required, int * err )
unsigned required, int *err, int metadata, int *phys_block, int *created)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
......@@ -201,13 +201,19 @@ static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
tmp = SWAB32(*p);
lastfrag = inode->u.ufs_i.i_lastfrag;
if (tmp && fragment < lastfrag) {
result = getblk (sb->s_dev, uspi->s_sbbase + tmp + blockoff, sb->s_blocksize);
if (tmp == SWAB32(*p)) {
UFSD(("EXIT, result %u\n", tmp + blockoff))
return result;
if (metadata) {
result = getblk (sb->s_dev, uspi->s_sbbase + tmp + blockoff,
sb->s_blocksize);
if (tmp == SWAB32(*p)) {
UFSD(("EXIT, result %u\n", tmp + blockoff))
return result;
}
brelse (result);
goto repeat;
} else {
*phys_block = tmp;
return NULL;
}
brelse (result);
goto repeat;
}
*err = -EFBIG;
if (!create)
......@@ -269,7 +275,20 @@ static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
else
return NULL;
}
result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize);
/* The nullification of framgents done in ufs/balloc.c is
* something I don't have the stomache to move into here right
* now. -DaveM
*/
if (metadata) {
result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize);
} else {
*phys_block = tmp;
result = NULL;
*err = 0;
*created = 1;
}
inode->i_ctime = CURRENT_TIME;
if (IS_SYNC(inode))
ufs_sync_inode (inode);
......@@ -280,7 +299,7 @@ static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
static struct buffer_head * ufs_block_getfrag (struct inode * inode,
struct buffer_head * bh, unsigned fragment, unsigned new_fragment,
int create, unsigned blocksize, int * err)
int create, unsigned blocksize, int * err, int metadata, int *phys_block, int *created)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
......@@ -312,19 +331,36 @@ static struct buffer_head * ufs_block_getfrag (struct inode * inode,
repeat:
tmp = SWAB32(*p);
if (tmp) {
result = getblk (bh->b_dev, uspi->s_sbbase + tmp + blockoff, sb->s_blocksize);
if (tmp == SWAB32(*p)) {
if (metadata) {
result = getblk (bh->b_dev, uspi->s_sbbase + tmp + blockoff,
sb->s_blocksize);
if (tmp == SWAB32(*p)) {
brelse (bh);
UFSD(("EXIT, result %u\n", tmp + blockoff))
return result;
}
brelse (result);
goto repeat;
} else {
*phys_block = tmp;
brelse (bh);
UFSD(("EXIT, result %u\n", tmp + blockoff))
return result;
return NULL;
}
brelse (result);
goto repeat;
}
if (!create || new_fragment >= (current->rlim[RLIMIT_FSIZE].rlim_cur >> sb->s_blocksize)) {
*err = -EFBIG;
if (!create) {
brelse (bh);
*err = -EFBIG;
return NULL;
} else {
unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit < RLIM_INFINITY) {
limit >>= sb->s_blocksize_bits;
if (new_fragment >= limit) {
brelse (bh);
send_sig(SIGXFSZ, current, 0);
return NULL;
}
}
}
if (block && (tmp = SWAB32(((u32*)bh->b_data)[block-1]) + uspi->s_fpb))
goal = tmp + uspi->s_fpb;
......@@ -334,12 +370,25 @@ static struct buffer_head * ufs_block_getfrag (struct inode * inode,
if (!tmp) {
if (SWAB32(*p)) {
goto repeat;
}
else {
} else {
brelse (bh);
return NULL;
}
}
result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
/* The nullification of framgents done in ufs/balloc.c is
* something I don't have the stomache to move into here right
* now. -DaveM
*/
if (metadata) {
result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
} else {
*phys_block = tmp;
result = NULL;
*err = 0;
*created = 1;
}
mark_buffer_dirty(bh, 1);
if (IS_SYNC(inode)) {
ll_rw_block (WRITE, 1, &bh);
......@@ -352,14 +401,15 @@ static struct buffer_head * ufs_block_getfrag (struct inode * inode,
return result;
}
struct buffer_head * ufs_getfrag (struct inode * inode, unsigned fragment,
int create, int * err)
int ufs_getfrag_block (struct inode * inode, long fragment,
int create, int * err, int *created)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * bh;
struct buffer_head * bh, * tmp;
unsigned f;
unsigned swab;
int phys_block;
sb = inode->i_sb;
uspi = sb->u.ufs_sb.s_uspi;
......@@ -367,19 +417,27 @@ struct buffer_head * ufs_getfrag (struct inode * inode, unsigned fragment,
*err = -EIO;
UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
if (fragment < 0) {
ufs_warning (sb, "ufs_getblk", "block < 0");
return 0;
}
if (fragment > ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
ufs_warning (sb, "ufs_getblk", "block > big");
return NULL;
return 0;
}
*err = -ENOSPC;
f = fragment;
*created = 0;
/*
* Direct fragment
*/
if (fragment < UFS_NDIR_FRAGMENT)
return ufs_inode_getfrag (inode, fragment, fragment, create, 1, err);
if (fragment < UFS_NDIR_FRAGMENT) {
tmp = ufs_inode_getfrag (inode, fragment, fragment, create, 1,
err, 0, &phys_block, created);
goto out;
}
/*
* Indirect fragment
*/
......@@ -387,10 +445,12 @@ struct buffer_head * ufs_getfrag (struct inode * inode, unsigned fragment,
if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
bh = ufs_inode_getfrag (inode,
UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift),
f, create, uspi->s_fpb, err);
return ufs_block_getfrag (inode, bh,
fragment & uspi->s_apbmask,
f, create, sb->s_blocksize, err);
f, create, uspi->s_fpb, err, 1, NULL, NULL);
tmp = ufs_block_getfrag (inode, bh,
fragment & uspi->s_apbmask,
f, create, sb->s_blocksize,
err, 0, &phys_block, created);
goto out;
}
/*
* Dindirect fragment
......@@ -398,14 +458,18 @@ struct buffer_head * ufs_getfrag (struct inode * inode, unsigned fragment,
fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
if ( fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
bh = ufs_inode_getfrag (inode,
UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift),
f, create, uspi->s_fpb, err);
UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift),
f, create, uspi->s_fpb, err,
1, NULL, NULL);
bh = ufs_block_getfrag (inode, bh,
(fragment >> uspi->s_apbshift) & uspi->s_apbmask,
f, create, sb->s_blocksize, err);
return ufs_block_getfrag (inode, bh,
f, create, sb->s_blocksize, err,
1, NULL, NULL);
tmp = ufs_block_getfrag (inode, bh,
fragment & uspi->s_apbmask,
f, create, sb->s_blocksize, err);
f, create, sb->s_blocksize, err,
0, &phys_block, created);
goto out;
}
/*
* Tindirect fragment
......@@ -413,19 +477,42 @@ struct buffer_head * ufs_getfrag (struct inode * inode, unsigned fragment,
fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
bh = ufs_inode_getfrag (inode,
UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift),
f, create, uspi->s_fpb, err);
f, create, uspi->s_fpb, err, 1, NULL, NULL);
bh = ufs_block_getfrag (inode, bh,
(fragment >> uspi->s_2apbshift) & uspi->s_apbmask,
f, create, sb->s_blocksize, err);
f, create, sb->s_blocksize, err, 1, NULL, NULL);
bh = ufs_block_getfrag (inode, bh,
(fragment >> uspi->s_apbshift) & uspi->s_apbmask,
f, create, sb->s_blocksize, err);
return ufs_block_getfrag (inode, bh,
f, create, sb->s_blocksize, err, 1, NULL, NULL);
tmp = ufs_block_getfrag (inode, bh,
fragment & uspi->s_apbmask,
f, create, sb->s_blocksize, err);
}
f, create, sb->s_blocksize, err, 0, &phys_block, created);
out:
if (!phys_block)
return 0;
if (*err)
return 0;
return phys_block;
}
struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment,
int create, int *err)
{
struct buffer_head *tmp = NULL;
int phys_block, created;
phys_block = ufs_getfrag_block(inode, fragment, create, err, &created);
if (phys_block) {
tmp = getblk(inode->i_dev, phys_block, inode->i_sb->s_blocksize);
if (created) {
memset(tmp->b_data, 0, inode->i_sb->s_blocksize);
mark_buffer_uptodate(tmp, 1);
mark_buffer_dirty(tmp, 1);
}
}
return tmp;
}
struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
int create, int * err)
......
......@@ -62,6 +62,9 @@
#define DIRECT_BLOCK howmany (inode->i_size, uspi->s_bsize)
#define DIRECT_FRAGMENT howmany (inode->i_size, uspi->s_fsize)
#define DATA_BUFFER_USED(bh) \
((bh->b_count > 1) || buffer_locked(bh))
static int ufs_trunc_direct (struct inode * inode)
{
struct super_block * sb;
......@@ -114,7 +117,7 @@ static int ufs_trunc_direct (struct inode * inode)
frag2 = ufs_fragnum (frag2);
for (j = frag1; j < frag2; j++) {
bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
if ((bh && DATA_BUFFER_USED(bh)) || tmp != SWAB32(*p)) {
retry = 1;
brelse (bh);
goto next1;
......@@ -137,7 +140,7 @@ static int ufs_trunc_direct (struct inode * inode)
continue;
for (j = 0; j < uspi->s_fpb; j++) {
bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
if ((bh && DATA_BUFFER_USED(bh)) || tmp != SWAB32(*p)) {
retry = 1;
brelse (bh);
goto next2;
......@@ -176,7 +179,7 @@ static int ufs_trunc_direct (struct inode * inode)
frag4 = ufs_fragnum (frag4);
for (j = 0; j < frag4; j++) {
bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
if ((bh && bh->b_count != 1) || tmp != SWAB32(*p)) {
if ((bh && DATA_BUFFER_USED(bh)) || tmp != SWAB32(*p)) {
retry = 1;
brelse (bh);
goto next1;
......@@ -237,7 +240,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, u32 * p)
continue;
for (j = 0; j < uspi->s_fpb; j++) {
bh = get_hash_table (sb->s_dev, tmp + j, uspi->s_fsize);
if ((bh && bh->b_count != 1) || tmp != SWAB32(*ind)) {
if ((bh && DATA_BUFFER_USED(bh)) || tmp != SWAB32(*ind)) {
retry = 1;
brelse (bh);
goto next;
......
......@@ -356,7 +356,6 @@ struct inode {
unsigned long i_version;
unsigned long i_nrpages;
struct semaphore i_sem;
struct semaphore i_atomic_write;
struct inode_operations *i_op;
struct super_block *i_sb;
wait_queue_head_t i_wait;
......@@ -622,7 +621,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);
int (*flushpage) (struct inode *, struct page *, unsigned long);
};
struct super_operations {
......@@ -750,15 +749,7 @@ extern struct file *inuse_filps;
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 void refile_buffer(struct buffer_head * buf);
extern int buffermem;
......@@ -881,8 +872,10 @@ 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 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);
extern void put_super(kdev_t);
......
......@@ -110,6 +110,7 @@ extern unsigned long minix_count_free_blocks(struct super_block *sb);
extern int minix_bmap(struct inode *,int);
extern struct buffer_head * minix_getblk(struct inode *, int, int);
extern int minix_getblk_block (struct inode *, long, int, int *, int *);
extern struct buffer_head * minix_bread(struct inode *, int, int);
extern void minix_truncate(struct inode *);
......
......@@ -192,7 +192,8 @@ extern struct inode_operations nfs_file_inode_operations;
*/
extern struct inode_operations nfs_dir_inode_operations;
extern struct dentry_operations nfs_dentry_operations;
extern void nfs_invalidate_dircache(struct inode *);
extern void nfs_flush_dircache(struct inode *);
extern void nfs_free_dircache(struct inode *);
/*
* linux/fs/nfs/symlink.c
......
......@@ -387,6 +387,7 @@ extern unsigned long sysv_count_free_blocks(struct super_block *sb);
extern int sysv_bmap(struct inode *,int);
extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int);
extern int sysv_getblk_block(struct inode *, long, int, int *, int *);
extern struct buffer_head * sysv_file_bread(struct inode *, int, int);
extern ssize_t sysv_file_read(struct file *, char *, size_t, loff_t *);
......
......@@ -537,6 +537,7 @@ extern int ufs_sync_inode (struct inode *);
extern void ufs_write_inode (struct inode *);
extern void ufs_delete_inode (struct inode *);
extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
extern int ufs_getfrag_block (struct inode *, long, int, int *, int *);
extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
/* namei.c */
......
......@@ -137,8 +137,6 @@ void truncate_inode_pages(struct inode * inode, unsigned long start)
page_cache_release(page);
goto repeat;
}
if (page_count(page) != 2)
printk("hm, busy page truncated? (not necesserily a bug)\n");
spin_unlock(&pagecache_lock);
if (inode->i_op->flushpage)
......@@ -160,9 +158,6 @@ void truncate_inode_pages(struct inode * inode, unsigned long start)
page->prev = NULL;
remove_page_from_hash_queue(page);
page->inode = NULL;
if (page_count(page) != 2)
printk("hm, busy page truncated? (not necesserily a bug)\n");
spin_unlock(&pagecache_lock);
UnlockPage(page);
......@@ -189,6 +184,13 @@ void truncate_inode_pages(struct inode * inode, unsigned long start)
/* partial truncate, clear end of page */
if (offset < PAGE_CACHE_SIZE) {
unsigned long address;
get_page(page);
if (TryLockPage(page)) {
spin_unlock(&pagecache_lock);
wait_on_page(page);
page_cache_release(page);
goto repeat;
}
/*
* It's worth dropping the write lock only at
* this point. We are holding the page lock
......@@ -200,10 +202,15 @@ void truncate_inode_pages(struct inode * inode, unsigned long start)
address = page_address(page);
memset((void *) (offset + address), 0, PAGE_CACHE_SIZE - offset);
flush_page_to_ram(address);
if (inode->i_op->flushpage)
inode->i_op->flushpage(inode, page, offset);
/*
* we have dropped the lock so we have to
* we have dropped the spinlock so we have to
* restart.
*/
UnlockPage(page);
page_cache_release(page);
goto repeat;
}
}
......@@ -217,25 +224,9 @@ void truncate_inode_pages(struct inode * inode, unsigned long start)
*/
void remove_inode_page(struct page *page)
{
struct inode *inode = page->inode;
if (!PageLocked(page))
PAGE_BUG(page);
/*
* We might sleep here. Other processes might arrive and sleep on
* the lock, but nobody is allowed to 'cross' the lock and get a
* reference to the page. We then remove the page from the hash
* before unlocking it. This mechanizm ensures that 1) nobody gets
* a half-freed page 2) nobody creates the same pagecache content
* before we finish destroying this page. This is not a
* performance problem as pages here are candidates for getting
* freed, ie. it's supposed to be unlikely that the above situation
* happens.
*/
if (inode->i_op->flushpage)
inode->i_op->flushpage(inode, page, 1);
spin_lock(&pagecache_lock);
remove_page_from_inode_queue(page);
remove_page_from_hash_queue(page);
......@@ -274,12 +265,27 @@ int shrink_mmap(int priority, int gfp_mask)
referenced = test_and_clear_bit(PG_referenced, &page->flags);
if (PageLocked(page))
if ((gfp_mask & __GFP_DMA) && !PageDMA(page))
continue;
if ((gfp_mask & __GFP_DMA) && !PageDMA(page))
if (PageLocked(page))
continue;
/* Is it a buffer page? */
if (page->buffers) {
if (buffer_under_min())
continue;
if (TryLockPage(page))
continue;
err = try_to_free_buffers(page);
UnlockPage(page);
if (!err)
continue;
goto out;
}
/* We can't free pages unless there's just one user */
if (page_count(page) != 1)
continue;
......@@ -309,13 +315,14 @@ int shrink_mmap(int priority, int gfp_mask)
goto unlock_continue;
if (TryLockPage(page))
goto unlock_continue;
if (page_count(page) != 1) {
UnlockPage(page);
goto unlock_continue;
if (page_count(page) == 1) {
remove_page_from_inode_queue(page);
remove_page_from_hash_queue(page);
page->inode = NULL;
}
spin_unlock(&pagecache_lock);
remove_inode_page(page);
UnlockPage(page);
page_cache_release(page);
err = 1;
......@@ -325,17 +332,6 @@ int shrink_mmap(int priority, int gfp_mask)
continue;
}
spin_unlock(&pagecache_lock);
/* Is it a buffer page? */
if (page->buffers) {
if (buffer_under_min())
continue;
if (!try_to_free_buffers(page))
continue;
err = 1;
goto out;
}
} while (count > 0);
err = 0;
out:
......@@ -1086,17 +1082,14 @@ static int file_send_actor(read_descriptor_t * desc, const char *area, unsigned
ssize_t written;
unsigned long count = desc->count;
struct file *file = (struct file *) desc->buf;
struct inode *inode = file->f_dentry->d_inode;
mm_segment_t old_fs;
if (size > count)
size = count;
down(&inode->i_sem);
old_fs = get_fs();
set_fs(KERNEL_DS);
written = file->f_op->write(file, area, size, &file->f_pos);
set_fs(old_fs);
up(&inode->i_sem);
if (written < 0) {
desc->error = written;
written = 0;
......@@ -1362,7 +1355,6 @@ static inline int do_write_page(struct inode * inode, struct file * file,
int retval;
unsigned long size;
loff_t loff = offset;
mm_segment_t old_fs;
int (*writepage) (struct file *, struct page *);
struct page * page;
......@@ -1376,8 +1368,6 @@ static inline int do_write_page(struct inode * inode, struct file * file,
return -EIO;
}
size -= offset;
old_fs = get_fs();
set_fs(KERNEL_DS);
retval = -EIO;
writepage = inode->i_op->writepage;
page = mem_map + MAP_NR(page_addr);
......@@ -1386,11 +1376,13 @@ static inline int do_write_page(struct inode * inode, struct file * file,
if (writepage) {
retval = writepage(file, page);
} else {
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
if (size == file->f_op->write(file, page_addr, size, &loff))
retval = 0;
retval = 0;
set_fs(old_fs);
}
UnlockPage(page);
set_fs(old_fs);
return retval;
}
......@@ -1426,9 +1418,7 @@ static int filemap_write_page(struct vm_area_struct * vma,
return 0;
}
down(&inode->i_sem);
result = do_write_page(inode, file, (const char *) page, offset);
up(&inode->i_sem);
fput(file);
return result;
}
......@@ -1642,10 +1632,7 @@ static int msync_interval(struct vm_area_struct * vma,
struct file * file = vma->vm_file;
if (file) {
struct dentry * dentry = file->f_dentry;
struct inode * inode = dentry->d_inode;
down(&inode->i_sem);
error = file_fsync(file, dentry);
up(&inode->i_sem);
}
}
return error;
......@@ -1972,10 +1959,8 @@ int kpiod(void * unused)
dentry = p->file->f_dentry;
inode = dentry->d_inode;
down(&inode->i_sem);
do_write_page(inode, p->file,
(const char *) p->page, p->offset);
up(&inode->i_sem);
fput(p->file);
page_cache_free(p->page);
kmem_cache_free(pio_request_cache, p);
......
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