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) ...@@ -1954,6 +1954,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;
......
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;
} }
......
...@@ -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;
......
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