Hello everyone,
Heinz Mauelshagen and I have come up with an API for LVM to use
for creating consistent snapshots. The idea is to block FS modifications
while the snapshot is being created, and to give the FS the chance to flush
everything (including all pending transactions) to disk before
LVM starts doing copy on write.
Without this api, an LVM snapshot created for a journaled FS probably won't
be mountable because it will have transactions that need replay. We have
LVM code to use the api, and reiserfs code to implement the FS
specific side, it can be sent along if the reaction to the patch below
is positive.
LVM does:
initial snapshot setup
fsync_dev_lockfs(original_dev) ;
finish snapshot setup
unlockfs(original_dev) ;
snapshot is now ready to be activated/mounted
Patch is against 2.4.0-test9-pre7
-chris
diff -urN diff/linux/fs/buffer.c linux/fs/buffer.c
--- diff/linux/fs/buffer.c Tue Oct 3 12:31:22 2000
+++ linux/fs/buffer.c Tue Oct 3 12:16:16 2000
@@ -312,6 +312,28 @@
return sync_buffers(dev, 1);
}
+int fsync_dev_lockfs(kdev_t dev)
+{
+ sync_buffers(dev, 0);
+
+ lock_kernel();
+ sync_supers(dev);
+ /* 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);
diff -urN diff/linux/fs/super.c linux/fs/super.c
--- diff/linux/fs/super.c Tue Oct 3 12:31:23 2000
+++ linux/fs/super.c Fri Sep 29 10:01:09 2000
@@ -628,6 +628,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
diff -urN diff/linux/include/linux/fs.h linux/include/linux/fs.h
--- diff/linux/include/linux/fs.h Tue Oct 3 12:31:25 2000
+++ linux/include/linux/fs.h Fri Sep 29 17:10:55 2000
@@ -809,6 +809,8 @@
void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
+ void (*write_super_lockfs) (struct super_block *);
+ void (*unlockfs) (struct super_block *);
int (*statfs) (struct super_block *, struct statfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
@@ -1051,7 +1053,10 @@
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 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);
diff -urN diff/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- diff/linux/kernel/ksyms.c Tue Oct 3 12:31:25 2000
+++ linux/kernel/ksyms.c Tue Oct 3 12:09:34 2000
@@ -181,6 +181,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(inode_setattr);
EXPORT_SYMBOL(inode_change_ok);
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to [EMAIL PROTECTED]