[PATCH] 2.5.x write_super is not for syncing

From: Chris Mason (mason@suse.com)
Date: Wed Oct 16 2002 - 13:00:06 EST


Hello all,

This patch adds a commit_super super operation that allows the journaled
filesystems to do something different for the periodic write_super calls
and sync.

Based on comments from Al about my last patch, alloc_super sets a
default empty super_operations struct on each super. This allows us to
get rid of all checks for sb->s_ops == NULL.

sync_supers is changed so that it doesn't loop on a single FS if the
write_super call leaves sb->s_dirt set. I did this by changing
generic_shutdown_super to use list_del_init(&sb->s_list), which allows
us to check for supers that have been removed from the super_blocks list
while we slept. The idea came from an sgi patch Hugh Dickins sent me.

Anyway, this is against 2.5.43, please review:

--- 1.161/fs/buffer.c Tue Oct 8 14:40:47 2002
+++ edited/fs/buffer.c Wed Oct 16 11:39:04 2002
@@ -217,8 +217,10 @@
         sync_inodes_sb(sb, 0);
         DQUOT_SYNC(sb);
         lock_super(sb);
- if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
+ if (sb->s_dirt && sb->s_op->write_super)
                 sb->s_op->write_super(sb);
+ if (sb->s_dirt && sb->s_op->commit_super)
+ sb->s_op->commit_super(sb);
         unlock_super(sb);
         sync_blockdev(sb->s_bdev);
         sync_inodes_sb(sb, 1);
@@ -251,7 +253,7 @@
         wakeup_bdflush(0);
         sync_inodes(0); /* All mappings and inodes, including block devices */
         DQUOT_SYNC(NULL);
- sync_supers(); /* Write the superblocks */
+ commit_supers(); /* Write the superblocks */
         sync_inodes(1); /* All the mappings and inodes, again. */
         return 0;
 }
@@ -274,7 +276,7 @@
         /* sync the superblock to buffers */
         sb = inode->i_sb;
         lock_super(sb);
- if (sb->s_op && sb->s_op->write_super)
+ if (sb->s_op->write_super)
                 sb->s_op->write_super(sb);
         unlock_super(sb);
 
--- 1.22/fs/fs-writeback.c Sun Sep 22 17:26:49 2002
+++ edited/fs/fs-writeback.c Wed Oct 16 13:29:51 2002
@@ -57,7 +57,7 @@
          * dirty the inode itself
          */
         if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
- if (sb->s_op && sb->s_op->dirty_inode)
+ if (sb->s_op->dirty_inode)
                         sb->s_op->dirty_inode(inode);
         }
 
@@ -103,8 +103,7 @@
 
 static void write_inode(struct inode *inode, int sync)
 {
- if (inode->i_sb->s_op && inode->i_sb->s_op->write_inode &&
- !is_bad_inode(inode))
+ if (inode->i_sb->s_op->write_inode && !is_bad_inode(inode))
                 inode->i_sb->s_op->write_inode(inode, sync);
 }
 
--- 1.83/fs/super.c Mon Sep 9 17:00:57 2002
+++ edited/fs/super.c Wed Oct 16 10:36:09 2002
@@ -48,6 +48,8 @@
  */
 static struct super_block *alloc_super(void)
 {
+ static struct super_operations default_op = {};
+
         struct super_block *s = kmalloc(sizeof(struct super_block), GFP_USER);
         if (s) {
                 memset(s, 0, sizeof(struct super_block));
@@ -72,6 +74,7 @@
                 s->s_maxbytes = MAX_NON_LFS;
                 s->dq_op = sb_dquot_ops;
                 s->s_qcop = sb_quotactl_ops;
+ s->s_op = &default_op;
         }
 out:
         return s;
@@ -203,7 +206,12 @@
                 unlock_super(sb);
         }
         spin_lock(&sb_lock);
- list_del(&sb->s_list);
+
+ /*
+ * use list_del_init so we can tell later if a super with an
+ * incremented count has been removed from all lists
+ */
+ list_del_init(&sb->s_list);
         list_del(&sb->s_instances);
         spin_unlock(&sb_lock);
         up_write(&sb->s_umount);
@@ -267,35 +275,65 @@
 {
         lock_super(sb);
         if (sb->s_root && sb->s_dirt)
- if (sb->s_op && sb->s_op->write_super)
+ if (sb->s_op->write_super)
                         sb->s_op->write_super(sb);
         unlock_super(sb);
 }
 
+static inline void commit_super(struct super_block *sb)
+{
+ lock_super(sb);
+ if (sb->s_root && sb->s_dirt) {
+ if (sb->s_op->write_super)
+ sb->s_op->write_super(sb);
+ if (sb->s_op->commit_super)
+ sb->s_op->commit_super(sb);
+ }
+ unlock_super(sb);
+}
+
 /*
  * Note: check the dirty flag before waiting, so we don't
  * hold up the sync while mounting a device. (The newly
  * mounted device won't need syncing.)
  */
-void sync_supers(void)
+void dirty_super_op(void (*func)(struct super_block *))
 {
         struct super_block * sb;
-restart:
         spin_lock(&sb_lock);
+restart:
         sb = sb_entry(super_blocks.next);
- while (sb != sb_entry(&super_blocks))
+ while (sb != sb_entry(&super_blocks)) {
                 if (sb->s_dirt) {
                         sb->s_count++;
                         spin_unlock(&sb_lock);
                         down_read(&sb->s_umount);
- write_super(sb);
- drop_super(sb);
- goto restart;
- } else
- sb = sb_entry(sb->s_list.next);
+ func(sb);
+ up_read(&sb->s_umount);
+
+ spin_lock(&sb_lock);
+ if (!--sb->s_count) {
+ destroy_super(sb);
+ goto restart;
+ } else if (list_empty(&sb->s_list)) {
+ goto restart;
+ }
+ }
+ sb = sb_entry(sb->s_list.next);
+ }
         spin_unlock(&sb_lock);
 }
 
+void sync_supers(void)
+{
+ dirty_super_op(write_super);
+}
+
+void commit_supers(void)
+{
+ dirty_super_op(commit_super);
+}
+
 /**
  * get_super - get the superblock of a device
  * @dev: device to get the superblock for
@@ -396,7 +434,7 @@
         if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
                 if (!fs_may_remount_ro(sb))
                         return -EBUSY;
- if (sb->s_op && sb->s_op->remount_fs) {
+ if (sb->s_op->remount_fs) {
                 lock_super(sb);
                 retval = sb->s_op->remount_fs(sb, &flags, data);
                 unlock_super(sb);
--- 1.170/include/linux/fs.h Fri Oct 11 04:49:46 2002
+++ edited/include/linux/fs.h Wed Oct 16 10:42:16 2002
@@ -818,6 +818,7 @@
         void (*umount_begin) (struct super_block *);
 
         int (*show_options)(struct seq_file *, struct vfsmount *);
+ void (*commit_super) (struct super_block *);
 };
 
 /* Inode state bits. Protected by inode_lock. */
@@ -1141,6 +1142,7 @@
 extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
 extern void sync_supers(void);
+extern void commit_supers(void);
 extern sector_t bmap(struct inode *, sector_t);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Oct 23 2002 - 22:00:29 EST