Commit 6c5e0f13 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] IS_SYNC diretory handling

A forward-port.  ext2, minix and sysv aren't handling directories
correctly when IS_SYNC is in place.  They call waitfor_one_page(),
but forgot to start the I/O.

The patch also moves waitfor_one_page and writeout_one_page
into fs/buffer.c, so mm/filemap.c now does not mention buffer_head
at all.
parent 4d32c6ba
......@@ -1954,6 +1954,48 @@ int block_write_full_page(struct page *page, get_block_t *get_block)
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,
get_block_t *get_block)
{
......
......@@ -52,8 +52,13 @@ static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to)
int err = 0;
dir->i_version = ++event;
page->mapping->a_ops->commit_write(NULL, page, from, to);
if (IS_SYNC(dir))
err = waitfor_one_page(page);
if (IS_SYNC(dir)) {
int err2;
err = writeout_one_page(page);
err2 = waitfor_one_page(page);
if (err == 0)
err = err2;
}
return err;
}
......
......@@ -36,8 +36,13 @@ static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
struct inode *dir = (struct inode *)page->mapping->host;
int err = 0;
page->mapping->a_ops->commit_write(NULL, page, from, to);
if (IS_SYNC(dir))
err = waitfor_one_page(page);
if (IS_SYNC(dir)) {
int err2;
err = writeout_one_page(page);
err2 = waitfor_one_page(page);
if (err == 0)
err = err2;
}
return err;
}
......@@ -236,10 +241,10 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
lock_page(page);
err = mapping->a_ops->prepare_write(NULL, page, from, to);
if (err)
BUG();
if (err == 0) {
de->inode = 0;
err = dir_commit_chunk(page, from, to);
}
UnlockPage(page);
dir_put_page(page);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
......@@ -336,10 +341,10 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page,
lock_page(page);
err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
if (err)
BUG();
if (err == 0) {
de->inode = inode->i_ino;
err = dir_commit_chunk(page, from, to);
}
UnlockPage(page);
dir_put_page(page);
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
......
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>
* super.c: switched to ->get_sb()
......@@ -97,3 +103,4 @@ Fri Oct 26 2001 Christoph Hellwig <hch@caldera.de>
Remove symlink faking. Noone really wants to use these as
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)
int err = 0;
page->mapping->a_ops->commit_write(NULL, page, from, to);
if (IS_SYNC(dir))
err = waitfor_one_page(page);
if (IS_SYNC(dir)) {
int err2;
err = writeout_one_page(page);
err2 = waitfor_one_page(page);
if (err == 0)
err = err2;
}
return err;
}
......
......@@ -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 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 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 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 *);
......
......@@ -213,7 +213,6 @@ EXPORT_SYMBOL(cont_prepare_write);
EXPORT_SYMBOL(generic_commit_write);
EXPORT_SYMBOL(block_truncate_page);
EXPORT_SYMBOL(generic_block_bmap);
EXPORT_SYMBOL(waitfor_one_page);
EXPORT_SYMBOL(generic_file_read);
EXPORT_SYMBOL(do_generic_file_read);
EXPORT_SYMBOL(generic_file_write);
......
......@@ -449,41 +449,6 @@ static inline struct page * __find_page_nolock(struct address_space *mapping, un
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 *))
{
struct list_head *curr;
......
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