aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeniy Dushistov <dushistov@mail.ru>2006-06-25 08:47:20 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:01 -0400
commit6ef4d6bf86a82965896eaa1a189177239ec2bbab (patch)
tree3217c5601d8cf6701f8783ec776aa96d0dd75d4a
parentc9a27b5dca52bbd0955e065e49e56eb313d02c34 (diff)
[PATCH] ufs: change block number on the fly
First of all some necessary notes about UFS by it self: To avoid waste of disk space the tail of file consists not from blocks (which is ordinary big enough, 16K usually), it consists from fragments(which is ordinary 2K). When file is growing its tail occupy 1 fragment, 2 fragments... At some stage decision to allocate whole block is made and all fragments are moved to one block. How this situation was handled before: ufs_prepare_write ->block_prepare_write ->ufs_getfrag_block ->... ->ufs_new_fragments: bh = sb_bread bh->b_blocknr = result + i; mark_buffer_dirty (bh); This is wrong solution, because: - it didn't take into consideration that there is another cache: "inode page cache" - because of sb_getblk uses not b_blocknr, (it uses page->index) to find certain block, this breaks sb_getblk. How this situation is handled now: we go though all "page inode cache", if there are no such page in cache we load it into cache, and change b_blocknr. Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/ufs/balloc.c137
-rw-r--r--fs/ufs/inode.c44
-rw-r--r--include/linux/ufs_fs.h3
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 */
42void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) { 42void 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 */
137void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) { 138void 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
227static struct page *ufs_get_locked_page(struct address_space *mapping,
228 unsigned long index)
229{
230 struct page *page;
231
232try_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 }
265out:
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 */
279static 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
226unsigned 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
332unsigned 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
175static struct buffer_head * ufs_inode_getfrag (struct inode *inode, 175static 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
306static struct buffer_head * ufs_block_getfrag (struct inode *inode, 310static 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 */
876extern void ufs_free_fragments (struct inode *, unsigned, unsigned); 876extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
877extern void ufs_free_blocks (struct inode *, unsigned, unsigned); 877extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
878extern unsigned ufs_new_fragments (struct inode *, __fs32 *, unsigned, unsigned, unsigned, int *); 878extern unsigned ufs_new_fragments(struct inode *, __fs32 *, unsigned, unsigned,
879 unsigned, int *, struct page *);
879 880
880/* cylinder.c */ 881/* cylinder.c */
881extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned); 882extern struct ufs_cg_private_info * ufs_load_cylinder (struct super_block *, unsigned);