diff options
Diffstat (limited to 'fs/ufs')
-rw-r--r-- | fs/ufs/balloc.c | 406 | ||||
-rw-r--r-- | fs/ufs/cylinder.c | 49 | ||||
-rw-r--r-- | fs/ufs/dir.c | 1000 | ||||
-rw-r--r-- | fs/ufs/file.c | 25 | ||||
-rw-r--r-- | fs/ufs/ialloc.c | 63 | ||||
-rw-r--r-- | fs/ufs/inode.c | 381 | ||||
-rw-r--r-- | fs/ufs/namei.c | 84 | ||||
-rw-r--r-- | fs/ufs/super.c | 437 | ||||
-rw-r--r-- | fs/ufs/truncate.c | 250 | ||||
-rw-r--r-- | fs/ufs/util.c | 102 | ||||
-rw-r--r-- | fs/ufs/util.h | 115 |
11 files changed, 1601 insertions, 1311 deletions
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 3ada9dcf55b8..b01804baa120 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -21,14 +21,6 @@ #include "swab.h" #include "util.h" -#undef UFS_BALLOC_DEBUG - -#ifdef UFS_BALLOC_DEBUG -#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - static unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *); static unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *); static unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *); @@ -39,7 +31,8 @@ static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, /* * Free 'count' fragments from fragment number 'fragment' */ -void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) { +void ufs_free_fragments(struct inode *inode, unsigned fragment, unsigned count) +{ struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; @@ -51,7 +44,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); - UFSD(("ENTER, fragment %u, count %u\n", fragment, count)) + UFSD("ENTER, fragment %u, count %u\n", fragment, count); if (ufs_fragnum(fragment) + count > uspi->s_fpg) ufs_error (sb, "ufs_free_fragments", "internal error"); @@ -68,7 +61,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) goto failed; - ucg = ubh_get_ucg (UCPI_UBH); + ucg = ubh_get_ucg (UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) { ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno); goto failed; @@ -76,11 +69,11 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count end_bit = bit + count; bbase = ufs_blknum (bit); - blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase); + blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase); ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1); for (i = bit; i < end_bit; i++) { - if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i)) - ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i); + if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i)) + ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i); else ufs_error (sb, "ufs_free_fragments", "bit already cleared for fragment %u", i); @@ -90,51 +83,52 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count fs32_add(sb, &ucg->cg_cs.cs_nffree, count); - fs32_add(sb, &usb1->fs_cstotal.cs_nffree, count); + uspi->cs_total.cs_nffree += count; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count); - blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase); + blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase); ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1); /* * Trying to reassemble free fragments into block */ blkno = ufs_fragstoblks (bbase); - if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) { + if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) { fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb); - fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, uspi->s_fpb); + uspi->cs_total.cs_nffree -= uspi->s_fpb; fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); - fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1); + uspi->cs_total.cs_nbfree++; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1); cylno = ufs_cbtocylno (bbase); fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1); fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); } - ubh_mark_buffer_dirty (USPI_UBH); - ubh_mark_buffer_dirty (UCPI_UBH); + ubh_mark_buffer_dirty (USPI_UBH(uspi)); + ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi); - ubh_wait_on_buffer (UCPI_UBH); + ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); + ubh_wait_on_buffer (UCPI_UBH(ucpi)); } sb->s_dirt = 1; unlock_super (sb); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return; failed: unlock_super (sb); - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return; } /* * Free 'count' fragments from fragment number 'fragment' (free whole blocks) */ -void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) { +void ufs_free_blocks(struct inode *inode, unsigned fragment, unsigned count) +{ struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; @@ -146,7 +140,7 @@ void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) { uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); - UFSD(("ENTER, fragment %u, count %u\n", fragment, count)) + UFSD("ENTER, fragment %u, count %u\n", fragment, count); if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) { ufs_error (sb, "ufs_free_blocks", "internal error, " @@ -162,7 +156,7 @@ do_more: bit = ufs_dtogd (fragment); if (cgno >= uspi->s_ncg) { ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device"); - goto failed; + goto failed_unlock; } end_bit = bit + count; if (end_bit > uspi->s_fpg) { @@ -173,36 +167,36 @@ do_more: ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) - goto failed; - ucg = ubh_get_ucg (UCPI_UBH); + goto failed_unlock; + ucg = ubh_get_ucg (UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) { ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno); - goto failed; + goto failed_unlock; } for (i = bit; i < end_bit; i += uspi->s_fpb) { blkno = ufs_fragstoblks(i); - if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) { + if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) { ufs_error(sb, "ufs_free_blocks", "freeing free fragment"); } - ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno); + ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); DQUOT_FREE_BLOCK(inode, uspi->s_fpb); fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); - fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1); + uspi->cs_total.cs_nbfree++; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1); cylno = ufs_cbtocylno(i); fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1); fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); } - ubh_mark_buffer_dirty (USPI_UBH); - ubh_mark_buffer_dirty (UCPI_UBH); + ubh_mark_buffer_dirty (USPI_UBH(uspi)); + ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi); - ubh_wait_on_buffer (UCPI_UBH); + ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); + ubh_wait_on_buffer (UCPI_UBH(ucpi)); } if (overflow) { @@ -213,38 +207,83 @@ do_more: sb->s_dirt = 1; unlock_super (sb); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return; -failed: +failed_unlock: unlock_super (sb); - UFSD(("EXIT (FAILED)\n")) +failed: + UFSD("EXIT (FAILED)\n"); return; } +/* + * Modify inode page cache in such way: + * have - blocks with b_blocknr equal to oldb...oldb+count-1 + * get - blocks with b_blocknr equal to newb...newb+count-1 + * also we suppose that oldb...oldb+count-1 blocks + * situated at the end of file. + * + * We can come here from ufs_writepage or ufs_prepare_write, + * locked_page is argument of these functions, so we already lock it. + */ +static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk, + unsigned int count, unsigned int oldb, + unsigned int newb, struct page *locked_page) +{ + unsigned int blk_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits); + struct address_space *mapping = inode->i_mapping; + pgoff_t index, cur_index = locked_page->index; + unsigned int i, j; + struct page *page; + struct buffer_head *head, *bh; + + UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n", + inode->i_ino, count, oldb, newb); + + BUG_ON(!PageLocked(locked_page)); + + for (i = 0; i < count; i += blk_per_page) { + index = (baseblk+i) >> (PAGE_CACHE_SHIFT - inode->i_blkbits); + + if (likely(cur_index != index)) { + page = ufs_get_locked_page(mapping, index); + if (IS_ERR(page)) + continue; + } else + page = locked_page; + + j = i; + head = page_buffers(page); + bh = head; + do { + if (likely(bh->b_blocknr == j + oldb && j < count)) { + unmap_underlying_metadata(bh->b_bdev, + bh->b_blocknr); + bh->b_blocknr = newb + j++; + mark_buffer_dirty(bh); + } + bh = bh->b_this_page; + } while (bh != head); -#define NULLIFY_FRAGMENTS \ - for (i = oldcount; i < newcount; i++) { \ - bh = sb_getblk(sb, result + i); \ - memset (bh->b_data, 0, sb->s_blocksize); \ - set_buffer_uptodate(bh); \ - mark_buffer_dirty (bh); \ - if (IS_SYNC(inode)) \ - sync_dirty_buffer(bh); \ - brelse (bh); \ - } + set_page_dirty(page); + + if (likely(cur_index != index)) + ufs_put_locked_page(page); + } + UFSD("EXIT\n"); +} -unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, - unsigned goal, unsigned count, int * err ) +unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, + unsigned goal, unsigned count, int * err, struct page *locked_page) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; - struct buffer_head * bh; - unsigned cgno, oldcount, newcount, tmp, request, i, result; + unsigned cgno, oldcount, newcount, tmp, request, result; - UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count)) + UFSD("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -273,14 +312,14 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, return (unsigned)-1; } if (fragment < UFS_I(inode)->i_lastfrag) { - UFSD(("EXIT (ALREADY ALLOCATED)\n")) + UFSD("EXIT (ALREADY ALLOCATED)\n"); unlock_super (sb); return 0; } } else { if (tmp) { - UFSD(("EXIT (ALREADY ALLOCATED)\n")) + UFSD("EXIT (ALREADY ALLOCATED)\n"); unlock_super(sb); return 0; } @@ -289,9 +328,9 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, /* * There is not enough space for user on the device */ - if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(usb1, UFS_MINFREE) <= 0) { + if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) { unlock_super (sb); - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return 0; } @@ -310,12 +349,10 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, if (result) { *p = cpu_to_fs32(sb, result); *err = 0; - inode->i_blocks += count << uspi->s_nspfshift; UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); - NULLIFY_FRAGMENTS } unlock_super(sb); - UFSD(("EXIT, result %u\n", result)) + UFSD("EXIT, result %u\n", result); return result; } @@ -325,11 +362,9 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, result = ufs_add_fragments (inode, tmp, oldcount, newcount, err); if (result) { *err = 0; - inode->i_blocks += count << uspi->s_nspfshift; UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); - NULLIFY_FRAGMENTS unlock_super(sb); - UFSD(("EXIT, result %u\n", result)) + UFSD("EXIT, result %u\n", result); return result; } @@ -339,8 +374,8 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, switch (fs32_to_cpu(sb, usb1->fs_optim)) { case UFS_OPTSPACE: request = newcount; - if (uspi->s_minfree < 5 || fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) - > uspi->s_dsize * uspi->s_minfree / (2 * 100) ) + if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree + > uspi->s_dsize * uspi->s_minfree / (2 * 100)) break; usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); break; @@ -349,7 +384,7 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, case UFS_OPTTIME: request = uspi->s_fpb; - if (fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) < uspi->s_dsize * + if (uspi->cs_total.cs_nffree < uspi->s_dsize * (uspi->s_minfree - 2) / 100) break; usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); @@ -357,39 +392,22 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment, } result = ufs_alloc_fragments (inode, cgno, goal, request, err); if (result) { - for (i = 0; i < oldcount; i++) { - bh = sb_bread(sb, tmp + i); - if(bh) - { - clear_buffer_dirty(bh); - bh->b_blocknr = result + i; - mark_buffer_dirty (bh); - if (IS_SYNC(inode)) - sync_dirty_buffer(bh); - brelse (bh); - } - else - { - printk(KERN_ERR "ufs_new_fragments: bread fail\n"); - unlock_super(sb); - return 0; - } - } + ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp, + result, locked_page); + *p = cpu_to_fs32(sb, result); *err = 0; - inode->i_blocks += count << uspi->s_nspfshift; UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); - NULLIFY_FRAGMENTS unlock_super(sb); if (newcount < request) ufs_free_fragments (inode, result + newcount, request - newcount); ufs_free_fragments (inode, tmp, oldcount); - UFSD(("EXIT, result %u\n", result)) + UFSD("EXIT, result %u\n", result); return result; } unlock_super(sb); - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return 0; } @@ -404,7 +422,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, struct ufs_cylinder_group * ucg; unsigned cgno, fragno, fragoff, count, fragsize, i; - UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount)) + UFSD("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -419,7 +437,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) return 0; - ucg = ubh_get_ucg (UCPI_UBH); + ucg = ubh_get_ucg (UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) { ufs_panic (sb, "ufs_add_fragments", "internal error, bad magic number on cg %u", cgno); @@ -429,14 +447,14 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, fragno = ufs_dtogd (fragment); fragoff = ufs_fragnum (fragno); for (i = oldcount; i < newcount; i++) - if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i)) + if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i)) return 0; /* * Block can be extended */ ucg->cg_time = cpu_to_fs32(sb, get_seconds()); for (i = newcount; i < (uspi->s_fpb - fragoff); i++) - if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, fragno + i)) + if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i)) break; fragsize = i - oldcount; if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize])) @@ -446,7 +464,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, if (fragsize != count) fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1); for (i = oldcount; i < newcount; i++) - ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, fragno + i); + ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i); if(DQUOT_ALLOC_BLOCK(inode, count)) { *err = -EDQUOT; return 0; @@ -454,17 +472,17 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, fs32_sub(sb, &ucg->cg_cs.cs_nffree, count); fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count); - fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count); + uspi->cs_total.cs_nffree -= count; - ubh_mark_buffer_dirty (USPI_UBH); - ubh_mark_buffer_dirty (UCPI_UBH); + ubh_mark_buffer_dirty (USPI_UBH(uspi)); + ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi); - ubh_wait_on_buffer (UCPI_UBH); + ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); + ubh_wait_on_buffer (UCPI_UBH(ucpi)); } sb->s_dirt = 1; - UFSD(("EXIT, fragment %u\n", fragment)) + UFSD("EXIT, fragment %u\n", fragment); return fragment; } @@ -487,7 +505,7 @@ static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno, struct ufs_cylinder_group * ucg; unsigned oldcg, i, j, k, result, allocsize; - UFSD(("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count)) + UFSD("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -521,14 +539,14 @@ static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno, UFS_TEST_FREE_SPACE_CG } - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return 0; cg_found: ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) return 0; - ucg = ubh_get_ucg (UCPI_UBH); + ucg = ubh_get_ucg (UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) ufs_panic (sb, "ufs_alloc_fragments", "internal error, bad magic number on cg %u", cgno); @@ -551,12 +569,12 @@ cg_found: return 0; goal = ufs_dtogd (result); for (i = count; i < uspi->s_fpb; i++) - ubh_setbit (UCPI_UBH, ucpi->c_freeoff, goal + i); + ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i); i = uspi->s_fpb - count; DQUOT_FREE_BLOCK(inode, i); fs32_add(sb, &ucg->cg_cs.cs_nffree, i); - fs32_add(sb, &usb1->fs_cstotal.cs_nffree, i); + uspi->cs_total.cs_nffree += i; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i); fs32_add(sb, &ucg->cg_frsum[i], 1); goto succed; @@ -570,10 +588,10 @@ cg_found: return 0; } for (i = 0; i < count; i++) - ubh_clrbit (UCPI_UBH, ucpi->c_freeoff, result + i); + ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i); fs32_sub(sb, &ucg->cg_cs.cs_nffree, count); - fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, count); + uspi->cs_total.cs_nffree -= count; fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count); fs32_sub(sb, &ucg->cg_frsum[allocsize], 1); @@ -581,16 +599,16 @@ cg_found: fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1); succed: - ubh_mark_buffer_dirty (USPI_UBH); - ubh_mark_buffer_dirty (UCPI_UBH); + ubh_mark_buffer_dirty (USPI_UBH(uspi)); + ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **)&ucpi); - ubh_wait_on_buffer (UCPI_UBH); + ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); + ubh_wait_on_buffer (UCPI_UBH(ucpi)); } sb->s_dirt = 1; result += cgno * uspi->s_fpg; - UFSD(("EXIT3, result %u\n", result)) + UFSD("EXIT3, result %u\n", result); return result; } @@ -603,12 +621,12 @@ static unsigned ufs_alloccg_block (struct inode * inode, struct ufs_cylinder_group * ucg; unsigned result, cylno, blkno; - UFSD(("ENTER, goal %u\n", goal)) + UFSD("ENTER, goal %u\n", goal); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); - ucg = ubh_get_ucg(UCPI_UBH); + ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (goal == 0) { goal = ucpi->c_rotor; @@ -620,7 +638,7 @@ static unsigned ufs_alloccg_block (struct inode * inode, /* * If the requested block is available, use it. */ - if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, ufs_fragstoblks(goal))) { + if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) { result = goal; goto gotit; } @@ -632,7 +650,7 @@ norot: ucpi->c_rotor = result; gotit: blkno = ufs_fragstoblks(result); - ubh_clrblock (UCPI_UBH, ucpi->c_freeoff, blkno); + ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, -1); if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) { @@ -641,31 +659,76 @@ gotit: } fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1); - fs32_sub(sb, &usb1->fs_cstotal.cs_nbfree, 1); + uspi->cs_total.cs_nbfree--; fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1); cylno = ufs_cbtocylno(result); fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)), 1); fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1); - UFSD(("EXIT, result %u\n", result)) + UFSD("EXIT, result %u\n", result); return result; } -static unsigned ufs_bitmap_search (struct super_block * sb, - struct ufs_cg_private_info * ucpi, unsigned goal, unsigned count) +static unsigned ubh_scanc(struct ufs_sb_private_info *uspi, + struct ufs_buffer_head *ubh, + unsigned begin, unsigned size, + unsigned char *table, unsigned char mask) { - struct ufs_sb_private_info * uspi; - struct ufs_super_block_first * usb1; - struct ufs_cylinder_group * ucg; - unsigned start, length, location, result; - unsigned possition, fragsize, blockmap, mask; - - UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count)) + unsigned rest, offset; + unsigned char *cp; + + + offset = begin & ~uspi->s_fmask; + begin >>= uspi->s_fshift; + for (;;) { + if ((offset + size) < uspi->s_fsize) + rest = size; + else + rest = uspi->s_fsize - offset; + size -= rest; + cp = ubh->bh[begin]->b_data + offset; + while ((table[*cp++] & mask) == 0 && --rest) + ; + if (rest || !size) + break; + begin++; + offset = 0; + } + return (size + rest); +} + +/* + * Find a block of the specified size in the specified cylinder group. + * @sp: pointer to super block + * @ucpi: pointer to cylinder group info + * @goal: near which block we want find new one + * @count: specified size + */ +static unsigned ufs_bitmap_search(struct super_block *sb, + struct ufs_cg_private_info *ucpi, + unsigned goal, unsigned count) +{ + /* + * Bit patterns for identifying fragments in the block map + * used as ((map & mask_arr) == want_arr) + */ + static const int mask_arr[9] = { + 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff + }; + static const int want_arr[9] = { + 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe + }; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + struct ufs_super_block_first *usb1; + struct ufs_cylinder_group *ucg; + unsigned start, length, loc, result; + unsigned pos, want, blockmap, mask, end; + + UFSD("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count); - uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first (uspi); - ucg = ubh_get_ucg(UCPI_UBH); + ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (goal) start = ufs_dtogd(goal) >> 3; @@ -673,53 +736,50 @@ static unsigned ufs_bitmap_search (struct super_block * sb, start = ucpi->c_frotor >> 3; length = ((uspi->s_fpg + 7) >> 3) - start; - location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length, + loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length, (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other, 1 << (count - 1 + (uspi->s_fpb & 7))); - if (location == 0) { + if (loc == 0) { length = start + 1; - location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff, length, - (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other, - 1 << (count - 1 + (uspi->s_fpb & 7))); - if (location == 0) { - ufs_error (sb, "ufs_bitmap_search", - "bitmap corrupted on cg %u, start %u, length %u, count %u, freeoff %u\n", - ucpi->c_cgx, start, length, count, ucpi->c_freeoff); + loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length, + (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : + ufs_fragtable_other, + 1 << (count - 1 + (uspi->s_fpb & 7))); + if (loc == 0) { + ufs_error(sb, "ufs_bitmap_search", + "bitmap corrupted on cg %u, start %u," + " length %u, count %u, freeoff %u\n", + ucpi->c_cgx, start, length, count, + ucpi->c_freeoff); return (unsigned)-1; } start = 0; } - result = (start + length - location) << 3; + result = (start + length - loc) << 3; ucpi->c_frotor = result; /* * found the byte in the map */ - blockmap = ubh_blkmap(UCPI_UBH, ucpi->c_freeoff, result); - fragsize = 0; - for (possition = 0, mask = 1; possition < 8; possition++, mask <<= 1) { - if (blockmap & mask) { - if (!(possition & uspi->s_fpbmask)) - fragsize = 1; - else - fragsize++; - } - else { - if (fragsize == count) { - result += possition - count; - UFSD(("EXIT, result %u\n", result)) - return result; - } - fragsize = 0; - } - } - if (fragsize == count) { - result += possition - count; - UFSD(("EXIT, result %u\n", result)) - return result; - } - ufs_error (sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx); - UFSD(("EXIT (FAILED)\n")) + + for (end = result + 8; result < end; result += uspi->s_fpb) { + blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result); + blockmap <<= 1; + mask = mask_arr[count]; + want = want_arr[count]; + for (pos = 0; pos <= uspi->s_fpb - count; pos++) { + if ((blockmap & mask) == want) { + UFSD("EXIT, result %u\n", result); + return result + pos; + } + mask <<= 1; + want <<= 1; + } + } + + ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n", + ucpi->c_cgx); + UFSD("EXIT (FAILED)\n"); return (unsigned)-1; } @@ -734,9 +794,9 @@ static void ufs_clusteracct(struct super_block * sb, return; if (cnt > 0) - ubh_setbit(UCPI_UBH, ucpi->c_clusteroff, blkno); + ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno); else - ubh_clrbit(UCPI_UBH, ucpi->c_clusteroff, blkno); + ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno); /* * Find the size of the cluster going forward. @@ -745,7 +805,7 @@ static void ufs_clusteracct(struct super_block * sb, end = start + uspi->s_contigsumsize; if ( end >= ucpi->c_nclusterblks) end = ucpi->c_nclusterblks; - i = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_clusteroff, end, start); + i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start); if (i > end) i = end; forw = i - start; @@ -757,7 +817,7 @@ static void ufs_clusteracct(struct super_block * sb, end = start - uspi->s_contigsumsize; if (end < 0 ) end = -1; - i = ubh_find_last_zero_bit (UCPI_UBH, ucpi->c_clusteroff, start, end); + i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end); if ( i < end) i = end; back = start - i; @@ -769,11 +829,11 @@ static void ufs_clusteracct(struct super_block * sb, i = back + forw + 1; if (i > uspi->s_contigsumsize) i = uspi->s_contigsumsize; - fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (i << 2)), cnt); + fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt); if (back > 0) - fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (back << 2)), cnt); + fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt); if (forw > 0) - fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH, ucpi->c_clustersumoff + (forw << 2)), cnt); + fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt); } diff --git a/fs/ufs/cylinder.c b/fs/ufs/cylinder.c index 14abb8b835f7..09c39e5e6386 100644 --- a/fs/ufs/cylinder.c +++ b/fs/ufs/cylinder.c @@ -20,15 +20,6 @@ #include "swab.h" #include "util.h" -#undef UFS_CYLINDER_DEBUG - -#ifdef UFS_CYLINDER_DEBUG -#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - - /* * Read cylinder group into cache. The memory space for ufs_cg_private_info * structure is already allocated during ufs_read_super. @@ -42,19 +33,19 @@ static void ufs_read_cylinder (struct super_block * sb, struct ufs_cylinder_group * ucg; unsigned i, j; - UFSD(("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr)) + UFSD("ENTER, cgno %u, bitmap_nr %u\n", cgno, bitmap_nr); uspi = sbi->s_uspi; ucpi = sbi->s_ucpi[bitmap_nr]; ucg = (struct ufs_cylinder_group *)sbi->s_ucg[cgno]->b_data; - UCPI_UBH->fragment = ufs_cgcmin(cgno); - UCPI_UBH->count = uspi->s_cgsize >> sb->s_blocksize_bits; + UCPI_UBH(ucpi)->fragment = ufs_cgcmin(cgno); + UCPI_UBH(ucpi)->count = uspi->s_cgsize >> sb->s_blocksize_bits; /* * We have already the first fragment of cylinder group block in buffer */ - UCPI_UBH->bh[0] = sbi->s_ucg[cgno]; - for (i = 1; i < UCPI_UBH->count; i++) - if (!(UCPI_UBH->bh[i] = sb_bread(sb, UCPI_UBH->fragment + i))) + UCPI_UBH(ucpi)->bh[0] = sbi->s_ucg[cgno]; + for (i = 1; i < UCPI_UBH(ucpi)->count; i++) + if (!(UCPI_UBH(ucpi)->bh[i] = sb_bread(sb, UCPI_UBH(ucpi)->fragment + i))) goto failed; sbi->s_cgno[bitmap_nr] = cgno; @@ -73,7 +64,7 @@ static void ufs_read_cylinder (struct super_block * sb, ucpi->c_clustersumoff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clustersumoff); ucpi->c_clusteroff = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_clusteroff); ucpi->c_nclusterblks = fs32_to_cpu(sb, ucg->cg_u.cg_44.cg_nclusterblks); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return; failed: @@ -95,15 +86,15 @@ void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr) struct ufs_cylinder_group * ucg; unsigned i; - UFSD(("ENTER, bitmap_nr %u\n", bitmap_nr)) + UFSD("ENTER, bitmap_nr %u\n", bitmap_nr); uspi = sbi->s_uspi; if (sbi->s_cgno[bitmap_nr] == UFS_CGNO_EMPTY) { - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return; } ucpi = sbi->s_ucpi[bitmap_nr]; - ucg = ubh_get_ucg(UCPI_UBH); + ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (uspi->s_ncg > UFS_MAX_GROUP_LOADED && bitmap_nr >= sbi->s_cg_loaded) { ufs_panic (sb, "ufs_put_cylinder", "internal error"); @@ -116,13 +107,13 @@ void ufs_put_cylinder (struct super_block * sb, unsigned bitmap_nr) ucg->cg_rotor = cpu_to_fs32(sb, ucpi->c_rotor); ucg->cg_frotor = cpu_to_fs32(sb, ucpi->c_frotor); ucg->cg_irotor = cpu_to_fs32(sb, ucpi->c_irotor); - ubh_mark_buffer_dirty (UCPI_UBH); - for (i = 1; i < UCPI_UBH->count; i++) { - brelse (UCPI_UBH->bh[i]); + ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); + for (i = 1; i < UCPI_UBH(ucpi)->count; i++) { + brelse (UCPI_UBH(ucpi)->bh[i]); } sbi->s_cgno[bitmap_nr] = UFS_CGNO_EMPTY; - UFSD(("EXIT\n")) + UFSD("EXIT\n"); } /* @@ -139,7 +130,7 @@ struct ufs_cg_private_info * ufs_load_cylinder ( struct ufs_cg_private_info * ucpi; unsigned cg, i, j; - UFSD(("ENTER, cgno %u\n", cgno)) + UFSD("ENTER, cgno %u\n", cgno); uspi = sbi->s_uspi; if (cgno >= uspi->s_ncg) { @@ -150,7 +141,7 @@ struct ufs_cg_private_info * ufs_load_cylinder ( * Cylinder group number cg it in cache and it was last used */ if (sbi->s_cgno[0] == cgno) { - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return sbi->s_ucpi[0]; } /* @@ -160,16 +151,16 @@ struct ufs_cg_private_info * ufs_load_cylinder ( if (sbi->s_cgno[cgno] != UFS_CGNO_EMPTY) { if (sbi->s_cgno[cgno] != cgno) { ufs_panic (sb, "ufs_load_cylinder", "internal error, wrong number of cg in cache"); - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return NULL; } else { - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return sbi->s_ucpi[cgno]; } } else { ufs_read_cylinder (sb, cgno, cgno); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return sbi->s_ucpi[cgno]; } } @@ -204,6 +195,6 @@ struct ufs_cg_private_info * ufs_load_cylinder ( sbi->s_ucpi[0] = ucpi; ufs_read_cylinder (sb, cgno, 0); } - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return sbi->s_ucpi[0]; } diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 1a561202d3f4..7f0a0aa63584 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -11,31 +11,20 @@ * 4.4BSD (FreeBSD) support added on February 1st 1998 by * Niels Kristian Bech Jensen <nkbj@image.dk> partially based * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>. + * + * Migration to usage of "page cache" on May 2006 by + * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base. */ #include <linux/time.h> #include <linux/fs.h> #include <linux/ufs_fs.h> #include <linux/smp_lock.h> -#include <linux/buffer_head.h> #include <linux/sched.h> #include "swab.h" #include "util.h" -#undef UFS_DIR_DEBUG - -#ifdef UFS_DIR_DEBUG -#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - -static int -ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, - struct buffer_head *, unsigned long); - - /* * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure. * @@ -51,495 +40,541 @@ static inline int ufs_match(struct super_block *sb, int len, return !memcmp(name, de->d_name, len); } -/* - * This is blatantly stolen from ext2fs - */ -static int -ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) +static int ufs_commit_chunk(struct page *page, unsigned from, unsigned to) { - struct inode *inode = filp->f_dentry->d_inode; - int error = 0; - unsigned long offset, lblk; - int i, stored; - struct buffer_head * bh; - struct ufs_dir_entry * de; - struct super_block * sb; - int de_reclen; - unsigned flags; - u64 blk= 0L; - - lock_kernel(); - - sb = inode->i_sb; - flags = UFS_SB(sb)->s_flags; - - UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos)) - - stored = 0; - bh = NULL; - offset = filp->f_pos & (sb->s_blocksize - 1); - - while (!error && !stored && filp->f_pos < inode->i_size) { - lblk = (filp->f_pos) >> sb->s_blocksize_bits; - blk = ufs_frag_map(inode, lblk); - if (!blk || !(bh = sb_bread(sb, blk))) { - /* XXX - error - skip to the next block */ - printk("ufs_readdir: " - "dir inode %lu has a hole at offset %lu\n", - inode->i_ino, (unsigned long int)filp->f_pos); - filp->f_pos += sb->s_blocksize - offset; - continue; - } - -revalidate: - /* If the dir block has changed since the last call to - * readdir(2), then we might be pointing to an invalid - * dirent right now. Scan from the start of the block - * to make sure. */ - if (filp->f_version != inode->i_version) { - for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ufs_dir_entry *)(bh->b_data + i); - /* It's too expensive to do a full - * dirent test each time round this - * loop, but we do have to test at - * least that it is non-zero. A - * failure will be detected in the - * dirent test below. */ - de_reclen = fs16_to_cpu(sb, de->d_reclen); - if (de_reclen < 1) - break; - i += de_reclen; - } - offset = i; - filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) - | offset; - filp->f_version = inode->i_version; - } + struct inode *dir = page->mapping->host; + int err = 0; + dir->i_version++; + page->mapping->a_ops->commit_write(NULL, page, from, to); + if (IS_DIRSYNC(dir)) + err = write_one_page(page, 1); + else + unlock_page(page); + return err; +} - while (!error && filp->f_pos < inode->i_size - && offset < sb->s_blocksize) { - de = (struct ufs_dir_entry *) (bh->b_data + offset); - /* XXX - put in a real ufs_check_dir_entry() */ - if ((de->d_reclen == 0) || (ufs_get_de_namlen(sb, de) == 0)) { - filp->f_pos = (filp->f_pos & - (sb->s_blocksize - 1)) + - sb->s_blocksize; - brelse(bh); - unlock_kernel(); - return stored; - } - if (!ufs_check_dir_entry ("ufs_readdir", inode, de, - bh, offset)) { - /* On error, skip the f_pos to the - next block. */ - filp->f_pos = (filp->f_pos | - (sb->s_blocksize - 1)) + - 1; - brelse (bh); - unlock_kernel(); - return stored; - } - offset += fs16_to_cpu(sb, de->d_reclen); - if (de->d_ino) { - /* We might block in the next section - * if the data destination is - * currently swapped out. So, use a - * version stamp to detect whether or - * not the directory has been modified - * during the copy operation. */ - unsigned long version = filp->f_version; - unsigned char d_type = DT_UNKNOWN; +static inline void ufs_put_page(struct page *page) +{ + kunmap(page); + page_cache_release(page); +} - UFSD(("filldir(%s,%u)\n", de->d_name, - fs32_to_cpu(sb, de->d_ino))) - UFSD(("namlen %u\n", ufs_get_de_namlen(sb, de))) +static inline unsigned long ufs_dir_pages(struct inode *inode) +{ + return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; +} - if ((flags & UFS_DE_MASK) == UFS_DE_44BSD) - d_type = de->d_u.d_44.d_type; - error = filldir(dirent, de->d_name, - ufs_get_de_namlen(sb, de), filp->f_pos, - fs32_to_cpu(sb, de->d_ino), d_type); - if (error) - break; - if (version != filp->f_version) - goto revalidate; - stored ++; - } - filp->f_pos += fs16_to_cpu(sb, de->d_reclen); - } - offset = 0; - brelse (bh); +ino_t ufs_inode_by_name(struct inode *dir, struct dentry *dentry) +{ + ino_t res = 0; + struct ufs_dir_entry *de; + struct page *page; + + de = ufs_find_entry(dir, dentry, &page); + if (de) { + res = fs32_to_cpu(dir->i_sb, de->d_ino); + ufs_put_page(page); } - unlock_kernel(); - return 0; + return res; } -/* - * define how far ahead to read directories while searching them. - */ -#define NAMEI_RA_CHUNKS 2 -#define NAMEI_RA_BLOCKS 4 -#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) -#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) -/* - * ufs_find_entry() - * - * finds an entry in the specified directory with the wanted name. It - * returns the cache buffer in which the entry was found, and the entry - * itself (as a parameter - res_bh). It does NOT read the inode of the - * entry - you'll have to do that yourself if you want to. - */ -struct ufs_dir_entry * ufs_find_entry (struct dentry *dentry, - struct buffer_head ** res_bh) +/* Releases the page */ +void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, + struct page *page, struct inode *inode) { - struct super_block * sb; - struct buffer_head * bh_use[NAMEI_RA_SIZE]; - struct buffer_head * bh_read[NAMEI_RA_SIZE]; - unsigned long offset; - int block, toread, i, err; - struct inode *dir = dentry->d_parent->d_inode; - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; + unsigned from = (char *) de - (char *) page_address(page); + unsigned to = from + fs16_to_cpu(dir->i_sb, de->d_reclen); + int err; - UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen)) - - *res_bh = NULL; - - sb = dir->i_sb; - - if (namelen > UFS_MAXNAMLEN) - return NULL; + lock_page(page); + err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + BUG_ON(err); + de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino); + ufs_set_de_type(dir->i_sb, de, inode->i_mode); + err = ufs_commit_chunk(page, from, to); + ufs_put_page(page); + dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(dir); +} - memset (bh_use, 0, sizeof (bh_use)); - toread = 0; - for (block = 0; block < NAMEI_RA_SIZE; ++block) { - struct buffer_head * bh; - if ((block << sb->s_blocksize_bits) >= dir->i_size) - break; - bh = ufs_getfrag (dir, block, 0, &err); - bh_use[block] = bh; - if (bh && !buffer_uptodate(bh)) - bh_read[toread++] = bh; +static void ufs_check_page(struct page *page) +{ + struct inode *dir = page->mapping->host; + struct super_block *sb = dir->i_sb; + char *kaddr = page_address(page); + unsigned offs, rec_len; + unsigned limit = PAGE_CACHE_SIZE; + struct ufs_dir_entry *p; + char *error; + + if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) { + limit = dir->i_size & ~PAGE_CACHE_MASK; + if (limit & (UFS_SECTOR_SIZE - 1)) + goto Ebadsize; + if (!limit) + goto out; } + for (offs = 0; offs <= limit - UFS_DIR_REC_LEN(1); offs += rec_len) { + p = (struct ufs_dir_entry *)(kaddr + offs); + rec_len = fs16_to_cpu(sb, p->d_reclen); + + if (rec_len < UFS_DIR_REC_LEN(1)) + goto Eshort; + if (rec_len & 3) + goto Ealign; + if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p))) + goto Enamelen; + if (((offs + rec_len - 1) ^ offs) & ~(UFS_SECTOR_SIZE-1)) + goto Espan; + if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg * + UFS_SB(sb)->s_uspi->s_ncg)) + goto Einumber; + } + if (offs != limit) + goto Eend; +out: + SetPageChecked(page); + return; + + /* Too bad, we had an error */ + +Ebadsize: + ufs_error(sb, "ufs_check_page", + "size of directory #%lu is not a multiple of chunk size", + dir->i_ino + ); + goto fail; +Eshort: + error = "rec_len is smaller than minimal"; + goto bad_entry; +Ealign: + error = "unaligned directory entry"; + goto bad_entry; +Enamelen: + error = "rec_len is too small for name_len"; + goto bad_entry; +Espan: + error = "directory entry across blocks"; + goto bad_entry; +Einumber: + error = "inode out of bounds"; +bad_entry: + ufs_error (sb, "ufs_check_page", "bad entry in directory #%lu: %s - " + "offset=%lu, rec_len=%d, name_len=%d", + dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs, + rec_len, ufs_get_de_namlen(sb, p)); + goto fail; +Eend: + p = (struct ufs_dir_entry *)(kaddr + offs); + ufs_error (sb, "ext2_check_page", + "entry in directory #%lu spans the page boundary" + "offset=%lu", + dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs); +fail: + SetPageChecked(page); + SetPageError(page); +} - for (block = 0, offset = 0; offset < dir->i_size; block++) { - struct buffer_head * bh; - struct ufs_dir_entry * de; - char * dlimit; - - if ((block % NAMEI_RA_BLOCKS) == 0 && toread) { - ll_rw_block (READ, toread, bh_read); - toread = 0; - } - bh = bh_use[block % NAMEI_RA_SIZE]; - if (!bh) { - ufs_error (sb, "ufs_find_entry", - "directory #%lu contains a hole at offset %lu", - dir->i_ino, offset); - offset += sb->s_blocksize; - continue; - } - wait_on_buffer (bh); - if (!buffer_uptodate(bh)) { - /* - * read error: all bets are off - */ - break; - } - - de = (struct ufs_dir_entry *) bh->b_data; - dlimit = bh->b_data + sb->s_blocksize; - while ((char *) de < dlimit && offset < dir->i_size) { - /* this code is executed quadratically often */ - /* do minimal checking by hand */ - int de_len; - - if ((char *) de + namelen <= dlimit && - ufs_match(sb, namelen, name, de)) { - /* found a match - - just to be sure, do a full check */ - if (!ufs_check_dir_entry("ufs_find_entry", - dir, de, bh, offset)) - goto failed; - for (i = 0; i < NAMEI_RA_SIZE; ++i) { - if (bh_use[i] != bh) - brelse (bh_use[i]); - } - *res_bh = bh; - return de; - } - /* prevent looping on a bad block */ - de_len = fs16_to_cpu(sb, de->d_reclen); - if (de_len <= 0) - goto failed; - offset += de_len; - de = (struct ufs_dir_entry *) ((char *) de + de_len); - } - - brelse (bh); - if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >= - dir->i_size) - bh = NULL; - else - bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err); - bh_use[block % NAMEI_RA_SIZE] = bh; - if (bh && !buffer_uptodate(bh)) - bh_read[toread++] = bh; +static struct page *ufs_get_page(struct inode *dir, unsigned long n) +{ + struct address_space *mapping = dir->i_mapping; + struct page *page = read_cache_page(mapping, n, + (filler_t*)mapping->a_ops->readpage, NULL); + if (!IS_ERR(page)) { + wait_on_page_locked(page); + kmap(page); + if (!PageUptodate(page)) + goto fail; + if (!PageChecked(page)) + ufs_check_page(page); + if (PageError(page)) + goto fail; } + return page; -failed: - for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]); - UFSD(("EXIT\n")) - return NULL; +fail: + ufs_put_page(page); + return ERR_PTR(-EIO); } -static int -ufs_check_dir_entry (const char *function, struct inode *dir, - struct ufs_dir_entry *de, struct buffer_head *bh, - unsigned long offset) +/* + * Return the offset into page `page_nr' of the last valid + * byte in that page, plus one. + */ +static unsigned +ufs_last_byte(struct inode *inode, unsigned long page_nr) { - struct super_block *sb = dir->i_sb; - const char *error_msg = NULL; - int rlen = fs16_to_cpu(sb, de->d_reclen); - - if (rlen < UFS_DIR_REC_LEN(1)) - error_msg = "reclen is smaller than minimal"; - else if (rlen % 4 != 0) - error_msg = "reclen % 4 != 0"; - else if (rlen < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))) - error_msg = "reclen is too small for namlen"; - else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) - error_msg = "directory entry across blocks"; - else if (fs32_to_cpu(sb, de->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg * - UFS_SB(sb)->s_uspi->s_ncg)) - error_msg = "inode out of bounds"; - - if (error_msg != NULL) - ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - " - "offset=%lu, inode=%lu, reclen=%d, namlen=%d", - dir->i_ino, dir->i_size, error_msg, offset, - (unsigned long)fs32_to_cpu(sb, de->d_ino), - rlen, ufs_get_de_namlen(sb, de)); - - return (error_msg == NULL ? 1 : 0); + unsigned last_byte = inode->i_size; + + last_byte -= page_nr << PAGE_CACHE_SHIFT; + if (last_byte > PAGE_CACHE_SIZE) + last_byte = PAGE_CACHE_SIZE; + return last_byte; } -struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct buffer_head **p) +static inline struct ufs_dir_entry * +ufs_next_entry(struct super_block *sb, struct ufs_dir_entry *p) { - int err; - struct buffer_head *bh = ufs_bread (dir, 0, 0, &err); - struct ufs_dir_entry *res = NULL; - - if (bh) { - res = (struct ufs_dir_entry *) bh->b_data; - res = (struct ufs_dir_entry *)((char *)res + - fs16_to_cpu(dir->i_sb, res->d_reclen)); - } - *p = bh; - return res; + return (struct ufs_dir_entry *)((char *)p + + fs16_to_cpu(sb, p->d_reclen)); } -ino_t ufs_inode_by_name(struct inode * dir, struct dentry *dentry) + +struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p) { - ino_t res = 0; - struct ufs_dir_entry * de; - struct buffer_head *bh; + struct page *page = ufs_get_page(dir, 0); + struct ufs_dir_entry *de = NULL; - de = ufs_find_entry (dentry, &bh); - if (de) { - res = fs32_to_cpu(dir->i_sb, de->d_ino); - brelse(bh); + if (!IS_ERR(page)) { + de = ufs_next_entry(dir->i_sb, + (struct ufs_dir_entry *)page_address(page)); + *p = page; } - return res; + return de; } -void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, - struct buffer_head *bh, struct inode *inode) +/* + * ufs_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the page in which the entry was found, and the entry itself + * (as a parameter - res_dir). Page is returned mapped and unlocked. + * Entry is guaranteed to be valid. + */ +struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct dentry *dentry, + struct page **res_page) { - dir->i_version++; - de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino); - mark_buffer_dirty(bh); - if (IS_DIRSYNC(dir)) - sync_dirty_buffer(bh); - brelse (bh); + struct super_block *sb = dir->i_sb; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; + unsigned reclen = UFS_DIR_REC_LEN(namelen); + unsigned long start, n; + unsigned long npages = ufs_dir_pages(dir); + struct page *page = NULL; + struct ufs_inode_info *ui = UFS_I(dir); + struct ufs_dir_entry *de; + + UFSD("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen); + + if (npages == 0 || namelen > UFS_MAXNAMLEN) + goto out; + + /* OFFSET_CACHE */ + *res_page = NULL; + + start = ui->i_dir_start_lookup; + + if (start >= npages) + start = 0; + n = start; + do { + char *kaddr; + page = ufs_get_page(dir, n); + if (!IS_ERR(page)) { + kaddr = page_address(page); + de = (struct ufs_dir_entry *) kaddr; + kaddr += ufs_last_byte(dir, n) - reclen; + while ((char *) de <= kaddr) { + if (de->d_reclen == 0) { + ufs_error(dir->i_sb, __FUNCTION__, + "zero-length directory entry"); + ufs_put_page(page); + goto out; + } + if (ufs_match(sb, namelen, name, de)) + goto found; + de = ufs_next_entry(sb, de); + } + ufs_put_page(page); + } + if (++n >= npages) + n = 0; + } while (n != start); +out: + return NULL; + +found: + *res_page = page; + ui->i_dir_start_lookup = n; + return de; } /* - * ufs_add_entry() - * - * adds a file entry to the specified directory, using the same - * semantics as ufs_find_entry(). It returns NULL if it failed. + * Parent is locked. */ int ufs_add_link(struct dentry *dentry, struct inode *inode) { - struct super_block * sb; - struct ufs_sb_private_info * uspi; - unsigned long offset; - unsigned fragoff; - unsigned short rec_len; - struct buffer_head * bh; - struct ufs_dir_entry * de, * de1; struct inode *dir = dentry->d_parent->d_inode; const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; + struct super_block *sb = dir->i_sb; + unsigned reclen = UFS_DIR_REC_LEN(namelen); + unsigned short rec_len, name_len; + struct page *page = NULL; + struct ufs_dir_entry *de; + unsigned long npages = ufs_dir_pages(dir); + unsigned long n; + char *kaddr; + unsigned from, to; int err; - UFSD(("ENTER, name %s, namelen %u\n", name, namelen)) - - sb = dir->i_sb; - uspi = UFS_SB(sb)->s_uspi; - - if (!namelen) - return -EINVAL; - bh = ufs_bread (dir, 0, 0, &err); - if (!bh) - return err; - rec_len = UFS_DIR_REC_LEN(namelen); - offset = 0; - de = (struct ufs_dir_entry *) bh->b_data; - while (1) { - if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) { - fragoff = offset & ~uspi->s_fmask; - if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE) - ufs_error (sb, "ufs_add_entry", "internal error" - " fragoff %u", fragoff); - if (!fragoff) { - brelse (bh); - bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, &err); - if (!bh) - return err; - } - if (dir->i_size <= offset) { - if (dir->i_size == 0) { - brelse(bh); - return -ENOENT; - } - de = (struct ufs_dir_entry *) (bh->b_data + fragoff); - de->d_ino = 0; + UFSD("ENTER, name %s, namelen %u\n", name, namelen); + + /* + * We take care of directory expansion in the same loop. + * This code plays outside i_size, so it locks the page + * to protect that region. + */ + for (n = 0; n <= npages; n++) { + char *dir_end; + + page = ufs_get_page(dir, n); + err = PTR_ERR(page); + if (IS_ERR(page)) + goto out; + lock_page(page); + kaddr = page_address(page); + dir_end = kaddr + ufs_last_byte(dir, n); + de = (struct ufs_dir_entry *)kaddr; + kaddr += PAGE_CACHE_SIZE - reclen; + while ((char *)de <= kaddr) { + if ((char *)de == dir_end) { + /* We hit i_size */ + name_len = 0; + rec_len = UFS_SECTOR_SIZE; de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE); - ufs_set_de_namlen(sb, de, 0); - dir->i_size = offset + UFS_SECTOR_SIZE; - mark_inode_dirty(dir); - } else { - de = (struct ufs_dir_entry *) bh->b_data; + de->d_ino = 0; + goto got_it; } + if (de->d_reclen == 0) { + ufs_error(dir->i_sb, __FUNCTION__, + "zero-length directory entry"); + err = -EIO; + goto out_unlock; + } + err = -EEXIST; + if (ufs_match(sb, namelen, name, de)) + goto out_unlock; + name_len = UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)); + rec_len = fs16_to_cpu(sb, de->d_reclen); + if (!de->d_ino && rec_len >= reclen) + goto got_it; + if (rec_len >= name_len + reclen) + goto got_it; + de = (struct ufs_dir_entry *) ((char *) de + rec_len); } - if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) { - brelse (bh); - return -ENOENT; - } - if (ufs_match(sb, namelen, name, de)) { - brelse (bh); - return -EEXIST; - } - if (de->d_ino == 0 && fs16_to_cpu(sb, de->d_reclen) >= rec_len) - break; - - if (fs16_to_cpu(sb, de->d_reclen) >= - UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)) + rec_len) - break; - offset += fs16_to_cpu(sb, de->d_reclen); - de = (struct ufs_dir_entry *) ((char *) de + fs16_to_cpu(sb, de->d_reclen)); + unlock_page(page); + ufs_put_page(page); } - + BUG(); + return -EINVAL; + +got_it: + from = (char*)de - (char*)page_address(page); + to = from + rec_len; + err = page->mapping->a_ops->prepare_write(NULL, page, from, to); + if (err) + goto out_unlock; if (de->d_ino) { - de1 = (struct ufs_dir_entry *) ((char *) de + - UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); - de1->d_reclen = - cpu_to_fs16(sb, fs16_to_cpu(sb, de->d_reclen) - - UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); - de->d_reclen = - cpu_to_fs16(sb, UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); + struct ufs_dir_entry *de1 = + (struct ufs_dir_entry *) ((char *) de + name_len); + de1->d_reclen = cpu_to_fs16(sb, rec_len - name_len); + de->d_reclen = cpu_to_fs16(sb, name_len); + de = de1; } - de->d_ino = 0; + ufs_set_de_namlen(sb, de, namelen); - memcpy (de->d_name, name, namelen + 1); + memcpy(de->d_name, name, namelen + 1); de->d_ino = cpu_to_fs32(sb, inode->i_ino); ufs_set_de_type(sb, de, inode->i_mode); - mark_buffer_dirty(bh); - if (IS_DIRSYNC(dir)) - sync_dirty_buffer(bh); - brelse (bh); + + err = ufs_commit_chunk(page, from, to); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; - dir->i_version++; + mark_inode_dirty(dir); + /* OFFSET_CACHE */ +out_put: + ufs_put_page(page); +out: + return err; +out_unlock: + unlock_page(page); + goto out_put; +} - UFSD(("EXIT\n")) +static inline unsigned +ufs_validate_entry(struct super_block *sb, char *base, + unsigned offset, unsigned mask) +{ + struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset); + struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask)); + while ((char*)p < (char*)de) { + if (p->d_reclen == 0) + break; + p = ufs_next_entry(sb, p); + } + return (char *)p - base; +} + + +/* + * This is blatantly stolen from ext2fs + */ +static int +ufs_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + loff_t pos = filp->f_pos; + struct inode *inode = filp->f_dentry->d_inode; + struct super_block *sb = inode->i_sb; + unsigned int offset = pos & ~PAGE_CACHE_MASK; + unsigned long n = pos >> PAGE_CACHE_SHIFT; + unsigned long npages = ufs_dir_pages(inode); + unsigned chunk_mask = ~(UFS_SECTOR_SIZE - 1); + int need_revalidate = filp->f_version != inode->i_version; + unsigned flags = UFS_SB(sb)->s_flags; + + UFSD("BEGIN\n"); + + if (pos > inode->i_size - UFS_DIR_REC_LEN(1)) + return 0; + + for ( ; n < npages; n++, offset = 0) { + char *kaddr, *limit; + struct ufs_dir_entry *de; + + struct page *page = ufs_get_page(inode, n); + + if (IS_ERR(page)) { + ufs_error(sb, __FUNCTION__, + "bad page in #%lu", + inode->i_ino); + filp->f_pos += PAGE_CACHE_SIZE - offset; + return -EIO; + } + kaddr = page_address(page); + if (unlikely(need_revalidate)) { + if (offset) { + offset = ufs_validate_entry(sb, kaddr, offset, chunk_mask); + filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset; + } + filp->f_version = inode->i_version; + need_revalidate = 0; + } + de = (struct ufs_dir_entry *)(kaddr+offset); + limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1); + for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) { + if (de->d_reclen == 0) { + ufs_error(sb, __FUNCTION__, + "zero-length directory entry"); + ufs_put_page(page); + return -EIO; + } + if (de->d_ino) { + int over; + unsigned char d_type = DT_UNKNOWN; + + offset = (char *)de - kaddr; + + UFSD("filldir(%s,%u)\n", de->d_name, + fs32_to_cpu(sb, de->d_ino)); + UFSD("namlen %u\n", ufs_get_de_namlen(sb, de)); + + if ((flags & UFS_DE_MASK) == UFS_DE_44BSD) + d_type = de->d_u.d_44.d_type; + + over = filldir(dirent, de->d_name, + ufs_get_de_namlen(sb, de), + (n<<PAGE_CACHE_SHIFT) | offset, + fs32_to_cpu(sb, de->d_ino), d_type); + if (over) { + ufs_put_page(page); + return 0; + } + } + filp->f_pos += fs16_to_cpu(sb, de->d_reclen); + } + ufs_put_page(page); + } return 0; } + /* * ufs_delete_entry deletes a directory entry by merging it with the * previous entry. */ -int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir, - struct buffer_head * bh ) - +int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, + struct page * page) { - struct super_block * sb; - struct ufs_dir_entry * de, * pde; - unsigned i; - - UFSD(("ENTER\n")) + struct super_block *sb = inode->i_sb; + struct address_space *mapping = page->mapping; + char *kaddr = page_address(page); + unsigned from = ((char*)dir - kaddr) & ~(UFS_SECTOR_SIZE - 1); + unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen); + struct ufs_dir_entry *pde = NULL; + struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from); + int err; - sb = inode->i_sb; - i = 0; - pde = NULL; - de = (struct ufs_dir_entry *) bh->b_data; - - UFSD(("ino %u, reclen %u, namlen %u, name %s\n", - fs32_to_cpu(sb, de->d_ino), - fs16_to_cpu(sb, de->d_reclen), - ufs_get_de_namlen(sb, de), de->d_name)) - - while (i < bh->b_size) { - if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i)) { - brelse(bh); - return -EIO; - } - if (de == dir) { - if (pde) - fs16_add(sb, &pde->d_reclen, - fs16_to_cpu(sb, dir->d_reclen)); - dir->d_ino = 0; - inode->i_version++; - inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - mark_buffer_dirty(bh); - if (IS_DIRSYNC(inode)) - sync_dirty_buffer(bh); - brelse(bh); - UFSD(("EXIT\n")) - return 0; + UFSD("ENTER\n"); + + UFSD("ino %u, reclen %u, namlen %u, name %s\n", + fs32_to_cpu(sb, de->d_ino), + fs16_to_cpu(sb, de->d_reclen), + ufs_get_de_namlen(sb, de), de->d_name); + + while ((char*)de < (char*)dir) { + if (de->d_reclen == 0) { + ufs_error(inode->i_sb, __FUNCTION__, + "zero-length directory entry"); + err = -EIO; + goto out; } - i += fs16_to_cpu(sb, de->d_reclen); - if (i == UFS_SECTOR_SIZE) pde = NULL; - else pde = de; - de = (struct ufs_dir_entry *) - ((char *) de + fs16_to_cpu(sb, de->d_reclen)); - if (i == UFS_SECTOR_SIZE && de->d_reclen == 0) - break; + pde = de; + de = ufs_next_entry(sb, de); } - UFSD(("EXIT\n")) - brelse(bh); - return -ENOENT; + if (pde) + from = (char*)pde - (char*)page_address(page); + lock_page(page); + err = mapping->a_ops->prepare_write(NULL, page, from, to); + BUG_ON(err); + if (pde) + pde->d_reclen = cpu_to_fs16(sb, to-from); + dir->d_ino = 0; + err = ufs_commit_chunk(page, from, to); + inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); +out: + ufs_put_page(page); + UFSD("EXIT\n"); + return err; } int ufs_make_empty(struct inode * inode, struct inode *dir) { struct super_block * sb = dir->i_sb; - struct buffer_head * dir_block; + struct address_space *mapping = inode->i_mapping; + struct page *page = grab_cache_page(mapping, 0); struct ufs_dir_entry * de; + char *base; int err; - dir_block = ufs_bread (inode, 0, 1, &err); - if (!dir_block) - return err; + if (!page) + return -ENOMEM; + kmap(page); + err = mapping->a_ops->prepare_write(NULL, page, 0, UFS_SECTOR_SIZE); + if (err) { + unlock_page(page); + goto fail; + } + + + base = (char*)page_address(page); + memset(base, 0, PAGE_CACHE_SIZE); + + de = (struct ufs_dir_entry *) base; - inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE; - de = (struct ufs_dir_entry *) dir_block->b_data; de->d_ino = cpu_to_fs32(sb, inode->i_ino); ufs_set_de_type(sb, de, inode->i_mode); ufs_set_de_namlen(sb, de, 1); @@ -552,72 +587,65 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1)); ufs_set_de_namlen(sb, de, 2); strcpy (de->d_name, ".."); - mark_buffer_dirty(dir_block); - brelse (dir_block); - mark_inode_dirty(inode); - return 0; + + err = ufs_commit_chunk(page, 0, UFS_SECTOR_SIZE); +fail: + kunmap(page); + page_cache_release(page); + return err; } /* * routine to check that the specified directory is empty (for rmdir) */ -int ufs_empty_dir (struct inode * inode) +int ufs_empty_dir(struct inode * inode) { - struct super_block * sb; - unsigned long offset; - struct buffer_head * bh; - struct ufs_dir_entry * de, * de1; - int err; - - sb = inode->i_sb; - - if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) || - !(bh = ufs_bread (inode, 0, 0, &err))) { - ufs_warning (inode->i_sb, "empty_dir", - "bad directory (dir #%lu) - no data block", - inode->i_ino); - return 1; - } - de = (struct ufs_dir_entry *) bh->b_data; - de1 = (struct ufs_dir_entry *) - ((char *)de + fs16_to_cpu(sb, de->d_reclen)); - if (fs32_to_cpu(sb, de->d_ino) != inode->i_ino || de1->d_ino == 0 || - strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) { - ufs_warning (inode->i_sb, "empty_dir", - "bad directory (dir #%lu) - no `.' or `..'", - inode->i_ino); - return 1; - } - offset = fs16_to_cpu(sb, de->d_reclen) + fs16_to_cpu(sb, de1->d_reclen); - de = (struct ufs_dir_entry *) - ((char *)de1 + fs16_to_cpu(sb, de1->d_reclen)); - while (offset < inode->i_size ) { - if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) { - brelse (bh); - bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err); - if (!bh) { - ufs_error (sb, "empty_dir", - "directory #%lu contains a hole at offset %lu", - inode->i_ino, offset); - offset += sb->s_blocksize; - continue; + struct super_block *sb = inode->i_sb; + struct page *page = NULL; + unsigned long i, npages = ufs_dir_pages(inode); + + for (i = 0; i < npages; i++) { + char *kaddr; + struct ufs_dir_entry *de; + page = ufs_get_page(inode, i); + + if (IS_ERR(page)) + continue; + + kaddr = page_address(page); + de = (struct ufs_dir_entry *)kaddr; + kaddr += ufs_last_byte(inode, i) - UFS_DIR_REC_LEN(1); + + while ((char *)de <= kaddr) { + if (de->d_reclen == 0) { + ufs_error(inode->i_sb, __FUNCTION__, + "zero-length directory entry: " + "kaddr=%p, de=%p\n", kaddr, de); + goto not_empty; } - de = (struct ufs_dir_entry *) bh->b_data; - } - if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) { - brelse (bh); - return 1; - } - if (de->d_ino) { - brelse (bh); - return 0; + if (de->d_ino) { + u16 namelen=ufs_get_de_namlen(sb, de); + /* check for . and .. */ + if (de->d_name[0] != '.') + goto not_empty; + if (namelen > 2) + goto not_empty; + if (namelen < 2) { + if (inode->i_ino != + fs32_to_cpu(sb, de->d_ino)) + goto not_empty; + } else if (de->d_name[1] != '.') + goto not_empty; + } + de = ufs_next_entry(sb, de); } - offset += fs16_to_cpu(sb, de->d_reclen); - de = (struct ufs_dir_entry *) - ((char *)de + fs16_to_cpu(sb, de->d_reclen)); + ufs_put_page(page); } - brelse (bh); return 1; + +not_empty: + ufs_put_page(page); + return 0; } const struct file_operations ufs_dir_operations = { diff --git a/fs/ufs/file.c b/fs/ufs/file.c index 312fd3f86313..a9c6e5f04fae 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -25,6 +25,26 @@ #include <linux/fs.h> #include <linux/ufs_fs.h> +#include <linux/buffer_head.h> /* for sync_mapping_buffers() */ + +static int ufs_sync_file(struct file *file, struct dentry *dentry, int datasync) +{ + struct inode *inode = dentry->d_inode; + int err; + int ret; + + ret = sync_mapping_buffers(inode->i_mapping); + if (!(inode->i_state & I_DIRTY)) + return ret; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + return ret; + + err = ufs_sync_inode(inode); + if (ret == 0) + ret = err; + return ret; +} + /* * We have mostly NULL's here: the current defaults are ok for @@ -37,9 +57,6 @@ const struct file_operations ufs_file_operations = { .write = generic_file_write, .mmap = generic_file_mmap, .open = generic_file_open, + .fsync = ufs_sync_file, .sendfile = generic_file_sendfile, }; - -struct inode_operations ufs_file_inode_operations = { - .truncate = ufs_truncate, -}; diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index c7a47ed4f430..9501dcd3b213 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -34,14 +34,6 @@ #include "swab.h" #include "util.h" -#undef UFS_IALLOC_DEBUG - -#ifdef UFS_IALLOC_DEBUG -#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - /* * NOTE! When we get the inode, we're the only people * that have access to it, and as such there are no @@ -68,7 +60,7 @@ void ufs_free_inode (struct inode * inode) int is_directory; unsigned ino, cg, bit; - UFSD(("ENTER, ino %lu\n", inode->i_ino)) + UFSD("ENTER, ino %lu\n", inode->i_ino); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -91,7 +83,7 @@ void ufs_free_inode (struct inode * inode) unlock_super (sb); return; } - ucg = ubh_get_ucg(UCPI_UBH); + ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) ufs_panic (sb, "ufs_free_fragments", "internal error, bad cg magic number"); @@ -104,33 +96,33 @@ void ufs_free_inode (struct inode * inode) clear_inode (inode); - if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit)) + if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit)) ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino); else { - ubh_clrbit (UCPI_UBH, ucpi->c_iusedoff, bit); + ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit); if (ino < ucpi->c_irotor) ucpi->c_irotor = ino; fs32_add(sb, &ucg->cg_cs.cs_nifree, 1); - fs32_add(sb, &usb1->fs_cstotal.cs_nifree, 1); + uspi->cs_total.cs_nifree++; fs32_add(sb, &UFS_SB(sb)->fs_cs(cg).cs_nifree, 1); if (is_directory) { fs32_sub(sb, &ucg->cg_cs.cs_ndir, 1); - fs32_sub(sb, &usb1->fs_cstotal.cs_ndir, 1); + uspi->cs_total.cs_ndir--; fs32_sub(sb, &UFS_SB(sb)->fs_cs(cg).cs_ndir, 1); } } - ubh_mark_buffer_dirty (USPI_UBH); - ubh_mark_buffer_dirty (UCPI_UBH); + ubh_mark_buffer_dirty (USPI_UBH(uspi)); + ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi); - ubh_wait_on_buffer (UCPI_UBH); + ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); + ubh_wait_on_buffer (UCPI_UBH(ucpi)); } sb->s_dirt = 1; unlock_super (sb); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); } /* @@ -155,7 +147,7 @@ struct inode * ufs_new_inode(struct inode * dir, int mode) unsigned cg, bit, i, j, start; struct ufs_inode_info *ufsi; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); /* Cannot create files in a deleted directory */ if (!dir || !dir->i_nlink) @@ -213,43 +205,43 @@ cg_found: ucpi = ufs_load_cylinder (sb, cg); if (!ucpi) goto failed; - ucg = ubh_get_ucg(UCPI_UBH); + ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number"); start = ucpi->c_irotor; - bit = ubh_find_next_zero_bit (UCPI_UBH, ucpi->c_iusedoff, uspi->s_ipg, start); + bit = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, uspi->s_ipg, start); if (!(bit < uspi->s_ipg)) { - bit = ubh_find_first_zero_bit (UCPI_UBH, ucpi->c_iusedoff, start); + bit = ubh_find_first_zero_bit (UCPI_UBH(ucpi), ucpi->c_iusedoff, start); if (!(bit < start)) { ufs_error (sb, "ufs_new_inode", "cylinder group %u corrupted - error in inode bitmap\n", cg); goto failed; } } - UFSD(("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg)) - if (ubh_isclr (UCPI_UBH, ucpi->c_iusedoff, bit)) - ubh_setbit (UCPI_UBH, ucpi->c_iusedoff, bit); + UFSD("start = %u, bit = %u, ipg = %u\n", start, bit, uspi->s_ipg); + if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit)) + ubh_setbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit); else { ufs_panic (sb, "ufs_new_inode", "internal error"); goto failed; } fs32_sub(sb, &ucg->cg_cs.cs_nifree, 1); - fs32_sub(sb, &usb1->fs_cstotal.cs_nifree, 1); + uspi->cs_total.cs_nifree--; fs32_sub(sb, &sbi->fs_cs(cg).cs_nifree, 1); if (S_ISDIR(mode)) { fs32_add(sb, &ucg->cg_cs.cs_ndir, 1); - fs32_add(sb, &usb1->fs_cstotal.cs_ndir, 1); + uspi->cs_total.cs_ndir++; fs32_add(sb, &sbi->fs_cs(cg).cs_ndir, 1); } - ubh_mark_buffer_dirty (USPI_UBH); - ubh_mark_buffer_dirty (UCPI_UBH); + ubh_mark_buffer_dirty (USPI_UBH(uspi)); + ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block (SWRITE, 1, (struct ufs_buffer_head **) &ucpi); - ubh_wait_on_buffer (UCPI_UBH); + ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); + ubh_wait_on_buffer (UCPI_UBH(ucpi)); } sb->s_dirt = 1; @@ -272,6 +264,7 @@ cg_found: ufsi->i_shadow = 0; ufsi->i_osync = 0; ufsi->i_oeftflag = 0; + ufsi->i_dir_start_lookup = 0; memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1)); insert_inode_hash(inode); @@ -287,14 +280,14 @@ cg_found: return ERR_PTR(-EDQUOT); } - UFSD(("allocating inode %lu\n", inode->i_ino)) - UFSD(("EXIT\n")) + UFSD("allocating inode %lu\n", inode->i_ino); + UFSD("EXIT\n"); return inode; failed: unlock_super (sb); make_bad_inode(inode); iput (inode); - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return ERR_PTR(-ENOSPC); } diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 3c3f62ce2ad9..e7c8615beb65 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -41,14 +41,7 @@ #include "swab.h" #include "util.h" -#undef UFS_INODE_DEBUG -#undef UFS_INODE_DEBUG_MORE - -#ifdef UFS_INODE_DEBUG -#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif +static u64 ufs_frag_map(struct inode *inode, sector_t frag); static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4]) { @@ -61,7 +54,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off int n = 0; - UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks)); + UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); if (i_block < 0) { ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0"); } else if (i_block < direct_blocks) { @@ -89,7 +82,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off * the begining of the filesystem. */ -u64 ufs_frag_map(struct inode *inode, sector_t frag) +static u64 ufs_frag_map(struct inode *inode, sector_t frag) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; @@ -104,8 +97,10 @@ u64 ufs_frag_map(struct inode *inode, sector_t frag) unsigned flags = UFS_SB(sb)->s_flags; u64 temp = 0L; - UFSD((": frag = %llu depth = %d\n", (unsigned long long)frag, depth)); - UFSD((": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask)); + UFSD(": frag = %llu depth = %d\n", (unsigned long long)frag, depth); + UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n", + uspi->s_fpbshift, uspi->s_apbmask, + (unsigned long long)mask); if (depth == 0) return 0; @@ -161,26 +156,64 @@ out: return ret; } -static struct buffer_head * ufs_inode_getfrag (struct inode *inode, - unsigned int fragment, unsigned int new_fragment, - unsigned int required, int *err, int metadata, long *phys, int *new) +static void ufs_clear_frag(struct inode *inode, struct buffer_head *bh) +{ + lock_buffer(bh); + memset(bh->b_data, 0, inode->i_sb->s_blocksize); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + unlock_buffer(bh); + if (IS_SYNC(inode)) + sync_dirty_buffer(bh); +} + +static struct buffer_head * +ufs_clear_frags(struct inode *inode, sector_t beg, + unsigned int n) +{ + struct buffer_head *res, *bh; + sector_t end = beg + n; + + res = sb_getblk(inode->i_sb, beg); + ufs_clear_frag(inode, res); + for (++beg; beg < end; ++beg) { + bh = sb_getblk(inode->i_sb, beg); + ufs_clear_frag(inode, bh); + brelse(bh); + } + return res; +} + +/** + * ufs_inode_getfrag() - allocate new fragment(s) + * @inode - pointer to inode + * @fragment - number of `fragment' which hold pointer + * to new allocated fragment(s) + * @new_fragment - number of new allocated fragment(s) + * @required - how many fragment(s) we require + * @err - we set it if something wrong + * @phys - pointer to where we save physical number of new allocated fragments, + * NULL if we allocate not data(indirect blocks for example). + * @new - we set it if we allocate new block + * @locked_page - for ufs_new_fragments() + */ +static struct buffer_head * +ufs_inode_getfrag(struct inode *inode, unsigned int fragment, + sector_t new_fragment, unsigned int required, int *err, + long *phys, int *new, struct page *locked_page) { struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block * sb; - struct ufs_sb_private_info * uspi; + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct buffer_head * result; unsigned block, blockoff, lastfrag, lastblock, lastblockoff; unsigned tmp, goal; __fs32 * p, * p2; - unsigned flags = 0; - UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n", - inode->i_ino, fragment, new_fragment, required)) + UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, required %u, " + "metadata %d\n", inode->i_ino, fragment, + (unsigned long long)new_fragment, required, !phys); - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - - flags = UFS_SB(sb)->s_flags; /* TODO : to be done for write support if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) goto ufs2; @@ -195,16 +228,16 @@ repeat: tmp = fs32_to_cpu(sb, *p); lastfrag = ufsi->i_lastfrag; if (tmp && fragment < lastfrag) { - if (metadata) { + if (!phys) { result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); if (tmp == fs32_to_cpu(sb, *p)) { - UFSD(("EXIT, result %u\n", tmp + blockoff)) + UFSD("EXIT, result %u\n", tmp + blockoff); return result; } brelse (result); goto repeat; } else { - *phys = tmp; + *phys = tmp + blockoff; return NULL; } } @@ -221,7 +254,8 @@ repeat: if (lastblockoff) { p2 = ufsi->i_u1.i_data + lastblock; tmp = ufs_new_fragments (inode, p2, lastfrag, - fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, err); + fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, + err, locked_page); if (!tmp) { if (lastfrag != ufsi->i_lastfrag) goto repeat; @@ -233,14 +267,16 @@ repeat: } goal = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]) + uspi->s_fpb; tmp = ufs_new_fragments (inode, p, fragment - blockoff, - goal, required + blockoff, err); + goal, required + blockoff, + err, locked_page); } /* * We will extend last allocated block */ else if (lastblock == block) { - tmp = ufs_new_fragments (inode, p, fragment - (blockoff - lastblockoff), - fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), err); + tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff), + fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), + err, locked_page); } /* * We will allocate new block before last allocated block @@ -248,8 +284,8 @@ repeat: else /* (lastblock > block) */ { if (lastblock && (tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock-1]))) goal = tmp + uspi->s_fpb; - tmp = ufs_new_fragments (inode, p, fragment - blockoff, - goal, uspi->s_fpb, err); + tmp = ufs_new_fragments(inode, p, fragment - blockoff, + goal, uspi->s_fpb, err, locked_page); } if (!tmp) { if ((!blockoff && *p) || @@ -259,14 +295,10 @@ repeat: return NULL; } - /* The nullification of framgents done in ufs/balloc.c is - * something I don't have the stomache to move into here right - * now. -DaveM - */ - if (metadata) { - result = sb_getblk(inode->i_sb, tmp + blockoff); + if (!phys) { + result = ufs_clear_frags(inode, tmp + blockoff, required); } else { - *phys = tmp; + *phys = tmp + blockoff; result = NULL; *err = 0; *new = 1; @@ -276,7 +308,7 @@ repeat: if (IS_SYNC(inode)) ufs_sync_inode (inode); mark_inode_dirty(inode); - UFSD(("EXIT, result %u\n", tmp + blockoff)) + UFSD("EXIT, result %u\n", tmp + blockoff); return result; /* This part : To be implemented .... @@ -295,22 +327,35 @@ repeat2: */ } -static struct buffer_head * ufs_block_getfrag (struct inode *inode, - struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment, - unsigned int blocksize, int * err, int metadata, long *phys, int *new) +/** + * ufs_inode_getblock() - allocate new block + * @inode - pointer to inode + * @bh - pointer to block which hold "pointer" to new allocated block + * @fragment - number of `fragment' which hold pointer + * to new allocated block + * @new_fragment - number of new allocated fragment + * (block will hold this fragment and also uspi->s_fpb-1) + * @err - see ufs_inode_getfrag() + * @phys - see ufs_inode_getfrag() + * @new - see ufs_inode_getfrag() + * @locked_page - see ufs_inode_getfrag() + */ +static struct buffer_head * +ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, + unsigned int fragment, sector_t new_fragment, int *err, + long *phys, int *new, struct page *locked_page) { - struct super_block * sb; - struct ufs_sb_private_info * uspi; + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct buffer_head * result; unsigned tmp, goal, block, blockoff; __fs32 * p; - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; block = ufs_fragstoblks (fragment); blockoff = ufs_fragnum (fragment); - UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment)) + UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, metadata %d\n", + inode->i_ino, fragment, (unsigned long long)new_fragment, !phys); result = NULL; if (!bh) @@ -326,14 +371,14 @@ static struct buffer_head * ufs_block_getfrag (struct inode *inode, repeat: tmp = fs32_to_cpu(sb, *p); if (tmp) { - if (metadata) { + if (!phys) { result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); if (tmp == fs32_to_cpu(sb, *p)) goto out; brelse (result); goto repeat; } else { - *phys = tmp; + *phys = tmp + blockoff; goto out; } } @@ -342,21 +387,19 @@ repeat: goal = tmp + uspi->s_fpb; else goal = bh->b_blocknr + uspi->s_fpb; - tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err); + tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, + uspi->s_fpb, err, locked_page); if (!tmp) { if (fs32_to_cpu(sb, *p)) goto repeat; goto out; } - /* The nullification of framgents done in ufs/balloc.c is - * something I don't have the stomache to move into here right - * now. -DaveM - */ - if (metadata) { - result = sb_getblk(sb, tmp + blockoff); + + if (!phys) { + result = ufs_clear_frags(inode, tmp + blockoff, uspi->s_fpb); } else { - *phys = tmp; + *phys = tmp + blockoff; *new = 1; } @@ -365,18 +408,19 @@ repeat: sync_dirty_buffer(bh); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - UFSD(("result %u\n", tmp + blockoff)); + UFSD("result %u\n", tmp + blockoff); out: brelse (bh); - UFSD(("EXIT\n")); + UFSD("EXIT\n"); return result; } -/* - * This function gets the block which contains the fragment. +/** + * ufs_getfrag_bloc() - `get_block_t' function, interface between UFS and + * readpage, writepage and so on */ -int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) +int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) { struct super_block * sb = inode->i_sb; struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi; @@ -387,7 +431,7 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea if (!create) { phys64 = ufs_frag_map(inode, fragment); - UFSD(("phys64 = %llu \n",phys64)); + UFSD("phys64 = %llu\n", (unsigned long long)phys64); if (phys64) map_bh(bh_result, sb, phys64); return 0; @@ -402,7 +446,7 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea lock_kernel(); - UFSD(("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment)) + UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); if (fragment < 0) goto abort_negative; if (fragment > @@ -418,15 +462,15 @@ int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_hea * it much more readable: */ #define GET_INODE_DATABLOCK(x) \ - ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new) + ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new, bh_result->b_page) #define GET_INODE_PTR(x) \ - ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL) + ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page) #define GET_INDIRECT_DATABLOCK(x) \ - ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \ - &err, 0, &phys, &new); + ufs_inode_getblock(inode, bh, x, fragment, \ + &err, &phys, &new, bh_result->b_page); #define GET_INDIRECT_PTR(x) \ - ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \ - &err, 1, NULL, NULL); + ufs_inode_getblock(inode, bh, x, fragment, \ + &err, NULL, NULL, bh_result->b_page); if (ptr < UFS_NDIR_FRAGMENT) { bh = GET_INODE_DATABLOCK(ptr); @@ -474,8 +518,9 @@ abort_too_big: goto abort; } -struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment, - int create, int *err) +static struct buffer_head *ufs_getfrag(struct inode *inode, + unsigned int fragment, + int create, int *err) { struct buffer_head dummy; int error; @@ -502,7 +547,7 @@ struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment, { struct buffer_head * bh; - UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment)) + UFSD("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment); bh = ufs_getfrag (inode, fragment, create, err); if (!bh || buffer_uptodate(bh)) return bh; @@ -531,7 +576,7 @@ static sector_t ufs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,ufs_getfrag_block); } -struct address_space_operations ufs_aops = { +const struct address_space_operations ufs_aops = { .readpage = ufs_readpage, .writepage = ufs_writepage, .sync_page = block_sync_page, @@ -540,39 +585,34 @@ struct address_space_operations ufs_aops = { .bmap = ufs_bmap }; -void ufs_read_inode (struct inode * inode) +static void ufs_set_inode_ops(struct inode *inode) +{ + if (S_ISREG(inode->i_mode)) { + inode->i_op = &ufs_file_inode_operations; + inode->i_fop = &ufs_file_operations; + inode->i_mapping->a_ops = &ufs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ufs_dir_inode_operations; + inode->i_fop = &ufs_dir_operations; + inode->i_mapping->a_ops = &ufs_aops; + } else if (S_ISLNK(inode->i_mode)) { + if (!inode->i_blocks) + inode->i_op = &ufs_fast_symlink_inode_operations; + else { + inode->i_op = &page_symlink_inode_operations; + inode->i_mapping->a_ops = &ufs_aops; + } + } else + init_special_inode(inode, inode->i_mode, + ufs_get_inode_dev(inode->i_sb, UFS_I(inode))); +} + +static void ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) { struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block * sb; - struct ufs_sb_private_info * uspi; - struct ufs_inode * ufs_inode; - struct ufs2_inode *ufs2_inode; - struct buffer_head * bh; + struct super_block *sb = inode->i_sb; mode_t mode; unsigned i; - unsigned flags; - - UFSD(("ENTER, ino %lu\n", inode->i_ino)) - - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - flags = UFS_SB(sb)->s_flags; - - if (inode->i_ino < UFS_ROOTINO || - inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { - ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); - goto bad_inode; - } - - bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); - if (!bh) { - ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); - goto bad_inode; - } - if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) - goto ufs2_inode; - - ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino)); /* * Copy data to the in-core inode. @@ -596,56 +636,29 @@ void ufs_read_inode (struct inode * inode) inode->i_atime.tv_nsec = 0; inode->i_ctime.tv_nsec = 0; inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks); - inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat) */ - inode->i_version++; ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags); ufsi->i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen); ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); - ufsi->i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift; + if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) ufsi->i_u1.i_data[i] = ufs_inode->ui_u2.ui_addr.ui_db[i]; - } - else { + } else { for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) ufsi->i_u1.i_symlink[i] = ufs_inode->ui_u2.ui_symlink[i]; } - ufsi->i_osync = 0; - - if (S_ISREG(inode->i_mode)) { - inode->i_op = &ufs_file_inode_operations; - inode->i_fop = &ufs_file_operations; - inode->i_mapping->a_ops = &ufs_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &ufs_dir_inode_operations; - inode->i_fop = &ufs_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - if (!inode->i_blocks) - inode->i_op = &ufs_fast_symlink_inode_operations; - else { - inode->i_op = &page_symlink_inode_operations; - inode->i_mapping->a_ops = &ufs_aops; - } - } else - init_special_inode(inode, inode->i_mode, - ufs_get_inode_dev(sb, ufsi)); - - brelse (bh); - - UFSD(("EXIT\n")) - return; - -bad_inode: - make_bad_inode(inode); - return; - -ufs2_inode : - UFSD(("Reading ufs2 inode, ino %lu\n", inode->i_ino)) +} - ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino)); +static void ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) +{ + struct ufs_inode_info *ufsi = UFS_I(inode); + struct super_block *sb = inode->i_sb; + mode_t mode; + unsigned i; + UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino); /* * Copy data to the in-core inode. */ @@ -668,50 +681,75 @@ ufs2_inode : inode->i_atime.tv_nsec = 0; inode->i_ctime.tv_nsec = 0; inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks); - inode->i_blksize = PAGE_SIZE; /*This is the optimal IO size(for stat)*/ - - inode->i_version++; ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags); ufsi->i_gen = fs32_to_cpu(sb, ufs2_inode->ui_gen); /* ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); */ - ufsi->i_lastfrag= (inode->i_size + uspi->s_fsize- 1) >> uspi->s_fshift; if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) ufsi->i_u1.u2_i_data[i] = ufs2_inode->ui_u2.ui_addr.ui_db[i]; - } - else { + } else { for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) ufsi->i_u1.i_symlink[i] = ufs2_inode->ui_u2.ui_symlink[i]; } +} + +void ufs_read_inode(struct inode * inode) +{ + struct ufs_inode_info *ufsi = UFS_I(inode); + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct buffer_head * bh; + + UFSD("ENTER, ino %lu\n", inode->i_ino); + + sb = inode->i_sb; + uspi = UFS_SB(sb)->s_uspi; + + if (inode->i_ino < UFS_ROOTINO || + inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { + ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n", + inode->i_ino); + goto bad_inode; + } + + bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); + if (!bh) { + ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n", + inode->i_ino); + goto bad_inode; + } + if ((UFS_SB(sb)->s_flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; + + ufs2_read_inode(inode, + ufs2_inode + ufs_inotofsbo(inode->i_ino)); + } else { + struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data; + + ufs1_read_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino)); + } + + inode->i_blksize = PAGE_SIZE;/*This is the optimal IO size (for stat)*/ + inode->i_version++; + ufsi->i_lastfrag = + (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift; + ufsi->i_dir_start_lookup = 0; ufsi->i_osync = 0; - if (S_ISREG(inode->i_mode)) { - inode->i_op = &ufs_file_inode_operations; - inode->i_fop = &ufs_file_operations; - inode->i_mapping->a_ops = &ufs_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &ufs_dir_inode_operations; - inode->i_fop = &ufs_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - if (!inode->i_blocks) - inode->i_op = &ufs_fast_symlink_inode_operations; - else { - inode->i_op = &page_symlink_inode_operations; - inode->i_mapping->a_ops = &ufs_aops; - } - } else /* TODO : here ...*/ - init_special_inode(inode, inode->i_mode, - ufs_get_inode_dev(sb, ufsi)); + ufs_set_inode_ops(inode); brelse(bh); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return; + +bad_inode: + make_bad_inode(inode); } static int ufs_update_inode(struct inode * inode, int do_sync) @@ -724,7 +762,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync) unsigned i; unsigned flags; - UFSD(("ENTER, ino %lu\n", inode->i_ino)) + UFSD("ENTER, ino %lu\n", inode->i_ino); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -785,7 +823,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync) sync_dirty_buffer(bh); brelse (bh); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return 0; } @@ -805,14 +843,17 @@ int ufs_sync_inode (struct inode *inode) void ufs_delete_inode (struct inode * inode) { + loff_t old_i_size; + truncate_inode_pages(&inode->i_data, 0); /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ lock_kernel(); mark_inode_dirty(inode); ufs_update_inode(inode, IS_SYNC(inode)); + old_i_size = inode->i_size; inode->i_size = 0; - if (inode->i_blocks) - ufs_truncate (inode); + if (inode->i_blocks && ufs_truncate(inode, old_i_size)) + ufs_warning(inode->i_sb, __FUNCTION__, "ufs_truncate failed\n"); ufs_free_inode (inode); unlock_kernel(); } diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 8d5f98a01c74..abd5f23a426d 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -1,6 +1,9 @@ /* * linux/fs/ufs/namei.c * + * Migration to usage of "page cache" on May 2006 by + * Evgeniy Dushistov <dushistov@mail.ru> based on ext2 code base. + * * Copyright (C) 1998 * Daniel Pirkl <daniel.pirkl@email.cz> * Charles University, Faculty of Mathematics and Physics @@ -28,21 +31,9 @@ #include <linux/fs.h> #include <linux/ufs_fs.h> #include <linux/smp_lock.h> -#include <linux/buffer_head.h> #include "swab.h" /* will go away - see comment in mknod() */ #include "util.h" -/* -#undef UFS_NAMEI_DEBUG -*/ -#define UFS_NAMEI_DEBUG - -#ifdef UFS_NAMEI_DEBUG -#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode) { int err = ufs_add_link(dentry, inode); @@ -88,8 +79,13 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru static int ufs_create (struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd) { - struct inode * inode = ufs_new_inode(dir, mode); - int err = PTR_ERR(inode); + struct inode *inode; + int err; + + UFSD("BEGIN\n"); + inode = ufs_new_inode(dir, mode); + err = PTR_ERR(inode); + if (!IS_ERR(inode)) { inode->i_op = &ufs_file_inode_operations; inode->i_fop = &ufs_file_operations; @@ -99,6 +95,7 @@ static int ufs_create (struct inode * dir, struct dentry * dentry, int mode, err = ufs_add_nondir(dentry, inode); unlock_kernel(); } + UFSD("END: err=%d\n", err); return err; } @@ -205,6 +202,7 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode) inode->i_op = &ufs_dir_inode_operations; inode->i_fop = &ufs_dir_operations; + inode->i_mapping->a_ops = &ufs_aops; inode_inc_link_count(inode); @@ -231,19 +229,18 @@ out_dir: goto out; } -static int ufs_unlink(struct inode * dir, struct dentry *dentry) +static int ufs_unlink(struct inode *dir, struct dentry *dentry) { struct inode * inode = dentry->d_inode; - struct buffer_head * bh; - struct ufs_dir_entry * de; + struct ufs_dir_entry *de; + struct page *page; int err = -ENOENT; - lock_kernel(); - de = ufs_find_entry (dentry, &bh); + de = ufs_find_entry(dir, dentry, &page); if (!de) goto out; - err = ufs_delete_entry (dir, de, bh); + err = ufs_delete_entry(dir, de, page); if (err) goto out; @@ -251,7 +248,6 @@ static int ufs_unlink(struct inode * dir, struct dentry *dentry) inode_dec_link_count(inode); err = 0; out: - unlock_kernel(); return err; } @@ -273,42 +269,42 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry) return err; } -static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, - struct inode * new_dir, struct dentry * new_dentry ) +static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; - struct buffer_head *dir_bh = NULL; - struct ufs_dir_entry *dir_de = NULL; - struct buffer_head *old_bh; + struct page *dir_page = NULL; + struct ufs_dir_entry * dir_de = NULL; + struct page *old_page; struct ufs_dir_entry *old_de; int err = -ENOENT; - lock_kernel(); - old_de = ufs_find_entry (old_dentry, &old_bh); + old_de = ufs_find_entry(old_dir, old_dentry, &old_page); if (!old_de) goto out; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; - dir_de = ufs_dotdot(old_inode, &dir_bh); + dir_de = ufs_dotdot(old_inode, &dir_page); if (!dir_de) goto out_old; } if (new_inode) { - struct buffer_head *new_bh; + struct page *new_page; struct ufs_dir_entry *new_de; err = -ENOTEMPTY; - if (dir_de && !ufs_empty_dir (new_inode)) + if (dir_de && !ufs_empty_dir(new_inode)) goto out_dir; + err = -ENOENT; - new_de = ufs_find_entry (new_dentry, &new_bh); + new_de = ufs_find_entry(new_dir, new_dentry, &new_page); if (!new_de) goto out_dir; inode_inc_link_count(old_inode); - ufs_set_link(new_dir, new_de, new_bh, old_inode); + ufs_set_link(new_dir, new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) new_inode->i_nlink--; @@ -329,24 +325,32 @@ static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry, inode_inc_link_count(new_dir); } - ufs_delete_entry (old_dir, old_de, old_bh); + /* + * Like most other Unix systems, set the ctime for inodes on a + * rename. + * inode_dec_link_count() will mark the inode dirty. + */ + old_inode->i_ctime = CURRENT_TIME_SEC; + ufs_delete_entry(old_dir, old_de, old_page); inode_dec_link_count(old_inode); if (dir_de) { - ufs_set_link(old_inode, dir_de, dir_bh, new_dir); + ufs_set_link(old_inode, dir_de, dir_page, new_dir); inode_dec_link_count(old_dir); } - unlock_kernel(); return 0; + out_dir: - if (dir_de) - brelse(dir_bh); + if (dir_de) { + kunmap(dir_page); + page_cache_release(dir_page); + } out_old: - brelse (old_bh); + kunmap(old_page); + page_cache_release(old_page); out: - unlock_kernel(); return err; } diff --git a/fs/ufs/super.c b/fs/ufs/super.c index db98a4c71e63..19a99726e58d 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -64,7 +64,6 @@ */ -#include <linux/config.h> #include <linux/module.h> #include <linux/bitops.h> @@ -90,95 +89,84 @@ #include "swab.h" #include "util.h" -#undef UFS_SUPER_DEBUG -#undef UFS_SUPER_DEBUG_MORE - - -#undef UFS_SUPER_DEBUG_MORE -#ifdef UFS_SUPER_DEBUG -#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - -#ifdef UFS_SUPER_DEBUG_MORE +#ifdef CONFIG_UFS_DEBUG /* * Print contents of ufs_super_block, useful for debugging */ -void ufs_print_super_stuff(struct super_block *sb, - struct ufs_super_block_first * usb1, - struct ufs_super_block_second * usb2, - struct ufs_super_block_third * usb3) +static void ufs_print_super_stuff(struct super_block *sb, unsigned flags, + struct ufs_super_block_first *usb1, + struct ufs_super_block_second *usb2, + struct ufs_super_block_third *usb3) { printk("ufs_print_super_stuff\n"); - printk("size of usb: %u\n", sizeof(struct ufs_super_block)); - printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb3->fs_magic)); - printk(" sblkno: %u\n", fs32_to_cpu(sb, usb1->fs_sblkno)); - printk(" cblkno: %u\n", fs32_to_cpu(sb, usb1->fs_cblkno)); - printk(" iblkno: %u\n", fs32_to_cpu(sb, usb1->fs_iblkno)); - printk(" dblkno: %u\n", fs32_to_cpu(sb, usb1->fs_dblkno)); - printk(" cgoffset: %u\n", fs32_to_cpu(sb, usb1->fs_cgoffset)); - printk(" ~cgmask: 0x%x\n", ~fs32_to_cpu(sb, usb1->fs_cgmask)); - printk(" size: %u\n", fs32_to_cpu(sb, usb1->fs_size)); - printk(" dsize: %u\n", fs32_to_cpu(sb, usb1->fs_dsize)); - printk(" ncg: %u\n", fs32_to_cpu(sb, usb1->fs_ncg)); - printk(" bsize: %u\n", fs32_to_cpu(sb, usb1->fs_bsize)); - printk(" fsize: %u\n", fs32_to_cpu(sb, usb1->fs_fsize)); - printk(" frag: %u\n", fs32_to_cpu(sb, usb1->fs_frag)); - printk(" fragshift: %u\n", fs32_to_cpu(sb, usb1->fs_fragshift)); - printk(" ~fmask: %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask)); - printk(" fshift: %u\n", fs32_to_cpu(sb, usb1->fs_fshift)); - printk(" sbsize: %u\n", fs32_to_cpu(sb, usb1->fs_sbsize)); - printk(" spc: %u\n", fs32_to_cpu(sb, usb1->fs_spc)); - printk(" cpg: %u\n", fs32_to_cpu(sb, usb1->fs_cpg)); - printk(" ipg: %u\n", fs32_to_cpu(sb, usb1->fs_ipg)); - printk(" fpg: %u\n", fs32_to_cpu(sb, usb1->fs_fpg)); - printk(" csaddr: %u\n", fs32_to_cpu(sb, usb1->fs_csaddr)); - printk(" cssize: %u\n", fs32_to_cpu(sb, usb1->fs_cssize)); - printk(" cgsize: %u\n", fs32_to_cpu(sb, usb1->fs_cgsize)); - printk(" fstodb: %u\n", fs32_to_cpu(sb, usb1->fs_fsbtodb)); - printk(" contigsumsize: %d\n", fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize)); - printk(" postblformat: %u\n", fs32_to_cpu(sb, usb3->fs_postblformat)); - printk(" nrpos: %u\n", fs32_to_cpu(sb, usb3->fs_nrpos)); - printk(" ndir %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir)); - printk(" nifree %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree)); - printk(" nbfree %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)); - printk(" nffree %u\n", fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree)); - printk("\n"); -} - -/* - * Print contents of ufs2 ufs_super_block, useful for debugging - */ -void ufs2_print_super_stuff( - struct super_block *sb, - struct ufs_super_block *usb) -{ - printk("ufs_print_super_stuff\n"); - printk("size of usb: %u\n", sizeof(struct ufs_super_block)); - printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb->fs_magic)); - printk(" fs_size: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size)); - printk(" fs_dsize: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize)); - printk(" bsize: %u\n", fs32_to_cpu(usb, usb->fs_bsize)); - printk(" fsize: %u\n", fs32_to_cpu(usb, usb->fs_fsize)); - printk(" fs_volname: %s\n", usb->fs_u11.fs_u2.fs_volname); - printk(" fs_fsmnt: %s\n", usb->fs_u11.fs_u2.fs_fsmnt); - printk(" fs_sblockloc: %u\n",fs64_to_cpu(sb, - usb->fs_u11.fs_u2.fs_sblockloc)); - printk(" cs_ndir(No of dirs): %u\n",fs64_to_cpu(sb, - usb->fs_u11.fs_u2.fs_cstotal.cs_ndir)); - printk(" cs_nbfree(No of free blocks): %u\n",fs64_to_cpu(sb, - usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)); + printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb3->fs_magic)); + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + printk(" fs_size: %llu\n", (unsigned long long) + fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size)); + printk(" fs_dsize: %llu\n", (unsigned long long) + fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize)); + printk(" bsize: %u\n", + fs32_to_cpu(sb, usb1->fs_bsize)); + printk(" fsize: %u\n", + fs32_to_cpu(sb, usb1->fs_fsize)); + printk(" fs_volname: %s\n", usb2->fs_un.fs_u2.fs_volname); + printk(" fs_sblockloc: %llu\n", (unsigned long long) + fs64_to_cpu(sb, usb2->fs_un.fs_u2.fs_sblockloc)); + printk(" cs_ndir(No of dirs): %llu\n", (unsigned long long) + fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir)); + printk(" cs_nbfree(No of free blocks): %llu\n", + (unsigned long long) + fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree)); + } else { + printk(" sblkno: %u\n", fs32_to_cpu(sb, usb1->fs_sblkno)); + printk(" cblkno: %u\n", fs32_to_cpu(sb, usb1->fs_cblkno)); + printk(" iblkno: %u\n", fs32_to_cpu(sb, usb1->fs_iblkno)); + printk(" dblkno: %u\n", fs32_to_cpu(sb, usb1->fs_dblkno)); + printk(" cgoffset: %u\n", + fs32_to_cpu(sb, usb1->fs_cgoffset)); + printk(" ~cgmask: 0x%x\n", + ~fs32_to_cpu(sb, usb1->fs_cgmask)); + printk(" size: %u\n", fs32_to_cpu(sb, usb1->fs_size)); + printk(" dsize: %u\n", fs32_to_cpu(sb, usb1->fs_dsize)); + printk(" ncg: %u\n", fs32_to_cpu(sb, usb1->fs_ncg)); + printk(" bsize: %u\n", fs32_to_cpu(sb, usb1->fs_bsize)); + printk(" fsize: %u\n", fs32_to_cpu(sb, usb1->fs_fsize)); + printk(" frag: %u\n", fs32_to_cpu(sb, usb1->fs_frag)); + printk(" fragshift: %u\n", + fs32_to_cpu(sb, usb1->fs_fragshift)); + printk(" ~fmask: %u\n", ~fs32_to_cpu(sb, usb1->fs_fmask)); + printk(" fshift: %u\n", fs32_to_cpu(sb, usb1->fs_fshift)); + printk(" sbsize: %u\n", fs32_to_cpu(sb, usb1->fs_sbsize)); + printk(" spc: %u\n", fs32_to_cpu(sb, usb1->fs_spc)); + printk(" cpg: %u\n", fs32_to_cpu(sb, usb1->fs_cpg)); + printk(" ipg: %u\n", fs32_to_cpu(sb, usb1->fs_ipg)); + printk(" fpg: %u\n", fs32_to_cpu(sb, usb1->fs_fpg)); + printk(" csaddr: %u\n", fs32_to_cpu(sb, usb1->fs_csaddr)); + printk(" cssize: %u\n", fs32_to_cpu(sb, usb1->fs_cssize)); + printk(" cgsize: %u\n", fs32_to_cpu(sb, usb1->fs_cgsize)); + printk(" fstodb: %u\n", + fs32_to_cpu(sb, usb1->fs_fsbtodb)); + printk(" nrpos: %u\n", fs32_to_cpu(sb, usb3->fs_nrpos)); + printk(" ndir %u\n", + fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir)); + printk(" nifree %u\n", + fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree)); + printk(" nbfree %u\n", + fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)); + printk(" nffree %u\n", + fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree)); + } printk("\n"); } /* * Print contents of ufs_cylinder_group, useful for debugging */ -void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group *cg) +static void ufs_print_cylinder_stuff(struct super_block *sb, + struct ufs_cylinder_group *cg) { printk("\nufs_print_cylinder_stuff\n"); - printk("size of ucg: %u\n", sizeof(struct ufs_cylinder_group)); + printk("size of ucg: %zu\n", sizeof(struct ufs_cylinder_group)); printk(" magic: %x\n", fs32_to_cpu(sb, cg->cg_magic)); printk(" time: %u\n", fs32_to_cpu(sb, cg->cg_time)); printk(" cgx: %u\n", fs32_to_cpu(sb, cg->cg_cgx)); @@ -202,12 +190,18 @@ void ufs_print_cylinder_stuff(struct super_block *sb, struct ufs_cylinder_group printk(" iuseoff: %u\n", fs32_to_cpu(sb, cg->cg_iusedoff)); printk(" freeoff: %u\n", fs32_to_cpu(sb, cg->cg_freeoff)); printk(" nextfreeoff: %u\n", fs32_to_cpu(sb, cg->cg_nextfreeoff)); - printk(" clustersumoff %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff)); - printk(" clusteroff %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff)); - printk(" nclusterblks %u\n", fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks)); + printk(" clustersumoff %u\n", + fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clustersumoff)); + printk(" clusteroff %u\n", + fs32_to_cpu(sb, cg->cg_u.cg_44.cg_clusteroff)); + printk(" nclusterblks %u\n", + fs32_to_cpu(sb, cg->cg_u.cg_44.cg_nclusterblks)); printk("\n"); } -#endif /* UFS_SUPER_DEBUG_MORE */ +#else +# define ufs_print_super_stuff(sb, flags, usb1, usb2, usb3) /**/ +# define ufs_print_cylinder_stuff(sb, cg) /**/ +#endif /* CONFIG_UFS_DEBUG */ static struct super_operations ufs_super_ops; @@ -225,7 +219,7 @@ void ufs_error (struct super_block * sb, const char * function, if (!(sb->s_flags & MS_RDONLY)) { usb1->fs_clean = UFS_FSBAD; - ubh_mark_buffer_dirty(USPI_UBH); + ubh_mark_buffer_dirty(USPI_UBH(uspi)); sb->s_dirt = 1; sb->s_flags |= MS_RDONLY; } @@ -257,7 +251,7 @@ void ufs_panic (struct super_block * sb, const char * function, if (!(sb->s_flags & MS_RDONLY)) { usb1->fs_clean = UFS_FSBAD; - ubh_mark_buffer_dirty(USPI_UBH); + ubh_mark_buffer_dirty(USPI_UBH(uspi)); sb->s_dirt = 1; } va_start (args, fmt); @@ -309,7 +303,7 @@ static int ufs_parse_options (char * options, unsigned * mount_options) { char * p; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); if (!options) return 1; @@ -386,27 +380,57 @@ static int ufs_parse_options (char * options, unsigned * mount_options) } /* + * Diffrent types of UFS hold fs_cstotal in different + * places, and use diffrent data structure for it. + * To make things simplier we just copy fs_cstotal to ufs_sb_private_info + */ +static void ufs_setup_cstotal(struct super_block *sb) +{ + struct ufs_sb_info *sbi = UFS_SB(sb); + struct ufs_sb_private_info *uspi = sbi->s_uspi; + struct ufs_super_block_first *usb1; + struct ufs_super_block_second *usb2; + struct ufs_super_block_third *usb3; + unsigned mtype = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE; + + UFSD("ENTER, mtype=%u\n", mtype); + usb1 = ubh_get_usb_first(uspi); + usb2 = ubh_get_usb_second(uspi); + usb3 = ubh_get_usb_third(uspi); + + if ((mtype == UFS_MOUNT_UFSTYPE_44BSD && + (usb1->fs_flags & UFS_FLAGS_UPDATED)) || + mtype == UFS_MOUNT_UFSTYPE_UFS2) { + /*we have statistic in different place, then usual*/ + uspi->cs_total.cs_ndir = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_ndir); + uspi->cs_total.cs_nbfree = fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree); + uspi->cs_total.cs_nifree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nifree); + uspi->cs_total.cs_nffree = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nffree); + } else { + uspi->cs_total.cs_ndir = fs32_to_cpu(sb, usb1->fs_cstotal.cs_ndir); + uspi->cs_total.cs_nbfree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree); + uspi->cs_total.cs_nifree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree); + uspi->cs_total.cs_nffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree); + } + UFSD("EXIT\n"); +} + +/* * Read on-disk structures associated with cylinder groups */ -static int ufs_read_cylinder_structures (struct super_block *sb) +static int ufs_read_cylinder_structures(struct super_block *sb) { - struct ufs_sb_info * sbi = UFS_SB(sb); - struct ufs_sb_private_info * uspi; - struct ufs_super_block *usb; + struct ufs_sb_info *sbi = UFS_SB(sb); + struct ufs_sb_private_info *uspi = sbi->s_uspi; + unsigned flags = sbi->s_flags; struct ufs_buffer_head * ubh; unsigned char * base, * space; unsigned size, blks, i; - unsigned flags = 0; - - UFSD(("ENTER\n")) - - uspi = sbi->s_uspi; + struct ufs_super_block_third *usb3; - usb = (struct ufs_super_block *) - ((struct ufs_buffer_head *)uspi)->bh[0]->b_data; + UFSD("ENTER\n"); - flags = UFS_SB(sb)->s_flags; - + usb3 = ubh_get_usb_third(uspi); /* * Read cs structures from (usually) first data block * on the device. @@ -424,7 +448,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb) if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) ubh = ubh_bread(sb, - fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size); + fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr) + i, size); else ubh = ubh_bread(sb, uspi->s_csaddr + i, size); @@ -451,14 +475,13 @@ static int ufs_read_cylinder_structures (struct super_block *sb) sbi->s_cgno[i] = UFS_CGNO_EMPTY; } for (i = 0; i < uspi->s_ncg; i++) { - UFSD(("read cg %u\n", i)) + UFSD("read cg %u\n", i); if (!(sbi->s_ucg[i] = sb_bread(sb, ufs_cgcmin(i)))) goto failed; if (!ufs_cg_chkmagic (sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data)) goto failed; -#ifdef UFS_SUPER_DEBUG_MORE + ufs_print_cylinder_stuff(sb, (struct ufs_cylinder_group *) sbi->s_ucg[i]->b_data); -#endif } for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) { if (!(sbi->s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL))) @@ -466,7 +489,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb) sbi->s_cgno[i] = UFS_CGNO_EMPTY; } sbi->s_cg_loaded = 0; - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return 1; failed: @@ -479,26 +502,69 @@ failed: for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) kfree (sbi->s_ucpi[i]); } - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return 0; } /* - * Put on-disk structures associated with cylinder groups and - * write them back to disk + * Sync our internal copy of fs_cstotal with disk */ -static void ufs_put_cylinder_structures (struct super_block *sb) +static void ufs_put_cstotal(struct super_block *sb) { - struct ufs_sb_info * sbi = UFS_SB(sb); - struct ufs_sb_private_info * uspi; + unsigned mtype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + struct ufs_super_block_first *usb1; + struct ufs_super_block_second *usb2; + struct ufs_super_block_third *usb3; + + UFSD("ENTER\n"); + usb1 = ubh_get_usb_first(uspi); + usb2 = ubh_get_usb_second(uspi); + usb3 = ubh_get_usb_third(uspi); + + if ((mtype == UFS_MOUNT_UFSTYPE_44BSD && + (usb1->fs_flags & UFS_FLAGS_UPDATED)) || + mtype == UFS_MOUNT_UFSTYPE_UFS2) { + /*we have statistic in different place, then usual*/ + usb2->fs_un.fs_u2.cs_ndir = + cpu_to_fs64(sb, uspi->cs_total.cs_ndir); + usb2->fs_un.fs_u2.cs_nbfree = + cpu_to_fs64(sb, uspi->cs_total.cs_nbfree); + usb3->fs_un1.fs_u2.cs_nifree = + cpu_to_fs64(sb, uspi->cs_total.cs_nifree); + usb3->fs_un1.fs_u2.cs_nffree = + cpu_to_fs64(sb, uspi->cs_total.cs_nffree); + } else { + usb1->fs_cstotal.cs_ndir = + cpu_to_fs32(sb, uspi->cs_total.cs_ndir); + usb1->fs_cstotal.cs_nbfree = + cpu_to_fs32(sb, uspi->cs_total.cs_nbfree); + usb1->fs_cstotal.cs_nifree = + cpu_to_fs32(sb, uspi->cs_total.cs_nifree); + usb1->fs_cstotal.cs_nffree = + cpu_to_fs32(sb, uspi->cs_total.cs_nffree); + } + ubh_mark_buffer_dirty(USPI_UBH(uspi)); + UFSD("EXIT\n"); +} + +/** + * ufs_put_super_internal() - put on-disk intrenal structures + * @sb: pointer to super_block structure + * Put on-disk structures associated with cylinder groups + * and write them back to disk, also update cs_total on disk + */ +static void ufs_put_super_internal(struct super_block *sb) +{ + struct ufs_sb_info *sbi = UFS_SB(sb); + struct ufs_sb_private_info *uspi = sbi->s_uspi; struct ufs_buffer_head * ubh; unsigned char * base, * space; unsigned blks, size, i; - - UFSD(("ENTER\n")) - - uspi = sbi->s_uspi; + + UFSD("ENTER\n"); + ufs_put_cstotal(sb); size = uspi->s_cssize; blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; base = space = (char*) sbi->s_csp; @@ -523,7 +589,7 @@ static void ufs_put_cylinder_structures (struct super_block *sb) brelse (sbi->s_ucg[i]); kfree (sbi->s_ucg); kfree (base); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); } static int ufs_fill_super(struct super_block *sb, void *data, int silent) @@ -533,7 +599,6 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) struct ufs_super_block_first * usb1; struct ufs_super_block_second * usb2; struct ufs_super_block_third * usb3; - struct ufs_super_block *usb; struct ufs_buffer_head * ubh; struct inode *inode; unsigned block_size, super_block_size; @@ -544,7 +609,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) ubh = NULL; flags = 0; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL); if (!sbi) @@ -552,7 +617,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) sb->s_fs_info = sbi; memset(sbi, 0, sizeof(struct ufs_sb_info)); - UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY))) + UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY)); #ifndef CONFIG_UFS_FS_WRITE if (!(sb->s_flags & MS_RDONLY)) { @@ -593,7 +658,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) the rules */ switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) { case UFS_MOUNT_UFSTYPE_44BSD: - UFSD(("ufstype=44bsd\n")) + UFSD("ufstype=44bsd\n"); uspi->s_fsize = block_size = 512; uspi->s_fmask = ~(512 - 1); uspi->s_fshift = 9; @@ -602,7 +667,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; break; case UFS_MOUNT_UFSTYPE_UFS2: - UFSD(("ufstype=ufs2\n")); + UFSD("ufstype=ufs2\n"); super_block_offset=SBLOCK_UFS2; uspi->s_fsize = block_size = 512; uspi->s_fmask = ~(512 - 1); @@ -617,7 +682,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_SUN: - UFSD(("ufstype=sun\n")) + UFSD("ufstype=sun\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; @@ -628,7 +693,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_SUNx86: - UFSD(("ufstype=sunx86\n")) + UFSD("ufstype=sunx86\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; @@ -639,7 +704,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_OLD: - UFSD(("ufstype=old\n")) + UFSD("ufstype=old\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; @@ -654,7 +719,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP: - UFSD(("ufstype=nextstep\n")) + UFSD("ufstype=nextstep\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; @@ -669,7 +734,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD: - UFSD(("ufstype=nextstep-cd\n")) + UFSD("ufstype=nextstep-cd\n"); uspi->s_fsize = block_size = 2048; uspi->s_fmask = ~(2048 - 1); uspi->s_fshift = 11; @@ -684,7 +749,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_OPENSTEP: - UFSD(("ufstype=openstep\n")) + UFSD("ufstype=openstep\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; @@ -699,7 +764,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_HP: - UFSD(("ufstype=hp\n")) + UFSD("ufstype=hp\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); uspi->s_fshift = 10; @@ -737,8 +802,6 @@ again: usb1 = ubh_get_usb_first(uspi); usb2 = ubh_get_usb_second(uspi); usb3 = ubh_get_usb_third(uspi); - usb = (struct ufs_super_block *) - ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ; /* * Check ufs magic number @@ -820,16 +883,12 @@ magic_found: ubh = NULL; block_size = uspi->s_fsize; super_block_size = uspi->s_sbsize; - UFSD(("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size)) + UFSD("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size); goto again; } -#ifdef UFS_SUPER_DEBUG_MORE - if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) - ufs2_print_super_stuff(sb,usb); - else - ufs_print_super_stuff(sb, usb1, usb2, usb3); -#endif + + ufs_print_super_stuff(sb, flags, usb1, usb2, usb3); /* * Check, if file system was correctly unmounted. @@ -842,13 +901,13 @@ magic_found: (ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time))))) { switch(usb1->fs_clean) { case UFS_FSCLEAN: - UFSD(("fs is clean\n")) + UFSD("fs is clean\n"); break; case UFS_FSSTABLE: - UFSD(("fs is stable\n")) + UFSD("fs is stable\n"); break; case UFS_FSOSF1: - UFSD(("fs is DEC OSF/1\n")) + UFSD("fs is DEC OSF/1\n"); break; case UFS_FSACTIVE: printk("ufs_read_super: fs is active\n"); @@ -863,8 +922,7 @@ magic_found: sb->s_flags |= MS_RDONLY; break; } - } - else { + } else { printk("ufs_read_super: fs needs fsck\n"); sb->s_flags |= MS_RDONLY; } @@ -884,10 +942,9 @@ magic_found: uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask); if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { - uspi->s_u2_size = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size); - uspi->s_u2_dsize = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize); - } - else { + uspi->s_u2_size = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size); + uspi->s_u2_dsize = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize); + } else { uspi->s_size = fs32_to_cpu(sb, usb1->fs_size); uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize); } @@ -901,8 +958,8 @@ magic_found: uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask); uspi->s_bshift = fs32_to_cpu(sb, usb1->fs_bshift); uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift); - UFSD(("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift, - uspi->s_fshift)); + UFSD("uspi->s_bshift = %d,uspi->s_fshift = %d", uspi->s_bshift, + uspi->s_fshift); uspi->s_fpbshift = fs32_to_cpu(sb, usb1->fs_fragshift); uspi->s_fsbtodb = fs32_to_cpu(sb, usb1->fs_fsbtodb); /* s_sbsize already set */ @@ -922,8 +979,8 @@ magic_found: uspi->s_spc = fs32_to_cpu(sb, usb1->fs_spc); uspi->s_ipg = fs32_to_cpu(sb, usb1->fs_ipg); uspi->s_fpg = fs32_to_cpu(sb, usb1->fs_fpg); - uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_cpc); - uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_contigsumsize); + uspi->s_cpc = fs32_to_cpu(sb, usb2->fs_un.fs_u1.fs_cpc); + uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_contigsumsize); uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3); uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3); uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat); @@ -935,12 +992,11 @@ magic_found: * Compute another frequently used values */ uspi->s_fpbmask = uspi->s_fpb - 1; - if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) uspi->s_apbshift = uspi->s_bshift - 3; - } - else { + else uspi->s_apbshift = uspi->s_bshift - 2; - } + uspi->s_2apbshift = uspi->s_apbshift * 2; uspi->s_3apbshift = uspi->s_apbshift * 3; uspi->s_apb = 1 << uspi->s_apbshift; @@ -956,7 +1012,7 @@ magic_found: if ((sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_44BSD) uspi->s_maxsymlinklen = - fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_maxsymlinklen); + fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen); sbi->s_flags = flags; @@ -967,7 +1023,7 @@ magic_found: if (!sb->s_root) goto dalloc_failed; - + ufs_setup_cstotal(sb); /* * Read cylinder group structures */ @@ -975,7 +1031,7 @@ magic_found: if (!ufs_read_cylinder_structures(sb)) goto failed; - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return 0; dalloc_failed: @@ -986,15 +1042,16 @@ failed: kfree (uspi); kfree(sbi); sb->s_fs_info = NULL; - UFSD(("EXIT (FAILED)\n")) + UFSD("EXIT (FAILED)\n"); return -EINVAL; failed_nomem: - UFSD(("EXIT (NOMEM)\n")) + UFSD("EXIT (NOMEM)\n"); return -ENOMEM; } -static void ufs_write_super (struct super_block *sb) { +static void ufs_write_super(struct super_block *sb) +{ struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_super_block_third * usb3; @@ -1002,7 +1059,7 @@ static void ufs_write_super (struct super_block *sb) { lock_kernel(); - UFSD(("ENTER\n")) + UFSD("ENTER\n"); flags = UFS_SB(sb)->s_flags; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); @@ -1014,26 +1071,27 @@ static void ufs_write_super (struct super_block *sb) { || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(sb, usb1, usb3, UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); - ubh_mark_buffer_dirty (USPI_UBH); + ufs_put_cstotal(sb); } sb->s_dirt = 0; - UFSD(("EXIT\n")) + UFSD("EXIT\n"); unlock_kernel(); } -static void ufs_put_super (struct super_block *sb) +static void ufs_put_super(struct super_block *sb) { struct ufs_sb_info * sbi = UFS_SB(sb); - UFSD(("ENTER\n")) + UFSD("ENTER\n"); if (!(sb->s_flags & MS_RDONLY)) - ufs_put_cylinder_structures (sb); + ufs_put_super_internal(sb); ubh_brelse_uspi (sbi->s_uspi); kfree (sbi->s_uspi); kfree (sbi); sb->s_fs_info = NULL; + UFSD("EXIT\n"); return; } @@ -1062,8 +1120,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) return -EINVAL; if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) { new_mount_opt |= ufstype; - } - else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { + } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { printk("ufstype can't be changed during remount\n"); return -EINVAL; } @@ -1077,20 +1134,19 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) * fs was mouted as rw, remounting ro */ if (*mount_flags & MS_RDONLY) { - ufs_put_cylinder_structures(sb); + ufs_put_super_internal(sb); usb1->fs_time = cpu_to_fs32(sb, get_seconds()); if ((flags & UFS_ST_MASK) == UFS_ST_SUN || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(sb, usb1, usb3, UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); - ubh_mark_buffer_dirty (USPI_UBH); + ubh_mark_buffer_dirty (USPI_UBH(uspi)); sb->s_dirt = 0; sb->s_flags |= MS_RDONLY; - } + } else { /* * fs was mounted as ro, remounting rw */ - else { #ifndef CONFIG_UFS_FS_WRITE printk("ufs was compiled with read-only support, " "can't be mounted as read-write\n"); @@ -1102,7 +1158,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) printk("this ufstype is read-only supported\n"); return -EINVAL; } - if (!ufs_read_cylinder_structures (sb)) { + if (!ufs_read_cylinder_structures(sb)) { printk("failed during remounting\n"); return -EPERM; } @@ -1113,36 +1169,31 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) return 0; } -static int ufs_statfs (struct super_block *sb, struct kstatfs *buf) +static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct ufs_sb_private_info * uspi; - struct ufs_super_block_first * usb1; - struct ufs_super_block * usb; - unsigned flags = 0; + struct super_block *sb = dentry->d_sb; + struct ufs_sb_private_info *uspi= UFS_SB(sb)->s_uspi; + unsigned flags = UFS_SB(sb)->s_flags; + struct ufs_super_block_first *usb1; + struct ufs_super_block_second *usb2; + struct ufs_super_block_third *usb3; lock_kernel(); - uspi = UFS_SB(sb)->s_uspi; - usb1 = ubh_get_usb_first (uspi); - usb = (struct ufs_super_block *) - ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ; + usb1 = ubh_get_usb_first(uspi); + usb2 = ubh_get_usb_second(uspi); + usb3 = ubh_get_usb_third(uspi); - flags = UFS_SB(sb)->s_flags; if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { buf->f_type = UFS2_MAGIC; - buf->f_blocks = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize); - buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) + - fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree); - buf->f_ffree = fs64_to_cpu(sb, - usb->fs_u11.fs_u2.fs_cstotal.cs_nifree); - } - else { + buf->f_blocks = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_dsize); + } else { buf->f_type = UFS_MAGIC; buf->f_blocks = uspi->s_dsize; - buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) + - fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree); - buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree); } + buf->f_bfree = ufs_blkstofrags(uspi->cs_total.cs_nbfree) + + uspi->cs_total.cs_nffree; + buf->f_ffree = uspi->cs_total.cs_nifree; buf->f_bsize = sb->s_blocksize; buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree)) ? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0; @@ -1311,10 +1362,10 @@ out: #endif -static struct super_block *ufs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int ufs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super); + return get_sb_bdev(fs_type, flags, dev_name, data, ufs_fill_super, mnt); } static struct file_system_type ufs_fs_type = { diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 02e86291ef8a..c9b55872079b 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -49,14 +49,6 @@ #include "swab.h" #include "util.h" -#undef UFS_TRUNCATE_DEBUG - -#ifdef UFS_TRUNCATE_DEBUG -#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - /* * Secure deletion currently doesn't work. It interacts very badly * with buffers shared with memory mappings, and for that reason @@ -82,7 +74,7 @@ static int ufs_trunc_direct (struct inode * inode) unsigned i, tmp; int retry; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -105,7 +97,7 @@ static int ufs_trunc_direct (struct inode * inode) block2 = ufs_fragstoblks (frag3); } - UFSD(("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4)) + UFSD("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4); if (frag1 >= frag2) goto next1; @@ -120,9 +112,8 @@ static int ufs_trunc_direct (struct inode * inode) frag1 = ufs_fragnum (frag1); frag2 = ufs_fragnum (frag2); - inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift; - mark_inode_dirty(inode); ufs_free_fragments (inode, tmp + frag1, frag2 - frag1); + mark_inode_dirty(inode); frag_to_free = tmp + frag1; next1: @@ -136,8 +127,7 @@ next1: continue; *p = 0; - inode->i_blocks -= uspi->s_nspb; - mark_inode_dirty(inode); + if (free_count == 0) { frag_to_free = tmp; free_count = uspi->s_fpb; @@ -148,6 +138,7 @@ next1: frag_to_free = tmp; free_count = uspi->s_fpb; } + mark_inode_dirty(inode); } if (free_count > 0) @@ -166,12 +157,12 @@ next1: frag4 = ufs_fragnum (frag4); *p = 0; - inode->i_blocks -= frag4 << uspi->s_nspfshift; - mark_inode_dirty(inode); + ufs_free_fragments (inode, tmp, frag4); + mark_inode_dirty(inode); next3: - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return retry; } @@ -186,7 +177,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) unsigned frag_to_free, free_count; int retry; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -227,7 +218,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) frag_to_free = tmp; free_count = uspi->s_fpb; } - inode->i_blocks -= uspi->s_nspb; + mark_inode_dirty(inode); } @@ -238,26 +229,21 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) if (*ubh_get_addr32(ind_ubh,i)) break; if (i >= uspi->s_apb) { - if (ubh_max_bcount(ind_ubh) != 1) { - retry = 1; - } - else { - tmp = fs32_to_cpu(sb, *p); - *p = 0; - inode->i_blocks -= uspi->s_nspb; - mark_inode_dirty(inode); - ufs_free_blocks (inode, tmp, uspi->s_fpb); - ubh_bforget(ind_ubh); - ind_ubh = NULL; - } + tmp = fs32_to_cpu(sb, *p); + *p = 0; + + ufs_free_blocks (inode, tmp, uspi->s_fpb); + mark_inode_dirty(inode); + ubh_bforget(ind_ubh); + ind_ubh = NULL; } if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) { - ubh_ll_rw_block (SWRITE, 1, &ind_ubh); + ubh_ll_rw_block(SWRITE, ind_ubh); ubh_wait_on_buffer (ind_ubh); } ubh_brelse (ind_ubh); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return retry; } @@ -271,7 +257,7 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p) __fs32 * dind; int retry = 0; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -306,25 +292,21 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p) if (*ubh_get_addr32 (dind_bh, i)) break; if (i >= uspi->s_apb) { - if (ubh_max_bcount(dind_bh) != 1) - retry = 1; - else { - tmp = fs32_to_cpu(sb, *p); - *p = 0; - inode->i_blocks -= uspi->s_nspb; - mark_inode_dirty(inode); - ufs_free_blocks (inode, tmp, uspi->s_fpb); - ubh_bforget(dind_bh); - dind_bh = NULL; - } + tmp = fs32_to_cpu(sb, *p); + *p = 0; + + ufs_free_blocks(inode, tmp, uspi->s_fpb); + mark_inode_dirty(inode); + ubh_bforget(dind_bh); + dind_bh = NULL; } if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) { - ubh_ll_rw_block (SWRITE, 1, &dind_bh); + ubh_ll_rw_block(SWRITE, dind_bh); ubh_wait_on_buffer (dind_bh); } ubh_brelse (dind_bh); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return retry; } @@ -339,7 +321,7 @@ static int ufs_trunc_tindirect (struct inode * inode) __fs32 * tind, * p; int retry; - UFSD(("ENTER\n")) + UFSD("ENTER\n"); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -370,45 +352,114 @@ static int ufs_trunc_tindirect (struct inode * inode) if (*ubh_get_addr32 (tind_bh, i)) break; if (i >= uspi->s_apb) { - if (ubh_max_bcount(tind_bh) != 1) - retry = 1; - else { - tmp = fs32_to_cpu(sb, *p); - *p = 0; - inode->i_blocks -= uspi->s_nspb; - mark_inode_dirty(inode); - ufs_free_blocks (inode, tmp, uspi->s_fpb); - ubh_bforget(tind_bh); - tind_bh = NULL; - } + tmp = fs32_to_cpu(sb, *p); + *p = 0; + + ufs_free_blocks(inode, tmp, uspi->s_fpb); + mark_inode_dirty(inode); + ubh_bforget(tind_bh); + tind_bh = NULL; } if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { - ubh_ll_rw_block (SWRITE, 1, &tind_bh); + ubh_ll_rw_block(SWRITE, tind_bh); ubh_wait_on_buffer (tind_bh); } ubh_brelse (tind_bh); - UFSD(("EXIT\n")) + UFSD("EXIT\n"); return retry; } - -void ufs_truncate (struct inode * inode) + +static int ufs_alloc_lastblock(struct inode *inode) { + int err = 0; + struct address_space *mapping = inode->i_mapping; + struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block * sb; - struct ufs_sb_private_info * uspi; - int retry; + unsigned lastfrag, i, end; + struct page *lastpage; + struct buffer_head *bh; + + lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift; + + if (!lastfrag) { + ufsi->i_lastfrag = 0; + goto out; + } + lastfrag--; + + lastpage = ufs_get_locked_page(mapping, lastfrag >> + (PAGE_CACHE_SHIFT - inode->i_blkbits)); + if (IS_ERR(lastpage)) { + err = -EIO; + goto out; + } + + end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1); + bh = page_buffers(lastpage); + for (i = 0; i < end; ++i) + bh = bh->b_this_page; + + if (!buffer_mapped(bh)) { + err = ufs_getfrag_block(inode, lastfrag, bh, 1); + + if (unlikely(err)) + goto out_unlock; + + if (buffer_new(bh)) { + clear_buffer_new(bh); + unmap_underlying_metadata(bh->b_bdev, + bh->b_blocknr); + /* + * we do not zeroize fragment, because of + * if it maped to hole, it already contains zeroes + */ + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + set_page_dirty(lastpage); + } + } +out_unlock: + ufs_put_locked_page(lastpage); +out: + return err; +} + +int ufs_truncate(struct inode *inode, loff_t old_i_size) +{ + struct ufs_inode_info *ufsi = UFS_I(inode); + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + int retry, err = 0; - UFSD(("ENTER\n")) - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; + UFSD("ENTER\n"); - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) - return; + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; + return -EPERM; + + if (inode->i_size > old_i_size) { + /* + * if we expand file we should care about + * allocation of block for last byte first of all + */ + err = ufs_alloc_lastblock(inode); + + if (err) { + i_size_write(inode, old_i_size); + goto out; + } + /* + * go away, because of we expand file, and we do not + * need free blocks, and zeroizes page + */ + lock_kernel(); + goto almost_end; + } - block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); + block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); lock_kernel(); while (1) { @@ -426,9 +477,58 @@ void ufs_truncate (struct inode * inode) yield(); } + if (inode->i_size < old_i_size) { + /* + * now we should have enough space + * to allocate block for last byte + */ + err = ufs_alloc_lastblock(inode); + if (err) + /* + * looks like all the same - we have no space, + * but we truncate file already + */ + inode->i_size = (ufsi->i_lastfrag - 1) * uspi->s_fsize; + } +almost_end: inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - ufsi->i_lastfrag = DIRECT_FRAGMENT; unlock_kernel(); mark_inode_dirty(inode); - UFSD(("EXIT\n")) +out: + UFSD("EXIT: err %d\n", err); + return err; } + + +/* + * We don't define our `inode->i_op->truncate', and call it here, + * because of: + * - there is no way to know old size + * - there is no way inform user about error, if it happens in `truncate' + */ +static int ufs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + unsigned int ia_valid = attr->ia_valid; + int error; + + error = inode_change_ok(inode, attr); + if (error) + return error; + + if (ia_valid & ATTR_SIZE && + attr->ia_size != i_size_read(inode)) { + loff_t old_i_size = inode->i_size; + error = vmtruncate(inode, attr->ia_size); + if (error) + return error; + error = ufs_truncate(inode, old_i_size); + if (error) + return error; + } + return inode_setattr(inode, attr); +} + +struct inode_operations ufs_file_inode_operations = { + .setattr = ufs_setattr, +}; diff --git a/fs/ufs/util.c b/fs/ufs/util.c index 59acc8f073ac..337cf2c46d10 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c @@ -14,15 +14,6 @@ #include "swab.h" #include "util.h" -#undef UFS_UTILS_DEBUG - -#ifdef UFS_UTILS_DEBUG -#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; -#else -#define UFSD(x) -#endif - - struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi, struct super_block *sb, u64 fragment, u64 size) { @@ -63,17 +54,17 @@ struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi, count = size >> uspi->s_fshift; if (count <= 0 || count > UFS_MAXFRAG) return NULL; - USPI_UBH->fragment = fragment; - USPI_UBH->count = count; + USPI_UBH(uspi)->fragment = fragment; + USPI_UBH(uspi)->count = count; for (i = 0; i < count; i++) - if (!(USPI_UBH->bh[i] = sb_bread(sb, fragment + i))) + if (!(USPI_UBH(uspi)->bh[i] = sb_bread(sb, fragment + i))) goto failed; for (; i < UFS_MAXFRAG; i++) - USPI_UBH->bh[i] = NULL; - return USPI_UBH; + USPI_UBH(uspi)->bh[i] = NULL; + return USPI_UBH(uspi); failed: for (j = 0; j < i; j++) - brelse (USPI_UBH->bh[j]); + brelse (USPI_UBH(uspi)->bh[j]); return NULL; } @@ -90,11 +81,11 @@ void ubh_brelse (struct ufs_buffer_head * ubh) void ubh_brelse_uspi (struct ufs_sb_private_info * uspi) { unsigned i; - if (!USPI_UBH) + if (!USPI_UBH(uspi)) return; - for ( i = 0; i < USPI_UBH->count; i++ ) { - brelse (USPI_UBH->bh[i]); - USPI_UBH->bh[i] = NULL; + for ( i = 0; i < USPI_UBH(uspi)->count; i++ ) { + brelse (USPI_UBH(uspi)->bh[i]); + USPI_UBH(uspi)->bh[i] = NULL; } } @@ -121,13 +112,12 @@ void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag) } } -void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[]) +void ubh_ll_rw_block(int rw, struct ufs_buffer_head *ubh) { - unsigned i; if (!ubh) return; - for ( i = 0; i < nr; i++ ) - ll_rw_block (rw, ubh[i]->count, ubh[i]->bh); + + ll_rw_block(rw, ubh->count, ubh->bh); } void ubh_wait_on_buffer (struct ufs_buffer_head * ubh) @@ -139,18 +129,6 @@ void ubh_wait_on_buffer (struct ufs_buffer_head * ubh) wait_on_buffer (ubh->bh[i]); } -unsigned ubh_max_bcount (struct ufs_buffer_head * ubh) -{ - unsigned i; - unsigned max = 0; - if (!ubh) - return 0; - for ( i = 0; i < ubh->count; i++ ) - if ( atomic_read(&ubh->bh[i]->b_count) > max ) - max = atomic_read(&ubh->bh[i]->b_count); - return max; -} - void ubh_bforget (struct ufs_buffer_head * ubh) { unsigned i; @@ -255,3 +233,57 @@ ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev else ufsi->i_u1.i_data[0] = fs32; } + +/** + * ufs_get_locked_page() - locate, pin and lock a pagecache page, if not exist + * read it from disk. + * @mapping: the address_space to search + * @index: the page index + * + * Locates the desired pagecache page, if not exist we'll read it, + * locks it, increments its reference + * count and returns its address. + * + */ + +struct page *ufs_get_locked_page(struct address_space *mapping, + pgoff_t index) +{ + struct page *page; + +try_again: + page = find_lock_page(mapping, index); + if (!page) { + page = read_cache_page(mapping, index, + (filler_t*)mapping->a_ops->readpage, + NULL); + if (IS_ERR(page)) { + printk(KERN_ERR "ufs_change_blocknr: " + "read_cache_page error: ino %lu, index: %lu\n", + mapping->host->i_ino, index); + goto out; + } + + lock_page(page); + + if (!PageUptodate(page) || PageError(page)) { + unlock_page(page); + page_cache_release(page); + + printk(KERN_ERR "ufs_change_blocknr: " + "can not read page: ino %lu, index: %lu\n", + mapping->host->i_ino, index); + + page = ERR_PTR(-EIO); + goto out; + } + } + + if (unlikely(!page->mapping || !page_has_buffers(page))) { + unlock_page(page); + page_cache_release(page); + goto try_again;/*we really need these buffers*/ + } +out: + return page; +} diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 48d6d9bcc157..28fce6c239b5 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h @@ -17,10 +17,16 @@ #define in_range(b,first,len) ((b)>=(first)&&(b)<(first)+(len)) /* - * macros used for retyping + * functions used for retyping */ -#define UCPI_UBH ((struct ufs_buffer_head *)ucpi) -#define USPI_UBH ((struct ufs_buffer_head *)uspi) +static inline struct ufs_buffer_head *UCPI_UBH(struct ufs_cg_private_info *cpi) +{ + return &cpi->c_ubh; +} +static inline struct ufs_buffer_head *USPI_UBH(struct ufs_sb_private_info *spi) +{ + return &spi->s_ubh; +} @@ -33,12 +39,12 @@ ufs_get_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1, { switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { case UFS_ST_SUN: - return fs32_to_cpu(sb, usb3->fs_u2.fs_sun.fs_state); + return fs32_to_cpu(sb, usb3->fs_un2.fs_sun.fs_state); case UFS_ST_SUNx86: return fs32_to_cpu(sb, usb1->fs_u1.fs_sunx86.fs_state); case UFS_ST_44BSD: default: - return fs32_to_cpu(sb, usb3->fs_u2.fs_44.fs_state); + return fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_state); } } @@ -48,13 +54,13 @@ ufs_set_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1, { switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { case UFS_ST_SUN: - usb3->fs_u2.fs_sun.fs_state = cpu_to_fs32(sb, value); + usb3->fs_un2.fs_sun.fs_state = cpu_to_fs32(sb, value); break; case UFS_ST_SUNx86: usb1->fs_u1.fs_sunx86.fs_state = cpu_to_fs32(sb, value); break; case UFS_ST_44BSD: - usb3->fs_u2.fs_44.fs_state = cpu_to_fs32(sb, value); + usb3->fs_un2.fs_44.fs_state = cpu_to_fs32(sb, value); break; } } @@ -64,7 +70,7 @@ ufs_get_fs_npsect(struct super_block *sb, struct ufs_super_block_first *usb1, struct ufs_super_block_third *usb3) { if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86) - return fs32_to_cpu(sb, usb3->fs_u2.fs_sunx86.fs_npsect); + return fs32_to_cpu(sb, usb3->fs_un2.fs_sunx86.fs_npsect); else return fs32_to_cpu(sb, usb1->fs_u1.fs_sun.fs_npsect); } @@ -76,16 +82,16 @@ ufs_get_fs_qbmask(struct super_block *sb, struct ufs_super_block_third *usb3) switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { case UFS_ST_SUN: - ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qbmask[0]; - ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qbmask[1]; + ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qbmask[0]; + ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qbmask[1]; break; case UFS_ST_SUNx86: - ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qbmask[0]; - ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qbmask[1]; + ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sunx86.fs_qbmask[0]; + ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sunx86.fs_qbmask[1]; break; case UFS_ST_44BSD: - ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qbmask[0]; - ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qbmask[1]; + ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_44.fs_qbmask[0]; + ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_44.fs_qbmask[1]; break; } @@ -99,16 +105,16 @@ ufs_get_fs_qfmask(struct super_block *sb, struct ufs_super_block_third *usb3) switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { case UFS_ST_SUN: - ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sun.fs_qfmask[0]; - ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sun.fs_qfmask[1]; + ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qfmask[0]; + ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qfmask[1]; break; case UFS_ST_SUNx86: - ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_sunx86.fs_qfmask[0]; - ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_sunx86.fs_qfmask[1]; + ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sunx86.fs_qfmask[0]; + ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sunx86.fs_qfmask[1]; break; case UFS_ST_44BSD: - ((__fs32 *)&tmp)[0] = usb3->fs_u2.fs_44.fs_qfmask[0]; - ((__fs32 *)&tmp)[1] = usb3->fs_u2.fs_44.fs_qfmask[1]; + ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_44.fs_qfmask[0]; + ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_44.fs_qfmask[1]; break; } @@ -236,9 +242,8 @@ extern void ubh_brelse (struct ufs_buffer_head *); extern void ubh_brelse_uspi (struct ufs_sb_private_info *); extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *); extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int); -extern void ubh_ll_rw_block (int, unsigned, struct ufs_buffer_head **); +extern void ubh_ll_rw_block(int, struct ufs_buffer_head *); extern void ubh_wait_on_buffer (struct ufs_buffer_head *); -extern unsigned ubh_max_bcount (struct ufs_buffer_head *); extern void ubh_bforget (struct ufs_buffer_head *); extern int ubh_buffer_dirty (struct ufs_buffer_head *); #define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size) @@ -246,6 +251,14 @@ extern void _ubh_ubhcpymem_(struct ufs_sb_private_info *, unsigned char *, struc #define ubh_memcpyubh(ubh,mem,size) _ubh_memcpyubh_(uspi,ubh,mem,size) extern void _ubh_memcpyubh_(struct ufs_sb_private_info *, struct ufs_buffer_head *, unsigned char *, unsigned); +/* This functions works with cache pages*/ +extern struct page *ufs_get_locked_page(struct address_space *mapping, + pgoff_t index); +static inline void ufs_put_locked_page(struct page *page) +{ + unlock_page(page); + page_cache_release(page); +} /* @@ -297,40 +310,26 @@ static inline void *get_usb_offset(struct ufs_sb_private_info *uspi, #define ubh_blkmap(ubh,begin,bit) \ ((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb))) - -/* - * Macros for access to superblock array structures - */ -#define ubh_postbl(ubh,cylno,i) \ - ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \ - ? (*(__s16*)(ubh_get_addr(ubh, \ - (unsigned)(&((struct ufs_super_block *)0)->fs_opostbl) \ - + (((cylno) * 16 + (i)) << 1) ) )) \ - : (*(__s16*)(ubh_get_addr(ubh, \ - uspi->s_postbloff + (((cylno) * uspi->s_nrpos + (i)) << 1) )))) - -#define ubh_rotbl(ubh,i) \ - ((uspi->s_postblformat != UFS_DYNAMICPOSTBLFMT) \ - ? (*(__u8*)(ubh_get_addr(ubh, \ - (unsigned)(&((struct ufs_super_block *)0)->fs_space) + (i)))) \ - : (*(__u8*)(ubh_get_addr(ubh, uspi->s_rotbloff + (i))))) - /* * Determine the number of available frags given a * percentage to hold in reserve. */ -#define ufs_freespace(usb, percentreserved) \ - (ufs_blkstofrags(fs32_to_cpu(sb, (usb)->fs_cstotal.cs_nbfree)) + \ - fs32_to_cpu(sb, (usb)->fs_cstotal.cs_nffree) - (uspi->s_dsize * (percentreserved) / 100)) +static inline u64 +ufs_freespace(struct ufs_sb_private_info *uspi, int percentreserved) +{ + return ufs_blkstofrags(uspi->cs_total.cs_nbfree) + + uspi->cs_total.cs_nffree - + (uspi->s_dsize * (percentreserved) / 100); +} /* * Macros to access cylinder group array structures */ #define ubh_cg_blktot(ucpi,cylno) \ - (*((__fs32*)ubh_get_addr(UCPI_UBH, (ucpi)->c_btotoff + ((cylno) << 2)))) + (*((__fs32*)ubh_get_addr(UCPI_UBH(ucpi), (ucpi)->c_btotoff + ((cylno) << 2)))) #define ubh_cg_blks(ucpi,cylno,rpos) \ - (*((__fs16*)ubh_get_addr(UCPI_UBH, \ + (*((__fs16*)ubh_get_addr(UCPI_UBH(ucpi), \ (ucpi)->c_boff + (((cylno) * uspi->s_nrpos + (rpos)) << 1 )))) /* @@ -508,29 +507,3 @@ static inline void ufs_fragacct (struct super_block * sb, unsigned blockmap, if (fragsize > 0 && fragsize < uspi->s_fpb) fs32_add(sb, &fraglist[fragsize], cnt); } - -#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask) -static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh, - unsigned begin, unsigned size, unsigned char * table, unsigned char mask) -{ - unsigned rest, offset; - unsigned char * cp; - - - offset = begin & ~uspi->s_fmask; - begin >>= uspi->s_fshift; - for (;;) { - if ((offset + size) < uspi->s_fsize) - rest = size; - else - rest = uspi->s_fsize - offset; - size -= rest; - cp = ubh->bh[begin]->b_data + offset; - while ((table[*cp++] & mask) == 0 && --rest); - if (rest || !size) - break; - begin++; - offset = 0; - } - return (size + rest); -} |