Commit c7f37b79 authored by Anton Blanchard's avatar Anton Blanchard

Merge samba.org:/scratch/anton/linux-2.5

into samba.org:/scratch/anton/linux-2.5_bar
parents 0e1e2d82 2b5d7502
......@@ -161,7 +161,7 @@ KAO -->
</sect1>
<sect1><title>MTRR Handling</title>
!Earch/i386/kernel/mtrr.c
!Earch/i386/kernel/cpu/mtrr/main.c
</sect1>
<sect1><title>PCI Support Library</title>
!Edrivers/pci/pci.c
......
......@@ -80,14 +80,14 @@ would have a contended child and we had assumed that no object is its
own descendent. Moreover, there is exactly one cross-directory rename
(see above).
Consider the object blocking the cross-directory rename. One of
its descendents is locked by cross-directory rename (otherwise we would again
have an infinite set of of contended objects). But that means that means
that cross-directory rename is taking locks out of order. Due to (2) the
order hadn't changed since we had acquired filesystem lock. But locking
rules for cross-directory rename guarantee that we do not try to acquire
lock on descendent before the lock on ancestor. Contradiction. I.e.
deadlock is impossible. Q.E.D.
Consider the object blocking the cross-directory rename. One
of its descendents is locked by cross-directory rename (otherwise we
would again have an infinite set of of contended objects). But that
means that cross-directory rename is taking locks out of order. Due
to (2) the order hadn't changed since we had acquired filesystem lock.
But locking rules for cross-directory rename guarantee that we do not
try to acquire lock on descendent before the lock on ancestor.
Contradiction. I.e. deadlock is impossible. Q.E.D.
These operations are guaranteed to avoid loop creation. Indeed,
......
......@@ -69,7 +69,7 @@ Locking change: ->s_vfs_rename_sem is taken only by cross-directory renames.
Most likely there is no need to change anything, but if you relied on
global exclusion between renames for some internal purpose - you need to
change your internal locking. Otherwise exclusion warranties remain the
same (i.e. parents are victim are locked, etc.).
same (i.e. parents and victim are locked, etc.).
---
[informational]
......
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 33
SUBLEVEL = 34
EXTRAVERSION =
# *DOCUMENTATION*
......
......@@ -156,6 +156,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
}
#endif
get_model_name(c);
if (c->cpuid_level > 1) {
/* supports eax=2 call */
......
......@@ -114,11 +114,10 @@ static int tosh_fn_status(void)
if (tosh_fn!=0) {
scan = inb(tosh_fn);
} else {
save_flags(flags);
cli();
local_irq_save(flags);
outb(0x8e, 0xe4);
scan = inb(0xe5);
restore_flags(flags);
local_irq_restore(flags);
}
return (int) scan;
......@@ -141,35 +140,32 @@ static int tosh_emulate_fan(SMMRegisters *regs)
if (tosh_id==0xfccb) {
if (eax==0xfe00) {
/* fan status */
save_flags(flags);
cli();
local_irq_save(flags);
outb(0xbe, 0xe4);
al = inb(0xe5);
restore_flags(flags);
local_irq_restore(flags);
regs->eax = 0x00;
regs->ecx = (unsigned int) (al & 0x01);
}
if ((eax==0xff00) && (ecx==0x0000)) {
/* fan off */
save_flags(flags);
cli();
local_irq_save(flags);
outb(0xbe, 0xe4);
al = inb(0xe5);
outb(0xbe, 0xe4);
outb (al | 0x01, 0xe5);
restore_flags(flags);
local_irq_restore(flags);
regs->eax = 0x00;
regs->ecx = 0x00;
}
if ((eax==0xff00) && (ecx==0x0001)) {
/* fan on */
save_flags(flags);
cli();
local_irq_save(flags);
outb(0xbe, 0xe4);
al = inb(0xe5);
outb(0xbe, 0xe4);
outb(al & 0xfe, 0xe5);
restore_flags(flags);
local_irq_restore(flags);
regs->eax = 0x00;
regs->ecx = 0x01;
}
......@@ -180,33 +176,30 @@ static int tosh_emulate_fan(SMMRegisters *regs)
if (tosh_id==0xfccc) {
if (eax==0xfe00) {
/* fan status */
save_flags(flags);
cli();
local_irq_save(flags);
outb(0xe0, 0xe4);
al = inb(0xe5);
restore_flags(flags);
local_irq_restore(flags);
regs->eax = 0x00;
regs->ecx = al & 0x01;
}
if ((eax==0xff00) && (ecx==0x0000)) {
/* fan off */
save_flags(flags);
cli();
local_irq_save(flags);
outb(0xe0, 0xe4);
al = inb(0xe5);
outw(0xe0 | ((al & 0xfe) << 8), 0xe4);
restore_flags(flags);
local_irq_restore(flags);
regs->eax = 0x00;
regs->ecx = 0x00;
}
if ((eax==0xff00) && (ecx==0x0001)) {
/* fan on */
save_flags(flags);
cli();
local_irq_save(flags);
outb(0xe0, 0xe4);
al = inb(0xe5);
outw(0xe0 | ((al | 0x01) << 8), 0xe4);
restore_flags(flags);
local_irq_restore(flags);
regs->eax = 0x00;
regs->ecx = 0x01;
}
......
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
/* Reiserfs block (de)allocator, bitmap-based. */
#include <linux/config.h>
#include <linux/time.h>
#include <linux/reiserfs_fs.h>
#include <asm/bitops.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/buffer_head.h>
#include <linux/kernel.h>
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_fs_sb.h>
#include <linux/reiserfs_fs_i.h>
#define PREALLOCATION_SIZE 9
/* different reiserfs block allocator options */
#define SB_ALLOC_OPTS(s) (REISERFS_SB(s)->s_alloc_options.bits)
#define _ALLOC_concentrating_formatted_nodes 0
#define _ALLOC_displacing_large_files 1
#define _ALLOC_displacing_new_packing_localities 2
#define _ALLOC_old_hashed_relocation 3
#define _ALLOC_new_hashed_relocation 4
#define _ALLOC_skip_busy 5
#define _ALLOC_displace_based_on_dirid 6
#define _ALLOC_hashed_formatted_nodes 7
#define _ALLOC_old_way 8
#define _ALLOC_hundredth_slices 9
#define concentrating_formatted_nodes(s) test_bit(_ALLOC_concentrating_formatted_nodes, &SB_ALLOC_OPTS(s))
#define displacing_large_files(s) test_bit(_ALLOC_displacing_large_files, &SB_ALLOC_OPTS(s))
#define displacing_new_packing_localities(s) test_bit(_ALLOC_displacing_new_packing_localities, &SB_ALLOC_OPTS(s))
#define SET_OPTION(optname) \
do { \
reiserfs_warning("reiserfs: option \"%s\" is set\n", #optname); \
set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \
} while(0)
#define TEST_OPTION(optname, s) \
test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
static inline void get_bit_address (struct super_block * s,
unsigned long block, int * bmap_nr, int * offset)
{
/* It is in the bitmap block number equal to the block
* number divided by the number of bits in a block. */
*bmap_nr = block / (s->s_blocksize << 3);
/* Within that bitmap block it is located at bit offset *offset. */
*offset = block & ((s->s_blocksize << 3) - 1 );
return;
}
#ifdef CONFIG_REISERFS_CHECK
/* this is a safety check to make sure
** blocks are reused properly. used for debugging only.
**
** this checks, that block can be reused, and it has correct state
** (free or busy)
*/
int is_reusable (struct super_block * s, unsigned long block, int bit_value)
{
int i, j;
if (block == 0 || block >= SB_BLOCK_COUNT (s)) {
reiserfs_warning ("vs-4010: is_reusable: block number is out of range %lu (%u)\n",
block, SB_BLOCK_COUNT (s));
......@@ -29,104 +66,269 @@ int is_reusable (struct super_block * s, unsigned long block, int bit_value)
/* it can't be one of the bitmap blocks */
for (i = 0; i < SB_BMAP_NR (s); i ++)
if (block == SB_AP_BITMAP (s)[i]->b_blocknr) {
if (block == SB_AP_BITMAP (s)[i].bh->b_blocknr) {
reiserfs_warning ("vs: 4020: is_reusable: "
"bitmap block %lu(%u) can't be freed or reused\n",
block, SB_BMAP_NR (s));
return 0;
}
i = block / (s->s_blocksize << 3);
get_bit_address (s, block, &i, &j);
if (i >= SB_BMAP_NR (s)) {
reiserfs_warning ("vs-4030: is_reusable: there is no so many bitmap blocks: "
"block=%lu, bitmap_nr=%d\n", block, i);
return 0;
}
j = block % (s->s_blocksize << 3);
if ((bit_value == 0 &&
reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i]->b_data)) ||
reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data)) ||
(bit_value == 1 &&
reiserfs_test_le_bit(j, SB_AP_BITMAP (s)[i]->b_data) == 0)) {
reiserfs_test_le_bit(j, SB_AP_BITMAP (s)[i].bh->b_data) == 0)) {
reiserfs_warning ("vs-4040: is_reusable: corresponding bit of block %lu does not "
"match required value (i==%d, j==%d) test_bit==%d\n",
block, i, j, reiserfs_test_le_bit (j, SB_AP_BITMAP (s)[i]->b_data));
block, i, j, reiserfs_test_le_bit (j, SB_AP_BITMAP (s)[i].bh->b_data));
return 0;
}
if (bit_value == 0 && block == SB_ROOT_BLOCK (s)) {
reiserfs_warning ("vs-4050: is_reusable: this is root block (%u), "
"it must be busy", SB_ROOT_BLOCK (s));
"it must be busy\n", SB_ROOT_BLOCK (s));
return 0;
}
return 1;
}
#endif /* CONFIG_REISERFS_CHECK */
/* searches in journal structures for a given block number (bmap, off). If block
is found in reiserfs journal it suggests next free block candidate to test. */
static inline int is_block_in_journal (struct super_block * s, int bmap, int
off, int *next)
{
unsigned long tmp;
if (reiserfs_in_journal (s, bmap, off, 1, &tmp)) {
if (tmp) { /* hint supplied */
*next = tmp;
PROC_INFO_INC( s, scan_bitmap.in_journal_hint );
} else {
(*next) = off + 1; /* inc offset to avoid looping. */
PROC_INFO_INC( s, scan_bitmap.in_journal_nohint );
}
PROC_INFO_INC( s, scan_bitmap.retry );
return 1;
}
return 0;
}
/* it searches for a window of zero bits with given minimum and maximum lengths in one bitmap
* block; */
static int scan_bitmap_block (struct reiserfs_transaction_handle *th,
int bmap_n, int *beg, int boundary, int min, int max, int unfm)
{
struct super_block *s = th->t_super;
struct reiserfs_bitmap_info *bi=&SB_AP_BITMAP(s)[bmap_n];
int end, next;
int org = *beg;
RFALSE(bmap_n >= SB_BMAP_NR (s), "Bitmap %d is out of range (0..%d)\n",bmap_n, SB_BMAP_NR (s) - 1);
PROC_INFO_INC( s, scan_bitmap.bmap );
/* this is unclear and lacks comments, explain how journal bitmaps
work here for the reader. Convey a sense of the design here. What
is a window? */
/* - I mean `a window of zero bits' as in description of this function - Zam. */
if ( !bi ) {
printk("Hey, bitmap info pointer is zero for bitmap %d!\n",bmap_n);
return 0;
}
if (buffer_locked (bi->bh)) {
PROC_INFO_INC( s, scan_bitmap.wait );
__wait_on_buffer (bi->bh);
}
/* If we know that first zero bit is only one or first zero bit is
closer to the end of bitmap than our start pointer */
if (bi->first_zero_hint > *beg || bi->free_count == 1)
*beg = bi->first_zero_hint;
#endif /* CONFIG_REISERFS_CHECK */
while (1) {
cont:
if (bi->free_count < min)
return 0; // No free blocks in this bitmap
/* search for a first zero bit -- beggining of a window */
*beg = reiserfs_find_next_zero_le_bit
((unsigned long*)(bi->bh->b_data), boundary, *beg);
if (*beg + min > boundary) { /* search for a zero bit fails or the rest of bitmap block
* cannot contain a zero window of minimum size */
return 0;
}
/* get address of corresponding bit (bitmap block number and offset in it) */
static inline void get_bit_address (struct super_block * s, unsigned long block, int * bmap_nr, int * offset)
if (unfm && is_block_in_journal(s,bmap_n, *beg, beg))
continue;
/* first zero bit found; we check next bits */
for (end = *beg + 1;; end ++) {
if (end >= *beg + max || end >= boundary || reiserfs_test_le_bit (end, bi->bh->b_data)) {
next = end;
break;
}
/* finding the other end of zero bit window requires looking into journal structures (in
* case of searching for free blocks for unformatted nodes) */
if (unfm && is_block_in_journal(s, bmap_n, end, &next))
break;
}
/* now (*beg) points to beginning of zero bits window,
* (end) points to one bit after the window end */
if (end - *beg >= min) { /* it seems we have found window of proper size */
int i;
reiserfs_prepare_for_journal (s, bi->bh, 1);
/* try to set all blocks used checking are they still free */
for (i = *beg; i < end; i++) {
/* It seems that we should not check in journal again. */
if (reiserfs_test_and_set_le_bit (i, bi->bh->b_data)) {
/* bit was set by another process
* while we slept in prepare_for_journal() */
PROC_INFO_INC( s, scan_bitmap.stolen );
if (i >= *beg + min) { /* we can continue with smaller set of allocated blocks,
* if length of this set is more or equal to `min' */
end = i;
break;
}
/* otherwise we clear all bit were set ... */
while (--i >= *beg)
reiserfs_test_and_clear_le_bit (i, bi->bh->b_data);
reiserfs_restore_prepared_buffer (s, bi->bh);
*beg = max(org, (int)bi->first_zero_hint);
/* ... and search again in current block from beginning */
goto cont;
}
}
bi->free_count -= (end - *beg);
/* if search started from zero_hint bit, and zero hint have not
changed since, then we need to update first_zero_hint */
if ( bi->first_zero_hint >= *beg)
/* no point in looking for free bit if there is not any */
bi->first_zero_hint = (bi->free_count > 0 ) ?
reiserfs_find_next_zero_le_bit
((unsigned long*)(bi->bh->b_data), s->s_blocksize << 3, end) : (s->s_blocksize << 3);
journal_mark_dirty (th, s, bi->bh);
/* free block count calculation */
reiserfs_prepare_for_journal (s, SB_BUFFER_WITH_SB(s), 1);
PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg));
journal_mark_dirty (th, s, SB_BUFFER_WITH_SB(s));
return end - (*beg);
} else {
*beg = next;
}
}
}
/* Tries to find contiguous zero bit window (given size) in given region of
* bitmap and place new blocks there. Returns number of allocated blocks. */
static int scan_bitmap (struct reiserfs_transaction_handle *th,
unsigned long *start, unsigned long finish,
int min, int max, int unfm, unsigned long file_block)
{
/* It is in the bitmap block number equal to the block number divided by the number of
bits in a block. */
*bmap_nr = block / (s->s_blocksize << 3);
/* Within that bitmap block it is located at bit offset *offset. */
*offset = block % (s->s_blocksize << 3);
return;
}
int nr_allocated=0;
struct super_block * s = th->t_super;
/* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr
* - Hans, it is not a block number - Zam. */
int bm, off;
int end_bm, end_off;
int off_max = s->s_blocksize << 3;
PROC_INFO_INC( s, scan_bitmap.call );
if ( SB_FREE_BLOCKS(s) <= 0)
return 0; // No point in looking for more free blocks
get_bit_address (s, *start, &bm, &off);
get_bit_address (s, finish, &end_bm, &end_off);
// With this option set first we try to find a bitmap that is at least 10%
// free, and if that fails, then we fall back to old whole bitmap scanning
if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) {
for (;bm < end_bm; bm++, off = 0) {
if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 )
nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
if (nr_allocated)
goto ret;
}
get_bit_address (s, *start, &bm, &off);
}
for (;bm < end_bm; bm++, off = 0) {
nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
if (nr_allocated)
goto ret;
}
nr_allocated = scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);
ret:
*start = bm * off_max + off;
return nr_allocated;
}
/* There would be a modest performance benefit if we write a version
to free a list of blocks at once. -Hans */
/* I wonder if it would be less modest
now that we use journaling. -Hans */
static void _reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long block)
static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
unsigned long block)
{
struct super_block * s = th->t_super;
struct reiserfs_super_block * rs;
struct buffer_head * sbh;
struct buffer_head ** apbh;
struct reiserfs_bitmap_info *apbi;
int nr, offset;
PROC_INFO_INC( s, free_block );
PROC_INFO_INC( s, free_block );
rs = SB_DISK_SUPER_BLOCK (s);
sbh = SB_BUFFER_WITH_SB (s);
apbh = SB_AP_BITMAP (s);
rs = SB_DISK_SUPER_BLOCK (s);
sbh = SB_BUFFER_WITH_SB (s);
apbi = SB_AP_BITMAP(s);
get_bit_address (s, block, &nr, &offset);
get_bit_address (s, block, &nr, &offset);
if (nr >= sb_bmap_nr (rs)) {
reiserfs_warning ("vs-4075: reiserfs_free_block: "
"block %lu is out of range on %s\n",
block, reiserfs_bdevname (s));
return;
}
if (nr >= sb_bmap_nr (rs)) {
reiserfs_warning ("vs-4075: reiserfs_free_block: "
"block %lu is out of range on %s\n",
block, reiserfs_bdevname (s));
return;
}
reiserfs_prepare_for_journal(s, apbh[nr], 1 ) ;
reiserfs_prepare_for_journal(s, apbi[nr].bh, 1 ) ;
/* clear bit for the given block in bit map */
if (!reiserfs_test_and_clear_le_bit (offset, apbh[nr]->b_data)) {
reiserfs_warning ("vs-4080: reiserfs_free_block: "
"free_block (%s:%lu)[dev:blocknr]: bit already cleared\n",
reiserfs_bdevname (s), block);
}
journal_mark_dirty (th, s, apbh[nr]);
/* clear bit for the given block in bit map */
if (!reiserfs_test_and_clear_le_bit (offset, apbi[nr].bh->b_data)) {
reiserfs_warning ("vs-4080: reiserfs_free_block: "
"free_block (%s:%lu)[dev:blocknr]: bit already cleared\n",
reiserfs_bdevname (s), block);
}
if (offset < apbi[nr].first_zero_hint) {
apbi[nr].first_zero_hint = offset;
}
apbi[nr].free_count ++;
journal_mark_dirty (th, s, apbi[nr].bh);
reiserfs_prepare_for_journal(s, sbh, 1) ;
/* update super block */
set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
reiserfs_prepare_for_journal(s, sbh, 1) ;
/* update super block */
set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
journal_mark_dirty (th, s, sbh);
journal_mark_dirty (th, s, sbh);
s->s_dirt = 1;
}
void reiserfs_free_block (struct reiserfs_transaction_handle *th,
unsigned long block) {
unsigned long block)
{
struct super_block * s = th->t_super;
RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
......@@ -144,571 +346,557 @@ void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th,
_reiserfs_free_block(th, block) ;
}
/* beginning from offset-th bit in bmap_nr-th bitmap block,
find_forward finds the closest zero bit. It returns 1 and zero
bit address (bitmap, offset) if zero bit found or 0 if there is no
zero bit in the forward direction */
/* The function is NOT SCHEDULE-SAFE! */
static int find_forward (struct super_block * s, int * bmap_nr, int * offset, int for_unformatted)
static void __discard_prealloc (struct reiserfs_transaction_handle * th,
struct reiserfs_inode_info *ei)
{
unsigned long save = ei->i_prealloc_block ;
#ifdef CONFIG_REISERFS_CHECK
if (ei->i_prealloc_count < 0)
reiserfs_warning("zam-4001:%s: inode has negative prealloc blocks count.\n", __FUNCTION__ );
#endif
while (ei->i_prealloc_count > 0) {
reiserfs_free_prealloc_block(th,ei->i_prealloc_block);
ei->i_prealloc_block++;
ei->i_prealloc_count --;
}
ei->i_prealloc_block = save;
list_del_init(&(ei->i_prealloc_list));
}
/* FIXME: It should be inline function */
void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
struct inode * inode)
{
int i, j;
struct buffer_head * bh;
unsigned long block_to_try = 0;
unsigned long next_block_to_try = 0 ;
PROC_INFO_INC( s, find_forward.call );
for (i = *bmap_nr; i < SB_BMAP_NR (s); i ++, *offset = 0,
PROC_INFO_INC( s, find_forward.bmap )) {
/* get corresponding bitmap block */
bh = SB_AP_BITMAP (s)[i];
if (buffer_locked (bh)) {
PROC_INFO_INC( s, find_forward.wait );
__wait_on_buffer (bh);
struct reiserfs_inode_info *ei = REISERFS_I(inode);
if (ei->i_prealloc_count) {
__discard_prealloc(th, ei);
}
retry:
j = reiserfs_find_next_zero_le_bit ((unsigned long *)bh->b_data,
s->s_blocksize << 3, *offset);
/* wow, this really needs to be redone. We can't allocate a block if
** it is in the journal somehow. reiserfs_in_journal makes a suggestion
** for a good block if the one you ask for is in the journal. Note,
** reiserfs_in_journal might reject the block it suggests. The big
** gain from the suggestion is when a big file has been deleted, and
** many blocks show free in the real bitmap, but are all not free
** in the journal list bitmaps.
**
** this whole system sucks. The bitmaps should reflect exactly what
** can and can't be allocated, and the journal should update them as
** it goes. TODO.
*/
if (j < (s->s_blocksize << 3)) {
block_to_try = (i * (s->s_blocksize << 3)) + j;
/* the block is not in the journal, we can proceed */
if (!(reiserfs_in_journal(s, block_to_try, for_unformatted, &next_block_to_try))) {
*bmap_nr = i;
*offset = j;
return 1;
}
/* the block is in the journal */
else if ((j+1) < (s->s_blocksize << 3)) { /* try again */
/* reiserfs_in_journal suggested a new block to try */
if (next_block_to_try > 0) {
int new_i ;
get_bit_address (s, next_block_to_try, &new_i, offset);
PROC_INFO_INC( s, find_forward.in_journal_hint );
/* block is not in this bitmap. reset i and continue
** we only reset i if new_i is in a later bitmap.
*/
if (new_i > i) {
i = (new_i - 1 ); /* i gets incremented by the for loop */
PROC_INFO_INC( s, find_forward.in_journal_out );
continue ;
}
} else {
/* no suggestion was made, just try the next block */
*offset = j+1 ;
}
void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
{
struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
while (!list_empty(plist)) {
struct reiserfs_inode_info *ei;
ei = list_entry(plist->next, struct reiserfs_inode_info, i_prealloc_list);
#ifdef CONFIG_REISERFS_CHECK
if (!ei->i_prealloc_count) {
reiserfs_warning("zam-4001:%s: inode is in prealloc list but has no preallocated blocks.\n", __FUNCTION__);
}
PROC_INFO_INC( s, find_forward.retry );
goto retry ;
}
#endif
__discard_prealloc(th, ei);
}
}
/* zero bit not found */
return 0;
}
/* return 0 if no free blocks, else return 1 */
/* The function is NOT SCHEDULE-SAFE!
** because the bitmap block we want to change could be locked, and on its
** way to the disk when we want to read it, and because of the
** flush_async_commits. Per bitmap block locks won't help much, and
** really aren't needed, as we retry later on if we try to set the bit
** and it is already set.
*/
static int find_zero_bit_in_bitmap (struct super_block * s,
unsigned long search_start,
int * bmap_nr, int * offset,
int for_unformatted)
/* block allocator related options are parsed here */
int reiserfs_parse_alloc_options(struct super_block * s, char * options)
{
int retry_count = 0 ;
/* get bit location (bitmap number and bit offset) of search_start block */
get_bit_address (s, search_start, bmap_nr, offset);
/* note that we search forward in the bitmap, benchmarks have shown that it is better to allocate in increasing
sequence, which is probably due to the disk spinning in the forward direction.. */
if (find_forward (s, bmap_nr, offset, for_unformatted) == 0) {
/* there wasn't a free block with number greater than our
starting point, so we are going to go to the beginning of the disk */
retry:
search_start = 0; /* caller will reset search_start for itself also. */
get_bit_address (s, search_start, bmap_nr, offset);
if (find_forward (s, bmap_nr,offset,for_unformatted) == 0) {
if (for_unformatted) { /* why only unformatted nodes? -Hans */
if (retry_count == 0) {
/* we've got a chance that flushing async commits will free up
** some space. Sync then retry
*/
flush_async_commits(s) ;
retry_count++ ;
goto retry ;
} else if (retry_count > 0) {
/* nothing more we can do. Make the others wait, flush
** all log blocks to disk, and flush to their home locations.
** this will free up any blocks held by the journal
*/
SB_JOURNAL(s)->j_must_wait = 1 ;
}
char * this_char, * value;
REISERFS_SB(s)->s_alloc_options.bits = 0; /* clear default settings */
for (this_char = strsep (&options, ":"); this_char != NULL; ) {
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0;
if (!strcmp(this_char, "concentrating_formatted_nodes")) {
int temp;
SET_OPTION(concentrating_formatted_nodes);
temp = (value && *value) ? simple_strtoul (value, &value, 0) : 10;
if (temp <= 0 || temp > 100) {
REISERFS_SB(s)->s_alloc_options.border = 10;
} else {
REISERFS_SB(s)->s_alloc_options.border = 100 / temp;
}
continue;
}
if (!strcmp(this_char, "displacing_large_files")) {
SET_OPTION(displacing_large_files);
REISERFS_SB(s)->s_alloc_options.large_file_size =
(value && *value) ? simple_strtoul (value, &value, 0) : 16;
continue;
}
if (!strcmp(this_char, "displacing_new_packing_localities")) {
SET_OPTION(displacing_new_packing_localities);
continue;
};
if (!strcmp(this_char, "old_hashed_relocation")) {
SET_OPTION(old_hashed_relocation);
continue;
}
return 0;
if (!strcmp(this_char, "new_hashed_relocation")) {
SET_OPTION(new_hashed_relocation);
continue;
}
if (!strcmp(this_char, "hashed_formatted_nodes")) {
SET_OPTION(hashed_formatted_nodes);
continue;
}
if (!strcmp(this_char, "skip_busy")) {
SET_OPTION(skip_busy);
continue;
}
if (!strcmp(this_char, "hundredth_slices")) {
SET_OPTION(hundredth_slices);
continue;
}
if (!strcmp(this_char, "old_way")) {
SET_OPTION(old_way);
continue;
}
if (!strcmp(this_char, "displace_based_on_dirid")) {
SET_OPTION(displace_based_on_dirid);
continue;
}
if (!strcmp(this_char, "preallocmin")) {
REISERFS_SB(s)->s_alloc_options.preallocmin =
(value && *value) ? simple_strtoul (value, &value, 0) : 4;
continue;
}
if (!strcmp(this_char, "preallocsize")) {
REISERFS_SB(s)->s_alloc_options.preallocsize =
(value && *value) ? simple_strtoul (value, &value, 0) : PREALLOCATION_SIZE;
continue;
}
reiserfs_warning("zam-4001: %s : unknown option - %s\n", __FUNCTION__ , this_char);
return 1;
}
}
return 1;
return 0;
}
static void inline new_hashed_relocation (reiserfs_blocknr_hint_t * hint)
{
char * hash_in;
if (hint->formatted_node) {
hash_in = (char*)&hint->key.k_dir_id;
} else {
if (!hint->inode) {
//hint->search_start = hint->beg;
hash_in = (char*)&hint->key.k_dir_id;
} else
if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
else
hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
}
hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
}
/* get amount_needed free block numbers from scanning the bitmap of
free/used blocks.
Optimize layout by trying to find them starting from search_start
and moving in increasing blocknr direction. (This was found to be
faster than using a bi-directional elevator_direction, in part
because of disk spin direction, in part because by the time one
reaches the end of the disk the beginning of the disk is the least
congested).
search_start is the block number of the left
semantic neighbor of the node we create.
return CARRY_ON if everything is ok
return NO_DISK_SPACE if out of disk space
return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS if the block we found is not contiguous to the last one
return block numbers found, in the array free_blocknrs. assumes
that any non-zero entries already present in the array are valid.
This feature is perhaps convenient coding when one might not have
used all blocknrs from the last time one called this function, or
perhaps it is an archaism from the days of schedule tracking, one
of us ought to reread the code that calls this, and analyze whether
it is still the right way to code it.
spare space is used only when priority is set to 1. reiserfsck has
its own reiserfs_new_blocknrs, which can use reserved space
exactly what reserved space? the SPARE_SPACE? if so, please comment reiserfs.h.
Give example of who uses spare space, and say that it is a deadlock
avoidance mechanism. -Hans */
/* This function is NOT SCHEDULE-SAFE! */
static int do_reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th,
unsigned long * free_blocknrs,
unsigned long search_start,
int amount_needed, int priority,
int for_unformatted,
int for_prealloc)
static void inline get_left_neighbor(reiserfs_blocknr_hint_t *hint)
{
struct super_block * s = th->t_super;
int i, j;
unsigned long * block_list_start = free_blocknrs;
int init_amount_needed = amount_needed;
unsigned long new_block = 0 ;
if (SB_FREE_BLOCKS (s) < SPARE_SPACE && !priority)
/* we can answer NO_DISK_SPACE being asked for new block with
priority 0 */
return NO_DISK_SPACE;
RFALSE( !s, "vs-4090: trying to get new block from nonexistent device");
RFALSE( search_start == MAX_B_NUM,
"vs-4100: we are optimizing location based on "
"the bogus location of a temp buffer (%lu).", search_start);
RFALSE( amount_needed < 1 || amount_needed > 2,
"vs-4110: amount_needed parameter incorrect (%d)", amount_needed);
/* We continue the while loop if another process snatches our found
* free block from us after we find it but before we successfully
* mark it as in use */
while (amount_needed--) {
/* skip over any blocknrs already gotten last time. */
if (*(free_blocknrs) != 0) {
RFALSE( is_reusable (s, *free_blocknrs, 1) == 0,
"vs-4120: bad blocknr on free_blocknrs list");
free_blocknrs++;
continue;
}
/* look for zero bits in bitmap */
if (find_zero_bit_in_bitmap(s,search_start, &i, &j,for_unformatted) == 0) {
if (find_zero_bit_in_bitmap(s,search_start,&i,&j, for_unformatted) == 0) {
/* recode without the goto and without
the if. It will require a
duplicate for. This is worth the
code clarity. Your way was
admirable, and just a bit too
clever in saving instructions.:-)
I'd say create a new function, but
that would slow things also, yes?
-Hans */
free_and_return:
for ( ; block_list_start != free_blocknrs; block_list_start++) {
reiserfs_free_block (th, *block_list_start);
*block_list_start = 0;
struct path * path;
struct buffer_head * bh;
struct item_head * ih;
int pos_in_item;
__u32 * item;
if (!hint->path) /* reiserfs code can call this function w/o pointer to path
* structure supplied; then we rely on supplied search_start */
return;
path = hint->path;
bh = get_last_bh(path);
RFALSE( !bh, "green-4002: Illegal path specified to get_left_neighbor\n");
ih = get_ih(path);
pos_in_item = path->pos_in_item;
item = get_item (path);
hint->search_start = bh->b_blocknr;
if (!hint->formatted_node && is_indirect_le_ih (ih)) {
/* for indirect item: go to left and look for the first non-hole entry
in the indirect item */
if (pos_in_item == I_UNFM_NUM (ih))
pos_in_item--;
// pos_in_item = I_UNFM_NUM (ih) - 1;
while (pos_in_item >= 0) {
int t=get_block_num(item,pos_in_item);
if (t) {
hint->search_start = t;
break;
}
pos_in_item --;
}
if (for_prealloc)
return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS;
else
return NO_DISK_SPACE;
} else {
}
}
/* i and j now contain the results of the search. i = bitmap block
number containing free block, j = offset in this block. we
compute the blocknr which is our result, store it in
free_blocknrs, and increment the pointer so that on the next
loop we will insert into the next location in the array. Also
in preparation for the next loop, search_start is changed so
that the next search will not rescan the same range but will
start where this search finished. Note that while it is
possible that schedule has occurred and blocks have been freed
in that range, it is perhaps more important that the blocks
returned be near each other than that they be near their other
neighbors, and it also simplifies and speeds the code this way. */
/* journal: we need to make sure the block we are giving out is not
** a log block, horrible things would happen there.
*/
new_block = (i * (s->s_blocksize << 3)) + j;
if (for_prealloc && (new_block - 1) != search_start) {
/* preallocated blocks must be contiguous, bail if we didnt find one.
** this is not a bug. We want to do the check here, before the
** bitmap block is prepared, and before we set the bit and log the
** bitmap.
**
** If we do the check after this function returns, we have to
** call reiserfs_free_block for new_block, which would be pure
** overhead.
**
** for_prealloc should only be set if the caller can deal with the
** NO_MORE_UNUSED_CONTIGUOUS_BLOCKS return value. This can be
** returned before the disk is actually full
*/
goto free_and_return ;
}
search_start = new_block ;
/* does result value fit into specified region? */
return;
}
/* make sure the block is not of journal or reserved area */
if (is_block_in_log_or_reserved_area(s, search_start)) {
reiserfs_warning("vs-4130: reiserfs_new_blocknrs: trying to allocate log block %lu\n",
search_start) ;
search_start++ ;
amount_needed++ ;
continue ;
}
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[i], 1) ;
RFALSE( buffer_locked (SB_AP_BITMAP (s)[i]) ||
is_reusable (s, search_start, 0) == 0,
"vs-4140: bitmap block is locked or bad block number found");
/* if this bit was already set, we've scheduled, and someone else
** has allocated it. loop around and try again
*/
if (reiserfs_test_and_set_le_bit (j, SB_AP_BITMAP (s)[i]->b_data)) {
reiserfs_warning("vs-4150: reiserfs_new_blocknrs, block not free");
reiserfs_restore_prepared_buffer(s, SB_AP_BITMAP(s)[i]) ;
amount_needed++ ;
continue ;
}
journal_mark_dirty (th, s, SB_AP_BITMAP (s)[i]);
*free_blocknrs = search_start ;
free_blocknrs ++;
}
/* should be, if formatted node, then try to put on first part of the device
specified as number of percent with mount option device, else try to put
on last of device. This is not to say it is good code to do so,
but the effect should be measured. */
static void inline set_border_in_hint(struct super_block *s, reiserfs_blocknr_hint_t *hint)
{
b_blocknr_t border = SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border;
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
/* update free block count in super block */
PUT_SB_FREE_BLOCKS( s, SB_FREE_BLOCKS(s) - init_amount_needed );
journal_mark_dirty (th, s, SB_BUFFER_WITH_SB (s));
s->s_dirt = 1;
if (hint->formatted_node)
hint->end = border - 1;
else
hint->beg = border;
}
return CARRY_ON;
static void inline displace_large_file(reiserfs_blocknr_hint_t *hint)
{
if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id), 4) % (hint->end - hint->beg);
else
hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid), 4) % (hint->end - hint->beg);
}
// this is called only by get_empty_nodes
int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
unsigned long search_start, int amount_needed) {
return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, amount_needed, 0/*priority*/, 0/*for_formatted*/, 0/*for_prealloc */) ;
static void inline hash_formatted_node(reiserfs_blocknr_hint_t *hint)
{
char * hash_in;
if (!hint->inode)
hash_in = (char*)&hint->key.k_dir_id;
else if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
else
hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
}
static int inline this_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t *hint)
{
return hint->block == REISERFS_SB(hint->th->t_super)->s_alloc_options.large_file_size;
}
// called by get_new_buffer and by reiserfs_get_block with amount_needed == 1
int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs,
unsigned long search_start) {
return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start,
1/*amount_needed*/,
0/*priority*/,
1/*for formatted*/,
0/*for prealloc */) ;
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
static void inline displace_new_packing_locality (reiserfs_blocknr_hint_t *hint)
{
struct key * key = &hint->key;
hint->th->displace_new_blocks = 0;
hint->search_start = hint->beg + keyed_hash((char*)(&key->k_objectid),4) % (hint->end - hint->beg);
}
#endif
#ifdef REISERFS_PREALLOCATE
/*
** We pre-allocate 8 blocks. Pre-allocation is used for files > 16 KB only.
** This lowers fragmentation on large files by grabbing a contiguous set of
** blocks at once. It also limits the number of times the bitmap block is
** logged by making X number of allocation changes in a single transaction.
**
** We are using a border to divide the disk into two parts. The first part
** is used for tree blocks, which have a very high turnover rate (they
** are constantly allocated then freed)
**
** The second part of the disk is for the unformatted nodes of larger files.
** Putting them away from the tree blocks lowers fragmentation, and makes
** it easier to group files together. There are a number of different
** allocation schemes being tried right now, each is documented below.
**
** A great deal of the allocator's speed comes because reiserfs_get_block
** sends us the block number of the last unformatted node in the file. Once
** a given block is allocated past the border, we don't collide with the
** blocks near the search_start again.
**
*/
int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th,
struct inode * p_s_inode,
unsigned long * free_blocknrs,
unsigned long search_start)
static int inline old_hashed_relocation (reiserfs_blocknr_hint_t * hint)
{
struct reiserfs_inode_info *ei = REISERFS_I(p_s_inode);
int ret=0, blks_gotten=0;
unsigned long border = 0;
unsigned long bstart = 0;
unsigned long hash_in, hash_out;
unsigned long saved_search_start=search_start;
int allocated[PREALLOCATION_SIZE];
int blks;
if (!reiserfs_no_border(th->t_super)) {
/* we default to having the border at the 10% mark of the disk. This
** is an arbitrary decision and it needs tuning. It also needs a limit
** to prevent it from taking too much space on huge drives.
*/
bstart = (SB_BLOCK_COUNT(th->t_super) / 10);
}
if (!reiserfs_no_unhashed_relocation(th->t_super)) {
/* this is a very simple first attempt at preventing too much grouping
** around the border value. Since k_dir_id is never larger than the
** highest allocated oid, it is far from perfect, and files will tend
** to be grouped towards the start of the border
*/
border = le32_to_cpu(INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
} else if (!reiserfs_hashed_relocation(th->t_super)) {
hash_in = le32_to_cpu((INODE_PKEY(p_s_inode))->k_dir_id);
/* I wonder if the CPU cost of the
hash will obscure the layout
effect? Of course, whether that
effect is good or bad we don't
know.... :-) */
hash_out = keyed_hash(((char *) (&hash_in)), 4);
border = hash_out % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ;
unsigned long border;
unsigned long hash_in;
if (hint->formatted_node || hint->inode == NULL) {
return 0;
}
hash_in = le32_to_cpu((INODE_PKEY(hint->inode))->k_dir_id);
border = hint->beg + (unsigned long) keyed_hash(((char *) (&hash_in)), 4) % (hint->end - hint->beg - 1);
if (border > hint->search_start)
hint->search_start = border;
return 1;
}
border += bstart ;
allocated[0] = 0 ; /* important. Allows a check later on to see if at
* least one block was allocated. This prevents false
* no disk space returns
*/
if ( (p_s_inode->i_size < 4 * 4096) ||
!(S_ISREG(p_s_inode->i_mode)) )
{
if ( search_start < border
|| (
/* allow us to test whether it is a
good idea to prevent files from
getting too far away from their
packing locality by some unexpected
means. This might be poor code for
directories whose files total
larger than 1/10th of the disk, and
it might be good code for
suffering from old insertions when the disk
was almost full. */
/* changed from !reiserfs_test3(th->t_super), which doesn't
** seem like a good idea. Think about adding blocks to
** a large file. If you've allocated 10% of the disk
** in contiguous blocks, you start over at the border value
** for every new allocation. This throws away all the
** information sent in about the last block that was allocated
** in the file. Not a good general case at all.
** -chris
*/
reiserfs_test4(th->t_super) &&
(search_start > border + (SB_BLOCK_COUNT(th->t_super) / 10))
)
)
search_start=border;
ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start,
1/*amount_needed*/,
0/*use reserved blocks for root */,
1/*for_formatted*/,
0/*for prealloc */) ;
return ret;
static int inline old_way (reiserfs_blocknr_hint_t * hint)
{
unsigned long border;
if (hint->formatted_node || hint->inode == NULL) {
return 0;
}
border = hint->beg + le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id) % (hint->end - hint->beg);
if (border > hint->search_start)
hint->search_start = border;
/* take a block off the prealloc list and return it -Hans */
if (ei->i_prealloc_count > 0) {
ei->i_prealloc_count--;
*free_blocknrs = ei->i_prealloc_block++;
return 1;
}
/* if no more preallocated blocks, remove inode from list */
if (! ei->i_prealloc_count) {
list_del_init(&ei->i_prealloc_list);
}
return ret;
}
static void inline hundredth_slices (reiserfs_blocknr_hint_t * hint)
{
struct key * key = &hint->key;
unsigned long slice_start;
/* else get a new preallocation for the file */
reiserfs_discard_prealloc (th, p_s_inode);
/* this uses the last preallocated block as the search_start. discard
** prealloc does not zero out this number.
*/
if (search_start <= ei->i_prealloc_block) {
search_start = ei->i_prealloc_block;
}
slice_start = (keyed_hash((char*)(&key->k_dir_id),4) % 100) * (hint->end / 100);
if ( slice_start > hint->search_start || slice_start + (hint->end / 100) <= hint->search_start) {
hint->search_start = slice_start;
}
}
/* doing the compare again forces search_start to be >= the border,
** even if the file already had prealloction done. This seems extra,
** and should probably be removed
*/
if ( search_start < border ) search_start=border;
/* If the disk free space is already below 10% we should
** start looking for the free blocks from the beginning
** of the partition, before the border line.
*/
if ( SB_FREE_BLOCKS(th->t_super) <= (SB_BLOCK_COUNT(th->t_super) / 10) ) {
search_start=saved_search_start;
}
static void inline determine_search_start(reiserfs_blocknr_hint_t *hint,
int amount_needed)
{
struct super_block *s = hint->th->t_super;
hint->beg = 0;
hint->end = SB_BLOCK_COUNT(s) - 1;
/* This is former border algorithm. Now with tunable border offset */
if (concentrating_formatted_nodes(s))
set_border_in_hint(s, hint);
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
/* whenever we create a new directory, we displace it. At first we will
hash for location, later we might look for a moderately empty place for
it */
if (displacing_new_packing_localities(s)
&& hint->th->displace_new_blocks) {
displace_new_packing_locality(hint);
/* we do not continue determine_search_start,
* if new packing locality is being displaced */
return;
}
#endif
/* all persons should feel encouraged to add more special cases here and
* test them */
*free_blocknrs = 0;
blks = PREALLOCATION_SIZE-1;
for (blks_gotten=0; blks_gotten<PREALLOCATION_SIZE; blks_gotten++) {
ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start,
1/*amount_needed*/,
0/*for root reserved*/,
1/*for_formatted*/,
(blks_gotten > 0)/*must_be_contiguous*/) ;
/* if we didn't find a block this time, adjust blks to reflect
** the actual number of blocks allocated
*/
if (ret != CARRY_ON) {
blks = blks_gotten > 0 ? (blks_gotten - 1) : 0 ;
break ;
if (displacing_large_files(s) && !hint->formatted_node
&& this_blocknr_allocation_would_make_it_a_large_file(hint)) {
displace_large_file(hint);
return;
}
allocated[blks_gotten]= *free_blocknrs;
#ifdef CONFIG_REISERFS_CHECK
if ( (blks_gotten>0) && (allocated[blks_gotten] - allocated[blks_gotten-1]) != 1 ) {
/* this should be caught by new_blocknrs now, checking code */
reiserfs_warning("yura-1, reiserfs_new_unf_blocknrs2: pre-allocated not contiguous set of blocks!\n") ;
reiserfs_free_block(th, allocated[blks_gotten]);
blks = blks_gotten-1;
break;
/* attempt to copy a feature from old block allocator code */
if (TEST_OPTION(old_hashed_relocation, s) && !hint->formatted_node) {
old_hashed_relocation(hint);
}
#endif
if (blks_gotten==0) {
ei->i_prealloc_block = *free_blocknrs;
/* if none of our special cases is relevant, use the left neighbor in the
tree order of the new node we are allocating for */
if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes,s)) {
hash_formatted_node(hint);
return;
}
get_left_neighbor(hint);
/* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,
new blocks are displaced based on directory ID. Also, if suggested search_start
is less than last preallocated block, we start searching from it, assuming that
HDD dataflow is faster in forward direction */
if ( TEST_OPTION(old_way, s)) {
if (!hint->formatted_node) {
if ( !reiserfs_hashed_relocation(s))
old_way(hint);
else if (!reiserfs_no_unhashed_relocation(s))
old_hashed_relocation(hint);
if ( hint->inode && hint->search_start < REISERFS_I(hint->inode)->i_prealloc_block)
hint->search_start = REISERFS_I(hint->inode)->i_prealloc_block;
}
return;
}
search_start = *free_blocknrs;
*free_blocknrs = 0;
}
ei->i_prealloc_count = blks;
*free_blocknrs = ei->i_prealloc_block;
ei->i_prealloc_block++;
/* if inode has preallocated blocks, link him to list */
if (ei->i_prealloc_count) {
list_add(&ei->i_prealloc_list,
&SB_JOURNAL(th->t_super)->j_prealloc_list);
}
/* we did actually manage to get 1 block */
if (ret != CARRY_ON && allocated[0] > 0) {
return CARRY_ON ;
}
/* NO_MORE_UNUSED_CONTIGUOUS_BLOCKS should only mean something to
** the preallocation code. The rest of the filesystem asks for a block
** and should either get it, or know the disk is full. The code
** above should never allow ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCK,
** as it doesn't send for_prealloc = 1 to do_reiserfs_new_blocknrs
** unless it has already successfully allocated at least one block.
** Just in case, we translate into a return value the rest of the
** filesystem can understand.
**
** It is an error to change this without making the
** rest of the filesystem understand NO_MORE_UNUSED_CONTIGUOUS_BLOCKS
** If you consider it a bug to return NO_DISK_SPACE here, fix the rest
** of the fs first.
*/
if (ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCKS) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning("reiser-2015: this shouldn't happen, may cause false out of disk space error");
#endif
return NO_DISK_SPACE;
}
return ret;
/* This is an approach proposed by Hans */
if ( TEST_OPTION(hundredth_slices, s) && ! (displacing_large_files(s) && !hint->formatted_node)) {
hundredth_slices(hint);
return;
}
if (TEST_OPTION(old_hashed_relocation, s))
old_hashed_relocation(hint);
if (TEST_OPTION(new_hashed_relocation, s))
new_hashed_relocation(hint);
return;
}
static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
{
/* make minimum size a mount option and benchmark both ways */
/* we preallocate blocks only for regular files, specific size */
/* benchmark preallocating always and see what happens */
static void __discard_prealloc (struct reiserfs_transaction_handle * th,
struct reiserfs_inode_info *ei)
hint->prealloc_size = 0;
if (!hint->formatted_node && hint->preallocate) {
if (S_ISREG(hint->inode->i_mode)
&& hint->inode->i_size >= REISERFS_SB(hint->th->t_super)->s_alloc_options.preallocmin * hint->inode->i_sb->s_blocksize)
hint->prealloc_size = REISERFS_SB(hint->th->t_super)->s_alloc_options.preallocsize - 1;
}
return CARRY_ON;
}
/* XXX I know it could be merged with upper-level function;
but may be result function would be too complex. */
static inline int allocate_without_wrapping_disk (reiserfs_blocknr_hint_t * hint,
b_blocknr_t * new_blocknrs,
b_blocknr_t start, b_blocknr_t finish,
int amount_needed, int prealloc_size)
{
unsigned long save = ei->i_prealloc_block ;
while (ei->i_prealloc_count > 0) {
reiserfs_free_prealloc_block(th,ei->i_prealloc_block);
ei->i_prealloc_block++;
ei->i_prealloc_count --;
}
ei->i_prealloc_block = save;
list_del_init(&(ei->i_prealloc_list));
int rest = amount_needed;
int nr_allocated;
while (rest > 0) {
nr_allocated = scan_bitmap (hint->th, &start, finish, 1,
rest + prealloc_size, !hint->formatted_node,
hint->block);
if (nr_allocated == 0) /* no new blocks allocated, return */
break;
/* fill free_blocknrs array first */
while (rest > 0 && nr_allocated > 0) {
* new_blocknrs ++ = start ++;
rest --; nr_allocated --;
}
/* do we have something to fill prealloc. array also ? */
if (nr_allocated > 0) {
/* it means prealloc_size was greater that 0 and we do preallocation */
list_add(&REISERFS_I(hint->inode)->i_prealloc_list,
&SB_JOURNAL(hint->th->t_super)->j_prealloc_list);
REISERFS_I(hint->inode)->i_prealloc_block = start;
REISERFS_I(hint->inode)->i_prealloc_count = nr_allocated;
break;
}
}
return (amount_needed - rest);
}
static inline int blocknrs_and_prealloc_arrays_from_search_start
(reiserfs_blocknr_hint_t *hint, b_blocknr_t *new_blocknrs, int amount_needed)
{
struct super_block *s = hint->th->t_super;
b_blocknr_t start = hint->search_start;
b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
int second_pass = 0;
int nr_allocated = 0;
determine_prealloc_size(hint);
while((nr_allocated
+= allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish,
amount_needed - nr_allocated, hint->prealloc_size))
< amount_needed) {
/* not all blocks were successfully allocated yet*/
if (second_pass) { /* it was a second pass; we must free all blocks */
while (nr_allocated --)
reiserfs_free_block(hint->th, new_blocknrs[nr_allocated]);
void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
struct inode * inode)
return NO_DISK_SPACE;
} else { /* refine search parameters for next pass */
second_pass = 1;
finish = start;
start = 0;
continue;
}
}
return CARRY_ON;
}
/* grab new blocknrs from preallocated list */
/* return amount still needed after using them */
static int use_preallocated_list_if_available (reiserfs_blocknr_hint_t *hint,
b_blocknr_t *new_blocknrs, int amount_needed)
{
struct reiserfs_inode_info *ei = REISERFS_I(inode);
#ifdef CONFIG_REISERFS_CHECK
if (ei->i_prealloc_count < 0)
reiserfs_warning("zam-4001:%s inode has negative prealloc blocks count.\n", __FUNCTION__);
#endif
if (ei->i_prealloc_count > 0) {
__discard_prealloc(th, ei);
}
struct inode * inode = hint->inode;
if (REISERFS_I(inode)->i_prealloc_count > 0) {
while (amount_needed) {
*new_blocknrs ++ = REISERFS_I(inode)->i_prealloc_block ++;
REISERFS_I(inode)->i_prealloc_count --;
amount_needed --;
if (REISERFS_I(inode)->i_prealloc_count <= 0) {
list_del(&REISERFS_I(inode)->i_prealloc_list);
break;
}
}
}
/* return amount still needed after using preallocated blocks */
return amount_needed;
}
void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,
b_blocknr_t * new_blocknrs, int amount_needed,
int reserved_by_us /* Amount of blocks we have
already reserved */)
{
struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
while (!list_empty(plist)) {
struct reiserfs_inode_info *ei;
ei = list_entry(plist->next, struct reiserfs_inode_info, i_prealloc_list);
#ifdef CONFIG_REISERFS_CHECK
if (!ei->i_prealloc_count) {
reiserfs_warning("zam-4001:%s: inode is in prealloc list but has no preallocated blocks.\n", __FUNCTION__);
int initial_amount_needed = amount_needed;
int ret;
/* Check if there is enough space, taking into account reserved space */
if ( SB_FREE_BLOCKS(hint->th->t_super) - REISERFS_SB(hint->th->t_super)->reserved_blocks <
amount_needed - reserved_by_us)
return NO_DISK_SPACE;
/* should this be if !hint->inode && hint->preallocate? */
/* do you mean hint->formatted_node can be removed ? - Zam */
/* hint->formatted_node cannot be removed because we try to access
inode information here, and there is often no inode assotiated with
metadata allocations - green */
if (!hint->formatted_node && hint->preallocate) {
amount_needed = use_preallocated_list_if_available
(hint, new_blocknrs, amount_needed);
if (amount_needed == 0) /* all blocknrs we need we got from
prealloc. list */
return CARRY_ON;
new_blocknrs += (initial_amount_needed - amount_needed);
}
/* find search start and save it in hint structure */
determine_search_start(hint, amount_needed);
/* allocation itself; fill new_blocknrs and preallocation arrays */
ret = blocknrs_and_prealloc_arrays_from_search_start
(hint, new_blocknrs, amount_needed);
/* we used prealloc. list to fill (partially) new_blocknrs array. If final allocation fails we
* need to return blocks back to prealloc. list or just free them. -- Zam (I chose second
* variant) */
if (ret != CARRY_ON) {
while (amount_needed ++ < initial_amount_needed) {
reiserfs_free_block(hint->th, *(--new_blocknrs));
}
#endif
__discard_prealloc(th, ei);
}
return ret;
}
/* These 2 functions are here to provide blocks reservation to the rest of kernel */
/* Reserve @blocks amount of blocks in fs pointed by @sb. Caller must make sure
there are actually this much blocks on the FS available */
void reiserfs_claim_blocks_to_be_allocated(
struct super_block *sb, /* super block of
filesystem where
blocks should be
reserved */
int blocks /* How much to reserve */
)
{
/* Fast case, if reservation is zero - exit immediately. */
if ( !blocks )
return;
REISERFS_SB(sb)->reserved_blocks += blocks;
}
/* Unreserve @blocks amount of blocks in fs pointed by @sb */
void reiserfs_release_claimed_blocks(
struct super_block *sb, /* super block of
filesystem where
blocks should be
reserved */
int blocks /* How much to unreserve */
)
{
/* Fast case, if unreservation is zero - exit immediately. */
if ( !blocks )
return;
REISERFS_SB(sb)->reserved_blocks -= blocks;
RFALSE( REISERFS_SB(sb)->reserved_blocks < 0, "amount of blocks reserved became zero?");
}
#endif
......@@ -795,8 +795,8 @@ static int get_empty_nodes(
else /* If we have enough already then there is nothing to do. */
return CARRY_ON;
if ( reiserfs_new_blocknrs (p_s_tb->transaction_handle, a_n_blocknrs,
PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_blocknr, n_amount_needed) == NO_DISK_SPACE )
if ( reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs,
n_amount_needed) == NO_DISK_SPACE )
return NO_DISK_SPACE;
/* for each blocknumber we just got, get a buffer and stick it on FEB */
......
......@@ -19,6 +19,7 @@
//
#include <asm/types.h>
#include <asm/page.h>
......@@ -57,7 +58,6 @@ u32 keyed_hash(const signed char *msg, int len)
u32 pad;
int i;
// assert(len >= 0 && len < 256);
pad = (u32)len | ((u32)len << 8);
......@@ -92,7 +92,7 @@ u32 keyed_hash(const signed char *msg, int len)
{
//assert(len < 16);
if (len >= 16)
*(int *)0 = 0;
BUG();
a = (u32)msg[ 0] |
(u32)msg[ 1] << 8 |
......@@ -118,7 +118,7 @@ u32 keyed_hash(const signed char *msg, int len)
{
//assert(len < 12);
if (len >= 12)
*(int *)0 = 0;
BUG();
a = (u32)msg[ 0] |
(u32)msg[ 1] << 8 |
(u32)msg[ 2] << 16|
......@@ -139,7 +139,7 @@ u32 keyed_hash(const signed char *msg, int len)
{
//assert(len < 8);
if (len >= 8)
*(int *)0 = 0;
BUG();
a = (u32)msg[ 0] |
(u32)msg[ 1] << 8 |
(u32)msg[ 2] << 16|
......@@ -156,7 +156,7 @@ u32 keyed_hash(const signed char *msg, int len)
{
//assert(len < 4);
if (len >= 4)
*(int *)0 = 0;
BUG();
a = b = c = d = pad;
for(i = 0; i < len; i++)
{
......
......@@ -157,33 +157,6 @@ static inline void fix_tail_page_for_writing(struct page *page) {
}
}
/* we need to allocate a block for new unformatted node. Try to figure out
what point in bitmap reiserfs_new_blocknrs should start from. */
static b_blocknr_t find_tag (struct buffer_head * bh, struct item_head * ih,
__u32 * item, int pos_in_item)
{
__u32 block ;
if (!is_indirect_le_ih (ih))
/* something more complicated could be here */
return bh->b_blocknr;
/* for indirect item: go to left and look for the first non-hole entry in
the indirect item */
if (pos_in_item == I_UNFM_NUM (ih))
pos_in_item --;
while (pos_in_item >= 0) {
block = get_block_num(item, pos_in_item) ;
if (block)
return block ;
pos_in_item --;
}
return bh->b_blocknr;
}
/* reiserfs_get_block does not need to allocate a block only if it has been
done already or non-hole position has been found in the indirect item */
static inline int allocation_needed (int retval, b_blocknr_t allocated,
......@@ -342,10 +315,10 @@ static int _get_block_create_0 (struct inode * inode, long block,
** kmap schedules
*/
if (!p) {
p = (char *)kmap(bh_result->b_page) ;
if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
goto research;
}
p = (char *)kmap(bh_result->b_page) ;
if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
goto research;
}
}
p += offset ;
memset (p, 0, inode->i_sb->s_blocksize);
......@@ -506,24 +479,24 @@ static int convert_tail_for_hole(struct inode *inode,
}
static inline int _allocate_block(struct reiserfs_transaction_handle *th,
long block,
struct inode *inode,
b_blocknr_t *allocated_block_nr,
unsigned long tag,
struct path * path,
int flags) {
#ifdef REISERFS_PREALLOCATE
if (!(flags & GET_BLOCK_NO_ISEM)) {
return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, tag);
return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, path, block);
}
#endif
return reiserfs_new_unf_blocknrs (th, allocated_block_nr, tag);
return reiserfs_new_unf_blocknrs (th, allocated_block_nr, path, block);
}
int reiserfs_get_block (struct inode * inode, sector_t block,
struct buffer_head * bh_result, int create)
{
int repeat, retval;
unsigned long tag;
b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is unsigned long
INITIALIZE_PATH(path);
int pos_in_item;
......@@ -602,7 +575,6 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
if (allocation_needed (retval, allocated_block_nr, ih, item, pos_in_item)) {
/* we have to allocate block for the unformatted node */
tag = find_tag (bh, ih, item, pos_in_item);
if (!transaction_started) {
pathrelse(&path) ;
journal_begin(&th, inode->i_sb, jbegin_count) ;
......@@ -611,7 +583,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
goto research ;
}
repeat = _allocate_block(&th, inode, &allocated_block_nr, tag, create);
repeat = _allocate_block(&th, block, inode, &allocated_block_nr, &path, create);
if (repeat == NO_DISK_SPACE) {
/* restart the transaction to give the journal a chance to free
......@@ -619,7 +591,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
** research if we succeed on the second try
*/
restart_transaction(&th, inode, &path) ;
repeat = _allocate_block(&th, inode,&allocated_block_nr,tag,create);
repeat = _allocate_block(&th, block, inode, &allocated_block_nr, NULL, create);
if (repeat != NO_DISK_SPACE) {
goto research ;
......@@ -770,8 +742,8 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
add_to_flushlist(inode, unbh) ;
/* mark it dirty now to prevent commit_write from adding
** this buffer to the inode's dirty buffer list
*/
** this buffer to the inode's dirty buffer list
*/
/*
* AKPM: changed __mark_buffer_dirty to mark_buffer_dirty().
* It's still atomic, but it sets the page dirty too,
......@@ -779,7 +751,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
* VM (which was also the case with __mark_buffer_dirty())
*/
mark_buffer_dirty(unbh) ;
//inode->i_blocks += inode->i_sb->s_blocksize / 512;
//mark_tail_converted (inode);
} else {
......@@ -920,7 +892,7 @@ static void init_inode (struct inode * inode, struct path * path)
inode->i_blocks = sd_v1_blocks(sd);
inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id);
blocks = (inode->i_size + 511) >> 9;
blocks = _ROUND_UP (blocks, inode->i_blksize >> 9);
blocks = _ROUND_UP (blocks, inode->i_sb->s_blocksize >> 9);
if (inode->i_blocks > blocks) {
// there was a bug in <=3.5.23 when i_blocks could take negative
// values. Starting from 3.5.17 this value could even be stored in
......@@ -1592,6 +1564,10 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
set_inode_sd_version (inode, STAT_DATA_V2);
/* insert the stat data into the tree */
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
if (REISERFS_I(dir)->new_packing_locality)
th->displace_new_blocks = 1;
#endif
retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
if (retval) {
err = retval;
......@@ -1599,6 +1575,10 @@ int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
goto out_bad_inode;
}
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
if (!th->displace_new_blocks)
REISERFS_I(dir)->new_packing_locality = 0;
#endif
if (S_ISDIR(mode)) {
/* insert item with "." and ".." */
retval = reiserfs_new_directory (th, &ih, &path_to_key, dir);
......@@ -1772,16 +1752,16 @@ void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
reiserfs_update_inode_transaction(p_s_inode) ;
windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
if (update_timestamps)
/* we are doing real truncate: if the system crashes before the last
transaction of truncating gets committed - on reboot the file
either appears truncated properly or not truncated at all */
add_save_link (&th, p_s_inode, 1);
/* we are doing real truncate: if the system crashes before the last
transaction of truncating gets committed - on reboot the file
either appears truncated properly or not truncated at all */
add_save_link (&th, p_s_inode, 1);
reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
pop_journal_writer(windex) ;
journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
if (update_timestamps)
remove_save_link (p_s_inode, 1/* truncate */);
remove_save_link (p_s_inode, 1/* truncate */);
if (page) {
length = offset & (blocksize - 1) ;
......
......@@ -510,14 +510,12 @@ int dump_journal_writers(void) {
**
*/
int reiserfs_in_journal(struct super_block *p_s_sb,
unsigned long bl, int search_all,
int bmap_nr, int bit_nr, int search_all,
unsigned long *next_zero_bit) {
struct reiserfs_journal_cnode *cn ;
struct reiserfs_list_bitmap *jb ;
int i ;
int bmap_nr = bl / (p_s_sb->s_blocksize << 3) ;
int bit_nr = bl % (p_s_sb->s_blocksize << 3) ;
int tmp_bit ;
unsigned long bl;
*next_zero_bit = 0 ; /* always start this at zero. */
......@@ -537,15 +535,15 @@ int reiserfs_in_journal(struct super_block *p_s_sb,
jb = SB_JOURNAL(p_s_sb)->j_list_bitmap + i ;
if (jb->journal_list && jb->bitmaps[bmap_nr] &&
test_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data)) {
tmp_bit = find_next_zero_bit((unsigned long *)
*next_zero_bit = find_next_zero_bit((unsigned long *)
(jb->bitmaps[bmap_nr]->data),
p_s_sb->s_blocksize << 3, bit_nr+1) ;
*next_zero_bit = bmap_nr * (p_s_sb->s_blocksize << 3) + tmp_bit ;
return 1 ;
}
}
}
bl = bmap_nr * (p_s_sb->s_blocksize << 3) + bit_nr;
/* is it in any old transactions? */
if (search_all && (cn = get_journal_hash_dev(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_hash_table, bl))) {
return 1;
......@@ -1820,7 +1818,8 @@ static void reiserfs_journal_commit_task_func(struct reiserfs_journal_commit_tas
jl = SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex ;
flush_commit_list(ct->p_s_sb, SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex, 1) ;
if (jl->j_len > 0 && atomic_read(&(jl->j_nonzerolen)) > 0 &&
if (jl->j_len > 0 && atomic_read(&(jl->j_nonzerolen)) > 0 &&
atomic_read(&(jl->j_commit_left)) == 0) {
kupdate_one_transaction(ct->p_s_sb, jl) ;
}
......
......@@ -661,6 +661,10 @@ static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
struct reiserfs_transaction_handle th ;
int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
/* set flag that new packing locality created and new blocks for the content * of that directory are not displaced yet */
REISERFS_I(dir)->new_packing_locality = 1;
#endif
mode = S_IFDIR | mode;
if (!(inode = new_inode(dir->i_sb))) {
return -ENOMEM ;
......
......@@ -111,7 +111,7 @@ int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
#define SF( x ) ( r -> x )
#define SFP( x ) SF( s_proc_info_data.x )
#define SFPL( x ) SFP( x[ level ] )
#define SFPF( x ) SFP( find_forward.x )
#define SFPF( x ) SFP( scan_bitmap.x )
#define SFPJ( x ) SFP( journal.x )
#define D2C( x ) le16_to_cpu( x )
......@@ -165,6 +165,12 @@ int reiserfs_super_in_proc( char *buffer, char **start, off_t offset,
"search_by_key_fs_changed: \t%lu\n"
"search_by_key_restarted: \t%lu\n"
"insert_item_restarted: \t%lu\n"
"paste_into_item_restarted: \t%lu\n"
"cut_from_item_restarted: \t%lu\n"
"delete_solid_item_restarted: \t%lu\n"
"delete_item_restarted: \t%lu\n"
"leaked_oid: \t%lu\n"
"leaves_removable: \t%lu\n",
......@@ -178,7 +184,7 @@ int reiserfs_super_in_proc( char *buffer, char **start, off_t offset,
reiserfs_no_unhashed_relocation( sb ) ? "NO_UNHASHED_RELOCATION " : "",
reiserfs_hashed_relocation( sb ) ? "UNHASHED_RELOCATION " : "",
reiserfs_test4( sb ) ? "TEST4 " : "",
dont_have_tails( sb ) ? "NO_TAILS " : "TAILS ",
have_large_tails( sb ) ? "TAILS " : have_small_tails(sb)?"SMALL_TAILS ":"NO_TAILS ",
replay_only( sb ) ? "REPLAY_ONLY " : "",
reiserfs_dont_log( sb ) ? "DONT_LOG " : "LOG ",
convert_reiserfs( sb ) ? "CONV " : "",
......@@ -201,6 +207,13 @@ int reiserfs_super_in_proc( char *buffer, char **start, off_t offset,
SFP( search_by_key ),
SFP( search_by_key_fs_changed ),
SFP( search_by_key_restarted ),
SFP( insert_item_restarted ),
SFP( paste_into_item_restarted ),
SFP( cut_from_item_restarted ),
SFP( delete_solid_item_restarted ),
SFP( delete_item_restarted ),
SFP( leaked_oid ),
SFP( leaves_removable ) );
......@@ -301,27 +314,30 @@ int reiserfs_bitmap_in_proc( char *buffer, char **start, off_t offset,
r = REISERFS_SB(sb);
len += sprintf( &buffer[ len ], "free_block: %lu\n"
"find_forward:"
" wait"
" bmap"
" retry"
" journal_hint"
" journal_out"
" scan_bitmap:"
" wait"
" bmap"
" retry"
" stolen"
" journal_hint"
"journal_nohint"
"\n"
" %12lu"
" %12lu"
" %12lu"
" %12lu"
" %12lu"
" %12lu"
" %14lu"
" %14lu"
" %14lu"
" %14lu"
" %14lu"
" %14lu"
" %14lu"
"\n",
SFP( free_block ),
SFPF( call ),
SFPF( wait ),
SFPF( bmap ),
SFPF( retry ),
SFPF( stolen ),
SFPF( in_journal_hint ),
SFPF( in_journal_out ) );
SFPF( in_journal_nohint ) );
procinfo_epilogue( sb );
return reiserfs_proc_tail( len, buffer, start, offset, count, eof );
......
......@@ -19,7 +19,8 @@
int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
{
struct reiserfs_super_block * sb;
struct buffer_head ** bitmap, * bh;
struct reiserfs_bitmap_info *bitmap;
struct buffer_head * bh;
struct reiserfs_transaction_handle th;
unsigned int bmap_nr_new, bmap_nr;
unsigned int block_r_new, block_r;
......@@ -103,26 +104,29 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
/* allocate additional bitmap blocks, reallocate array of bitmap
* block pointers */
bitmap = reiserfs_kmalloc(sizeof(struct buffer_head *) * bmap_nr_new, GFP_KERNEL, s);
bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
if (!bitmap) {
printk("reiserfs_resize: unable to allocate memory.\n");
return -ENOMEM;
}
memset (bitmap, 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
for (i = 0; i < bmap_nr; i++)
bitmap[i] = SB_AP_BITMAP(s)[i];
for (i = bmap_nr; i < bmap_nr_new; i++) {
bitmap[i] = sb_getblk(s, i * s->s_blocksize * 8);
memset(bitmap[i]->b_data, 0, sb_blocksize(sb));
reiserfs_test_and_set_le_bit(0, bitmap[i]->b_data);
mark_buffer_dirty(bitmap[i]) ;
set_buffer_uptodate(bitmap[i]);
ll_rw_block(WRITE, 1, bitmap + i);
wait_on_buffer(bitmap[i]);
bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);
mark_buffer_dirty(bitmap[i].bh) ;
set_buffer_uptodate(bitmap[i].bh);
ll_rw_block(WRITE, 1, &bitmap[i].bh);
wait_on_buffer(bitmap[i].bh);
// update bitmap_info stuff
bitmap[i].first_zero_hint=1;
bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
}
/* free old bitmap blocks array */
reiserfs_kfree(SB_AP_BITMAP(s),
sizeof(struct buffer_head *) * bmap_nr, s);
vfree(SB_AP_BITMAP(s));
SB_AP_BITMAP(s) = bitmap;
}
......@@ -130,18 +134,26 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
journal_begin(&th, s, 10);
/* correct last bitmap blocks in old and new disk layout */
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1], 1);
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
for (i = block_r; i < s->s_blocksize * 8; i++)
reiserfs_test_and_clear_le_bit(i,
SB_AP_BITMAP(s)[bmap_nr - 1]->b_data);
journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1]);
SB_AP_BITMAP(s)[bmap_nr - 1].bh->b_data);
SB_AP_BITMAP(s)[bmap_nr - 1].free_count += s->s_blocksize * 8 - block_r;
if ( !SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint)
SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r;
journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh);
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1], 1);
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1);
for (i = block_r_new; i < s->s_blocksize * 8; i++)
reiserfs_test_and_set_le_bit(i,
SB_AP_BITMAP(s)[bmap_nr_new - 1]->b_data);
journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1]);
SB_AP_BITMAP(s)[bmap_nr_new - 1].bh->b_data);
journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh);
SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -= s->s_blocksize * 8 - block_r_new;
/* Extreme case where last bitmap is the only valid block in itself. */
if ( !SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count )
SB_AP_BITMAP(s)[bmap_nr_new - 1].first_zero_hint = 0;
/* update super */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
free_blocks = SB_FREE_BLOCKS(s);
......
......@@ -1245,6 +1245,8 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
if ( n_ret_value != REPEAT_SEARCH )
break;
PROC_INFO_INC( p_s_sb, delete_item_restarted );
// file system changed, repeat search
n_ret_value = search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
if (n_ret_value == IO_ERROR)
......@@ -1355,8 +1357,10 @@ void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
}
retval = fix_nodes (M_DELETE, &tb, NULL, 0);
if (retval == REPEAT_SEARCH)
if (retval == REPEAT_SEARCH) {
PROC_INFO_INC( th -> t_super, delete_solid_item_restarted );
continue;
}
if (retval == CARRY_ON) {
do_balance (&tb, 0, 0, M_DELETE);
......@@ -1543,6 +1547,8 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
if ( n_ret_value != REPEAT_SEARCH )
break;
PROC_INFO_INC( p_s_sb, cut_from_item_restarted );
n_ret_value = search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
if (n_ret_value == POSITION_FOUND)
continue;
......@@ -1614,9 +1620,9 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
do_balance(&s_cut_balance, NULL, NULL, c_mode);
if ( n_is_inode_locked ) {
/* we've done an indirect->direct conversion. when the data block
** was freed, it was removed from the list of blocks that must
** be flushed before the transaction commits, so we don't need to
/* we've done an indirect->direct conversion. when the data block
** was freed, it was removed from the list of blocks that must
** be flushed before the transaction commits, so we don't need to
** deal with it here.
*/
REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ;
......@@ -1807,16 +1813,20 @@ int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th,
int retval;
init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size);
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
s_paste_balance.key = p_s_key->on_disk_key;
#endif
while ( (retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == REPEAT_SEARCH ) {
/* file system changed while we were in the fix_nodes */
PROC_INFO_INC( th -> t_super, paste_into_item_restarted );
retval = search_for_position_by_key (th->t_super, p_s_key, p_s_search_path);
if (retval == IO_ERROR) {
retval = -EIO ;
goto error_out ;
}
if (retval == POSITION_FOUND) {
reiserfs_warning ("PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists", p_s_key);
reiserfs_warning ("PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists\n", p_s_key);
retval = -EEXIST ;
goto error_out ;
}
......@@ -1851,6 +1861,9 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
int retval;
init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih));
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
s_ins_balance.key = key->on_disk_key;
#endif
/*
if (p_c_body == 0)
......@@ -1860,6 +1873,7 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
while ( (retval = fix_nodes(M_INSERT, &s_ins_balance, p_s_ih, p_c_body)) == REPEAT_SEARCH) {
/* file system changed while we were in the fix_nodes */
PROC_INFO_INC( th -> t_super, insert_item_restarted );
retval = search_item (th->t_super, key, p_s_path);
if (retval == IO_ERROR) {
retval = -EIO;
......
......@@ -13,6 +13,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include <linux/reiserfs_fs.h>
......@@ -374,9 +375,9 @@ static void reiserfs_put_super (struct super_block * s)
journal_release(&th, s) ;
for (i = 0; i < SB_BMAP_NR (s); i ++)
brelse (SB_AP_BITMAP (s)[i]);
brelse (SB_AP_BITMAP (s)[i].bh);
reiserfs_kfree (SB_AP_BITMAP (s), sizeof (struct buffer_head *) * SB_BMAP_NR (s), s);
vfree (SB_AP_BITMAP (s));
brelse (SB_BUFFER_WITH_SB (s));
......@@ -387,6 +388,11 @@ static void reiserfs_put_super (struct super_block * s)
REISERFS_SB(s)->s_kmallocs);
}
if (REISERFS_SB(s)->reserved_blocks != 0) {
reiserfs_warning ("green-2005: reiserfs_put_super: reserved blocks left %d\n",
REISERFS_SB(s)->reserved_blocks);
}
reiserfs_proc_unregister( s, "journal" );
reiserfs_proc_unregister( s, "oidmap" );
reiserfs_proc_unregister( s, "on-disk-super" );
......@@ -518,6 +524,13 @@ const arg_desc_t balloc[] = {
{NULL, -1}
};
const arg_desc_t tails[] = {
{"on", REISERFS_LARGETAIL},
{"off", -1},
{"small", REISERFS_SMALLTAIL},
{NULL, 0}
};
/* proceed only one option from a list *cur - string containing of mount options
opts - array of options which are accepted
......@@ -525,7 +538,7 @@ const arg_desc_t balloc[] = {
in the input - pointer to the argument is stored here
bit_flags - if option requires to set a certain bit - it is set here
return -1 if unknown option is found, opt->arg_required otherwise */
static int reiserfs_getopt (char ** cur, opt_desc_t * opts, char ** opt_arg,
static int reiserfs_getopt ( struct super_block * s, char ** cur, opt_desc_t * opts, char ** opt_arg,
unsigned long * bit_flags)
{
char * p;
......@@ -547,7 +560,16 @@ static int reiserfs_getopt (char ** cur, opt_desc_t * opts, char ** opt_arg,
*(*cur) = '\0';
(*cur) ++;
}
if ( !strncmp (p, "alloc=", 6) ) {
/* Ugly special case, probably we should redo options parser so that
it can understand several arguments for some options, also so that
it can fill several bitfields with option values. */
reiserfs_parse_alloc_options( s, p + 6);
return 0;
}
/* for every option in the list */
for (opt = opts; opt->option_name; opt ++) {
if (!strncmp (p, opt->option_name, strlen (opt->option_name))) {
......@@ -612,7 +634,7 @@ static int reiserfs_getopt (char ** cur, opt_desc_t * opts, char ** opt_arg,
/* returns 0 if something is wrong in option string, 1 - otherwise */
static int reiserfs_parse_options (char * options, /* string given via mount's -o */
static int reiserfs_parse_options (struct super_block * s, char * options, /* string given via mount's -o */
unsigned long * mount_options,
/* after the parsing phase, contains the
collection of bitflags defining what
......@@ -624,14 +646,14 @@ static int reiserfs_parse_options (char * options, /* string given via mount's -
char * arg = NULL;
char * pos;
opt_desc_t opts[] = {
{"notail", 0, 0, NOTAIL},
{"tails", 't', tails, -1},
{"notail", 0, 0, -1}, /* Compatibility stuff, so that -o notail
for old setups still work */
{"conv", 0, 0, REISERFS_CONVERT},
{"attrs", 0, 0, REISERFS_ATTRS},
{"nolog", 0, 0, -1},
{"replayonly", 0, 0, REPLAYONLY},
{"block-allocator", 'a', balloc, -1},
{"resize", 'r', 0, -1},
{"jdev", 'j', 0, -1},
{NULL, 0, 0, -1}
......@@ -642,9 +664,12 @@ static int reiserfs_parse_options (char * options, /* string given via mount's -
/* use default configuration: create tails, journaling on, no
conversion to newest format */
return 1;
else
/* Drop defaults to zeroes */
*mount_options = 0;
for (pos = options; pos; ) {
c = reiserfs_getopt (&pos, opts, &arg, mount_options);
c = reiserfs_getopt (s, &pos, opts, &arg, mount_options);
if (c == -1)
/* wrong option is given */
return 0;
......@@ -681,7 +706,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
rs = SB_DISK_SUPER_BLOCK (s);
if (!reiserfs_parse_options(arg, &mount_options, &blocks, NULL))
if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL))
return -EINVAL;
if(blocks) {
......@@ -731,32 +756,84 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
return 0;
}
/* load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure from disk.
* @sb - superblock for this filesystem
* @bi - the bitmap info to be loaded. Requires that bi->bh is valid.
*
* This routine counts how many free bits there are, finding the first zero
* as a side effect. Could also be implemented as a loop of test_bit() calls, or
* a loop of find_first_zero_bit() calls. This implementation is similar to
* find_first_zero_bit(), but doesn't return after it finds the first bit.
* Should only be called on fs mount, but should be fairly efficient anyways.
*
* bi->first_zero_hint is considered unset if it == 0, since the bitmap itself
* will * invariably occupt block 0 represented in the bitmap. The only
* exception to this is when free_count also == 0, since there will be no
* free blocks at all.
*/
static void load_bitmap_info_data (struct super_block *sb,
struct reiserfs_bitmap_info *bi)
{
unsigned long *cur = (unsigned long *)bi->bh->b_data;
while ((char *)cur < (bi->bh->b_data + sb->s_blocksize)) {
/* No need to scan if all 0's or all 1's.
* Since we're only counting 0's, we can simply ignore all 1's */
if (*cur == 0) {
if (bi->first_zero_hint == 0) {
bi->first_zero_hint = ((char *)cur - bi->bh->b_data) << 3;
}
bi->free_count += sizeof(unsigned long)*8;
} else if (*cur != ~0L) {
int b;
for (b = 0; b < sizeof(unsigned long)*8; b++) {
if (!reiserfs_test_le_bit (b, cur)) {
bi->free_count ++;
if (bi->first_zero_hint == 0)
bi->first_zero_hint =
(((char *)cur - bi->bh->b_data) << 3) + b;
}
}
}
cur ++;
}
#ifdef CONFIG_REISERFS_CHECK
// This outputs a lot of unneded info on big FSes
// reiserfs_warning ("bitmap loaded from block %d: %d free blocks\n",
// bi->bh->b_blocknr, bi->free_count);
#endif
}
static int read_bitmaps (struct super_block * s)
{
int i, bmap_nr;
SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * SB_BMAP_NR(s), GFP_NOFS, s);
SB_AP_BITMAP (s) = vmalloc (sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
if (SB_AP_BITMAP (s) == 0)
return 1;
memset (SB_AP_BITMAP (s), 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
for (i = 0, bmap_nr = REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
i < SB_BMAP_NR(s); i++, bmap_nr = s->s_blocksize * 8 * i) {
SB_AP_BITMAP (s)[i] = sb_getblk(s, bmap_nr);
if (!buffer_uptodate(SB_AP_BITMAP(s)[i]))
ll_rw_block(READ, 1, SB_AP_BITMAP(s) + i);
SB_AP_BITMAP (s)[i].bh = sb_getblk(s, bmap_nr);
if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh))
ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh);
}
for (i = 0; i < SB_BMAP_NR(s); i++) {
wait_on_buffer(SB_AP_BITMAP (s)[i]);
if (!buffer_uptodate(SB_AP_BITMAP(s)[i])) {
wait_on_buffer(SB_AP_BITMAP (s)[i].bh);
if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
reiserfs_warning("sh-2029: reiserfs read_bitmaps: "
"bitmap block (#%lu) reading failed\n",
SB_AP_BITMAP(s)[i]->b_blocknr);
SB_AP_BITMAP(s)[i].bh->b_blocknr);
for (i = 0; i < SB_BMAP_NR(s); i++)
brelse(SB_AP_BITMAP(s)[i]);
reiserfs_kfree(SB_AP_BITMAP(s), sizeof(struct buffer_head *) * SB_BMAP_NR(s), s);
brelse(SB_AP_BITMAP(s)[i].bh);
vfree(SB_AP_BITMAP(s));
SB_AP_BITMAP(s) = NULL;
return 1;
}
load_bitmap_info_data (s, SB_AP_BITMAP (s) + i);
}
return 0;
}
......@@ -768,16 +845,17 @@ static int read_old_bitmaps (struct super_block * s)
int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */
/* read true bitmap */
SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * sb_bmap_nr(rs), GFP_NOFS, s);
SB_AP_BITMAP (s) = vmalloc (sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
if (SB_AP_BITMAP (s) == 0)
return 1;
memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * sb_bmap_nr(rs));
memset (SB_AP_BITMAP (s), 0, sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
for (i = 0; i < sb_bmap_nr(rs); i ++) {
SB_AP_BITMAP (s)[i] = sb_bread (s, bmp1 + i);
if (!SB_AP_BITMAP (s)[i])
SB_AP_BITMAP (s)[i].bh = sb_bread (s, bmp1 + i);
if (!SB_AP_BITMAP (s)[i].bh)
return 1;
load_bitmap_info_data (s, SB_AP_BITMAP (s) + i);
}
return 0;
......@@ -790,7 +868,7 @@ void check_bitmap (struct super_block * s)
char * buf;
while (i < SB_BLOCK_COUNT (s)) {
buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)]->b_data;
buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)].bh->b_data;
if (!reiserfs_test_le_bit (i % (s->s_blocksize * 8), buf))
free ++;
i ++;
......@@ -899,10 +977,11 @@ static int reread_meta_blocks(struct super_block *s) {
}
for (i = 0; i < SB_BMAP_NR(s) ; i++) {
ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i])) ;
wait_on_buffer(SB_AP_BITMAP(s)[i]) ;
if (!buffer_uptodate(SB_AP_BITMAP(s)[i])) {
printk("reread_meta_blocks, error reading bitmap block number %d at %ld\n", i, SB_AP_BITMAP(s)[i]->b_blocknr) ;
ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh)) ;
wait_on_buffer(SB_AP_BITMAP(s)[i].bh) ;
if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
printk("reread_meta_blocks, error reading bitmap block number %d at
%ld\n", i, SB_AP_BITMAP(s)[i].bh->b_blocknr) ;
return 1 ;
}
}
......@@ -1087,9 +1166,17 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
}
s->u.generic_sbp = sbi;
memset (sbi, 0, sizeof (struct reiserfs_sb_info));
/* Set default values for options: non-aggressive tails */
REISERFS_SB(s)->s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
/* default block allocator option: skip_busy */
REISERFS_SB(s)->s_alloc_options.bits = ( 1 << 5);
/* If file grew past 4 blocks, start preallocation blocks for it. */
REISERFS_SB(s)->s_alloc_options.preallocmin = 4;
/* Preallocate by 8 blocks (9-1) at once */
REISERFS_SB(s)->s_alloc_options.preallocsize = 9;
jdev_name = NULL;
if (reiserfs_parse_options ((char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name) == 0) {
if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name) == 0) {
goto error;
}
......@@ -1236,10 +1323,10 @@ static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
if (SB_DISK_SUPER_BLOCK (s)) {
for (j = 0; j < SB_BMAP_NR (s); j ++) {
if (SB_AP_BITMAP (s))
brelse (SB_AP_BITMAP (s)[j]);
brelse (SB_AP_BITMAP (s)[j].bh);
}
if (SB_AP_BITMAP (s))
reiserfs_kfree (SB_AP_BITMAP (s), sizeof (struct buffer_head *) * SB_BMAP_NR (s), s);
vfree (SB_AP_BITMAP (s));
}
if (SB_BUFFER_WITH_SB (s))
brelse(SB_BUFFER_WITH_SB (s));
......
......@@ -59,7 +59,8 @@
#define USE_INODE_GENERATION_COUNTER
#define REISERFS_PREALLOCATE
#define PREALLOCATION_SIZE 8
#define DISPLACE_NEW_PACKING_LOCALITIES
#define PREALLOCATION_SIZE 9
/* n must be power of 2 */
#define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u))
......@@ -326,7 +327,7 @@ static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
time cost for a 4 block file and saves an amount of space that is
less significant as a percentage of space, or so goes the hypothesis.
-Hans */
#define STORE_TAIL_IN_UNFM(n_file_size,n_tail_size,n_block_size) \
#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
(\
(!(n_tail_size)) || \
(((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
......@@ -339,6 +340,18 @@ static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
)
/* Another strategy for tails, this one means only create a tail if all the
file would fit into one DIRECT item.
Primary intention for this one is to increase performance by decreasing
seeking.
*/
#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
(\
(!(n_tail_size)) || \
(((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
)
/*
* values for s_umount_state field
......@@ -1433,6 +1446,10 @@ struct tree_balance
int fs_gen; /* saved value of `reiserfs_generation' counter
see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
struct key key; /* key pointer, to pass to block allocator or
another low-level subsystem */
#endif
} ;
/* These are modes of balancing */
......@@ -1673,7 +1690,7 @@ int journal_mark_freed(struct reiserfs_transaction_handle *, struct super_block
int push_journal_writer(char *w) ;
int pop_journal_writer(int windex) ;
int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
int reiserfs_in_journal(struct super_block *p_s_sb, unsigned long bl, int searchall, unsigned long *next) ;
int reiserfs_in_journal(struct super_block *p_s_sb, int bmap_nr, int bit_nr, int searchall, unsigned long *next) ;
int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
void flush_async_commits(struct super_block *p_s_sb) ;
......@@ -1818,8 +1835,8 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
#define file_size(inode) ((inode)->i_size)
#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
#define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
!STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), i_block_size (inode)))
#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
void padd_item (char * item, int total_length, int length);
......@@ -2015,22 +2032,87 @@ void make_empty_node (struct buffer_info *);
struct buffer_head * get_FEB (struct tree_balance *);
/* bitmap.c */
/* structure contains hints for block allocator, and it is a container for
* arguments, such as node, search path, transaction_handle, etc. */
struct __reiserfs_blocknr_hint {
struct inode * inode; /* inode passed to allocator, if we allocate unf. nodes */
long block; /* file offset, in blocks */
struct key key;
struct path * path; /* search path, used by allocator to deternine search_start by
* various ways */
struct reiserfs_transaction_handle * th; /* transaction handle is needed to log super blocks and
* bitmap blocks changes */
b_blocknr_t beg, end;
b_blocknr_t search_start; /* a field used to transfer search start value (block number)
* between different block allocator procedures
* (determine_search_start() and others) */
int prealloc_size; /* is set in determine_prealloc_size() function, used by underlayed
* function that do actual allocation */
int formatted_node:1; /* the allocator uses different polices for getting disk space for
* formatted/unformatted blocks with/without preallocation */
int preallocate:1;
};
typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
int reiserfs_parse_alloc_options (struct super_block *, char *);
int is_reusable (struct super_block * s, unsigned long block, int bit_value);
void reiserfs_free_block (struct reiserfs_transaction_handle *th, unsigned long);
int reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th,
unsigned long * pblocknrs, unsigned long start_from, int amount_needed);
int reiserfs_new_unf_blocknrs (struct reiserfs_transaction_handle *th,
unsigned long * pblocknr, unsigned long start_from);
int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int);
extern inline int reiserfs_new_form_blocknrs (struct tree_balance * tb,
b_blocknr_t *new_blocknrs, int amount_needed)
{
reiserfs_blocknr_hint_t hint = {
th:tb->transaction_handle,
path: tb->tb_path,
inode: NULL,
key: tb->key,
block: 0,
formatted_node:1
};
return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed, 0);
}
extern inline int reiserfs_new_unf_blocknrs (struct reiserfs_transaction_handle *th,
b_blocknr_t *new_blocknrs,
struct path * path, long block)
{
reiserfs_blocknr_hint_t hint = {
th: th,
path: path,
inode: NULL,
block: block,
formatted_node: 0,
preallocate: 0
};
return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
}
#ifdef REISERFS_PREALLOCATE
int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th,
struct inode * inode,
unsigned long * pblocknr,
unsigned long start_from);
extern inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle *th,
struct inode * inode,
b_blocknr_t *new_blocknrs,
struct path * path, long block)
{
reiserfs_blocknr_hint_t hint = {
th: th,
path: path,
inode: inode,
block: block,
formatted_node: 0,
preallocate: 1
};
return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
}
void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
struct inode * inode);
void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th);
#endif
void reiserfs_claim_blocks_to_be_allocated( struct super_block *sb, int blocks);
void reiserfs_release_claimed_blocks( struct super_block *sb, int blocks);
/* hashes.c */
__u32 keyed_hash (const signed char *msg, int len);
......
......@@ -37,6 +37,10 @@ struct reiserfs_inode_info {
struct list_head i_prealloc_list; /* per-transaction list of inodes which
* have preallocated blocks */
int new_packing_locality:1; /* new_packig_locality is created; new blocks
* for the contents of this directory should be
* displaced */
/* we use these for fsync or O_SYNC to decide which transaction
** needs to be committed in order for this inode to be properly
** flushed */
......
......@@ -160,7 +160,10 @@ struct reiserfs_transaction_handle {
int t_blocks_allocated ; /* number of blocks this writer allocated */
unsigned long t_trans_id ; /* sanity check, equals the current trans id */
struct super_block *t_super ; /* super for this FS when journal_begin was
called. */
called. saves calls to reiserfs_get_super */
int displace_new_blocks:1; /* if new block allocation occurres, that block
should be displaced from others */
} ;
/*
......@@ -254,6 +257,14 @@ struct reiserfs_journal {
typedef __u32 (*hashf_t) (const signed char *, int);
struct reiserfs_bitmap_info
{
// FIXME: Won't work with block sizes > 8K
__u16 first_zero_hint;
__u16 free_count;
struct buffer_head *bh; /* the actual bitmap */
};
struct proc_dir_entry;
#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
......@@ -270,6 +281,12 @@ typedef struct reiserfs_proc_info_data
stat_cnt_t search_by_key_fs_changed;
stat_cnt_t search_by_key_restarted;
stat_cnt_t insert_item_restarted;
stat_cnt_t paste_into_item_restarted;
stat_cnt_t cut_from_item_restarted;
stat_cnt_t delete_solid_item_restarted;
stat_cnt_t delete_item_restarted;
stat_cnt_t leaked_oid;
stat_cnt_t leaves_removable;
......@@ -292,14 +309,15 @@ typedef struct reiserfs_proc_info_data
stat_cnt_t need_r_neighbor[ 5 ];
stat_cnt_t free_block;
struct __find_forward_stats {
struct __scan_bitmap_stats {
stat_cnt_t call;
stat_cnt_t wait;
stat_cnt_t bmap;
stat_cnt_t retry;
stat_cnt_t in_journal_hint;
stat_cnt_t in_journal_out;
} find_forward;
stat_cnt_t in_journal_nohint;
stat_cnt_t stolen;
} scan_bitmap;
struct __journal_stats {
stat_cnt_t in_journal;
stat_cnt_t in_journal_bitmap;
......@@ -329,7 +347,7 @@ struct reiserfs_sb_info
/* both the comment and the choice of
name are unclear for s_rs -Hans */
struct reiserfs_super_block * s_rs; /* Pointer to the super block in the buffer */
struct buffer_head ** s_ap_bitmap; /* array of buffers, holding block bitmap */
struct reiserfs_bitmap_info * s_ap_bitmap;
struct reiserfs_journal *s_journal ; /* pointer to journal information */
unsigned short s_mount_state; /* reiserfs state (valid, invalid) */
......@@ -342,6 +360,16 @@ struct reiserfs_sb_info
here (currently - NOTAIL, NOLOG,
REPLAYONLY) */
struct { /* This is a structure that describes block allocator options */
unsigned long bits; /* Bitfield for enable/disable kind of options */
unsigned long large_file_size; /* size started from which we consider file to be a large one(in blocks) */
int border; /* percentage of disk, border takes */
int preallocmin; /* Minimal file size (in blocks) starting from which we do preallocations */
int preallocsize; /* Number of blocks we try to prealloc when file
reaches preallocmin size (in blocks) or
prealloc_list is empty. */
} s_alloc_options;
/* Comment? -Hans */
wait_queue_head_t s_wait;
/* To be obsoleted soon by per buffer seals.. -Hans */
......@@ -368,6 +396,7 @@ struct reiserfs_sb_info
int s_is_unlinked_ok;
reiserfs_proc_info_data_t s_proc_info_data;
struct proc_dir_entry *procdir;
int reserved_blocks; /* amount of blocks reserved for further allocations */
};
/* Definitions of reiserfs on-disk properties: */
......@@ -375,7 +404,8 @@ struct reiserfs_sb_info
#define REISERFS_3_6 1
/* Mount options */
#define NOTAIL 0 /* -o notail: no tails will be created in a session */
#define REISERFS_LARGETAIL 0 /* large tails will be created in a session */
#define REISERFS_SMALLTAIL 17 /* small (for files less than block size) tails will be created in a session */
#define REPLAYONLY 3 /* replay journal and return 0. Use by fsck */
#define REISERFS_NOLOG 4 /* -o nolog: turn journalling off */
#define REISERFS_CONVERT 5 /* -o conv: causes conversion of old
......@@ -423,7 +453,8 @@ struct reiserfs_sb_info
#define reiserfs_hashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
#define reiserfs_test4(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TEST4))
#define dont_have_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << NOTAIL))
#define have_large_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_LARGETAIL))
#define have_small_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_SMALLTAIL))
#define replay_only(s) (REISERFS_SB(s)->s_mount_opt & (1 << REPLAYONLY))
#define reiserfs_dont_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NOLOG))
#define old_format_only(s) (REISERFS_SB(s)->s_properties & (1 << REISERFS_3_5))
......
......@@ -490,15 +490,6 @@ static void __init do_initcalls(void)
*/
static void __init do_basic_setup(void)
{
#if defined(CONFIG_MTRR) /* Do this after SMP initialization */
/*
* We should probably create some architecture-dependent "fixup after
* everything is up" style function where this would belong better
* than in init/main.c..
*/
mtrr_init();
#endif
#ifdef CONFIG_SYSCTL
sysctl_init();
#endif
......@@ -545,6 +536,15 @@ static int init(void * unused)
*/
child_reaper = current;
#if defined(CONFIG_MTRR) /* Do this after SMP initialization */
/*
* We should probably create some architecture-dependent "fixup after
* everything is up" style function where this would belong better
* than in init/main.c..
*/
mtrr_init();
#endif
/* Sets up cpus_possible() */
smp_prepare_cpus(max_cpus);
......
......@@ -532,7 +532,7 @@ static void exit_notify(void)
*
*/
if(current->exit_signal != SIGCHLD &&
if (current->exit_signal != SIGCHLD && current->exit_signal != -1 &&
( current->parent_exec_id != t->self_exec_id ||
current->self_exec_id != current->parent_exec_id)
&& !capable(CAP_KILL))
......
......@@ -1220,6 +1220,7 @@ int get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs)
#endif
EXPORT_SYMBOL(recalc_sigpending);
EXPORT_SYMBOL(dequeue_signal);
EXPORT_SYMBOL(flush_signals);
EXPORT_SYMBOL(force_sig);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment