Skip to contentSkip to conversation

LVM snapshot support for reiserfs and others

PATCH In review Chris Mason 4 participants 13 messages Aug 9, 2001 – Aug 22, 2001 VFS

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 LVM snapshot support for reiserfs and others

Hello everyone,

This patch has been floating around for a while and is heavily used; Heinz and I coded it last October or so. Minor change in the port to 2.4.8-pre was moving the sync_supers call in fsync_dev_lockfs to match the changes in fsync_dev.

It adds calls to make use of the write_super_lockfs and unlockfs callbacks, which allows the filesystem to do a full sync and block new writers while LVM creates a snapshot. This way, the snapshot is actually consistent on creation.

There's one reiserfs hunk in there (also very old) to fix a bug in my initial reiserfs_write_super_lockfs call.

Patch against 2.4.8-pre6, it won't apply on top of -ac due to Al's changes. I'm merging a bunch of stuff into -ac again, I'll merge this as well.

Linus, please apply

-chris

drivers/md/lvm.c +1 -1
diff -Nru a/drivers/md/lvm.c b/drivers/md/lvm.c
@@ -162,7 +162,7 @@
 #define	DEVICE_OFF(device)
 
 /* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */
-/* #define	LVM_VFS_ENHANCEMENT */
+#define	LVM_VFS_ENHANCEMENT
 
 #include <linux/config.h>
 #include <linux/version.h>
fs/buffer.c +27 -0
diff -Nru a/fs/buffer.c b/fs/buffer.c
@@ -367,6 +367,33 @@
 	fsync_dev(dev);
 }
 
+int fsync_dev_lockfs(kdev_t dev)
+{
+	sync_buffers(dev, 0);
+
+	lock_kernel();
+	/* note, the FS might need to start transactions to 
+	** sync the inodes, or the quota, no locking until
+	** after these are done
+	*/
+	sync_inodes(dev);
+	DQUOT_SYNC(dev);
+	/* if inodes or quotas could be dirtied during the
+	** sync_supers_lockfs call, the FS is responsible for getting
+	** them on disk, without deadlocking against the lock
+	**
+	** we call sync_supers first so that 
+	** fsync_dev_lockfs == fsync_dev for filesystems that don't provide
+	** a lockfs call.  Yes, it could be done in sync_supers_lockfs
+	** instead, but this just makes it more explicit...
+	*/
+	sync_supers(dev) ;
+	sync_supers_lockfs(dev) ;
+	unlock_kernel();
+
+	return sync_buffers(dev, 1) ;
+}
+
 asmlinkage long sys_sync(void)
 {
 	fsync_dev(0);
fs/reiserfs/super.c +1 -1
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
@@ -80,7 +80,7 @@
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     reiserfs_block_writes(&th) ;
-    journal_end(&th, s, 1) ;
+    journal_end_sync(&th, s, 1) ;
   }
   s->s_dirt = dirty;
   unlock_kernel() ;
fs/super.c +40 -0
diff -Nru a/fs/super.c b/fs/super.c
@@ -672,6 +672,46 @@
 	}
 }
 
