[Devel] [PATCH 05/25] record when sb_writer_count elevated for inode

Dave Hansen haveblue at us.ibm.com
Mon Dec 11 14:30:05 PST 2006



There are a number of filesystems that do iput()s without first
having messed with i_nlink.  In order to keep from accidentally
decrementing the superblock writer count for these, we record
when the count is bumped up, so that we can properly balance
it.

I first tried to do this by assuming that, for each dec_nlink() to
zero, there was exactly one call to iput_final().  But, there are
a number of cases where this isn't true, especially in error handling
code.  Even if all of the filesystems were fixed up, it would be simple
to reintroduce new bugs imbalancing the mnt writer count.  This patch
trades that possibility for the chance that we will miss a i_nlink--,
and not bump the sb writer count.

I like the idea screwing up writing out a single inode better than
screwing up a global superblock count imbalance that will affect
all inodes on the superblock.

Signed-off-by: Dave Hansen <haveblue at us.ibm.com>
---

 lxc-dave/fs/inode.c         |    7 ++++++-
 lxc-dave/fs/libfs.c         |    1 +
 lxc-dave/include/linux/fs.h |   12 ++++++++++++
 3 files changed, 19 insertions(+), 1 deletion(-)

diff -puN fs/inode.c~04-24-record-when-sb-writer-count-elevated-for-inode fs/inode.c
--- lxc/fs/inode.c~04-24-record-when-sb-writer-count-elevated-for-inode	2006-12-11 14:21:59.000000000 -0800
+++ lxc-dave/fs/inode.c	2006-12-11 14:21:59.000000000 -0800
@@ -1092,12 +1092,17 @@ EXPORT_SYMBOL_GPL(generic_drop_inode);
  */
 static inline void iput_final(struct inode *inode)
 {
-	struct super_operations *op = inode->i_sb->s_op;
+	struct super_block *sb = inode->i_sb;
+	struct super_operations *op = sb->s_op;
 	void (*drop)(struct inode *) = generic_drop_inode;
+	int must_drop_sb_write = (inode->i_state & I_AWAITING_FINAL_IPUT);
 
+	inode->i_state &= ~I_AWAITING_FINAL_IPUT;
 	if (op && op->drop_inode)
 		drop = op->drop_inode;
 	drop(inode);
+	if (must_drop_sb_write)
+		atomic_dec(&sb->s_mnt_writers);
 }
 
 /**
diff -puN fs/libfs.c~04-24-record-when-sb-writer-count-elevated-for-inode fs/libfs.c
--- lxc/fs/libfs.c~04-24-record-when-sb-writer-count-elevated-for-inode	2006-12-11 14:21:59.000000000 -0800
+++ lxc-dave/fs/libfs.c	2006-12-11 14:21:59.000000000 -0800
@@ -376,6 +376,7 @@ int simple_fill_super(struct super_block
 	inode = new_inode(s);
 	if (!inode)
 		return -ENOMEM;
+	inode->i_state |= I_AWAITING_FINAL_IPUT;
 	inode->i_mode = S_IFDIR | 0755;
 	inode->i_uid = inode->i_gid = 0;
 	inode->i_blocks = 0;
diff -puN include/linux/fs.h~04-24-record-when-sb-writer-count-elevated-for-inode include/linux/fs.h
--- lxc/include/linux/fs.h~04-24-record-when-sb-writer-count-elevated-for-inode	2006-12-11 14:21:59.000000000 -0800
+++ lxc-dave/include/linux/fs.h	2006-12-11 14:21:59.000000000 -0800
@@ -1227,6 +1227,7 @@ struct super_operations {
 #define I_CLEAR			32
 #define I_NEW			64
 #define I_WILL_FREE		128
+#define I_AWAITING_FINAL_IPUT		256
 
 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
 
@@ -1252,14 +1253,25 @@ static inline void inode_inc_link_count(
 	mark_inode_dirty(inode);
 }
 
+static inline void check_nlink(struct inode *inode)
+{
+	if (inode->i_nlink)
+		return;
+
+	inode->i_state |= I_AWAITING_FINAL_IPUT;
+	atomic_inc(&inode->i_sb->s_mnt_writers);
+}
+
 static inline void drop_nlink(struct inode *inode)
 {
 	inode->i_nlink--;
+	check_nlink(inode);
 }
 
 static inline void clear_nlink(struct inode *inode)
 {
 	inode->i_nlink = 0;
+	check_nlink(inode);
 }
 
 static inline void inode_dec_link_count(struct inode *inode)
_
_______________________________________________
Containers mailing list
Containers at lists.osdl.org
https://lists.osdl.org/mailman/listinfo/containers




More information about the Devel mailing list