diff options
Diffstat (limited to 'fs/ufs/balloc.c')
-rw-r--r-- | fs/ufs/balloc.c | 137 |
1 files changed, 113 insertions, 24 deletions
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index cc0c8f15d8fd..06f970d02e3d 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c | |||
@@ -39,7 +39,8 @@ static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, | |||
39 | /* | 39 | /* |
40 | * Free 'count' fragments from fragment number 'fragment' | 40 | * Free 'count' fragments from fragment number 'fragment' |
41 | */ | 41 | */ |
42 | void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) { | 42 | void ufs_free_fragments(struct inode *inode, unsigned fragment, unsigned count) |
43 | { | ||
43 | struct super_block * sb; | 44 | struct super_block * sb; |
44 | struct ufs_sb_private_info * uspi; | 45 | struct ufs_sb_private_info * uspi; |
45 | struct ufs_super_block_first * usb1; | 46 | struct ufs_super_block_first * usb1; |
@@ -134,7 +135,8 @@ failed: | |||
134 | /* | 135 | /* |
135 | * Free 'count' fragments from fragment number 'fragment' (free whole blocks) | 136 | * Free 'count' fragments from fragment number 'fragment' (free whole blocks) |
136 | */ | 137 | */ |
137 | void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) { | 138 | void ufs_free_blocks(struct inode *inode, unsigned fragment, unsigned count) |
139 | { | ||
138 | struct super_block * sb; | 140 | struct super_block * sb; |
139 | struct ufs_sb_private_info * uspi; | 141 | struct ufs_sb_private_info * uspi; |
140 | struct ufs_super_block_first * usb1; | 142 | struct ufs_super_block_first * usb1; |
@@ -222,15 +224,118 @@ failed: | |||
222 | return; | 224 | return; |
223 | } | 225 | } |
224 | 226 | ||
227 | static struct page *ufs_get_locked_page(struct address_space *mapping, | ||
228 | unsigned long index) | ||
229 | { | ||
230 | struct page *page; | ||
231 | |||
232 | try_again: | ||
233 | page = find_lock_page(mapping, index); | ||
234 | if (!page) { | ||
235 | page = read_cache_page(mapping, index, | ||
236 | (filler_t*)mapping->a_ops->readpage, | ||
237 | NULL); | ||
238 | if (IS_ERR(page)) { | ||
239 | printk(KERN_ERR "ufs_change_blocknr: " | ||
240 | "read_cache_page error: ino %lu, index: %lu\n", | ||
241 | mapping->host->i_ino, index); | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | lock_page(page); | ||
246 | |||
247 | if (!PageUptodate(page) || PageError(page)) { | ||
248 | unlock_page(page); | ||
249 | page_cache_release(page); | ||
250 | |||
251 | printk(KERN_ERR "ufs_change_blocknr: " | ||
252 | "can not read page: ino %lu, index: %lu\n", | ||
253 | mapping->host->i_ino, index); | ||
254 | |||
255 | page = ERR_PTR(-EIO); | ||
256 | goto out; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | if (unlikely(!page->mapping || !page_has_buffers(page))) { | ||
261 | unlock_page(page); | ||
262 | page_cache_release(page); | ||
263 | goto try_again;/*we really need these buffers*/ | ||
264 | } | ||
265 | out: | ||
266 | return page; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * Modify inode page cache in such way: | ||
271 | * have - blocks with b_blocknr equal to oldb...oldb+count-1 | ||
272 | * get - blocks with b_blocknr equal to newb...newb+count-1 | ||
273 | * also we suppose that oldb...oldb+count-1 blocks | ||
274 | * situated at the end of file. | ||
275 | * | ||
276 | * We can come here from ufs_writepage or ufs_prepare_write, | ||
277 | * locked_page is argument of these functions, so we already lock it. | ||
278 | */ | ||
279 | static void ufs_change_blocknr(struct inode *inode, unsigned int count, | ||
280 | unsigned int oldb, unsigned int newb, | ||
281 | struct page *locked_page) | ||
282 | { | ||
283 | unsigned int blk_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
284 | sector_t baseblk; | ||
285 | struct address_space *mapping = inode->i_mapping; | ||
286 | pgoff_t index, cur_index = locked_page->index; | ||
287 | unsigned int i, j; | ||
288 | struct page *page; | ||
289 | struct buffer_head *head, *bh; | ||
290 | |||
291 | baseblk = ((i_size_read(inode) - 1) >> inode->i_blkbits) + 1 - count; | ||
292 | |||
293 | UFSD(("ENTER, ino %lu, count %u, oldb %u, newb %u\n", | ||
294 | inode->i_ino, count, oldb, newb)); | ||
295 | |||
296 | BUG_ON(!PageLocked(locked_page)); | ||
297 | |||
298 | for (i = 0; i < count; i += blk_per_page) { | ||
299 | index = (baseblk+i) >> (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
300 | |||
301 | if (likely(cur_index != index)) { | ||
302 | page = ufs_get_locked_page(mapping, index); | ||
303 | if (IS_ERR(page)) | ||
304 | continue; | ||
305 | } else | ||
306 | page = locked_page; | ||
307 | |||
308 | j = i; | ||
309 | head = page_buffers(page); | ||
310 | bh = head; | ||
311 | do { | ||
312 | if (likely(bh->b_blocknr == j + oldb && j < count)) { | ||
313 | unmap_underlying_metadata(bh->b_bdev, | ||
314 | bh->b_blocknr); | ||
315 | bh->b_blocknr = newb + j++; | ||
316 | mark_buffer_dirty(bh); | ||
317 | } | ||
318 | |||
319 | bh = bh->b_this_page; | ||
320 | } while (bh != head); | ||
321 | |||
322 | set_page_dirty(page); | ||
225 | 323 | ||
226 | unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, | 324 | if (likely(cur_index != index)) { |
227 | unsigned goal, unsigned count, int * err ) | 325 | unlock_page(page); |
326 | page_cache_release(page); | ||
327 | } | ||
328 | } | ||
329 | UFSD(("EXIT\n")); | ||
330 | } | ||
331 | |||
332 | unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, | ||
333 | unsigned goal, unsigned count, int * err, struct page *locked_page) | ||
228 | { | 334 | { |
229 | struct super_block * sb; | 335 | struct super_block * sb; |
230 | struct ufs_sb_private_info * uspi; | 336 | struct ufs_sb_private_info * uspi; |
231 | struct ufs_super_block_first * usb1; | 337 | struct ufs_super_block_first * usb1; |
232 | struct buffer_head * bh; | 338 | unsigned cgno, oldcount, newcount, tmp, request, result; |
233 | unsigned cgno, oldcount, newcount, tmp, request, i, result; | ||
234 | 339 | ||
235 | UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count)) | 340 | UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count)) |
236 | 341 | ||
@@ -343,24 +448,8 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, | |||
343 | } | 448 | } |
344 | result = ufs_alloc_fragments (inode, cgno, goal, request, err); | 449 | result = ufs_alloc_fragments (inode, cgno, goal, request, err); |
345 | if (result) { | 450 | if (result) { |
346 | for (i = 0; i < oldcount; i++) { | 451 | ufs_change_blocknr(inode, oldcount, tmp, result, locked_page); |
347 | bh = sb_bread(sb, tmp + i); | 452 | |
348 | if(bh) | ||
349 | { | ||
350 | clear_buffer_dirty(bh); | ||
351 | bh->b_blocknr = result + i; | ||
352 | mark_buffer_dirty (bh); | ||
353 | if (IS_SYNC(inode)) | ||
354 | sync_dirty_buffer(bh); | ||
355 | brelse (bh); | ||
356 | } | ||
357 | else | ||
358 | { | ||
359 | printk(KERN_ERR "ufs_new_fragments: bread fail\n"); | ||
360 | unlock_super(sb); | ||
361 | return 0; | ||
362 | } | ||
363 | } | ||
364 | *p = cpu_to_fs32(sb, result); | 453 | *p = cpu_to_fs32(sb, result); |
365 | *err = 0; | 454 | *err = 0; |
366 | inode->i_blocks += count << uspi->s_nspfshift; | 455 | inode->i_blocks += count << uspi->s_nspfshift; |