+/*
+ * Note: don't check the dirty flag before waiting, we want the lock
+ * to happen every time this is called.
+ */
+void sync_supers_lockfs(kdev_t dev)
+{
+	struct super_block * sb;
+
+	for (sb = sb_entry(super_blocks.next);
+	     sb != sb_entry(&super_blocks); 
+	     sb = sb_entry(sb->s_list.next)) {
+		if (!sb->s_dev)
+			continue;
+		if (dev && sb->s_dev != dev)
+			continue;
+		lock_super(sb);
+		if (sb->s_dev && (!dev || dev == sb->s_dev))
+			if (sb->s_op && sb->s_op->write_super_lockfs)
+				sb->s_op->write_super_lockfs(sb);
+		unlock_super(sb);
+	}
+}
+
+void unlockfs(kdev_t dev)
+{
+	struct super_block * sb;
+
+	for (sb = sb_entry(super_blocks.next);
+	     sb != sb_entry(&super_blocks); 
+	     sb = sb_entry(sb->s_list.next)) {
+		if (!sb->s_dev)
+			continue;
+		if (dev && sb->s_dev != dev)
+			continue;
+		if (sb->s_dev && (!dev || dev == sb->s_dev))
+			if (sb->s_op && sb->s_op->unlockfs)
+				sb->s_op->unlockfs(sb);
+	}
+}
+
 /**
  *	get_super	-	get the superblock of a device
  *	@dev: device to get the superblock for
include/linux/fs.h +3 -0
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
@@ -1160,6 +1160,7 @@
 extern void write_inode_now(struct inode *, int);
 extern void sync_dev(kdev_t);
 extern int fsync_dev(kdev_t);
+extern int fsync_dev_lockfs(kdev_t);
 extern int fsync_super(struct super_block *);
 extern void sync_inodes_sb(struct super_block *);
 extern int fsync_inode_buffers(struct inode *);
@@ -1168,6 +1169,8 @@
 extern void filemap_fdatasync(struct address_space *);
 extern void filemap_fdatawait(struct address_space *);
 extern void sync_supers(kdev_t);
+extern void sync_supers_lockfs(kdev_t);
+extern void unlockfs(kdev_t);
 extern int bmap(struct inode *, int);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);
kernel/ksyms.c +2 -0
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
@@ -176,6 +176,8 @@
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
+EXPORT_SYMBOL(fsync_dev_lockfs);
+EXPORT_SYMBOL(unlockfs);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(vfs_permission);
 EXPORT_SYMBOL(inode_setattr);
#1 lore raw
Quoted 2 lines · Chris Mason

Minor change in the port to 2.4.8-pre was moving the sync_supers call in fsync_dev_lockfs to match the changes in fsync_dev.

Good...

fs/buffer.c line 388

Quoted 4 lines
fs/buffer.c +4 -0
+	** we call sync_supers first so that 
+	** fsync_dev_lockfs == fsync_dev for filesystems that don't provide
+	** a lockfs call.  Yes, it could be done in sync_supers_lockfs
+	** instead, but this just makes it more explicit...

I would rather make it _less_ explicit, so that sync_supers_lockfs() actually does the sb->s_op->write_super() call for us... Why? Because we are already traversing the supers list at this function, and there is no reason to waste the CPU cycles traversing this list twice. I think the name "sync_supers_lockfs" is clear enough in showing that it is a superset of "sync_supers" (try saying that 5 times fast ;-).

On a similar note, it is redundant that LVM calls fsync_dev() AND fsync_dev_lockfs() if LVM_VFS_ENHANCEMENT is defined. From the above reasoning (to only walk the supers list once) it would make sense to call only *_lockfs() if it is available.

On an "add this patch to the kernel, please" note, support for the write_super_lockfs() VFS method is already in ext3, so it is a good thing, with the above caveats.

Cheers, Andreas

PS - I changed the CC list to have lvm-devel@ instead of [email protected]

Signature · 3 lines
Andreas Dilger  \ "If a man ate a pound of pasta and a pound of antipasto,
                 \  would they cancel out, leaving him still hungry?"
http://www-mddsp.enel.ucalgary.ca/People/adilger/               -- Dogbert
#2 lore raw
Quoted 5 lines · On Thursday, August 09, 2001 01:22:56 PM -0600 Andreas Dilger…

On an "add this patch to the kernel, please" note, support for the write_super_lockfs() VFS method is already in ext3, so it is a good thing, with the above caveats.

Ok, recoding with these suggestions. I'll need an ext3 tester, please drop me a line if you are willing ;-)

-chris

#3 lore raw

Chris, you write:

Quoted 7 lines
Quoted 3 lines · Andreas Dilger

On an "add this patch to the kernel, please" note, support for the write_super_lockfs() VFS method is already in ext3, so it is a good thing, with the above caveats.

Ok, recoding with these suggestions. I'll need an ext3 tester, please drop me a line if you are willing ;-)

Consider it tested. I already have my code changed like I suggested, but never heard back the last time I mentioned it. In the end I don't think the changes can have a behaviour impact other than a small CPU savings, and a few lines of comments removed.

Cheers, Andreas

Signature · 3 lines
Andreas Dilger  \ "If a man ate a pound of pasta and a pound of antipasto,
                 \  would they cancel out, leaving him still hungry?"
http://www-mddsp.enel.ucalgary.ca/People/adilger/               -- Dogbert
#4 lore raw

Ok, here it is:

LVM_VFS_ENHANCEMENT #define is gone, lvm only calls fsync_dev_lockfs when syncing for the snapshot

sync_supers_lockfs calls write_super if the super is dirty, and write_super_lockfs (regardless of dirty state).

Works on reiserfs and ext2, should not break other filesystems using the old patch.

updated to 2.4.8-pre7

-chris

drivers/md/lvm.c +0 -9
diff -Nru a/drivers/md/lvm.c b/drivers/md/lvm.c
@@ -161,9 +161,6 @@
 #define MAJOR_NR	LVM_BLK_MAJOR
 #define	DEVICE_OFF(device)
 
-/* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */
-/* #define	LVM_VFS_ENHANCEMENT */
-
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
@@ -2321,12 +2318,8 @@
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		lv_t *org = lv_ptr->lv_snapshot_org, *last;
 
