Commit 2796576e authored by Linus Torvalds's avatar Linus Torvalds

Merge home.transmeta.com:/home/torvalds/v2.5/morton

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 98d809e7 071c9b22
...@@ -195,11 +195,15 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin) ...@@ -195,11 +195,15 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
static int __block_fsync(struct inode * inode) static int __block_fsync(struct inode * inode)
{ {
int ret; int ret, err;
filemap_fdatasync(inode->i_mapping); ret = filemap_fdatasync(inode->i_mapping);
ret = sync_buffers(inode->i_rdev, 1); err = sync_buffers(inode->i_rdev, 1);
filemap_fdatawait(inode->i_mapping); if (err && !ret)
ret = err;
err = filemap_fdatawait(inode->i_mapping);
if (err && !ret)
ret = err;
return ret; return ret;
} }
......
...@@ -410,9 +410,9 @@ asmlinkage long sys_fsync(unsigned int fd) ...@@ -410,9 +410,9 @@ asmlinkage long sys_fsync(unsigned int fd)
struct file * file; struct file * file;
struct dentry * dentry; struct dentry * dentry;
struct inode * inode; struct inode * inode;
int err; int ret, err;
err = -EBADF; ret = -EBADF;
file = fget(fd); file = fget(fd);
if (!file) if (!file)
goto out; goto out;
...@@ -420,21 +420,27 @@ asmlinkage long sys_fsync(unsigned int fd) ...@@ -420,21 +420,27 @@ asmlinkage long sys_fsync(unsigned int fd)
dentry = file->f_dentry; dentry = file->f_dentry;
inode = dentry->d_inode; inode = dentry->d_inode;
err = -EINVAL; ret = -EINVAL;
if (!file->f_op || !file->f_op->fsync) if (!file->f_op || !file->f_op->fsync) {
/* Why? We can still call filemap_fdatasync */
goto out_putf; goto out_putf;
}
/* We need to protect against concurrent writers.. */ /* We need to protect against concurrent writers.. */
down(&inode->i_sem); down(&inode->i_sem);
filemap_fdatasync(inode->i_mapping); ret = filemap_fdatasync(inode->i_mapping);
err = file->f_op->fsync(file, dentry, 0); err = file->f_op->fsync(file, dentry, 0);
filemap_fdatawait(inode->i_mapping); if (err && !ret)
ret = err;
err = filemap_fdatawait(inode->i_mapping);
if (err && !ret)
ret = err;
up(&inode->i_sem); up(&inode->i_sem);
out_putf: out_putf:
fput(file); fput(file);
out: out:
return err; return ret;
} }
asmlinkage long sys_fdatasync(unsigned int fd) asmlinkage long sys_fdatasync(unsigned int fd)
...@@ -442,9 +448,9 @@ asmlinkage long sys_fdatasync(unsigned int fd) ...@@ -442,9 +448,9 @@ asmlinkage long sys_fdatasync(unsigned int fd)
struct file * file; struct file * file;
struct dentry * dentry; struct dentry * dentry;
struct inode * inode; struct inode * inode;
int err; int ret, err;
err = -EBADF; ret = -EBADF;
file = fget(fd); file = fget(fd);
if (!file) if (!file)
goto out; goto out;
...@@ -452,20 +458,24 @@ asmlinkage long sys_fdatasync(unsigned int fd) ...@@ -452,20 +458,24 @@ asmlinkage long sys_fdatasync(unsigned int fd)
dentry = file->f_dentry; dentry = file->f_dentry;
inode = dentry->d_inode; inode = dentry->d_inode;
err = -EINVAL; ret = -EINVAL;
if (!file->f_op || !file->f_op->fsync) if (!file->f_op || !file->f_op->fsync)
goto out_putf; goto out_putf;
down(&inode->i_sem); down(&inode->i_sem);
filemap_fdatasync(inode->i_mapping); ret = filemap_fdatasync(inode->i_mapping);
err = file->f_op->fsync(file, dentry, 1); err = file->f_op->fsync(file, dentry, 1);
filemap_fdatawait(inode->i_mapping); if (err && !ret)
ret = err;
err = filemap_fdatawait(inode->i_mapping);
if (err && !ret)
ret = err;
up(&inode->i_sem); up(&inode->i_sem);
out_putf: out_putf:
fput(file); fput(file);
out: out:
return err; return ret;
} }
/* After several hours of tedious analysis, the following hash /* After several hours of tedious analysis, the following hash
...@@ -1431,6 +1441,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b ...@@ -1431,6 +1441,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
int err, i; int err, i;
unsigned long block; unsigned long block;
struct buffer_head *bh, *head; struct buffer_head *bh, *head;
int need_unlock;
if (!PageLocked(page)) if (!PageLocked(page))
BUG(); BUG();
...@@ -1486,7 +1497,33 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b ...@@ -1486,7 +1497,33 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
return 0; return 0;
out: out:
/*
* ENOSPC, or some other error. We may already have added some
* blocks to the file, so we need to write these out to avoid
* exposing stale data.
*/
ClearPageUptodate(page); ClearPageUptodate(page);
bh = head;
need_unlock = 1;
/* Recovery: lock and submit the mapped buffers */
do {
if (buffer_mapped(bh)) {
lock_buffer(bh);
set_buffer_async_io(bh);
need_unlock = 0;
}
bh = bh->b_this_page;
} while (bh != head);
do {
struct buffer_head *next = bh->b_this_page;
if (buffer_mapped(bh)) {
set_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Dirty, &bh->b_state);
submit_bh(WRITE, bh);
}
bh = next;
} while (bh != head);
if (need_unlock)
UnlockPage(page); UnlockPage(page);
return err; return err;
} }
...@@ -1518,6 +1555,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page, ...@@ -1518,6 +1555,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
continue; continue;
if (block_start >= to) if (block_start >= to)
break; break;
clear_bit(BH_New, &bh->b_state);
if (!buffer_mapped(bh)) { if (!buffer_mapped(bh)) {
err = get_block(inode, block, bh, 1); err = get_block(inode, block, bh, 1);
if (err) if (err)
...@@ -1552,12 +1590,35 @@ static int __block_prepare_write(struct inode *inode, struct page *page, ...@@ -1552,12 +1590,35 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
*/ */
while(wait_bh > wait) { while(wait_bh > wait) {
wait_on_buffer(*--wait_bh); wait_on_buffer(*--wait_bh);
err = -EIO;
if (!buffer_uptodate(*wait_bh)) if (!buffer_uptodate(*wait_bh))
goto out; return -EIO;
} }
return 0; return 0;
out: out:
/*
* Zero out any newly allocated blocks to avoid exposing stale
* data. If BH_New is set, we know that the block was newly
* allocated in the above loop.
*/
bh = head;
block_start = 0;
do {
block_end = block_start+blocksize;
if (block_end <= from)
goto next_bh;
if (block_start >= to)
break;
if (buffer_new(bh)) {
if (buffer_uptodate(bh))
printk(KERN_ERR "%s: zeroing uptodate buffer!\n", __FUNCTION__);
memset(kaddr+block_start, 0, bh->b_size);
set_bit(BH_Uptodate, &bh->b_state);
mark_buffer_dirty(bh);
}
next_bh:
block_start = block_end;
bh = bh->b_this_page;
} while (bh != head);
return err; return err;
} }
...@@ -1954,6 +2015,48 @@ int block_write_full_page(struct page *page, get_block_t *get_block) ...@@ -1954,6 +2015,48 @@ int block_write_full_page(struct page *page, get_block_t *get_block)
goto done; goto done;
} }
/*
* Commence writeout of all the buffers against a page. The
* page must be locked. Returns zero on success or a negative
* errno.
*/
int writeout_one_page(struct page *page)
{
struct buffer_head *bh, *head = page->buffers;
if (!PageLocked(page))
BUG();
bh = head;
do {
if (buffer_locked(bh) || !buffer_dirty(bh) || !buffer_uptodate(bh))
continue;
bh->b_flushtime = jiffies;
ll_rw_block(WRITE, 1, &bh);
} while ((bh = bh->b_this_page) != head);
return 0;
}
EXPORT_SYMBOL(writeout_one_page);
/*
* Wait for completion of I/O of all buffers against a page. The page
* must be locked. Returns zero on success or a negative errno.
*/
int waitfor_one_page(struct page *page)
{
int error = 0;
struct buffer_head *bh, *head = page->buffers;
bh = head;
do {
wait_on_buffer(bh);
if (buffer_req(bh) && !buffer_uptodate(bh))
error = -EIO;
} while ((bh = bh->b_this_page) != head);
return error;
}
EXPORT_SYMBOL(waitfor_one_page);
sector_t generic_block_bmap(struct address_space *mapping, sector_t block, sector_t generic_block_bmap(struct address_space *mapping, sector_t block,
get_block_t *get_block) get_block_t *get_block)
{ {
......
...@@ -52,8 +52,13 @@ static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to) ...@@ -52,8 +52,13 @@ static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to)
int err = 0; int err = 0;
dir->i_version = ++event; dir->i_version = ++event;
page->mapping->a_ops->commit_write(NULL, page, from, to); page->mapping->a_ops->commit_write(NULL, page, from, to);
if (IS_SYNC(dir)) if (IS_SYNC(dir)) {
err = waitfor_one_page(page); int err2;
err = writeout_one_page(page);
err2 = waitfor_one_page(page);
if (err == 0)
err = err2;
}
return err; return err;
} }
......
...@@ -36,8 +36,13 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) ...@@ -36,8 +36,13 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
struct inode *dir = (struct inode *)page->mapping->host; struct inode *dir = (struct inode *)page->mapping->host;
int err = 0; int err = 0;
page->mapping->a_ops->commit_write(NULL, page, from, to); page->mapping->a_ops->commit_write(NULL, page, from, to);
if (IS_SYNC(dir)) if (IS_SYNC(dir)) {
err = waitfor_one_page(page); int err2;
err = writeout_one_page(page);
err2 = waitfor_one_page(page);
if (err == 0)
err = err2;
}
return err; return err;
} }
...@@ -236,10 +241,10 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page) ...@@ -236,10 +241,10 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
lock_page(page); lock_page(page);
err = mapping->a_ops->prepare_write(NULL, page, from, to); err = mapping->a_ops->prepare_write(NULL, page, from, to);
if (err) if (err == 0) {
BUG();
de->inode = 0; de->inode = 0;
err = dir_commit_chunk(page, from, to); err = dir_commit_chunk(page, from, to);
}
UnlockPage(page); UnlockPage(page);
dir_put_page(page); dir_put_page(page);
inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_ctime = inode->i_mtime = CURRENT_TIME;
...@@ -336,10 +341,10 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page, ...@@ -336,10 +341,10 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page,
lock_page(page); lock_page(page);
err = page->mapping->a_ops->prepare_write(NULL, page, from, to); err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
if (err) if (err == 0) {
BUG();
de->inode = inode->i_ino; de->inode = inode->i_ino;
err = dir_commit_chunk(page, from, to); err = dir_commit_chunk(page, from, to);
}
UnlockPage(page); UnlockPage(page);
dir_put_page(page); dir_put_page(page);
dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_mtime = dir->i_ctime = CURRENT_TIME;
......
...@@ -244,6 +244,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -244,6 +244,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
{ {
struct inode * inode = filp->f_dentry->d_inode; struct inode * inode = filp->f_dentry->d_inode;
int status = 0; int status = 0;
int status2;
dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n", dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
inode->i_sb->s_id, inode->i_ino, inode->i_sb->s_id, inode->i_ino,
...@@ -278,11 +279,15 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -278,11 +279,15 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
* Flush all pending writes before doing anything * Flush all pending writes before doing anything
* with locks.. * with locks..
*/ */
filemap_fdatasync(inode->i_mapping); status = filemap_fdatasync(inode->i_mapping);
down(&inode->i_sem); down(&inode->i_sem);
status = nfs_wb_all(inode); status2 = nfs_wb_all(inode);
if (status2 && !status)
status = status2;
up(&inode->i_sem); up(&inode->i_sem);
filemap_fdatawait(inode->i_mapping); status2 = filemap_fdatawait(inode->i_mapping);
if (status2 && !status)
status = status2;
if (status < 0) if (status < 0)
return status; return status;
......
Thu Feb 14 2002 Andrew Morton <akpm@zip.com.au>
* dir_commit_chunk(): call writeout_one_page() as well as
waitfor_one_page() for IS_SYNC directories, so that we
actually do sync the directory. (forward-port from 2.4).
Thu Feb 7 2002 Alexander Viro <viro@math.psu.edu> Thu Feb 7 2002 Alexander Viro <viro@math.psu.edu>
* super.c: switched to ->get_sb() * super.c: switched to ->get_sb()
...@@ -97,3 +103,4 @@ Fri Oct 26 2001 Christoph Hellwig <hch@caldera.de> ...@@ -97,3 +103,4 @@ Fri Oct 26 2001 Christoph Hellwig <hch@caldera.de>
Remove symlink faking. Noone really wants to use these as Remove symlink faking. Noone really wants to use these as
linux filesystems and native OSes don't support it anyway. linux filesystems and native OSes don't support it anyway.
...@@ -42,8 +42,13 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to) ...@@ -42,8 +42,13 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
int err = 0; int err = 0;
page->mapping->a_ops->commit_write(NULL, page, from, to); page->mapping->a_ops->commit_write(NULL, page, from, to);
if (IS_SYNC(dir)) if (IS_SYNC(dir)) {
err = waitfor_one_page(page); int err2;
err = writeout_one_page(page);
err2 = waitfor_one_page(page);
if (err == 0)
err = err2;
}
return err; return err;
} }
......
...@@ -1230,8 +1230,8 @@ static inline int fsync_inode_data_buffers(struct inode *inode) ...@@ -1230,8 +1230,8 @@ static inline int fsync_inode_data_buffers(struct inode *inode)
return fsync_buffers_list(&inode->i_dirty_data_buffers); return fsync_buffers_list(&inode->i_dirty_data_buffers);
} }
extern int inode_has_buffers(struct inode *); extern int inode_has_buffers(struct inode *);
extern void filemap_fdatasync(struct address_space *); extern int filemap_fdatasync(struct address_space *);
extern void filemap_fdatawait(struct address_space *); extern int filemap_fdatawait(struct address_space *);
extern void sync_supers(kdev_t); extern void sync_supers(kdev_t);
extern int bmap(struct inode *, int); extern int bmap(struct inode *, int);
extern int notify_change(struct dentry *, struct iattr *); extern int notify_change(struct dentry *, struct iattr *);
...@@ -1440,8 +1440,9 @@ sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); ...@@ -1440,8 +1440,9 @@ sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
int generic_commit_write(struct file *, struct page *, unsigned, unsigned); int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
int block_truncate_page(struct address_space *, loff_t, get_block_t *); int block_truncate_page(struct address_space *, loff_t, get_block_t *);
extern int generic_direct_IO(int, struct inode *, struct kiobuf *, unsigned long, int, get_block_t *); extern int generic_direct_IO(int, struct inode *, struct kiobuf *, unsigned long, int, get_block_t *);
extern int waitfor_one_page(struct page *);
extern int writeout_one_page(struct page *);
extern int waitfor_one_page(struct page*);
extern int generic_file_mmap(struct file *, struct vm_area_struct *); extern int generic_file_mmap(struct file *, struct vm_area_struct *);
extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size); extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
......
...@@ -213,7 +213,6 @@ EXPORT_SYMBOL(cont_prepare_write); ...@@ -213,7 +213,6 @@ EXPORT_SYMBOL(cont_prepare_write);
EXPORT_SYMBOL(generic_commit_write); EXPORT_SYMBOL(generic_commit_write);
EXPORT_SYMBOL(block_truncate_page); EXPORT_SYMBOL(block_truncate_page);
EXPORT_SYMBOL(generic_block_bmap); EXPORT_SYMBOL(generic_block_bmap);
EXPORT_SYMBOL(waitfor_one_page);
EXPORT_SYMBOL(generic_file_read); EXPORT_SYMBOL(generic_file_read);
EXPORT_SYMBOL(do_generic_file_read); EXPORT_SYMBOL(do_generic_file_read);
EXPORT_SYMBOL(generic_file_write); EXPORT_SYMBOL(generic_file_write);
......
...@@ -449,41 +449,6 @@ static inline struct page * __find_page_nolock(struct address_space *mapping, un ...@@ -449,41 +449,6 @@ static inline struct page * __find_page_nolock(struct address_space *mapping, un
return page; return page;
} }
/*
* By the time this is called, the page is locked and
* we don't have to worry about any races any more.
*
* Start the IO..
*/
static int writeout_one_page(struct page *page)
{
struct buffer_head *bh, *head = page->buffers;
bh = head;
do {
if (buffer_locked(bh) || !buffer_dirty(bh) || !buffer_uptodate(bh))
continue;
bh->b_flushtime = jiffies;
ll_rw_block(WRITE, 1, &bh);
} while ((bh = bh->b_this_page) != head);
return 0;
}
int waitfor_one_page(struct page *page)
{
int error = 0;
struct buffer_head *bh, *head = page->buffers;
bh = head;
do {
wait_on_buffer(bh);
if (buffer_req(bh) && !buffer_uptodate(bh))
error = -EIO;
} while ((bh = bh->b_this_page) != head);
return error;
}
static int do_buffer_fdatasync(struct list_head *head, unsigned long start, unsigned long end, int (*fn)(struct page *)) static int do_buffer_fdatasync(struct list_head *head, unsigned long start, unsigned long end, int (*fn)(struct page *))
{ {
struct list_head *curr; struct list_head *curr;
...@@ -577,8 +542,9 @@ EXPORT_SYMBOL(fail_writepage); ...@@ -577,8 +542,9 @@ EXPORT_SYMBOL(fail_writepage);
* @mapping: address space structure to write * @mapping: address space structure to write
* *
*/ */
void filemap_fdatasync(struct address_space * mapping) int filemap_fdatasync(struct address_space * mapping)
{ {
int ret = 0;
int (*writepage)(struct page *) = mapping->a_ops->writepage; int (*writepage)(struct page *) = mapping->a_ops->writepage;
spin_lock(&pagecache_lock); spin_lock(&pagecache_lock);
...@@ -598,8 +564,11 @@ void filemap_fdatasync(struct address_space * mapping) ...@@ -598,8 +564,11 @@ void filemap_fdatasync(struct address_space * mapping)
lock_page(page); lock_page(page);
if (PageDirty(page)) { if (PageDirty(page)) {
int err;
ClearPageDirty(page); ClearPageDirty(page);
writepage(page); err = writepage(page);
if (err && !ret)
ret = err;
} else } else
UnlockPage(page); UnlockPage(page);
...@@ -607,6 +576,7 @@ void filemap_fdatasync(struct address_space * mapping) ...@@ -607,6 +576,7 @@ void filemap_fdatasync(struct address_space * mapping)
spin_lock(&pagecache_lock); spin_lock(&pagecache_lock);
} }
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
return ret;
} }
/** /**
...@@ -616,8 +586,10 @@ void filemap_fdatasync(struct address_space * mapping) ...@@ -616,8 +586,10 @@ void filemap_fdatasync(struct address_space * mapping)
* @mapping: address space structure to wait for * @mapping: address space structure to wait for
* *
*/ */
void filemap_fdatawait(struct address_space * mapping) int filemap_fdatawait(struct address_space * mapping)
{ {
int ret = 0;
spin_lock(&pagecache_lock); spin_lock(&pagecache_lock);
while (!list_empty(&mapping->locked_pages)) { while (!list_empty(&mapping->locked_pages)) {
...@@ -633,11 +605,14 @@ void filemap_fdatawait(struct address_space * mapping) ...@@ -633,11 +605,14 @@ void filemap_fdatawait(struct address_space * mapping)
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
___wait_on_page(page); ___wait_on_page(page);
if (PageError(page))
ret = -EIO;
page_cache_release(page); page_cache_release(page);
spin_lock(&pagecache_lock); spin_lock(&pagecache_lock);
} }
spin_unlock(&pagecache_lock); spin_unlock(&pagecache_lock);
return ret;
} }
/* /*
...@@ -1514,12 +1489,14 @@ static ssize_t generic_file_direct_IO(int rw, struct file * filp, char * buf, si ...@@ -1514,12 +1489,14 @@ static ssize_t generic_file_direct_IO(int rw, struct file * filp, char * buf, si
goto out_free; goto out_free;
/* /*
* Flush to disk exlusively the _data_, metadata must remains * Flush to disk exclusively the _data_, metadata must remain
* completly asynchronous or performance will go to /dev/null. * completly asynchronous or performance will go to /dev/null.
*/ */
filemap_fdatasync(mapping); retval = filemap_fdatasync(mapping);
if (retval == 0)
retval = fsync_inode_data_buffers(inode); retval = fsync_inode_data_buffers(inode);
filemap_fdatawait(mapping); if (retval == 0)
retval = filemap_fdatawait(mapping);
if (retval < 0) if (retval < 0)
goto out_free; goto out_free;
...@@ -2136,26 +2113,45 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma) ...@@ -2136,26 +2113,45 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
* The msync() system call. * The msync() system call.
*/ */
/*
* MS_SYNC syncs the entire file - including mappings.
*
* MS_ASYNC initiates writeout of just the dirty mapped data.
* This provides no guarantee of file integrity - things like indirect
* blocks may not have started writeout. MS_ASYNC is primarily useful
* where the application knows that it has finished with the data and
* wishes to intelligently schedule its own I/O traffic.
*/
static int msync_interval(struct vm_area_struct * vma, static int msync_interval(struct vm_area_struct * vma,
unsigned long start, unsigned long end, int flags) unsigned long start, unsigned long end, int flags)
{ {
int ret = 0;
struct file * file = vma->vm_file; struct file * file = vma->vm_file;
if (file && (vma->vm_flags & VM_SHARED)) { if (file && (vma->vm_flags & VM_SHARED)) {
int error; ret = filemap_sync(vma, start, end-start, flags);
error = filemap_sync(vma, start, end-start, flags);
if (!error && (flags & MS_SYNC)) { if (!ret && (flags & (MS_SYNC|MS_ASYNC))) {
struct inode * inode = file->f_dentry->d_inode; struct inode * inode = file->f_dentry->d_inode;
down(&inode->i_sem); down(&inode->i_sem);
filemap_fdatasync(inode->i_mapping); ret = filemap_fdatasync(inode->i_mapping);
if (file->f_op && file->f_op->fsync) if (flags & MS_SYNC) {
error = file->f_op->fsync(file, file->f_dentry, 1); int err;
filemap_fdatawait(inode->i_mapping);
if (file->f_op && file->f_op->fsync) {
err = file->f_op->fsync(file, file->f_dentry, 1);
if (err && !ret)
ret = err;
}
err = filemap_fdatawait(inode->i_mapping);
if (err && !ret)
ret = err;
}
up(&inode->i_sem); up(&inode->i_sem);
} }
return error;
} }
return 0; return ret;
} }
asmlinkage long sys_msync(unsigned long start, size_t len, int flags) asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
...@@ -2999,7 +2995,7 @@ generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos) ...@@ -2999,7 +2995,7 @@ generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos)
kaddr = kmap(page); kaddr = kmap(page);
status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes); status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes);
if (status) if (status)
goto unlock; goto sync_failure;
page_fault = __copy_from_user(kaddr+offset, buf, bytes); page_fault = __copy_from_user(kaddr+offset, buf, bytes);
flush_dcache_page(page); flush_dcache_page(page);
status = mapping->a_ops->commit_write(file, page, offset, offset+bytes); status = mapping->a_ops->commit_write(file, page, offset, offset+bytes);
...@@ -3024,6 +3020,7 @@ generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos) ...@@ -3024,6 +3020,7 @@ generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos)
if (status < 0) if (status < 0)
break; break;
} while (count); } while (count);
done:
*ppos = pos; *ppos = pos;
if (cached_page) if (cached_page)
...@@ -3046,6 +3043,18 @@ generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos) ...@@ -3046,6 +3043,18 @@ generic_file_write(struct file *file,const char *buf,size_t count, loff_t *ppos)
status = -EFAULT; status = -EFAULT;
goto unlock; goto unlock;
sync_failure:
/*
* If blocksize < pagesize, prepare_write() may have instantiated a
* few blocks outside i_size. Trim these off again.
*/
kunmap(page);
UnlockPage(page);
page_cache_release(page);
if (pos + bytes > inode->i_size)
vmtruncate(inode, inode->i_size);
goto done;
o_direct: o_direct:
written = generic_file_direct_IO(WRITE, file, (char *) buf, count, pos); written = generic_file_direct_IO(WRITE, file, (char *) buf, count, pos);
if (written > 0) { if (written > 0) {
......
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