Commit f51dc7a2 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Linus Torvalds

[PATCH] affs remount fixes

AFFS: Fix oops on write after remount (from Roman Zippel):
  - Allocate/free bitmap as necessary
  - Remove last uses of SF_READONLY
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 74325fde
...@@ -458,7 +458,6 @@ affs_error(struct super_block *sb, const char *function, const char *fmt, ...) ...@@ -458,7 +458,6 @@ affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
if (!(sb->s_flags & MS_RDONLY)) if (!(sb->s_flags & MS_RDONLY))
printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n"); printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
AFFS_SB(sb)->s_flags |= SF_READONLY; /* Don't allow to remount rw */
} }
void void
......
...@@ -272,8 +272,7 @@ affs_alloc_block(struct inode *inode, u32 goal) ...@@ -272,8 +272,7 @@ affs_alloc_block(struct inode *inode, u32 goal)
return 0; return 0;
} }
int int affs_init_bitmap(struct super_block *sb, int *flags)
affs_init_bitmap(struct super_block *sb)
{ {
struct affs_bm_info *bm; struct affs_bm_info *bm;
struct buffer_head *bmap_bh = NULL, *bh = NULL; struct buffer_head *bmap_bh = NULL, *bh = NULL;
...@@ -282,13 +281,13 @@ affs_init_bitmap(struct super_block *sb) ...@@ -282,13 +281,13 @@ affs_init_bitmap(struct super_block *sb)
int i, res = 0; int i, res = 0;
struct affs_sb_info *sbi = AFFS_SB(sb); struct affs_sb_info *sbi = AFFS_SB(sb);
if (sb->s_flags & MS_RDONLY) if (*flags & MS_RDONLY)
return 0; return 0;
if (!AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag) { if (!AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag) {
printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n", printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
sb->s_id); sb->s_id);
sb->s_flags |= MS_RDONLY; *flags |= MS_RDONLY;
return 0; return 0;
} }
...@@ -301,7 +300,7 @@ affs_init_bitmap(struct super_block *sb) ...@@ -301,7 +300,7 @@ affs_init_bitmap(struct super_block *sb)
bm = sbi->s_bitmap = kmalloc(size, GFP_KERNEL); bm = sbi->s_bitmap = kmalloc(size, GFP_KERNEL);
if (!sbi->s_bitmap) { if (!sbi->s_bitmap) {
printk(KERN_ERR "AFFS: Bitmap allocation failed\n"); printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
return 1; return -ENOMEM;
} }
memset(sbi->s_bitmap, 0, size); memset(sbi->s_bitmap, 0, size);
...@@ -316,13 +315,13 @@ affs_init_bitmap(struct super_block *sb) ...@@ -316,13 +315,13 @@ affs_init_bitmap(struct super_block *sb)
bh = affs_bread(sb, bm->bm_key); bh = affs_bread(sb, bm->bm_key);
if (!bh) { if (!bh) {
printk(KERN_ERR "AFFS: Cannot read bitmap\n"); printk(KERN_ERR "AFFS: Cannot read bitmap\n");
res = 1; res = -EIO;
goto out; goto out;
} }
if (affs_checksum_block(sb, bh)) { if (affs_checksum_block(sb, bh)) {
printk(KERN_WARNING "AFFS: Bitmap %u invalid - mounting %s read only.\n", printk(KERN_WARNING "AFFS: Bitmap %u invalid - mounting %s read only.\n",
bm->bm_key, sb->s_id); bm->bm_key, sb->s_id);
sb->s_flags |= MS_RDONLY; *flags |= MS_RDONLY;
goto out; goto out;
} }
pr_debug("AFFS: read bitmap block %d: %d\n", blk, bm->bm_key); pr_debug("AFFS: read bitmap block %d: %d\n", blk, bm->bm_key);
...@@ -338,7 +337,7 @@ affs_init_bitmap(struct super_block *sb) ...@@ -338,7 +337,7 @@ affs_init_bitmap(struct super_block *sb)
bmap_bh = affs_bread(sb, be32_to_cpu(bmap_blk[blk])); bmap_bh = affs_bread(sb, be32_to_cpu(bmap_blk[blk]));
if (!bmap_bh) { if (!bmap_bh) {
printk(KERN_ERR "AFFS: Cannot read bitmap extension\n"); printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
res = 1; res = -EIO;
goto out; goto out;
} }
bmap_blk = (u32 *)bmap_bh->b_data; bmap_blk = (u32 *)bmap_bh->b_data;
...@@ -383,3 +382,17 @@ affs_init_bitmap(struct super_block *sb) ...@@ -383,3 +382,17 @@ affs_init_bitmap(struct super_block *sb)
affs_brelse(bmap_bh); affs_brelse(bmap_bh);
return res; return res;
} }
void affs_free_bitmap(struct super_block *sb)
{
struct affs_sb_info *sbi = AFFS_SB(sb);
if (!sbi->s_bitmap)
return;
affs_brelse(sbi->s_bmap_bh);
sbi->s_bmap_bh = NULL;
sbi->s_last_bmap = ~0;
kfree(sbi->s_bitmap);
sbi->s_bitmap = NULL;
}
...@@ -51,10 +51,9 @@ affs_put_super(struct super_block *sb) ...@@ -51,10 +51,9 @@ affs_put_super(struct super_block *sb)
mark_buffer_dirty(sbi->s_root_bh); mark_buffer_dirty(sbi->s_root_bh);
} }
affs_brelse(sbi->s_bmap_bh);
if (sbi->s_prefix) if (sbi->s_prefix)
kfree(sbi->s_prefix); kfree(sbi->s_prefix);
kfree(sbi->s_bitmap); affs_free_bitmap(sb);
affs_brelse(sbi->s_root_bh); affs_brelse(sbi->s_root_bh);
kfree(sbi); kfree(sbi);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
...@@ -288,6 +287,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -288,6 +287,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
gid_t gid; gid_t gid;
int reserved; int reserved;
unsigned long mount_flags; unsigned long mount_flags;
int tmp_flags; /* fix remount prototype... */
pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options"); pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
...@@ -399,7 +399,6 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -399,7 +399,6 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n", printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
sb->s_id); sb->s_id);
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
sbi->s_flags |= SF_READONLY;
} }
switch (chksum) { switch (chksum) {
case MUFS_FS: case MUFS_FS:
...@@ -455,8 +454,10 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -455,8 +454,10 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_root_bh = root_bh; sbi->s_root_bh = root_bh;
/* N.B. after this point s_root_bh must be released */ /* N.B. after this point s_root_bh must be released */
if (affs_init_bitmap(sb)) tmp_flags = sb->s_flags;
if (affs_init_bitmap(sb, &tmp_flags))
goto out_error; goto out_error;
sb->s_flags = tmp_flags;
/* set up enough so that it can read an inode */ /* set up enough so that it can read an inode */
...@@ -498,7 +499,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) ...@@ -498,7 +499,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
int reserved; int reserved;
int root_block; int root_block;
unsigned long mount_flags; unsigned long mount_flags;
unsigned long read_only = sbi->s_flags & SF_READONLY; int res = 0;
pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data); pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data);
...@@ -507,7 +508,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) ...@@ -507,7 +508,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block, if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block,
&blocksize,&sbi->s_prefix,sbi->s_volume,&mount_flags)) &blocksize,&sbi->s_prefix,sbi->s_volume,&mount_flags))
return -EINVAL; return -EINVAL;
sbi->s_flags = mount_flags | read_only; sbi->s_flags = mount_flags;
sbi->s_mode = mode; sbi->s_mode = mode;
sbi->s_uid = uid; sbi->s_uid = uid;
sbi->s_gid = gid; sbi->s_gid = gid;
...@@ -518,14 +519,11 @@ affs_remount(struct super_block *sb, int *flags, char *data) ...@@ -518,14 +519,11 @@ affs_remount(struct super_block *sb, int *flags, char *data)
sb->s_dirt = 1; sb->s_dirt = 1;
while (sb->s_dirt) while (sb->s_dirt)
affs_write_super(sb); affs_write_super(sb);
sb->s_flags |= MS_RDONLY; affs_free_bitmap(sb);
} else if (!(sbi->s_flags & SF_READONLY)) { } else
sb->s_flags &= ~MS_RDONLY; res = affs_init_bitmap(sb, flags);
} else {
affs_warning(sb,"remount","Cannot remount fs read/write because of errors"); return res;
return -EINVAL;
}
return 0;
} }
static int static int
......
...@@ -36,7 +36,8 @@ extern u32 affs_count_free_bits(u32 blocksize, const void *data); ...@@ -36,7 +36,8 @@ extern u32 affs_count_free_bits(u32 blocksize, const void *data);
extern u32 affs_count_free_blocks(struct super_block *s); extern u32 affs_count_free_blocks(struct super_block *s);
extern void affs_free_block(struct super_block *sb, u32 block); extern void affs_free_block(struct super_block *sb, u32 block);
extern u32 affs_alloc_block(struct inode *inode, u32 goal); extern u32 affs_alloc_block(struct inode *inode, u32 goal);
extern int affs_init_bitmap(struct super_block *sb); extern int affs_init_bitmap(struct super_block *sb, int *flags);
extern void affs_free_bitmap(struct super_block *sb);
/* namei.c */ /* namei.c */
......
...@@ -47,7 +47,6 @@ struct affs_sb_info { ...@@ -47,7 +47,6 @@ struct affs_sb_info {
#define SF_OFS 0x0200 /* Old filesystem */ #define SF_OFS 0x0200 /* Old filesystem */
#define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */ #define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */
#define SF_VERBOSE 0x0800 /* Talk about fs when mounting */ #define SF_VERBOSE 0x0800 /* Talk about fs when mounting */
#define SF_READONLY 0x1000 /* Don't allow to remount rw */
/* short cut to get to the affs specific sb data */ /* short cut to get to the affs specific sb data */
static inline struct affs_sb_info *AFFS_SB(struct super_block *sb) static inline struct affs_sb_info *AFFS_SB(struct super_block *sb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment