Skip to contentSkip to conversation

ext2, sysvfs, minixfs directory syncs

PATCH In review Andrew Morton 2 participants 2 messages Jan 11, 2002

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

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_sp
 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 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 page 
 	int 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_ent
 
 	lock_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.
+
#1 lore raw
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