diff options
-rw-r--r-- | fs/ufs/balloc.c | 137 | ||||
-rw-r--r-- | fs/ufs/inode.c | 44 | ||||
-rw-r--r-- | include/linux/ufs_fs.h | 3 |
3 files changed, 140 insertions, 44 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; |
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 2b2366360e5a..ea2267316a72 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c | |||
@@ -172,9 +172,10 @@ static void ufs_clear_block(struct inode *inode, struct buffer_head *bh) | |||
172 | sync_dirty_buffer(bh); | 172 | sync_dirty_buffer(bh); |
173 | } | 173 | } |
174 | 174 | ||
175 | static struct buffer_head * ufs_inode_getfrag (struct inode *inode, | 175 | static struct buffer_head *ufs_inode_getfrag(struct inode *inode, |
176 | unsigned int fragment, unsigned int new_fragment, | 176 | unsigned int fragment, unsigned int new_fragment, |
177 | unsigned int required, int *err, int metadata, long *phys, int *new) | 177 | unsigned int required, int *err, int metadata, |
178 | long *phys, int *new, struct page *locked_page) | ||
178 | { | 179 | { |
179 | struct ufs_inode_info *ufsi = UFS_I(inode); | 180 | struct ufs_inode_info *ufsi = UFS_I(inode); |
180 | struct super_block * sb; | 181 | struct super_block * sb; |
@@ -232,7 +233,8 @@ repeat: | |||
232 | if (lastblockoff) { | 233 | if (lastblockoff) { |
233 | p2 = ufsi->i_u1.i_data + lastblock; | 234 | p2 = ufsi->i_u1.i_data + lastblock; |
234 | tmp = ufs_new_fragments (inode, p2, lastfrag, | 235 | tmp = ufs_new_fragments (inode, p2, lastfrag, |
235 | fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, err); | 236 | fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, |
237 | err, locked_page); | ||
236 | if (!tmp) { | 238 | if (!tmp) { |
237 | if (lastfrag != ufsi->i_lastfrag) | 239 | if (lastfrag != ufsi->i_lastfrag) |
238 | goto repeat; | 240 | goto repeat; |
@@ -244,14 +246,16 @@ repeat: | |||
244 | } | 246 | } |
245 | goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb; | 247 | goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb; |
246 | tmp = ufs_new_fragments (inode, p, fragment - blockoff, | 248 | tmp = ufs_new_fragments (inode, p, fragment - blockoff, |
247 | goal, required + blockoff, err); | 249 | goal, required + blockoff, |
250 | err, locked_page); | ||
248 | } | 251 | } |
249 | /* | 252 | /* |
250 | * We will extend last allocated block | 253 | * We will extend last allocated block |
251 | */ | 254 | */ |
252 | else if (lastblock == block) { | 255 | else if (lastblock == block) { |
253 | tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff), | 256 | tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff), |
254 | fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), err); | 257 | fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), |
258 | err, locked_page); | ||
255 | } | 259 | } |
256 | /* | 260 | /* |
257 | * We will allocate new block before last allocated block | 261 | * We will allocate new block before last allocated block |
@@ -259,8 +263,8 @@ repeat: | |||
259 | else /* (lastblock > block) */ { | 263 | else /* (lastblock > block) */ { |
260 | if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1]))) | 264 | if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1]))) |
261 | goal = tmp + uspi->s_fpb; | 265 | goal = tmp + uspi->s_fpb; |
262 | tmp = ufs_new_fragments (inode, p, fragment - blockoff, | 266 | tmp = ufs_new_fragments(inode, p, fragment - blockoff, |
263 | goal, uspi->s_fpb, err); | 267 | goal, uspi->s_fpb, err, locked_page); |
264 | } | 268 | } |
265 | if (!tmp) { | 269 | if (!tmp) { |
266 | if ((!blockoff && *p) || | 270 | if ((!blockoff && *p) || |
@@ -303,9 +307,10 @@ repeat2: | |||
303 | */ | 307 | */ |
304 | } | 308 | } |
305 | 309 | ||
306 | static struct buffer_head * ufs_block_getfrag (struct inode *inode, | 310 | static struct buffer_head *ufs_block_getfrag(struct inode *inode, struct buffer_head *bh, |
307 | struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment, | 311 | unsigned int fragment, unsigned int new_fragment, |
308 | unsigned int blocksize, int * err, int metadata, long *phys, int *new) | 312 | unsigned int blocksize, int * err, int metadata, |
313 | long *phys, int *new, struct page *locked_page) | ||
309 | { | 314 | { |
310 | struct super_block * sb; | 315 | struct super_block * sb; |
311 | struct ufs_sb_private_info * uspi; | 316 | struct ufs_sb_private_info * uspi; |
@@ -350,7 +355,8 @@ repeat: | |||
350 | goal = tmp + uspi->s_fpb; | 355 | goal = tmp + uspi->s_fpb; |
351 | else | 356 | else |
352 | goal = bh->b_blocknr + uspi->s_fpb; | 357 | goal = bh->b_blocknr + uspi->s_fpb; |
353 | tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err); | 358 | tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, |
359 | uspi->s_fpb, err, locked_page); | ||
354 | if (!tmp) { | 360 | if (!tmp) { |
355 | if (fs32_to_cpu(sb, *p)) | 361 | if (fs32_to_cpu(sb, *p)) |
356 | goto repeat; | 362 | goto repeat; |
@@ -424,15 +430,15 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea | |||
424 | * it much more readable: | 430 | * it much more readable: |
425 | */ | 431 | */ |
426 | #define GET_INODE_DATABLOCK(x) \ | 432 | #define GET_INODE_DATABLOCK(x) \ |
427 | ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new) | 433 | ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new, bh_result->b_page) |
428 | #define GET_INODE_PTR(x) \ | 434 | #define GET_INODE_PTR(x) \ |
429 | ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL) | 435 | ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL, bh_result->b_page) |
430 | #define GET_INDIRECT_DATABLOCK(x) \ | 436 | #define GET_INDIRECT_DATABLOCK(x) \ |
431 | ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \ | 437 | ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \ |
432 | &err, 0, &phys, &new); | 438 | &err, 0, &phys, &new, bh_result->b_page); |
433 | #define GET_INDIRECT_PTR(x) \ | 439 | #define GET_INDIRECT_PTR(x) \ |
434 | ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \ | 440 | ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \ |
435 | &err, 1, NULL, NULL); | 441 | &err, 1, NULL, NULL, bh_result->b_page); |
436 | 442 | ||
437 | if (ptr < UFS_NDIR_FRAGMENT) { | 443 | if (ptr < UFS_NDIR_FRAGMENT) { |
438 | bh = GET_INODE_DATABLOCK(ptr); | 444 | bh = GET_INODE_DATABLOCK(ptr); |
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h index 86b5b4271b5a..ed5053f5cd71 100644 --- a/include/linux/ufs_fs.h +++ b/include/linux/ufs_fs.h | |||
@@ -875,7 +875,8 @@ struct ufs_super_block_third { | |||
875 | /* balloc.c */ | 875 | /* balloc.c */ |
876 | extern void ufs_free_fragments (struct inode *, unsigned, unsigned); | 876 | extern void ufs_free_fragments (struct inode *, unsigned, unsigned); |
877 | extern void ufs_free_blocks (struct inode *, unsigned, unsigned); | 877 | extern void ufs_free_blocks (struct inode *, unsigned, unsigned); |
878 | extern unsigned ufs_new_fragments (struct inode *, __fs32 *, unsigned, unsigned, unsigned, int *); | 878 | extern unsigned ufs_new_fragments(struct inode *, __fs32 *, unsigned, unsigned, |
879 | unsigned, int *, struct page *); | ||
879 | 880 | ||
880 | /* cylinder.c */ | 881 | /* cylinder.c */ |
881 | extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned); | 882 | extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned); |