2005-04-17 02:20:36 +04:00
/*
* linux / fs / ufs / balloc . c
*
* Copyright ( C ) 1998
* Daniel Pirkl < daniel . pirkl @ email . cz >
* Charles University , Faculty of Mathematics and Physics
2007-02-12 11:54:32 +03:00
*
* UFS2 write support Evgeniy Dushistov < dushistov @ mail . ru > , 2007
2005-04-17 02:20:36 +04:00
*/
# include <linux/fs.h>
# include <linux/ufs_fs.h>
# include <linux/stat.h>
# include <linux/time.h>
# include <linux/string.h>
# include <linux/quotaops.h>
# include <linux/buffer_head.h>
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/bitops.h>
# include <asm/byteorder.h>
# include "swab.h"
# include "util.h"
2007-02-12 11:54:32 +03:00
# define INVBLOCK ((u64)-1L)
static u64 ufs_add_fragments ( struct inode * , u64 , unsigned , unsigned , int * ) ;
static u64 ufs_alloc_fragments ( struct inode * , unsigned , u64 , unsigned , int * ) ;
static u64 ufs_alloccg_block ( struct inode * , struct ufs_cg_private_info * , u64 , int * ) ;
static u64 ufs_bitmap_search ( struct super_block * , struct ufs_cg_private_info * , u64 , unsigned ) ;
2005-04-17 02:20:36 +04:00
static unsigned char ufs_fragtable_8fpb [ ] , ufs_fragtable_other [ ] ;
static void ufs_clusteracct ( struct super_block * , struct ufs_cg_private_info * , unsigned , int ) ;
/*
* Free ' count ' fragments from fragment number ' fragment '
*/
2007-02-12 11:54:32 +03:00
void ufs_free_fragments ( struct inode * inode , u64 fragment , unsigned count )
2006-06-25 16:47:20 +04:00
{
2005-04-17 02:20:36 +04:00
struct super_block * sb ;
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_cg_private_info * ucpi ;
struct ufs_cylinder_group * ucg ;
2007-02-12 11:54:32 +03:00
unsigned cgno , bit , end_bit , bbase , blkmap , i ;
u64 blkno ;
2005-04-17 02:20:36 +04:00
sb = inode - > i_sb ;
uspi = UFS_SB ( sb ) - > s_uspi ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:54:32 +03:00
UFSD ( " ENTER, fragment %llu, count %u \n " ,
( unsigned long long ) fragment , count ) ;
2005-04-17 02:20:36 +04:00
if ( ufs_fragnum ( fragment ) + count > uspi - > s_fpg )
ufs_error ( sb , " ufs_free_fragments " , " internal error " ) ;
lock_super ( sb ) ;
2007-02-12 11:54:32 +03:00
cgno = ufs_dtog ( uspi , fragment ) ;
bit = ufs_dtogd ( uspi , fragment ) ;
2005-04-17 02:20:36 +04:00
if ( cgno > = uspi - > s_ncg ) {
ufs_panic ( sb , " ufs_free_fragments " , " freeing blocks are outside device " ) ;
goto failed ;
}
ucpi = ufs_load_cylinder ( sb , cgno ) ;
if ( ! ucpi )
goto failed ;
2006-06-25 16:47:22 +04:00
ucg = ubh_get_ucg ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! ufs_cg_chkmagic ( sb , ucg ) ) {
ufs_panic ( sb , " ufs_free_fragments " , " internal error, bad magic number on cg %u " , cgno ) ;
goto failed ;
}
end_bit = bit + count ;
bbase = ufs_blknum ( bit ) ;
2006-06-25 16:47:22 +04:00
blkmap = ubh_blkmap ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , bbase ) ;
2005-04-17 02:20:36 +04:00
ufs_fragacct ( sb , blkmap , ucg - > cg_frsum , - 1 ) ;
for ( i = bit ; i < end_bit ; i + + ) {
2006-06-25 16:47:22 +04:00
if ( ubh_isclr ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , i ) )
ubh_setbit ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , i ) ;
2006-01-14 11:42:06 +03:00
else
ufs_error ( sb , " ufs_free_fragments " ,
" bit already cleared for fragment %u " , i ) ;
2005-04-17 02:20:36 +04:00
}
DQUOT_FREE_BLOCK ( inode , count ) ;
fs32_add ( sb , & ucg - > cg_cs . cs_nffree , count ) ;
2006-06-25 16:47:30 +04:00
uspi - > cs_total . cs_nffree + = count ;
2005-04-17 02:20:36 +04:00
fs32_add ( sb , & UFS_SB ( sb ) - > fs_cs ( cgno ) . cs_nffree , count ) ;
2006-06-25 16:47:22 +04:00
blkmap = ubh_blkmap ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , bbase ) ;
2005-04-17 02:20:36 +04:00
ufs_fragacct ( sb , blkmap , ucg - > cg_frsum , 1 ) ;
/*
* Trying to reassemble free fragments into block
*/
blkno = ufs_fragstoblks ( bbase ) ;
2006-06-25 16:47:22 +04:00
if ( ubh_isblockset ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , blkno ) ) {
2005-04-17 02:20:36 +04:00
fs32_sub ( sb , & ucg - > cg_cs . cs_nffree , uspi - > s_fpb ) ;
2006-06-25 16:47:30 +04:00
uspi - > cs_total . cs_nffree - = uspi - > s_fpb ;
2005-04-17 02:20:36 +04:00
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 ) ;
2006-06-25 16:47:30 +04:00
uspi - > cs_total . cs_nbfree + + ;
2005-04-17 02:20:36 +04:00
fs32_add ( sb , & UFS_SB ( sb ) - > fs_cs ( cgno ) . cs_nbfree , 1 ) ;
2007-02-12 11:54:32 +03:00
if ( uspi - > fs_magic ! = UFS2_MAGIC ) {
unsigned 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 ) ;
}
2005-04-17 02:20:36 +04:00
}
2006-06-25 16:47:22 +04:00
ubh_mark_buffer_dirty ( USPI_UBH ( uspi ) ) ;
ubh_mark_buffer_dirty ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( sb - > s_flags & MS_SYNCHRONOUS ) {
2006-06-25 16:47:31 +04:00
ubh_ll_rw_block ( SWRITE , UCPI_UBH ( ucpi ) ) ;
2006-06-25 16:47:22 +04:00
ubh_wait_on_buffer ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
}
sb - > s_dirt = 1 ;
unlock_super ( sb ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
failed :
unlock_super ( sb ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (FAILED) \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/*
* Free ' count ' fragments from fragment number ' fragment ' ( free whole blocks )
*/
2007-02-12 11:54:32 +03:00
void ufs_free_blocks ( struct inode * inode , u64 fragment , unsigned count )
2006-06-25 16:47:20 +04:00
{
2005-04-17 02:20:36 +04:00
struct super_block * sb ;
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_cg_private_info * ucpi ;
struct ufs_cylinder_group * ucg ;
2007-02-12 11:54:32 +03:00
unsigned overflow , cgno , bit , end_bit , i ;
u64 blkno ;
2005-04-17 02:20:36 +04:00
sb = inode - > i_sb ;
uspi = UFS_SB ( sb ) - > s_uspi ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:54:32 +03:00
UFSD ( " ENTER, fragment %llu, count %u \n " ,
( unsigned long long ) fragment , count ) ;
2005-04-17 02:20:36 +04:00
if ( ( fragment & uspi - > s_fpbmask ) | | ( count & uspi - > s_fpbmask ) ) {
ufs_error ( sb , " ufs_free_blocks " , " internal error, "
2007-02-12 11:54:32 +03:00
" fragment %llu, count %u \n " ,
( unsigned long long ) fragment , count ) ;
2005-04-17 02:20:36 +04:00
goto failed ;
}
lock_super ( sb ) ;
do_more :
overflow = 0 ;
2007-02-12 11:54:32 +03:00
cgno = ufs_dtog ( uspi , fragment ) ;
bit = ufs_dtogd ( uspi , fragment ) ;
2005-04-17 02:20:36 +04:00
if ( cgno > = uspi - > s_ncg ) {
ufs_panic ( sb , " ufs_free_blocks " , " freeing blocks are outside device " ) ;
2006-06-25 16:47:26 +04:00
goto failed_unlock ;
2005-04-17 02:20:36 +04:00
}
end_bit = bit + count ;
if ( end_bit > uspi - > s_fpg ) {
overflow = bit + count - uspi - > s_fpg ;
count - = overflow ;
end_bit - = overflow ;
}
ucpi = ufs_load_cylinder ( sb , cgno ) ;
if ( ! ucpi )
2006-06-25 16:47:26 +04:00
goto failed_unlock ;
2006-06-25 16:47:22 +04:00
ucg = ubh_get_ucg ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! ufs_cg_chkmagic ( sb , ucg ) ) {
ufs_panic ( sb , " ufs_free_blocks " , " internal error, bad magic number on cg %u " , cgno ) ;
2006-06-25 16:47:26 +04:00
goto failed_unlock ;
2005-04-17 02:20:36 +04:00
}
for ( i = bit ; i < end_bit ; i + = uspi - > s_fpb ) {
blkno = ufs_fragstoblks ( i ) ;
2006-06-25 16:47:22 +04:00
if ( ubh_isblockset ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , blkno ) ) {
2005-04-17 02:20:36 +04:00
ufs_error ( sb , " ufs_free_blocks " , " freeing free fragment " ) ;
}
2006-06-25 16:47:22 +04:00
ubh_setblock ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , blkno ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2006-06-25 16:47:30 +04:00
uspi - > cs_total . cs_nbfree + + ;
2005-04-17 02:20:36 +04:00
fs32_add ( sb , & UFS_SB ( sb ) - > fs_cs ( cgno ) . cs_nbfree , 1 ) ;
2007-02-12 11:54:32 +03:00
if ( uspi - > fs_magic ! = UFS2_MAGIC ) {
unsigned 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 ) ;
}
2005-04-17 02:20:36 +04:00
}
2006-06-25 16:47:22 +04:00
ubh_mark_buffer_dirty ( USPI_UBH ( uspi ) ) ;
ubh_mark_buffer_dirty ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( sb - > s_flags & MS_SYNCHRONOUS ) {
2006-06-25 16:47:31 +04:00
ubh_ll_rw_block ( SWRITE , UCPI_UBH ( ucpi ) ) ;
2006-06-25 16:47:22 +04:00
ubh_wait_on_buffer ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
}
if ( overflow ) {
fragment + = count ;
count = overflow ;
goto do_more ;
}
sb - > s_dirt = 1 ;
unlock_super ( sb ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
2006-06-25 16:47:26 +04:00
failed_unlock :
2005-04-17 02:20:36 +04:00
unlock_super ( sb ) ;
2006-06-25 16:47:26 +04:00
failed :
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (FAILED) \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2006-06-25 16:47:20 +04:00
/*
* 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 .
*/
2007-01-30 00:19:56 +03:00
static void ufs_change_blocknr ( struct inode * inode , unsigned int beg ,
2006-06-25 16:47:28 +04:00
unsigned int count , unsigned int oldb ,
unsigned int newb , struct page * locked_page )
2006-06-25 16:47:20 +04:00
{
2007-01-30 00:19:56 +03:00
const unsigned mask = ( 1 < < ( PAGE_CACHE_SHIFT - inode - > i_blkbits ) ) - 1 ;
struct address_space * const mapping = inode - > i_mapping ;
2007-01-30 00:19:54 +03:00
pgoff_t index , cur_index ;
2007-01-30 00:19:56 +03:00
unsigned end , pos , j ;
2006-06-25 16:47:20 +04:00
struct page * page ;
struct buffer_head * head , * bh ;
2006-06-25 16:47:24 +04:00
UFSD ( " ENTER, ino %lu, count %u, oldb %u, newb %u \n " ,
inode - > i_ino , count , oldb , newb ) ;
2006-06-25 16:47:20 +04:00
2007-01-30 00:19:54 +03:00
BUG_ON ( ! locked_page ) ;
2006-06-25 16:47:20 +04:00
BUG_ON ( ! PageLocked ( locked_page ) ) ;
2007-01-30 00:19:54 +03:00
cur_index = locked_page - > index ;
2007-01-30 00:19:56 +03:00
for ( end = count + beg ; beg < end ; beg = ( beg | mask ) + 1 ) {
index = beg > > ( PAGE_CACHE_SHIFT - inode - > i_blkbits ) ;
2006-06-25 16:47:20 +04:00
if ( likely ( cur_index ! = index ) ) {
page = ufs_get_locked_page ( mapping , index ) ;
2006-08-05 23:13:57 +04:00
if ( ! page | | IS_ERR ( page ) ) /* it was truncated or EIO */
2006-06-25 16:47:20 +04:00
continue ;
} else
page = locked_page ;
head = page_buffers ( page ) ;
bh = head ;
2007-01-30 00:19:56 +03:00
pos = beg & mask ;
for ( j = 0 ; j < pos ; + + j )
bh = bh - > b_this_page ;
j = 0 ;
2006-06-25 16:47:20 +04:00
do {
2007-01-30 00:19:56 +03:00
if ( buffer_mapped ( bh ) ) {
pos = bh - > b_blocknr - oldb ;
if ( pos < count ) {
UFSD ( " change from %llu to %llu \n " ,
( unsigned long long ) pos + oldb ,
( unsigned long long ) pos + newb ) ;
bh - > b_blocknr = newb + pos ;
unmap_underlying_metadata ( bh - > b_bdev ,
bh - > b_blocknr ) ;
mark_buffer_dirty ( bh ) ;
+ + j ;
}
2006-06-25 16:47:20 +04:00
}
bh = bh - > b_this_page ;
} while ( bh ! = head ) ;
2007-01-30 00:19:56 +03:00
if ( j )
set_page_dirty ( page ) ;
2006-06-25 16:47:20 +04:00
2006-07-01 15:36:24 +04:00
if ( likely ( cur_index ! = index ) )
ufs_put_locked_page ( page ) ;
2006-06-25 16:47:20 +04:00
}
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2006-06-25 16:47:20 +04:00
}
[PATCH] fix garbage instead of zeroes in UFS
Looks like this is the problem, which point Al Viro some time ago:
ufs's get_block callback allocates 16k of disk at a time, and links that
entire 16k into the file's metadata. But because get_block is called for only
a single buffer_head (a 2k buffer_head in this case?) we are only able to tell
the VFS that this 2k is buffer_new().
So when ufs_getfrag_block() is later called to map some more data in the file,
and when that data resides within the remaining 14k of this fragment,
ufs_getfrag_block() will incorrectly return a !buffer_new() buffer_head.
I don't see _right_ way to do nullification of whole block, if use inode
page cache, some pages may be outside of inode limits (inode size), and
will be lost; if use blockdev page cache it is possible to zero real data,
if later inode page cache will be used.
The simpliest way, as can I see usage of block device page cache, but not only
mark dirty, but also sync it during "nullification". I use my simple tests
collection, which I used for check that create,open,write,read,close works on
ufs, and I see that this patch makes ufs code 18% slower then before.
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2007-01-06 03:37:04 +03:00
static void ufs_clear_frags ( struct inode * inode , sector_t beg , unsigned int n ,
int sync )
{
struct buffer_head * bh ;
sector_t end = beg + n ;
for ( ; beg < end ; + + beg ) {
bh = sb_getblk ( inode - > i_sb , beg ) ;
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 )
sync_dirty_buffer ( bh ) ;
brelse ( bh ) ;
}
}
2007-02-12 11:54:32 +03:00
u64 ufs_new_fragments ( struct inode * inode , void * p , u64 fragment ,
u64 goal , unsigned count , int * err ,
struct page * locked_page )
2005-04-17 02:20:36 +04:00
{
struct super_block * sb ;
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
2007-02-12 11:54:32 +03:00
unsigned cgno , oldcount , newcount ;
u64 tmp , request , result ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:54:32 +03:00
UFSD ( " ENTER, ino %lu, fragment %llu, goal %llu, count %u \n " ,
inode - > i_ino , ( unsigned long long ) fragment ,
( unsigned long long ) goal , count ) ;
2005-04-17 02:20:36 +04:00
sb = inode - > i_sb ;
uspi = UFS_SB ( sb ) - > s_uspi ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2005-04-17 02:20:36 +04:00
* err = - ENOSPC ;
lock_super ( sb ) ;
2007-02-12 11:54:32 +03:00
tmp = ufs_data_ptr_to_cpu ( sb , p ) ;
2005-04-17 02:20:36 +04:00
if ( count + ufs_fragnum ( fragment ) > uspi - > s_fpb ) {
2007-02-12 11:54:32 +03:00
ufs_warning ( sb , " ufs_new_fragments " , " internal warning "
" fragment %llu, count %u " ,
( unsigned long long ) fragment , count ) ;
2005-04-17 02:20:36 +04:00
count = uspi - > s_fpb - ufs_fragnum ( fragment ) ;
}
oldcount = ufs_fragnum ( fragment ) ;
newcount = oldcount + count ;
/*
* Somebody else has just allocated our fragments
*/
if ( oldcount ) {
if ( ! tmp ) {
2007-02-12 11:54:32 +03:00
ufs_error ( sb , " ufs_new_fragments " , " internal error, "
" fragment %llu, tmp %llu \n " ,
( unsigned long long ) fragment ,
( unsigned long long ) tmp ) ;
unlock_super ( sb ) ;
return INVBLOCK ;
2005-04-17 02:20:36 +04:00
}
if ( fragment < UFS_I ( inode ) - > i_lastfrag ) {
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (ALREADY ALLOCATED) \n " ) ;
2005-04-17 02:20:36 +04:00
unlock_super ( sb ) ;
return 0 ;
}
}
else {
if ( tmp ) {
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (ALREADY ALLOCATED) \n " ) ;
2005-04-17 02:20:36 +04:00
unlock_super ( sb ) ;
return 0 ;
}
}
/*
* There is not enough space for user on the device
*/
2006-06-25 16:47:30 +04:00
if ( ! capable ( CAP_SYS_RESOURCE ) & & ufs_freespace ( uspi , UFS_MINFREE ) < = 0 ) {
2005-04-17 02:20:36 +04:00
unlock_super ( sb ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (FAILED) \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
if ( goal > = uspi - > s_size )
goal = 0 ;
if ( goal = = 0 )
cgno = ufs_inotocg ( inode - > i_ino ) ;
else
2007-02-12 11:54:32 +03:00
cgno = ufs_dtog ( uspi , goal ) ;
2005-04-17 02:20:36 +04:00
/*
* allocate new fragment
*/
if ( oldcount = = 0 ) {
result = ufs_alloc_fragments ( inode , cgno , goal , count , err ) ;
if ( result ) {
2007-02-12 11:54:32 +03:00
ufs_cpu_to_data_ptr ( sb , p , result ) ;
2005-04-17 02:20:36 +04:00
* err = 0 ;
2007-02-12 11:54:32 +03:00
UFS_I ( inode ) - > i_lastfrag =
max_t ( u32 , UFS_I ( inode ) - > i_lastfrag ,
fragment + count ) ;
ufs_clear_frags ( inode , result + oldcount ,
newcount - oldcount , locked_page ! = NULL ) ;
2005-04-17 02:20:36 +04:00
}
unlock_super ( sb ) ;
2007-02-12 11:54:32 +03:00
UFSD ( " EXIT, result %llu \n " , ( unsigned long long ) result ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
/*
* resize block
*/
result = ufs_add_fragments ( inode , tmp , oldcount , newcount , err ) ;
if ( result ) {
* err = 0 ;
UFS_I ( inode ) - > i_lastfrag = max_t ( u32 , UFS_I ( inode ) - > i_lastfrag , fragment + count ) ;
[PATCH] fix garbage instead of zeroes in UFS
Looks like this is the problem, which point Al Viro some time ago:
ufs's get_block callback allocates 16k of disk at a time, and links that
entire 16k into the file's metadata. But because get_block is called for only
a single buffer_head (a 2k buffer_head in this case?) we are only able to tell
the VFS that this 2k is buffer_new().
So when ufs_getfrag_block() is later called to map some more data in the file,
and when that data resides within the remaining 14k of this fragment,
ufs_getfrag_block() will incorrectly return a !buffer_new() buffer_head.
I don't see _right_ way to do nullification of whole block, if use inode
page cache, some pages may be outside of inode limits (inode size), and
will be lost; if use blockdev page cache it is possible to zero real data,
if later inode page cache will be used.
The simpliest way, as can I see usage of block device page cache, but not only
mark dirty, but also sync it during "nullification". I use my simple tests
collection, which I used for check that create,open,write,read,close works on
ufs, and I see that this patch makes ufs code 18% slower then before.
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2007-01-06 03:37:04 +03:00
ufs_clear_frags ( inode , result + oldcount , newcount - oldcount ,
locked_page ! = NULL ) ;
2005-04-17 02:20:36 +04:00
unlock_super ( sb ) ;
2007-02-12 11:54:32 +03:00
UFSD ( " EXIT, result %llu \n " , ( unsigned long long ) result ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
/*
* allocate new block and move data
*/
switch ( fs32_to_cpu ( sb , usb1 - > fs_optim ) ) {
case UFS_OPTSPACE :
request = newcount ;
2006-06-25 16:47:30 +04:00
if ( uspi - > s_minfree < 5 | | uspi - > cs_total . cs_nffree
> uspi - > s_dsize * uspi - > s_minfree / ( 2 * 100 ) )
2005-04-17 02:20:36 +04:00
break ;
usb1 - > fs_optim = cpu_to_fs32 ( sb , UFS_OPTTIME ) ;
break ;
default :
usb1 - > fs_optim = cpu_to_fs32 ( sb , UFS_OPTTIME ) ;
case UFS_OPTTIME :
request = uspi - > s_fpb ;
2006-06-25 16:47:30 +04:00
if ( uspi - > cs_total . cs_nffree < uspi - > s_dsize *
2005-04-17 02:20:36 +04:00
( uspi - > s_minfree - 2 ) / 100 )
break ;
usb1 - > fs_optim = cpu_to_fs32 ( sb , UFS_OPTTIME ) ;
break ;
}
result = ufs_alloc_fragments ( inode , cgno , goal , request , err ) ;
if ( result ) {
2007-01-30 00:19:56 +03:00
ufs_clear_frags ( inode , result + oldcount , newcount - oldcount ,
locked_page ! = NULL ) ;
2006-06-25 16:47:28 +04:00
ufs_change_blocknr ( inode , fragment - oldcount , oldcount , tmp ,
result , locked_page ) ;
2007-02-12 11:54:32 +03:00
ufs_cpu_to_data_ptr ( sb , p , result ) ;
2005-04-17 02:20:36 +04:00
* err = 0 ;
UFS_I ( inode ) - > i_lastfrag = max_t ( u32 , UFS_I ( inode ) - > i_lastfrag , fragment + count ) ;
unlock_super ( sb ) ;
if ( newcount < request )
ufs_free_fragments ( inode , result + newcount , request - newcount ) ;
ufs_free_fragments ( inode , tmp , oldcount ) ;
2007-02-12 11:54:32 +03:00
UFSD ( " EXIT, result %llu \n " , ( unsigned long long ) result ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
unlock_super ( sb ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (FAILED) \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-02-12 11:54:32 +03:00
static u64 ufs_add_fragments ( struct inode * inode , u64 fragment ,
unsigned oldcount , unsigned newcount , int * err )
2005-04-17 02:20:36 +04:00
{
struct super_block * sb ;
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_cg_private_info * ucpi ;
struct ufs_cylinder_group * ucg ;
unsigned cgno , fragno , fragoff , count , fragsize , i ;
2007-02-12 11:54:32 +03:00
UFSD ( " ENTER, fragment %llu, oldcount %u, newcount %u \n " ,
( unsigned long long ) fragment , oldcount , newcount ) ;
2005-04-17 02:20:36 +04:00
sb = inode - > i_sb ;
uspi = UFS_SB ( sb ) - > s_uspi ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2005-04-17 02:20:36 +04:00
count = newcount - oldcount ;
2007-02-12 11:54:32 +03:00
cgno = ufs_dtog ( uspi , fragment ) ;
2005-04-17 02:20:36 +04:00
if ( fs32_to_cpu ( sb , UFS_SB ( sb ) - > fs_cs ( cgno ) . cs_nffree ) < count )
return 0 ;
if ( ( ufs_fragnum ( fragment ) + newcount ) > uspi - > s_fpb )
return 0 ;
ucpi = ufs_load_cylinder ( sb , cgno ) ;
if ( ! ucpi )
return 0 ;
2006-06-25 16:47:22 +04:00
ucg = ubh_get_ucg ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! ufs_cg_chkmagic ( sb , ucg ) ) {
ufs_panic ( sb , " ufs_add_fragments " ,
" internal error, bad magic number on cg %u " , cgno ) ;
return 0 ;
}
2007-02-12 11:54:32 +03:00
fragno = ufs_dtogd ( uspi , fragment ) ;
2005-04-17 02:20:36 +04:00
fragoff = ufs_fragnum ( fragno ) ;
for ( i = oldcount ; i < newcount ; i + + )
2006-06-25 16:47:22 +04:00
if ( ubh_isclr ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , fragno + i ) )
2005-04-17 02:20:36 +04:00
return 0 ;
/*
* Block can be extended
*/
ucg - > cg_time = cpu_to_fs32 ( sb , get_seconds ( ) ) ;
for ( i = newcount ; i < ( uspi - > s_fpb - fragoff ) ; i + + )
2006-06-25 16:47:22 +04:00
if ( ubh_isclr ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , fragno + i ) )
2005-04-17 02:20:36 +04:00
break ;
fragsize = i - oldcount ;
if ( ! fs32_to_cpu ( sb , ucg - > cg_frsum [ fragsize ] ) )
ufs_panic ( sb , " ufs_add_fragments " ,
" internal error or corrupted bitmap on cg %u " , cgno ) ;
fs32_sub ( sb , & ucg - > cg_frsum [ fragsize ] , 1 ) ;
if ( fragsize ! = count )
fs32_add ( sb , & ucg - > cg_frsum [ fragsize - count ] , 1 ) ;
for ( i = oldcount ; i < newcount ; i + + )
2006-06-25 16:47:22 +04:00
ubh_clrbit ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , fragno + i ) ;
2005-04-17 02:20:36 +04:00
if ( DQUOT_ALLOC_BLOCK ( inode , count ) ) {
* err = - EDQUOT ;
return 0 ;
}
fs32_sub ( sb , & ucg - > cg_cs . cs_nffree , count ) ;
fs32_sub ( sb , & UFS_SB ( sb ) - > fs_cs ( cgno ) . cs_nffree , count ) ;
2006-06-25 16:47:30 +04:00
uspi - > cs_total . cs_nffree - = count ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:22 +04:00
ubh_mark_buffer_dirty ( USPI_UBH ( uspi ) ) ;
ubh_mark_buffer_dirty ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( sb - > s_flags & MS_SYNCHRONOUS ) {
2006-06-25 16:47:31 +04:00
ubh_ll_rw_block ( SWRITE , UCPI_UBH ( ucpi ) ) ;
2006-06-25 16:47:22 +04:00
ubh_wait_on_buffer ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
}
sb - > s_dirt = 1 ;
2007-02-12 11:54:32 +03:00
UFSD ( " EXIT, fragment %llu \n " , ( unsigned long long ) fragment ) ;
2005-04-17 02:20:36 +04:00
return fragment ;
}
# define UFS_TEST_FREE_SPACE_CG \
ucg = ( struct ufs_cylinder_group * ) UFS_SB ( sb ) - > s_ucg [ cgno ] - > b_data ; \
if ( fs32_to_cpu ( sb , ucg - > cg_cs . cs_nbfree ) ) \
goto cg_found ; \
for ( k = count ; k < uspi - > s_fpb ; k + + ) \
if ( fs32_to_cpu ( sb , ucg - > cg_frsum [ k ] ) ) \
goto cg_found ;
2007-02-12 11:54:32 +03:00
static u64 ufs_alloc_fragments ( struct inode * inode , unsigned cgno ,
u64 goal , unsigned count , int * err )
2005-04-17 02:20:36 +04:00
{
struct super_block * sb ;
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_cg_private_info * ucpi ;
struct ufs_cylinder_group * ucg ;
2007-02-12 11:54:32 +03:00
unsigned oldcg , i , j , k , allocsize ;
u64 result ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:54:32 +03:00
UFSD ( " ENTER, ino %lu, cgno %u, goal %llu, count %u \n " ,
inode - > i_ino , cgno , ( unsigned long long ) goal , count ) ;
2005-04-17 02:20:36 +04:00
sb = inode - > i_sb ;
uspi = UFS_SB ( sb ) - > s_uspi ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2005-04-17 02:20:36 +04:00
oldcg = cgno ;
/*
* 1. searching on preferred cylinder group
*/
UFS_TEST_FREE_SPACE_CG
/*
* 2. quadratic rehash
*/
for ( j = 1 ; j < uspi - > s_ncg ; j * = 2 ) {
cgno + = j ;
if ( cgno > = uspi - > s_ncg )
cgno - = uspi - > s_ncg ;
UFS_TEST_FREE_SPACE_CG
}
/*
* 3. brute force search
* We start at i = 2 ( 0 is checked at 1. step , 1 at 2. step )
*/
cgno = ( oldcg + 1 ) % uspi - > s_ncg ;
for ( j = 2 ; j < uspi - > s_ncg ; j + + ) {
cgno + + ;
if ( cgno > = uspi - > s_ncg )
cgno = 0 ;
UFS_TEST_FREE_SPACE_CG
}
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (FAILED) \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
cg_found :
ucpi = ufs_load_cylinder ( sb , cgno ) ;
if ( ! ucpi )
return 0 ;
2006-06-25 16:47:22 +04:00
ucg = ubh_get_ucg ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! ufs_cg_chkmagic ( sb , ucg ) )
ufs_panic ( sb , " ufs_alloc_fragments " ,
" internal error, bad magic number on cg %u " , cgno ) ;
ucg - > cg_time = cpu_to_fs32 ( sb , get_seconds ( ) ) ;
if ( count = = uspi - > s_fpb ) {
result = ufs_alloccg_block ( inode , ucpi , goal , err ) ;
2007-02-12 11:54:32 +03:00
if ( result = = INVBLOCK )
2005-04-17 02:20:36 +04:00
return 0 ;
goto succed ;
}
for ( allocsize = count ; allocsize < uspi - > s_fpb ; allocsize + + )
if ( fs32_to_cpu ( sb , ucg - > cg_frsum [ allocsize ] ) ! = 0 )
break ;
if ( allocsize = = uspi - > s_fpb ) {
result = ufs_alloccg_block ( inode , ucpi , goal , err ) ;
2007-02-12 11:54:32 +03:00
if ( result = = INVBLOCK )
2005-04-17 02:20:36 +04:00
return 0 ;
2007-02-12 11:54:32 +03:00
goal = ufs_dtogd ( uspi , result ) ;
2005-04-17 02:20:36 +04:00
for ( i = count ; i < uspi - > s_fpb ; i + + )
2006-06-25 16:47:22 +04:00
ubh_setbit ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , goal + i ) ;
2005-04-17 02:20:36 +04:00
i = uspi - > s_fpb - count ;
DQUOT_FREE_BLOCK ( inode , i ) ;
fs32_add ( sb , & ucg - > cg_cs . cs_nffree , i ) ;
2006-06-25 16:47:30 +04:00
uspi - > cs_total . cs_nffree + = i ;
2005-04-17 02:20:36 +04:00
fs32_add ( sb , & UFS_SB ( sb ) - > fs_cs ( cgno ) . cs_nffree , i ) ;
fs32_add ( sb , & ucg - > cg_frsum [ i ] , 1 ) ;
goto succed ;
}
result = ufs_bitmap_search ( sb , ucpi , goal , allocsize ) ;
2007-02-12 11:54:32 +03:00
if ( result = = INVBLOCK )
2005-04-17 02:20:36 +04:00
return 0 ;
if ( DQUOT_ALLOC_BLOCK ( inode , count ) ) {
* err = - EDQUOT ;
return 0 ;
}
for ( i = 0 ; i < count ; i + + )
2006-06-25 16:47:22 +04:00
ubh_clrbit ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , result + i ) ;
2005-04-17 02:20:36 +04:00
fs32_sub ( sb , & ucg - > cg_cs . cs_nffree , count ) ;
2006-06-25 16:47:30 +04:00
uspi - > cs_total . cs_nffree - = count ;
2005-04-17 02:20:36 +04:00
fs32_sub ( sb , & UFS_SB ( sb ) - > fs_cs ( cgno ) . cs_nffree , count ) ;
fs32_sub ( sb , & ucg - > cg_frsum [ allocsize ] , 1 ) ;
if ( count ! = allocsize )
fs32_add ( sb , & ucg - > cg_frsum [ allocsize - count ] , 1 ) ;
succed :
2006-06-25 16:47:22 +04:00
ubh_mark_buffer_dirty ( USPI_UBH ( uspi ) ) ;
ubh_mark_buffer_dirty ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( sb - > s_flags & MS_SYNCHRONOUS ) {
2006-06-25 16:47:31 +04:00
ubh_ll_rw_block ( SWRITE , UCPI_UBH ( ucpi ) ) ;
2006-06-25 16:47:22 +04:00
ubh_wait_on_buffer ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
}
sb - > s_dirt = 1 ;
result + = cgno * uspi - > s_fpg ;
2007-02-12 11:54:32 +03:00
UFSD ( " EXIT3, result %llu \n " , ( unsigned long long ) result ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
2007-02-12 11:54:32 +03:00
static u64 ufs_alloccg_block ( struct inode * inode ,
struct ufs_cg_private_info * ucpi ,
u64 goal , int * err )
2005-04-17 02:20:36 +04:00
{
struct super_block * sb ;
struct ufs_sb_private_info * uspi ;
struct ufs_super_block_first * usb1 ;
struct ufs_cylinder_group * ucg ;
2007-02-12 11:54:32 +03:00
u64 result , blkno ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:54:32 +03:00
UFSD ( " ENTER, goal %llu \n " , ( unsigned long long ) goal ) ;
2005-04-17 02:20:36 +04:00
sb = inode - > i_sb ;
uspi = UFS_SB ( sb ) - > s_uspi ;
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2006-06-25 16:47:22 +04:00
ucg = ubh_get_ucg ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( goal = = 0 ) {
goal = ucpi - > c_rotor ;
goto norot ;
}
goal = ufs_blknum ( goal ) ;
2007-02-12 11:54:32 +03:00
goal = ufs_dtogd ( uspi , goal ) ;
2005-04-17 02:20:36 +04:00
/*
* If the requested block is available , use it .
*/
2006-06-25 16:47:22 +04:00
if ( ubh_isblockset ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , ufs_fragstoblks ( goal ) ) ) {
2005-04-17 02:20:36 +04:00
result = goal ;
goto gotit ;
}
norot :
result = ufs_bitmap_search ( sb , ucpi , goal , uspi - > s_fpb ) ;
2007-02-12 11:54:32 +03:00
if ( result = = INVBLOCK )
return INVBLOCK ;
2005-04-17 02:20:36 +04:00
ucpi - > c_rotor = result ;
gotit :
blkno = ufs_fragstoblks ( result ) ;
2006-06-25 16:47:22 +04:00
ubh_clrblock ( UCPI_UBH ( ucpi ) , ucpi - > c_freeoff , blkno ) ;
2005-04-17 02:20:36 +04:00
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 ) ) {
* err = - EDQUOT ;
2007-02-12 11:54:32 +03:00
return INVBLOCK ;
2005-04-17 02:20:36 +04:00
}
fs32_sub ( sb , & ucg - > cg_cs . cs_nbfree , 1 ) ;
2006-06-25 16:47:30 +04:00
uspi - > cs_total . cs_nbfree - - ;
2005-04-17 02:20:36 +04:00
fs32_sub ( sb , & UFS_SB ( sb ) - > fs_cs ( ucpi - > c_cgx ) . cs_nbfree , 1 ) ;
2007-02-12 11:54:32 +03:00
if ( uspi - > fs_magic ! = UFS2_MAGIC ) {
unsigned cylno = ufs_cbtocylno ( ( unsigned ) result ) ;
fs16_sub ( sb , & ubh_cg_blks ( ucpi , cylno ,
ufs_cbtorpos ( ( unsigned ) result ) ) , 1 ) ;
fs32_sub ( sb , & ubh_cg_blktot ( ucpi , cylno ) , 1 ) ;
}
2005-04-17 02:20:36 +04:00
2007-02-12 11:54:32 +03:00
UFSD ( " EXIT, result %llu \n " , ( unsigned long long ) result ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
2006-06-25 16:47:23 +04:00
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 )
2005-04-17 02:20:36 +04:00
{
2006-06-25 16:47:23 +04:00
unsigned rest , offset ;
unsigned char * cp ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:23 +04:00
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
*/
2007-02-12 11:54:32 +03:00
static u64 ufs_bitmap_search ( struct super_block * sb ,
struct ufs_cg_private_info * ucpi ,
u64 goal , unsigned count )
2006-06-25 16:47:23 +04:00
{
/*
* 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 ;
2007-02-12 11:54:32 +03:00
unsigned start , length , loc ;
2006-06-25 16:47:23 +04:00
unsigned pos , want , blockmap , mask , end ;
2007-02-12 11:54:32 +03:00
u64 result ;
2006-06-25 16:47:23 +04:00
2007-02-12 11:54:32 +03:00
UFSD ( " ENTER, cg %u, goal %llu, count %u \n " , ucpi - > c_cgx ,
( unsigned long long ) goal , count ) ;
2006-06-25 16:47:23 +04:00
2006-01-14 11:42:06 +03:00
usb1 = ubh_get_usb_first ( uspi ) ;
2006-06-25 16:47:22 +04:00
ucg = ubh_get_ucg ( UCPI_UBH ( ucpi ) ) ;
2005-04-17 02:20:36 +04:00
if ( goal )
2007-02-12 11:54:32 +03:00
start = ufs_dtogd ( uspi , goal ) > > 3 ;
2005-04-17 02:20:36 +04:00
else
start = ucpi - > c_frotor > > 3 ;
length = ( ( uspi - > s_fpg + 7 ) > > 3 ) - start ;
2006-06-25 16:47:23 +04:00
loc = ubh_scanc ( uspi , UCPI_UBH ( ucpi ) , ucpi - > c_freeoff + start , length ,
2005-04-17 02:20:36 +04:00
( uspi - > s_fpb = = 8 ) ? ufs_fragtable_8fpb : ufs_fragtable_other ,
1 < < ( count - 1 + ( uspi - > s_fpb & 7 ) ) ) ;
2006-06-25 16:47:23 +04:00
if ( loc = = 0 ) {
2005-04-17 02:20:36 +04:00
length = start + 1 ;
2006-06-25 16:47:23 +04:00
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 ) ;
2007-02-12 11:54:32 +03:00
return INVBLOCK ;
2005-04-17 02:20:36 +04:00
}
start = 0 ;
}
2006-06-25 16:47:23 +04:00
result = ( start + length - loc ) < < 3 ;
2005-04-17 02:20:36 +04:00
ucpi - > c_frotor = result ;
/*
* found the byte in the map
*/
2006-06-25 16:47:23 +04:00
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 ) {
2007-02-12 11:54:32 +03:00
UFSD ( " EXIT, result %llu \n " ,
( unsigned long long ) result ) ;
2006-06-25 16:47:23 +04:00
return result + pos ;
}
mask < < = 1 ;
want < < = 1 ;
}
}
ufs_error ( sb , " ufs_bitmap_search " , " block not in map on cg %u \n " ,
ucpi - > c_cgx ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT (FAILED) \n " ) ;
2007-02-12 11:54:32 +03:00
return INVBLOCK ;
2005-04-17 02:20:36 +04:00
}
static void ufs_clusteracct ( struct super_block * sb ,
struct ufs_cg_private_info * ucpi , unsigned blkno , int cnt )
{
struct ufs_sb_private_info * uspi ;
int i , start , end , forw , back ;
uspi = UFS_SB ( sb ) - > s_uspi ;
if ( uspi - > s_contigsumsize < = 0 )
return ;
if ( cnt > 0 )
2006-06-25 16:47:22 +04:00
ubh_setbit ( UCPI_UBH ( ucpi ) , ucpi - > c_clusteroff , blkno ) ;
2005-04-17 02:20:36 +04:00
else
2006-06-25 16:47:22 +04:00
ubh_clrbit ( UCPI_UBH ( ucpi ) , ucpi - > c_clusteroff , blkno ) ;
2005-04-17 02:20:36 +04:00
/*
* Find the size of the cluster going forward .
*/
start = blkno + 1 ;
end = start + uspi - > s_contigsumsize ;
if ( end > = ucpi - > c_nclusterblks )
end = ucpi - > c_nclusterblks ;
2006-06-25 16:47:22 +04:00
i = ubh_find_next_zero_bit ( UCPI_UBH ( ucpi ) , ucpi - > c_clusteroff , end , start ) ;
2005-04-17 02:20:36 +04:00
if ( i > end )
i = end ;
forw = i - start ;
/*
* Find the size of the cluster going backward .
*/
start = blkno - 1 ;
end = start - uspi - > s_contigsumsize ;
if ( end < 0 )
end = - 1 ;
2006-06-25 16:47:22 +04:00
i = ubh_find_last_zero_bit ( UCPI_UBH ( ucpi ) , ucpi - > c_clusteroff , start , end ) ;
2005-04-17 02:20:36 +04:00
if ( i < end )
i = end ;
back = start - i ;
/*
* Account for old cluster and the possibly new forward and
* back clusters .
*/
i = back + forw + 1 ;
if ( i > uspi - > s_contigsumsize )
i = uspi - > s_contigsumsize ;
2006-06-25 16:47:22 +04:00
fs32_add ( sb , ( __fs32 * ) ubh_get_addr ( UCPI_UBH ( ucpi ) , ucpi - > c_clustersumoff + ( i < < 2 ) ) , cnt ) ;
2005-04-17 02:20:36 +04:00
if ( back > 0 )
2006-06-25 16:47:22 +04:00
fs32_sub ( sb , ( __fs32 * ) ubh_get_addr ( UCPI_UBH ( ucpi ) , ucpi - > c_clustersumoff + ( back < < 2 ) ) , cnt ) ;
2005-04-17 02:20:36 +04:00
if ( forw > 0 )
2006-06-25 16:47:22 +04:00
fs32_sub ( sb , ( __fs32 * ) ubh_get_addr ( UCPI_UBH ( ucpi ) , ucpi - > c_clustersumoff + ( forw < < 2 ) ) , cnt ) ;
2005-04-17 02:20:36 +04:00
}
static unsigned char ufs_fragtable_8fpb [ ] = {
0x00 , 0x01 , 0x01 , 0x02 , 0x01 , 0x01 , 0x02 , 0x04 , 0x01 , 0x01 , 0x01 , 0x03 , 0x02 , 0x03 , 0x04 , 0x08 ,
0x01 , 0x01 , 0x01 , 0x03 , 0x01 , 0x01 , 0x03 , 0x05 , 0x02 , 0x03 , 0x03 , 0x02 , 0x04 , 0x05 , 0x08 , 0x10 ,
0x01 , 0x01 , 0x01 , 0x03 , 0x01 , 0x01 , 0x03 , 0x05 , 0x01 , 0x01 , 0x01 , 0x03 , 0x03 , 0x03 , 0x05 , 0x09 ,
0x02 , 0x03 , 0x03 , 0x02 , 0x03 , 0x03 , 0x02 , 0x06 , 0x04 , 0x05 , 0x05 , 0x06 , 0x08 , 0x09 , 0x10 , 0x20 ,
0x01 , 0x01 , 0x01 , 0x03 , 0x01 , 0x01 , 0x03 , 0x05 , 0x01 , 0x01 , 0x01 , 0x03 , 0x03 , 0x03 , 0x05 , 0x09 ,
0x01 , 0x01 , 0x01 , 0x03 , 0x01 , 0x01 , 0x03 , 0x05 , 0x03 , 0x03 , 0x03 , 0x03 , 0x05 , 0x05 , 0x09 , 0x11 ,
0x02 , 0x03 , 0x03 , 0x02 , 0x03 , 0x03 , 0x02 , 0x06 , 0x03 , 0x03 , 0x03 , 0x03 , 0x02 , 0x03 , 0x06 , 0x0A ,
0x04 , 0x05 , 0x05 , 0x06 , 0x05 , 0x05 , 0x06 , 0x04 , 0x08 , 0x09 , 0x09 , 0x0A , 0x10 , 0x11 , 0x20 , 0x40 ,
0x01 , 0x01 , 0x01 , 0x03 , 0x01 , 0x01 , 0x03 , 0x05 , 0x01 , 0x01 , 0x01 , 0x03 , 0x03 , 0x03 , 0x05 , 0x09 ,
0x01 , 0x01 , 0x01 , 0x03 , 0x01 , 0x01 , 0x03 , 0x05 , 0x03 , 0x03 , 0x03 , 0x03 , 0x05 , 0x05 , 0x09 , 0x11 ,
0x01 , 0x01 , 0x01 , 0x03 , 0x01 , 0x01 , 0x03 , 0x05 , 0x01 , 0x01 , 0x01 , 0x03 , 0x03 , 0x03 , 0x05 , 0x09 ,
0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x07 , 0x05 , 0x05 , 0x05 , 0x07 , 0x09 , 0x09 , 0x11 , 0x21 ,
0x02 , 0x03 , 0x03 , 0x02 , 0x03 , 0x03 , 0x02 , 0x06 , 0x03 , 0x03 , 0x03 , 0x03 , 0x02 , 0x03 , 0x06 , 0x0A ,
0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x03 , 0x07 , 0x02 , 0x03 , 0x03 , 0x02 , 0x06 , 0x07 , 0x0A , 0x12 ,
0x04 , 0x05 , 0x05 , 0x06 , 0x05 , 0x05 , 0x06 , 0x04 , 0x05 , 0x05 , 0x05 , 0x07 , 0x06 , 0x07 , 0x04 , 0x0C ,
0x08 , 0x09 , 0x09 , 0x0A , 0x09 , 0x09 , 0x0A , 0x0C , 0x10 , 0x11 , 0x11 , 0x12 , 0x20 , 0x21 , 0x40 , 0x80 ,
} ;
static unsigned char ufs_fragtable_other [ ] = {
0x00 , 0x16 , 0x16 , 0x2A , 0x16 , 0x16 , 0x26 , 0x4E , 0x16 , 0x16 , 0x16 , 0x3E , 0x2A , 0x3E , 0x4E , 0x8A ,
0x16 , 0x16 , 0x16 , 0x3E , 0x16 , 0x16 , 0x36 , 0x5E , 0x16 , 0x16 , 0x16 , 0x3E , 0x3E , 0x3E , 0x5E , 0x9E ,
0x16 , 0x16 , 0x16 , 0x3E , 0x16 , 0x16 , 0x36 , 0x5E , 0x16 , 0x16 , 0x16 , 0x3E , 0x3E , 0x3E , 0x5E , 0x9E ,
0x2A , 0x3E , 0x3E , 0x2A , 0x3E , 0x3E , 0x2E , 0x6E , 0x3E , 0x3E , 0x3E , 0x3E , 0x2A , 0x3E , 0x6E , 0xAA ,
0x16 , 0x16 , 0x16 , 0x3E , 0x16 , 0x16 , 0x36 , 0x5E , 0x16 , 0x16 , 0x16 , 0x3E , 0x3E , 0x3E , 0x5E , 0x9E ,
0x16 , 0x16 , 0x16 , 0x3E , 0x16 , 0x16 , 0x36 , 0x5E , 0x16 , 0x16 , 0x16 , 0x3E , 0x3E , 0x3E , 0x5E , 0x9E ,
0x26 , 0x36 , 0x36 , 0x2E , 0x36 , 0x36 , 0x26 , 0x6E , 0x36 , 0x36 , 0x36 , 0x3E , 0x2E , 0x3E , 0x6E , 0xAE ,
0x4E , 0x5E , 0x5E , 0x6E , 0x5E , 0x5E , 0x6E , 0x4E , 0x5E , 0x5E , 0x5E , 0x7E , 0x6E , 0x7E , 0x4E , 0xCE ,
0x16 , 0x16 , 0x16 , 0x3E , 0x16 , 0x16 , 0x36 , 0x5E , 0x16 , 0x16 , 0x16 , 0x3E , 0x3E , 0x3E , 0x5E , 0x9E ,
0x16 , 0x16 , 0x16 , 0x3E , 0x16 , 0x16 , 0x36 , 0x5E , 0x16 , 0x16 , 0x16 , 0x3E , 0x3E , 0x3E , 0x5E , 0x9E ,
0x16 , 0x16 , 0x16 , 0x3E , 0x16 , 0x16 , 0x36 , 0x5E , 0x16 , 0x16 , 0x16 , 0x3E , 0x3E , 0x3E , 0x5E , 0x9E ,
0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x7E , 0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x7E , 0xBE ,
0x2A , 0x3E , 0x3E , 0x2A , 0x3E , 0x3E , 0x2E , 0x6E , 0x3E , 0x3E , 0x3E , 0x3E , 0x2A , 0x3E , 0x6E , 0xAA ,
0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x7E , 0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x3E , 0x7E , 0xBE ,
0x4E , 0x5E , 0x5E , 0x6E , 0x5E , 0x5E , 0x6E , 0x4E , 0x5E , 0x5E , 0x5E , 0x7E , 0x6E , 0x7E , 0x4E , 0xCE ,
0x8A , 0x9E , 0x9E , 0xAA , 0x9E , 0x9E , 0xAE , 0xCE , 0x9E , 0x9E , 0x9E , 0xBE , 0xAA , 0xBE , 0xCE , 0x8A ,
} ;