-		/* sync the original logical volume */
-		fsync_dev(org->lv_dev);
-#ifdef	LVM_VFS_ENHANCEMENT
 		/* VFS function call to sync and lock the filesystem */
 		fsync_dev_lockfs(org->lv_dev);
-#endif
 
 		down(&org->lv_snapshot_sem);
 		org->lv_access |= LV_SNAPSHOT_ORG;
@@ -2346,12 +2339,10 @@
 	else
 		set_device_ro(lv_ptr->lv_dev, 1);
 
-#ifdef	LVM_VFS_ENHANCEMENT
 /* VFS function call to unlock the filesystem */
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		unlockfs(lv_ptr->lv_snapshot_org->lv_dev);
 	}
-#endif
 
 	lv_ptr->vg = vg_ptr;
 
fs/buffer.c +21 -0
diff -Nru a/fs/buffer.c b/fs/buffer.c
@@ -368,6 +368,27 @@
 	fsync_dev(dev);
 }
 
+int fsync_dev_lockfs(kdev_t dev)
+{
+	sync_buffers(dev, 0);
+
+	lock_kernel();
+	/* note, the FS might need to start transactions to 
+	** sync the inodes, or the quota, no locking until
+	** after these are done
+	*/
+	sync_inodes(dev);
+	DQUOT_SYNC(dev);
+	/* if inodes or quotas could be dirtied during the
+	** sync_supers_lockfs call, the FS is responsible for getting
+	** them on disk, without deadlocking against the lock
+	*/
+	sync_supers_lockfs(dev) ;
+	unlock_kernel();
+
+	return sync_buffers(dev, 1) ;
+}
+
 asmlinkage long sys_sync(void)
 {
 	fsync_dev(0);
fs/reiserfs/super.c +1 -1
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
@@ -80,7 +80,7 @@
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     reiserfs_block_writes(&th) ;
-    journal_end(&th, s, 1) ;
+    journal_end_sync(&th, s, 1) ;
   }
   s->s_dirt = dirty;
   unlock_kernel() ;
fs/super.c +43 -0

49 lines not on this page · raw message

include/linux/fs.h +3 -0
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
@@ -1160,6 +1160,7 @@
 extern void write_inode_now(struct inode *, int);
 extern void sync_dev(kdev_t);
 extern int fsync_dev(kdev_t);
+extern int fsync_dev_lockfs(kdev_t);
 extern int fsync_super(struct super_block *);
 extern void sync_inodes_sb(struct super_block *);
 extern int fsync_inode_buffers(struct inode *);
@@ -1168,6 +1169,8 @@
 extern void filemap_fdatasync(struct address_space *);
 extern void filemap_fdatawait(struct address_space *);
 extern void sync_supers(kdev_t);
+extern void sync_supers_lockfs(kdev_t);
+extern void unlockfs(kdev_t);
 extern int bmap(struct inode *, int);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);
kernel/ksyms.c +2 -0
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
@@ -176,6 +176,8 @@
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
+EXPORT_SYMBOL(fsync_dev_lockfs);
+EXPORT_SYMBOL(unlockfs);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(vfs_permission);
 EXPORT_SYMBOL(inode_setattr);
#5 lore raw
Quoted 6 lines · Chris Mason

Ok, here it is:

LVM_VFS_ENHANCEMENT #define is gone, lvm only calls fsync_dev_lockfs when syncing for the snapshot

