提交 09114eb8 编写于 作者: E Evgeniy Dushistov 提交者: Linus Torvalds

[PATCH] ufs: fix hang during `rm'

This fixes the code like this:

	bh = sb_find_get_block (sb, tmp + j);
	if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
		retry = 1;
		brelse (bh);
		goto next1;
	}
	bforget (bh);

sb_find_get_block() ordinarily returns a buffer_head with b_count>=2, and
this code assume that in case if "b_count>1" buffer is used, so this caused
infinite loop.

(akpm: that is-the-buffer-busy code is incomprehensible.  Good riddance.  Use
of block_truncate_page() seems sane).
Signed-off-by: NEvgeniy Dushistov <dushistov@mail.ru>
Signed-off-by: NAndrew Morton <akpm@osdl.org>
Signed-off-by: NLinus Torvalds <torvalds@osdl.org>
上级 e295cfcb
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -376,7 +376,7 @@ static struct buffer_head * ufs_block_getfrag (struct inode *inode,
* This function gets the block which contains the fragment.
*/
static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
{
struct super_block * sb = inode->i_sb;
struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
......
......@@ -29,6 +29,11 @@
* Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
*/
/*
* Modified to avoid infinite loop on 2006 by
* Evgeniy Dushistov <dushistov@mail.ru>
*/
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ufs_fs.h>
......@@ -65,19 +70,16 @@
#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
#define DATA_BUFFER_USED(bh) \
(atomic_read(&bh->b_count)>1 || buffer_locked(bh))
static int ufs_trunc_direct (struct inode * inode)
{
struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * bh;
__fs32 * p;
unsigned frag1, frag2, frag3, frag4, block1, block2;
unsigned frag_to_free, free_count;
unsigned i, j, tmp;
unsigned i, tmp;
int retry;
UFSD(("ENTER\n"))
......@@ -117,15 +119,7 @@ static int ufs_trunc_direct (struct inode * inode)
ufs_panic (sb, "ufs_trunc_direct", "internal error");
frag1 = ufs_fragnum (frag1);
frag2 = ufs_fragnum (frag2);
for (j = frag1; j < frag2; j++) {
bh = sb_find_get_block (sb, tmp + j);
if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
retry = 1;
brelse (bh);
goto next1;
}
bforget (bh);
}
inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift;
mark_inode_dirty(inode);
ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
......@@ -140,15 +134,7 @@ static int ufs_trunc_direct (struct inode * inode)
tmp = fs32_to_cpu(sb, *p);
if (!tmp)
continue;
for (j = 0; j < uspi->s_fpb; j++) {
bh = sb_find_get_block(sb, tmp + j);
if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
retry = 1;
brelse (bh);
goto next2;
}
bforget (bh);
}
*p = 0;
inode->i_blocks -= uspi->s_nspb;
mark_inode_dirty(inode);
......@@ -162,7 +148,6 @@ static int ufs_trunc_direct (struct inode * inode)
frag_to_free = tmp;
free_count = uspi->s_fpb;
}
next2:;
}
if (free_count > 0)
......@@ -179,15 +164,7 @@ next2:;
if (!tmp )
ufs_panic(sb, "ufs_truncate_direct", "internal error");
frag4 = ufs_fragnum (frag4);
for (j = 0; j < frag4; j++) {
bh = sb_find_get_block (sb, tmp + j);
if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
retry = 1;
brelse (bh);
goto next1;
}
bforget (bh);
}
*p = 0;
inode->i_blocks -= frag4 << uspi->s_nspfshift;
mark_inode_dirty(inode);
......@@ -204,9 +181,8 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct ufs_buffer_head * ind_ubh;
struct buffer_head * bh;
__fs32 * ind;
unsigned indirect_block, i, j, tmp;
unsigned indirect_block, i, tmp;
unsigned frag_to_free, free_count;
int retry;
......@@ -238,15 +214,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
tmp = fs32_to_cpu(sb, *ind);
if (!tmp)
continue;
for (j = 0; j < uspi->s_fpb; j++) {
bh = sb_find_get_block(sb, tmp + j);
if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *ind)) {
retry = 1;
brelse (bh);
goto next;
}
bforget (bh);
}
*ind = 0;
ubh_mark_buffer_dirty(ind_ubh);
if (free_count == 0) {
......@@ -261,7 +229,6 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
}
inode->i_blocks -= uspi->s_nspb;
mark_inode_dirty(inode);
next:;
}
if (free_count > 0) {
......@@ -430,9 +397,7 @@ void ufs_truncate (struct inode * inode)
struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * bh;
unsigned offset;
int err, retry;
int retry;
UFSD(("ENTER\n"))
sb = inode->i_sb;
......@@ -442,6 +407,9 @@ void ufs_truncate (struct inode * inode)
return;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block);
lock_kernel();
while (1) {
retry = ufs_trunc_direct(inode);
......@@ -457,15 +425,7 @@ void ufs_truncate (struct inode * inode)
blk_run_address_space(inode->i_mapping);
yield();
}
offset = inode->i_size & uspi->s_fshift;
if (offset) {
bh = ufs_bread (inode, inode->i_size >> uspi->s_fshift, 0, &err);
if (bh) {
memset (bh->b_data + offset, 0, uspi->s_fsize - offset);
mark_buffer_dirty (bh);
brelse (bh);
}
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
ufsi->i_lastfrag = DIRECT_FRAGMENT;
unlock_kernel();
......
......@@ -912,6 +912,7 @@ extern int ufs_sync_inode (struct inode *);
extern void ufs_delete_inode (struct inode *);
extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create);
/* namei.c */
extern struct file_operations ufs_dir_operations;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部