ext2, sysvfs, minixfs directory syncs
Subsystems (4)
PATCH 1/1 ext2, sysvfs, minixfs directory syncs
These three filesytems are not honouring synchronous mounts for directories, and ext2 is also not honouring `chattr +S' for directories. This is because they are calling waitfor_one_page() against the directory page without having started I/O.
- writeout_one_page() and waitfor_one_page() have been moved to fs/buffer.c. mm/filemap.c now has no mention of `buffer_head'.
- waitfor_one_page() was exported to modules in 2.4.5. This patch unexports it.
- The new function sync_one_page() has been created and exported to modules.
- The three filesystems are converted to use sync_one_page().
- Minixfs had a couple of BUG()s which appeared to be triggerable by -EIO or -ENOSPC in prepare_write(). These have been converted to proper error handling.
I've only tested ext2. Christoph, could you please test the
sysvfs changes? Thanks.
The time to create and remove 100 ext2 directories went from four seconds to seven on a disk which does not perform write caching, with a synchronous mount.
include/linux/fs.h +3 -1
@@ -1391,8 +1391,10 @@ int generic_block_bmap(struct address_spint 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 sync_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 *);
fs/buffer.c +52 -0
58 lines not on this page · raw message
mm/filemap.c +0 -35
@@ -454,41 +454,6 @@ not_found: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;
kernel/ksyms.c +0 -1
@@ -208,7 +208,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);
fs/ext2/dir.c +1 -1
@@ -54,7 +54,7 @@ static int ext2_commit_chunk(struct page dir->i_version = ++event; page->mapping->a_ops->commit_write (NULL , page, from, to);if (IS_SYNC (dir)) - err =waitfor_one_page (page); + err =sync_one_page (page);return err; }
fs/minix/dir.c +9 -9
@@ -37,7 +37,7 @@ static int dir_commit_chunk(struct pageint err =0 ; page->mapping->a_ops->commit_write (NULL , page, from, to);if (IS_SYNC (dir)) - err =waitfor_one_page (page); + err =sync_one_page (page);return err; }
@@ -236,10 +236,10 @@ int minix_delete_entry(struct minix_dir_lock_page (page); err = mapping->a_ops->prepare_write (NULL , page, from, to); -if (err) -BUG (); - de->inode =0 ; - err =dir_commit_chunk (page, from, to); +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 +336,10 @@ void minix_set_link(struct minix_dir_entlock_page (page); err = page->mapping->a_ops->prepare_write (NULL , page, from, to); -if (err) -BUG (); - de->inode = inode->i_ino; - err =dir_commit_chunk (page, from, to); +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 ;
fs/sysv/dir.c +1 -1
@@ -44,7 +44,7 @@ static int dir_commit_chunk(struct page dir->i_version = ++event; page->mapping->a_ops->commit_write (NULL , page, from, to);if (IS_SYNC (dir)) - err =waitfor_one_page (page); + err =sync_one_page (page);return err; }
fs/sysv/ChangeLog +5 -0
@@ -20,3 +20,8 @@ Fri Oct 26 2001 Christoph Hellwig <hch Remove symlink faking. Noone really wants to use these as linux filesystems and native OSes don't support it anyway. +Thu Jan 10 2002 Andrew Morton <[email protected]> + + * dir.c: use sync_one_page() rather than waitfor_one_page() for + IS_SYNC directories, so that we actually do sync the directory. +
Quoted 2 lines · Andrew Morton
I've only tested ext2. Christoph, could you please test the
sysvfs changes? Thanks.
The change if fine.
fs/sysv/ChangeLog Fri Oct 26 2001 Christoph Hellwig <hch · line 25
Quoted 9 lines
fs/sysv/ChangeLog +3
-0@@ -20,3 +20,8 @@ Fri Oct 26 2001 Christoph Hellwig <hch Remove symlink faking. Noone really wants to use these as linux filesystems and native OSes don't support it anyway. +Thu Jan 10 2002 Andrew Morton <[email protected]> + + * dir.c: use sync_one_page() rather than waitfor_one_page() for
This should be dir.c (dir_commit_chunk): ....
Also new changelog items get added at the top.
Christoph