Commit e431dd00 authored by Andrew Morton's avatar Andrew Morton Committed by Dave Jones

[PATCH] AFFS fixes

Patch from Roman Zippel <zippel@linux-m68k.org>

- remove lock_kernel() (It was buggy too - there are at present two missing
  unlock_kernel()s)

- fixes a bitmap corruption problem.
parent d4d68172
...@@ -28,6 +28,11 @@ Known bugs: ...@@ -28,6 +28,11 @@ Known bugs:
Please direct bug reports to: zippel@linux-m68k.org Please direct bug reports to: zippel@linux-m68k.org
Version 3.20
------------
- kill kernel lock
- fix for a possible bitmap corruption
Version 3.19 Version 3.19
------------ ------------
......
...@@ -185,6 +185,8 @@ affs_alloc_block(struct inode *inode, u32 goal) ...@@ -185,6 +185,8 @@ affs_alloc_block(struct inode *inode, u32 goal)
/* search for the next bmap buffer with free bits */ /* search for the next bmap buffer with free bits */
i = sbi->s_bmap_count; i = sbi->s_bmap_count;
do { do {
if (--i < 0)
goto err_full;
bmap++; bmap++;
bm++; bm++;
if (bmap < sbi->s_bmap_count) if (bmap < sbi->s_bmap_count)
...@@ -192,8 +194,6 @@ affs_alloc_block(struct inode *inode, u32 goal) ...@@ -192,8 +194,6 @@ affs_alloc_block(struct inode *inode, u32 goal)
/* restart search at zero */ /* restart search at zero */
bmap = 0; bmap = 0;
bm = sbi->s_bitmap; bm = sbi->s_bitmap;
if (--i <= 0)
goto err_full;
} while (!bm->bm_free); } while (!bm->bm_free);
blk = bmap * sbi->s_bmap_bits; blk = bmap * sbi->s_bmap_bits;
...@@ -216,8 +216,8 @@ affs_alloc_block(struct inode *inode, u32 goal) ...@@ -216,8 +216,8 @@ affs_alloc_block(struct inode *inode, u32 goal)
mask = ~0UL << (bit & 31); mask = ~0UL << (bit & 31);
blk &= ~31UL; blk &= ~31UL;
tmp = be32_to_cpu(*data) & mask; tmp = be32_to_cpu(*data);
if (tmp) if (tmp & mask)
goto find_bit; goto find_bit;
/* scan the rest of the buffer */ /* scan the rest of the buffer */
...@@ -230,10 +230,11 @@ affs_alloc_block(struct inode *inode, u32 goal) ...@@ -230,10 +230,11 @@ affs_alloc_block(struct inode *inode, u32 goal)
goto find_bmap; goto find_bmap;
} while (!(tmp = *data)); } while (!(tmp = *data));
tmp = be32_to_cpu(tmp); tmp = be32_to_cpu(tmp);
mask = ~0;
find_bit: find_bit:
/* finally look for a free bit in the word */ /* finally look for a free bit in the word */
bit = ffs(tmp) - 1; bit = ffs(tmp & mask) - 1;
blk += bit + sbi->s_reserved; blk += bit + sbi->s_reserved;
mask2 = mask = 1 << (bit & 31); mask2 = mask = 1 << (bit & 31);
AFFS_I(inode)->i_lastalloc = blk; AFFS_I(inode)->i_lastalloc = blk;
...@@ -266,8 +267,8 @@ affs_alloc_block(struct inode *inode, u32 goal) ...@@ -266,8 +267,8 @@ affs_alloc_block(struct inode *inode, u32 goal)
sbi->s_bmap_bh = NULL; sbi->s_bmap_bh = NULL;
sbi->s_last_bmap = ~0; sbi->s_last_bmap = ~0;
err_full: err_full:
pr_debug("failed\n");
up(&sbi->s_bmlock); up(&sbi->s_bmlock);
pr_debug("failed\n");
return 0; return 0;
} }
......
...@@ -65,8 +65,6 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -65,8 +65,6 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
int stored; int stored;
int res; int res;
lock_kernel();
pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos); pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
stored = 0; stored = 0;
...@@ -162,7 +160,6 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -162,7 +160,6 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
affs_brelse(dir_bh); affs_brelse(dir_bh);
affs_brelse(fh_bh); affs_brelse(fh_bh);
affs_unlock_dir(inode); affs_unlock_dir(inode);
unlock_kernel();
pr_debug("AFFS: readdir()=%d\n", stored); pr_debug("AFFS: readdir()=%d\n", stored);
return res; return res;
} }
...@@ -195,11 +195,9 @@ affs_write_inode(struct inode *inode, int unused) ...@@ -195,11 +195,9 @@ affs_write_inode(struct inode *inode, int unused)
if (!inode->i_nlink) if (!inode->i_nlink)
// possibly free block // possibly free block
return; return;
lock_kernel();
bh = affs_bread(sb, inode->i_ino); bh = affs_bread(sb, inode->i_ino);
if (!bh) { if (!bh) {
affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino); affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino);
unlock_kernel();
return; return;
} }
tail = AFFS_TAIL(sb, bh); tail = AFFS_TAIL(sb, bh);
...@@ -227,7 +225,7 @@ affs_write_inode(struct inode *inode, int unused) ...@@ -227,7 +225,7 @@ affs_write_inode(struct inode *inode, int unused)
affs_fix_checksum(sb, bh); affs_fix_checksum(sb, bh);
mark_buffer_dirty_inode(bh, inode); mark_buffer_dirty_inode(bh, inode);
affs_brelse(bh); affs_brelse(bh);
unlock_kernel(); affs_free_prealloc(inode);
} }
int int
...@@ -236,8 +234,6 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) ...@@ -236,8 +234,6 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
int error; int error;
lock_kernel();
pr_debug("AFFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid); pr_debug("AFFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid);
error = inode_change_ok(inode,attr); error = inode_change_ok(inode,attr);
...@@ -257,7 +253,6 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) ...@@ -257,7 +253,6 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
if (!error && (attr->ia_valid & ATTR_MODE)) if (!error && (attr->ia_valid & ATTR_MODE))
mode_to_prot(inode); mode_to_prot(inode);
out: out:
unlock_kernel();
return error; return error;
} }
...@@ -265,15 +260,13 @@ void ...@@ -265,15 +260,13 @@ void
affs_put_inode(struct inode *inode) affs_put_inode(struct inode *inode)
{ {
pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
lock_kernel();
affs_free_prealloc(inode); affs_free_prealloc(inode);
if (atomic_read(&inode->i_count) == 1) { if (atomic_read(&inode->i_count) == 1) {
down(&inode->i_sem);
if (inode->i_size != AFFS_I(inode)->mmu_private) if (inode->i_size != AFFS_I(inode)->mmu_private)
affs_truncate(inode); affs_truncate(inode);
//if (inode->i_nlink) up(&inode->i_sem);
// affs_clear_inode(inode);
} }
unlock_kernel();
} }
void void
...@@ -284,9 +277,7 @@ affs_delete_inode(struct inode *inode) ...@@ -284,9 +277,7 @@ affs_delete_inode(struct inode *inode)
if (S_ISREG(inode->i_mode)) if (S_ISREG(inode->i_mode))
affs_truncate(inode); affs_truncate(inode);
clear_inode(inode); clear_inode(inode);
lock_kernel();
affs_free_block(inode->i_sb, inode->i_ino); affs_free_block(inode->i_sb, inode->i_ino);
unlock_kernel();
} }
void void
......
...@@ -218,12 +218,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry) ...@@ -218,12 +218,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry)
pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name); pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
lock_kernel();
affs_lock_dir(dir); affs_lock_dir(dir);
bh = affs_find_entry(dir, dentry); bh = affs_find_entry(dir, dentry);
affs_unlock_dir(dir); affs_unlock_dir(dir);
if (IS_ERR(bh)) { if (IS_ERR(bh)) {
unlock_kernel();
return ERR_PTR(PTR_ERR(bh)); return ERR_PTR(PTR_ERR(bh));
} }
if (bh) { if (bh) {
...@@ -240,12 +238,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry) ...@@ -240,12 +238,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry)
affs_brelse(bh); affs_brelse(bh);
inode = iget(sb, ino); inode = iget(sb, ino);
if (!inode) { if (!inode) {
unlock_kernel();
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
} }
} }
dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations; dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
unlock_kernel();
d_add(dentry, inode); d_add(dentry, inode);
return NULL; return NULL;
} }
...@@ -253,17 +249,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry) ...@@ -253,17 +249,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry)
int int
affs_unlink(struct inode *dir, struct dentry *dentry) affs_unlink(struct inode *dir, struct dentry *dentry)
{ {
int res;
pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino, pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino,
(int)dentry->d_name.len, dentry->d_name.name); (int)dentry->d_name.len, dentry->d_name.name);
if (!dentry->d_inode) return affs_remove_header(dentry);
return -ENOENT;
lock_kernel();
res = affs_remove_header(dentry);
unlock_kernel();
return res;
} }
int int
...@@ -276,12 +265,9 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode) ...@@ -276,12 +265,9 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode)
pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len, pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
dentry->d_name.name,mode); dentry->d_name.name,mode);
lock_kernel();
inode = affs_new_inode(dir); inode = affs_new_inode(dir);
if (!inode) { if (!inode)
unlock_kernel();
return -ENOSPC; return -ENOSPC;
}
inode->i_mode = mode; inode->i_mode = mode;
mode_to_prot(inode); mode_to_prot(inode);
...@@ -294,10 +280,8 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode) ...@@ -294,10 +280,8 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode)
if (error) { if (error) {
inode->i_nlink = 0; inode->i_nlink = 0;
iput(inode); iput(inode);
unlock_kernel();
return error; return error;
} }
unlock_kernel();
return 0; return 0;
} }
...@@ -310,12 +294,9 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -310,12 +294,9 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino, pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name,mode); (int)dentry->d_name.len,dentry->d_name.name,mode);
lock_kernel();
inode = affs_new_inode(dir); inode = affs_new_inode(dir);
if (!inode) { if (!inode)
unlock_kernel();
return -ENOSPC; return -ENOSPC;
}
inode->i_mode = S_IFDIR | mode; inode->i_mode = S_IFDIR | mode;
mode_to_prot(inode); mode_to_prot(inode);
...@@ -328,10 +309,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -328,10 +309,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inode->i_nlink = 0; inode->i_nlink = 0;
mark_inode_dirty(inode); mark_inode_dirty(inode);
iput(inode); iput(inode);
unlock_kernel();
return error; return error;
} }
unlock_kernel();
return 0; return 0;
} }
...@@ -357,14 +336,10 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ...@@ -357,14 +336,10 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino, pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name,symname); (int)dentry->d_name.len,dentry->d_name.name,symname);
lock_kernel();
maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1; maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
error = -ENOSPC;
inode = affs_new_inode(dir); inode = affs_new_inode(dir);
if (!inode) { if (!inode)
unlock_kernel();
return -ENOSPC; return -ENOSPC;
}
inode->i_op = &affs_symlink_inode_operations; inode->i_op = &affs_symlink_inode_operations;
inode->i_data.a_ops = &affs_symlink_aops; inode->i_data.a_ops = &affs_symlink_aops;
...@@ -410,7 +385,6 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ...@@ -410,7 +385,6 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK); error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
if (error) if (error)
goto err; goto err;
unlock_kernel();
return 0; return 0;
...@@ -418,7 +392,6 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ...@@ -418,7 +392,6 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
inode->i_nlink = 0; inode->i_nlink = 0;
mark_inode_dirty(inode); mark_inode_dirty(inode);
iput(inode); iput(inode);
unlock_kernel();
return error; return error;
} }
...@@ -426,23 +399,11 @@ int ...@@ -426,23 +399,11 @@ int
affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{ {
struct inode *inode = old_dentry->d_inode; struct inode *inode = old_dentry->d_inode;
int error;
pr_debug("AFFS: link(%u, %u, \"%.*s\")\n", (u32)inode->i_ino, (u32)dir->i_ino, pr_debug("AFFS: link(%u, %u, \"%.*s\")\n", (u32)inode->i_ino, (u32)dir->i_ino,
(int)dentry->d_name.len,dentry->d_name.name); (int)dentry->d_name.len,dentry->d_name.name);
lock_kernel(); return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
error = affs_add_entry(dir, inode, dentry, ST_LINKFILE);
if (error) {
/* WTF??? */
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
unlock_kernel();
return error;
}
unlock_kernel();
return 0;
} }
int int
...@@ -453,21 +414,19 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -453,21 +414,19 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
int retval; int retval;
lock_kernel();
pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n", pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
(u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name, (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
(u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name); (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len))) retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len);
goto done; if (retval)
return retval;
/* Unlink destination if it already exists */ /* Unlink destination if it already exists */
if (new_dentry->d_inode) { if (new_dentry->d_inode) {
retval = affs_remove_header(new_dentry); retval = affs_remove_header(new_dentry);
if (retval) { if (retval)
unlock_kernel();
return retval; return retval;
}
} }
retval = -EIO; retval = -EIO;
...@@ -493,6 +452,5 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -493,6 +452,5 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
done: done:
mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir); mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
affs_brelse(bh); affs_brelse(bh);
unlock_kernel();
return retval; return retval;
} }
...@@ -40,7 +40,6 @@ static void ...@@ -40,7 +40,6 @@ static void
affs_put_super(struct super_block *sb) affs_put_super(struct super_block *sb)
{ {
struct affs_sb_info *sbi = AFFS_SB(sb); struct affs_sb_info *sbi = AFFS_SB(sb);
lock_kernel();
pr_debug("AFFS: put_super()\n"); pr_debug("AFFS: put_super()\n");
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
...@@ -58,7 +57,6 @@ affs_put_super(struct super_block *sb) ...@@ -58,7 +57,6 @@ affs_put_super(struct super_block *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;
unlock_kernel();
return; return;
} }
...@@ -67,7 +65,7 @@ affs_write_super(struct super_block *sb) ...@@ -67,7 +65,7 @@ affs_write_super(struct super_block *sb)
{ {
int clean = 2; int clean = 2;
struct affs_sb_info *sbi = AFFS_SB(sb); struct affs_sb_info *sbi = AFFS_SB(sb);
lock_kernel();
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
// if (sbi->s_bitmap[i].bm_bh) { // if (sbi->s_bitmap[i].bm_bh) {
// if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) { // if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) {
...@@ -81,7 +79,7 @@ affs_write_super(struct super_block *sb) ...@@ -81,7 +79,7 @@ affs_write_super(struct super_block *sb)
} else } else
sb->s_dirt = 0; sb->s_dirt = 0;
unlock_kernel(); pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean);
} }
static kmem_cache_t * affs_inode_cachep; static kmem_cache_t * affs_inode_cachep;
......
...@@ -32,9 +32,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page) ...@@ -32,9 +32,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino); pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
err = -EIO; err = -EIO;
lock_kernel();
bh = affs_bread(inode->i_sb, inode->i_ino); bh = affs_bread(inode->i_sb, inode->i_ino);
unlock_kernel();
if (!bh) if (!bh)
goto fail; goto fail;
i = 0; i = 0;
...@@ -63,9 +61,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page) ...@@ -63,9 +61,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
j++; j++;
} }
link[i] = '\0'; link[i] = '\0';
lock_kernel();
affs_brelse(bh); affs_brelse(bh);
unlock_kernel();
SetPageUptodate(page); SetPageUptodate(page);
kunmap(page); kunmap(page);
unlock_page(page); unlock_page(page);
......
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