Quoted 7 lines

sync_supers_lockfs calls write_super if the super is dirty, and write_super_lockfs (regardless of dirty state).

Works on reiserfs and ext2, should not break other filesystems using the old patch.

updated to 2.4.8-pre7

Chris, how about doing that after fs/super.c stuff (things that went into -ac)?

#6 lore raw
Quoted 3 lines · On Thursday, August 09, 2001 06:24:46 PM -0400 Alexander Viro…

Chris, how about doing that after fs/super.c stuff (things that went into -ac)?

well, it depends on how soon the fs/super.c stuff goes in ;-) I'd prefer to provide you with an updated patch for -ac, and get this into the kernel sooner than later. It's your call though, including if you just want to hold off until I've got the -ac patch done.

-chris

#7 lore raw
Quoted 9 lines · Chris Mason
Quoted 3 lines · On Thursday, August 09, 2001 06:24:46 PM -0400 Alexander Viro…

Chris, how about doing that after fs/super.c stuff (things that went into -ac)?

well, it depends on how soon the fs/super.c stuff goes in ;-)

That, in turn, depends on Linus. Since this stuff got public testing in -ac (since 2.4.7-ac3) and since Linus had said that he doesn't mind patches landing in his mailbox after each prerelease... ;-)

I'll resubmit that stuff - let's see when it gets applied...

Quoted 3 lines

I'd prefer to provide you with an updated patch for -ac, and get this into the kernel sooner than later. It's your call though, including if you just want to hold off until I've got the -ac patch done.

I think that doing variant against -ac first (or just fs/super.c stuff that went into -ac) makes a lot of sense, since it will simplify testing. We need this stuff in the tree and it's 2.4 matter - we need to close the oopsen. I'd rather get tricky (and already debugged) stuff first and then deal with relatively simple patch atop of it.

#8 lore raw
Quoted 2 lines · Alexander Viro

That, in turn, depends on Linus. Since this stuff got public testing in -ac (since 2.4.7-ac3) and since Linus had said that he doesn't mind

Sorry - -ac4, actually.

#9 lore raw
In reply to Alexander Viro

Hi guys,

Here's a new patch against 2.4.8-pre8, updated to Al's new super handling. The differences between the original are small, but they are big enough that I want extra testing from the LVM guys (and ext3/XFS). Linus is just cc'd as an FYI.

Changes:

fsync_dev_lockfs(0) will just call fsync_dev instead of trying to lock every FS on the system. LVM always sends a real device, so it doesn't change any of the current users. If someone wants to experiment with locking all of them, let me know (I'm guessing you'll end up deadlocked somewhere).

unlockfs() grabs mount_sem so that we don't race against someone mounting the FS. It can't lock the super because somebody might be waiting for the FS to unlock with the super lock already held.

-chris

include/linux/fs.h +3 -0
@@ -1161,6 +1161,7 @@
 extern void write_inode_now(struct inode *, int);
 extern void sync_dev(kdev_t);
 extern int fsync_dev(kdev_t);
+extern int fsync_dev_lockfs(kdev_t);
 extern int fsync_super(struct super_block *);
 extern int fsync_no_super(kdev_t);
 extern void sync_inodes_sb(struct super_block *);
@@ -1170,6 +1171,8 @@
 extern void filemap_fdatasync(struct address_space *);
 extern void filemap_fdatawait(struct address_space *);
 extern void sync_supers(kdev_t);
+extern void sync_supers_lockfs(kdev_t);
+extern void unlockfs(kdev_t);
 extern int bmap(struct inode *, int);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);
kernel/ksyms.c +2 -0
@@ -177,6 +177,8 @@
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
+EXPORT_SYMBOL(fsync_dev_lockfs);
+EXPORT_SYMBOL(unlockfs);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(vfs_permission);
 EXPORT_SYMBOL(inode_setattr);
drivers/md/lvm.c +0 -9
@@ -161,9 +161,6 @@
 #define MAJOR_NR	LVM_BLK_MAJOR
 #define	DEVICE_OFF(device)
 
-/* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */
-/* #define	LVM_VFS_ENHANCEMENT */
-
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
@@ -2321,12 +2318,8 @@
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		lv_t *org = lv_ptr->lv_snapshot_org, *last;
 
