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