aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ufs
diff options
context:
space:
mode:
authorEvgeniy Dushistov <dushistov@mail.ru>2006-06-25 08:47:18 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:01 -0400
commit2061df0f89201c0abeb4c17d343309c9fae5b861 (patch)
treea641b77e6197e6416dc043452db347dbfbb4bd3e /fs/ufs
parenta9adb8dbcd7a337620862106f8c17aeb5e7278c7 (diff)
[PATCH] ufs: ufs_trunc_indirect: infinite cycle
Currently, ufs write support have two sets of problems: work with files and work with directories. This series of patches should solve the first problem. This patch is similar to http://lkml.org/lkml/2006/1/17/61 this patch complements it. The situation the same: in ufs_trunc_(not direct), we read block, check if count of links to it is equal to one, if so we finish cycle, if not continue. Because of "count of links" always >=2 this operation cause infinite cycle and hang up the kernel. Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/ufs')
-rw-r--r--fs/ufs/truncate.c55
-rw-r--r--fs/ufs/util.c12
-rw-r--r--fs/ufs/util.h1
3 files changed, 21 insertions, 47 deletions
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 02e86291ef8a..29c66e1e24df 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -238,18 +238,13 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
238 if (*ubh_get_addr32(ind_ubh,i)) 238 if (*ubh_get_addr32(ind_ubh,i))
239 break; 239 break;
240 if (i >= uspi->s_apb) { 240 if (i >= uspi->s_apb) {
241 if (ubh_max_bcount(ind_ubh) != 1) { 241 tmp = fs32_to_cpu(sb, *p);
242 retry = 1; 242 *p = 0;
243 } 243 inode->i_blocks -= uspi->s_nspb;
244 else { 244 mark_inode_dirty(inode);
245 tmp = fs32_to_cpu(sb, *p); 245 ufs_free_blocks (inode, tmp, uspi->s_fpb);
246 *p = 0; 246 ubh_bforget(ind_ubh);
247 inode->i_blocks -= uspi->s_nspb; 247 ind_ubh = NULL;
248 mark_inode_dirty(inode);
249 ufs_free_blocks (inode, tmp, uspi->s_fpb);
250 ubh_bforget(ind_ubh);
251 ind_ubh = NULL;
252 }
253 } 248 }
254 if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) { 249 if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) {
255 ubh_ll_rw_block (SWRITE, 1, &ind_ubh); 250 ubh_ll_rw_block (SWRITE, 1, &ind_ubh);
@@ -306,17 +301,13 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p)
306 if (*ubh_get_addr32 (dind_bh, i)) 301 if (*ubh_get_addr32 (dind_bh, i))
307 break; 302 break;
308 if (i >= uspi->s_apb) { 303 if (i >= uspi->s_apb) {
309 if (ubh_max_bcount(dind_bh) != 1) 304 tmp = fs32_to_cpu(sb, *p);
310 retry = 1; 305 *p = 0;
311 else { 306 inode->i_blocks -= uspi->s_nspb;
312 tmp = fs32_to_cpu(sb, *p); 307 mark_inode_dirty(inode);
313 *p = 0; 308 ufs_free_blocks (inode, tmp, uspi->s_fpb);
314 inode->i_blocks -= uspi->s_nspb; 309 ubh_bforget(dind_bh);
315 mark_inode_dirty(inode); 310 dind_bh = NULL;
316 ufs_free_blocks (inode, tmp, uspi->s_fpb);
317 ubh_bforget(dind_bh);
318 dind_bh = NULL;
319 }
320 } 311 }
321 if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) { 312 if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) {
322 ubh_ll_rw_block (SWRITE, 1, &dind_bh); 313 ubh_ll_rw_block (SWRITE, 1, &dind_bh);
@@ -370,17 +361,13 @@ static int ufs_trunc_tindirect (struct inode * inode)
370 if (*ubh_get_addr32 (tind_bh, i)) 361 if (*ubh_get_addr32 (tind_bh, i))
371 break; 362 break;
372 if (i >= uspi->s_apb) { 363 if (i >= uspi->s_apb) {
373 if (ubh_max_bcount(tind_bh) != 1) 364 tmp = fs32_to_cpu(sb, *p);
374 retry = 1; 365 *p = 0;
375 else { 366 inode->i_blocks -= uspi->s_nspb;
376 tmp = fs32_to_cpu(sb, *p); 367 mark_inode_dirty(inode);
377 *p = 0; 368 ufs_free_blocks (inode, tmp, uspi->s_fpb);
378 inode->i_blocks -= uspi->s_nspb; 369 ubh_bforget(tind_bh);
379 mark_inode_dirty(inode); 370 tind_bh = NULL;
380 ufs_free_blocks (inode, tmp, uspi->s_fpb);
381 ubh_bforget(tind_bh);
382 tind_bh = NULL;
383 }
384 } 371 }
385 if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { 372 if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) {
386 ubh_ll_rw_block (SWRITE, 1, &tind_bh); 373 ubh_ll_rw_block (SWRITE, 1, &tind_bh);
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 59acc8f073ac..72f91cc84bfe 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -139,18 +139,6 @@ void ubh_wait_on_buffer (struct ufs_buffer_head * ubh)
139 wait_on_buffer (ubh->bh[i]); 139 wait_on_buffer (ubh->bh[i]);
140} 140}
141 141
142unsigned ubh_max_bcount (struct ufs_buffer_head * ubh)
143{
144 unsigned i;
145 unsigned max = 0;
146 if (!ubh)
147 return 0;
148 for ( i = 0; i < ubh->count; i++ )
149 if ( atomic_read(&ubh->bh[i]->b_count) > max )
150 max = atomic_read(&ubh->bh[i]->b_count);
151 return max;
152}
153
154void ubh_bforget (struct ufs_buffer_head * ubh) 142void ubh_bforget (struct ufs_buffer_head * ubh)
155{ 143{
156 unsigned i; 144 unsigned i;
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 48d6d9bcc157..e10362d8f456 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -238,7 +238,6 @@ extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
238extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int); 238extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int);
239extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **); 239extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **);
240extern void ubh_wait_on_buffer (struct ufs_buffer_head *); 240extern void ubh_wait_on_buffer (struct ufs_buffer_head *);
241extern unsigned ubh_max_bcount (struct ufs_buffer_head *);
242extern void ubh_bforget (struct ufs_buffer_head *); 241extern void ubh_bforget (struct ufs_buffer_head *);
243extern int ubh_buffer_dirty (struct ufs_buffer_head *); 242extern int ubh_buffer_dirty (struct ufs_buffer_head *);
244#define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size) 243#define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size)