-		/* sync the original logical volume */
-		fsync_dev(org->lv_dev);
-#ifdef	LVM_VFS_ENHANCEMENT
 		/* VFS function call to sync and lock the filesystem */
 		fsync_dev_lockfs(org->lv_dev);
-#endif
 
 		down(&org->lv_snapshot_sem);
 		org->lv_access |= LV_SNAPSHOT_ORG;
@@ -2346,12 +2339,10 @@
 	else
 		set_device_ro(lv_ptr->lv_dev, 1);
 
-#ifdef	LVM_VFS_ENHANCEMENT
 /* VFS function call to unlock the filesystem */
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		unlockfs(lv_ptr->lv_snapshot_org->lv_dev);
 	}
-#endif
 
 	lv_ptr->vg = vg_ptr;
 
fs/buffer.c +28 -0
@@ -374,6 +374,34 @@
 	fsync_dev(dev);
 }
 
+int fsync_dev_lockfs(kdev_t dev)
+{
+	/* you are not allowed to try locking all the filesystems
+	** on the system, your chances of getting through without
+	** total deadlock are slim to none.
+	*/
+	if (!dev)
+		return fsync_dev(dev) ;
+
+	sync_buffers(dev, 0);
+
+	lock_kernel();
+	/* note, the FS might need to start transactions to 
+	** sync the inodes, or the quota, no locking until
+	** after these are done
+	*/
+	sync_inodes(dev);
+	DQUOT_SYNC(dev);
+	/* if inodes or quotas could be dirtied during the
+	** sync_supers_lockfs call, the FS is responsible for getting
+	** them on disk, without deadlocking against the lock
+	*/
+	sync_supers_lockfs(dev) ;
+	unlock_kernel();
+
+	return sync_buffers(dev, 1) ;
+}
+
 asmlinkage long sys_sync(void)
 {
 	fsync_dev(0);
fs/super.c +54 -0

66 lines not on this page · raw message

fs/reiserfs/super.c +1 -1
@@ -80,7 +80,7 @@
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     reiserfs_block_writes(&th) ;
-    journal_end(&th, s, 1) ;
+    journal_end_sync(&th, s, 1) ;
   }
   s->s_dirt = dirty;
   unlock_kernel() ;
#10 lore raw

fs/super.c line 695

Quoted 11 lines · Chris
fs/super.c +11 -0
+static inline void write_super_lockfs(struct super_block *sb)
+{
+	lock_super(sb);
+	if (sb->s_root) {
+		if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
+			sb->s_op->write_super(sb);
+		if (sb->s_op && sb->s_op->write_super_lockfs)
+			sb->s_op->write_super_lockfs(sb);
+	}
+	unlock_super(sb);
+}

Minor nit, could it be:

	if (sb->s_root && sb->s_op) {
		if (sb->s_dirt && sb->s_op->write_super)
			sb->s_op->write_super(sb);
		if (sb->s_op->write_super_lockfs)
			sb->s_op->write_super_lockfs(sb);
	}

I'm just going to do some testing...

Cheers, Andreas

Signature · 3 lines
Andreas Dilger  \ "If a man ate a pound of pasta and a pound of antipasto,
                 \  would they cancel out, leaving him still hungry?"
http://www-mddsp.enel.ucalgary.ca/People/adilger/               -- Dogbert
#11 lore raw
In reply to Chris Mason

Ok, here's a version against 2.4.8-ac8, tested against ext2 and reiserfs. Andreas reported ext3 success with the last patch, and none of the LVM guys have complained yet ;-)

BTW [sistina folks], it might be a good idea to update lvm-1.0.x the 2.4.4 VFS-lock patches no longer apply cleanly.

Alan, please include:

-chris

# allow LVM to lock the filesystem during snapshot creation, so the
# FS can flush pending changes and put things into a consistent state.
#
# includes small fix to current reiserfs support, forcing a transaction
# commit during the lock.
#
#
diff -Nru a/drivers/md/lvm.c b/drivers/md/lvm.c
--- a/drivers/md/lvm.c	Tue Aug 21 23:55:59 2001
+++ b/drivers/md/lvm.c	Tue Aug 21 23:55:59 2001
@@ -182,9 +182,6 @@
 #define DEVICE_OFF(device)
 #define LOCAL_END_REQUEST

