diff options
author | Evgeniy Dushistov <dushistov@mail.ru> | 2006-06-25 08:47:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:01:01 -0400 |
commit | 2061df0f89201c0abeb4c17d343309c9fae5b861 (patch) | |
tree | a641b77e6197e6416dc043452db347dbfbb4bd3e /fs/ufs | |
parent | a9adb8dbcd7a337620862106f8c17aeb5e7278c7 (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.c | 55 | ||||
-rw-r--r-- | fs/ufs/util.c | 12 | ||||
-rw-r--r-- | fs/ufs/util.h | 1 |
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 | ||
142 | unsigned 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 | |||
154 | void ubh_bforget (struct ufs_buffer_head * ubh) | 142 | void 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 *); | |||
238 | extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int); | 238 | extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int); |
239 | extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **); | 239 | extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **); |
240 | extern void ubh_wait_on_buffer (struct ufs_buffer_head *); | 240 | extern void ubh_wait_on_buffer (struct ufs_buffer_head *); |
241 | extern unsigned ubh_max_bcount (struct ufs_buffer_head *); | ||
242 | extern void ubh_bforget (struct ufs_buffer_head *); | 241 | extern void ubh_bforget (struct ufs_buffer_head *); |
243 | extern int ubh_buffer_dirty (struct ufs_buffer_head *); | 242 | extern 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) |