From 466341bae2c891e86c0e2d4c64a890e51b158c1c Mon Sep 17 00:00:00 2001
From: Alexander Viro <viro@www.linux.org.uk>
Date: Fri, 16 Apr 2004 00:26:34 -0700
Subject: [PATCH] [PATCH] remount: fs/sysv fixes

 - several variants of sysv fs are supported only r/o.  Driver does
   force r/o on mount, but doesn't do anything on remount.  As the
   result, one can remount them r/w and results are Not Pretty(tm).
   Missing checks added, code cleaned up.

 - we had double-brelse() in v7fs - if sanity checks on root inode will
   succeed, but allocation of root dentry fails, we brelse() the same
   buffer_head twice.  Fixed.
---
 fs/sysv/inode.c | 11 +++++++++++
 fs/sysv/super.c |  8 +++++---
 fs/sysv/sysv.h  |  1 +
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 09c131fbb36f..379d42408f53 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -57,6 +57,16 @@ static void sysv_write_super(struct super_block *sb)
 	unlock_kernel();
 }
 
+static int sysv_remount(struct super_block *sb, int *flags, char *data)
+{
+	struct sysv_sb_info *sbi = SYSV_SB(sb);
+	if (sbi->s_forced_ro)
+		*flags |= MS_RDONLY;
+	if (!(*flags & MS_RDONLY))
+		sb->s_dirt = 1;
+	return 0;
+}
+
 static void sysv_put_super(struct super_block *sb)
 {
 	struct sysv_sb_info *sbi = SYSV_SB(sb);
@@ -321,6 +331,7 @@ struct super_operations sysv_sops = {
 	.delete_inode	= sysv_delete_inode,
 	.put_super	= sysv_put_super,
 	.write_super	= sysv_write_super,
+	.remount_fs	= sysv_remount,
 	.statfs		= sysv_statfs,
 };
 
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index baf3157204b3..f0e99fc617cc 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -206,11 +206,11 @@ static int detect_sysv(struct sysv_sb_info *sbi, struct buffer_head *bh)
  
  	if (fs16_to_cpu(sbi, sbd->s_nfree) == 0xffff) {
  		sbi->s_type = FSTYPE_AFS;
+		sbi->s_forced_ro = 1;
  		if (!(sb->s_flags & MS_RDONLY)) {
  			printk("SysV FS: SCO EAFS on %s detected, " 
  				"forcing read-only mode.\n", 
  				sb->s_id);
- 			sb->s_flags |= MS_RDONLY;
  		}
  		return sbd->s_type;
  	}
@@ -234,7 +234,7 @@ static int detect_sysv(struct sysv_sb_info *sbi, struct buffer_head *bh)
 	if (sbd->s_type >= 0x10) {
 		printk("SysV FS: can't handle long file names on %s, "
 		       "forcing read-only mode.\n", sb->s_id);
-		sb->s_flags |= MS_RDONLY;
+		sbi->s_forced_ro = 1;
 	}
 
 	sbi->s_type = FSTYPE_SYSV4;
@@ -335,9 +335,10 @@ static int complete_read_super(struct super_block *sb, int silent, int size)
 		printk("SysV FS: get root dentry failed\n");
 		return 0;
 	}
+	if (sbi->s_forced_ro)
+		sb->s_flags |= MS_RDONLY;
 	if (sbi->s_truncate)
 		sb->s_root->d_op = &sysv_dentry_operations;
-	sb->s_flags |= MS_RDONLY;
 	sb->s_dirt = 1;
 	return 1;
 }
@@ -481,6 +482,7 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)
 	    (fs32_to_cpu(sbi, v7i->i_size) & 017) != 0)
 		goto failed;
 	brelse(bh2);
+	bh2 = NULL;
 
 	sbi->s_bh1 = bh;
 	sbi->s_bh2 = bh;
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index f759717bd018..493b0a6a4f0e 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -54,6 +54,7 @@ struct sysv_sb_info {
 	u32            s_ndatazones;	/* total number of data zones */
 	u32            s_nzones;	/* same as s_sbd->s_fsize */
 	u16	       s_namelen;       /* max length of dir entry */
+	int	       s_forced_ro;
 };
 
 /*
-- 
2.30.9