-/* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */
-/* #define LVM_VFS_ENHANCEMENT */
-
#include <linux/config.h>
#include <linux/version.h>

@@ -1933,12 +1930,8 @@
if (lv_ptr->lv_access & LV_SNAPSHOT) {
lv_t *org = lv_ptr->lv_snapshot_org, *last;

- /* sync the original logical volume */
- fsync_dev(org->lv_dev);
-#ifdef LVM_VFS_ENHANCEMENT
/* VFS function call to sync and lock the filesystem */ fsync_dev_lockfs(org->lv_dev);
-#endif

down(&org->lv_snapshot_sem); org->lv_access |= LV_SNAPSHOT_ORG;
@@ -1962,12 +1955,10 @@
else
set_device_ro(lv_ptr->lv_dev, 1);

-#ifdef LVM_VFS_ENHANCEMENT
/* VFS function call to unlock the filesystem */
if (lv_ptr->lv_access & LV_SNAPSHOT) {
unlockfs(lv_ptr->lv_snapshot_org->lv_dev);
}
-#endif

lv_ptr->vg = vg_ptr;

fs/buffer.c +28 -0
diff -Nru a/fs/buffer.c b/fs/buffer.c
@@ -350,6 +350,34 @@
 	fsync_dev(dev);
 }
 
+int fsync_dev_lockfs(kdev_t dev)
+{
+	/* you are not allowed to try locking all the filesystems
+	** on the system, your chances of getting through without
+	** total deadlock are slim to none.
+	*/
+	if (!dev)
+		return fsync_dev(dev) ;
+
+	sync_buffers(dev, 0);
+
+	lock_kernel();
+	/* note, the FS might need to start transactions to 
+	** sync the inodes, or the quota, no locking until
+	** after these are done
+	*/
+	sync_inodes(dev);
+	DQUOT_SYNC(dev);
+	/* if inodes or quotas could be dirtied during the
+	** sync_supers_lockfs call, the FS is responsible for getting
+	** them on disk, without deadlocking against the lock
+	*/
+	sync_supers_lockfs(dev) ;
+	unlock_kernel();
+
+	return sync_buffers(dev, 1) ;
+}
+
 asmlinkage long sys_sync(void)
 {
 	fsync_dev(0);
fs/reiserfs/super.c +1 -1
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
@@ -66,7 +66,7 @@
     reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
     reiserfs_block_writes(&th) ;
-    journal_end(&th, s, 1) ;
+    journal_end_sync(&th, s, 1) ;
   }
   s->s_dirt = dirty;
   unlock_kernel() ;
fs/super.c +54 -0

66 lines not on this page · raw message

include/linux/fs.h +3 -0
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
@@ -1223,6 +1223,7 @@
 extern void write_inode_now(struct inode *, int);
 extern void sync_dev(kdev_t);
 extern int fsync_dev(kdev_t);
+extern int fsync_dev_lockfs(kdev_t);
 extern int fsync_super(struct super_block *);
 extern int fsync_no_super(kdev_t);
 extern void sync_inodes_sb(struct super_block *);
@@ -1232,6 +1233,8 @@
 extern void filemap_fdatasync(struct address_space *);
 extern void filemap_fdatawait(struct address_space *);
 extern void sync_supers(kdev_t);
+extern void sync_supers_lockfs(kdev_t);
+extern void unlockfs(kdev_t);
 extern int bmap(struct inode *, int);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);
kernel/ksyms.c +2 -0
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
@@ -178,6 +178,8 @@
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
+EXPORT_SYMBOL(fsync_dev_lockfs);
+EXPORT_SYMBOL(unlockfs);
 EXPORT_SYMBOL(fsync_no_super);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(vfs_permission);
#12 lore raw
In reply to Alexander Viro
Quoted 8 lines · Chris Mason

Hi guys,

Here's a new patch against 2.4.8-pre8, updated to Al's new super handling. The differences between the original are small, but they are big enough that I want extra testing from the LVM guys (and ext3/XFS).

ext3 will probably lock up on unmount with 2.4.8-pre8. The fix is to replace fsync_dev with fsync_no_super in fs/ext3/super.c and fs/jbd/recovery.c. I'll be generating a new patchset this weekend.

-