📄 io.c
字号:
/* * Copyright 1996-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */#include "io.h"#include <string.h>#include <errno.h>#include <asm/types.h>void check_memory_msg (void) { fprintf(stderr, "\nThe problem has occurred looks like a hardware problem (perhaps\n" "memory). Send us the bug report only if the second run dies at\n" "the same place with the same block number.\n");}void check_hd_msg (void) { fprintf(stderr, "\nThe problem has occurred looks like a hardware problem. If you have\n" "bad blocks, we advise you to get a new hard drive, because once you\n" "get one bad block that the disk drive internals cannot hide from\n" "your sight,the chances of getting more are generally said to become\n" "much higher (precise statistics are unknown to us), and this disk\n" "drive is probably not expensive enough for you to you to risk your\n" "time and data on it. If you don't want to follow that follow that\n" "advice then if you have just a few bad blocks, try writing to the\n" "bad blocks and see if the drive remaps the bad blocks (that means\n" "it takes a block it has in reserve and allocates it for use for\n" "of that block number). If it cannot remap the block, use badblock\n" "option (-B) with reiserfs utils to handle this block correctly.\n");}static int is_bad_block (unsigned long block){#ifdef IO_FAILURE_EMULATION /* this array similates bad blocks on the device */ unsigned long bad_blocks [] = { 8208, 8209, 8210/*, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19*/ }; int i; for (i = 0; i < sizeof (bad_blocks) / sizeof (bad_blocks[0]); i ++) if (bad_blocks [i] == block) return 1;#endif return 0;}/* All buffers are in double linked cycled list. If getblk found buffer with wanted block number in hash queue it moves buffer to the end of list. */static int g_nr_buffers;static unsigned long buffers_memory;/* create buffers until we spend this fraction of system memory, this** is a hard limit on the amount of buffer ram used*/#define BUFFER_MEMORY_FRACTION 10/* number of bytes in local buffer cache before we start forcing syncs** of dirty data and reusing unused buffers instead of allocating new** ones. If a flush doesn't find reusable buffers, new ones are** still allocated up to the BUFFER_MEMORY_FRACTION percentage***/#define BUFFER_SOFT_LIMIT (500 * 1024)static unsigned long buffer_soft_limit = BUFFER_SOFT_LIMIT;#define NR_HASH_QUEUES 4096static struct buffer_head * g_a_hash_queues [NR_HASH_QUEUES];static struct buffer_head * Buffer_list_head;static struct buffer_head * g_free_buffers = NULL ;static struct buffer_head * g_buffer_heads;static int buffer_hits = 0 ;static int buffer_misses = 0 ;static int buffer_reads = 0 ;static int buffer_writes = 0 ;static void _show_buffers(struct buffer_head **list, int dev, unsigned long size) { int all = 0; int dirty = 0; int in_use = 0; /* count != 0 */ int free = 0; struct buffer_head * next; next = *list; if (!next) return ; for (;;) { if (next->b_dev == dev && next->b_size == size) { all ++; if (next->b_count != 0) { in_use ++; } if (buffer_dirty (next)) { dirty ++; } if (buffer_clean (next) && next->b_count == 0) { free ++; } } next = next->b_next; if (next == *list) break; } printf("show_buffers (dev %d, size %lu): free %d, count != 0 %d, dirty %d, " "all %d\n", dev, size, free, in_use, dirty, all);}static void show_buffers (int dev, int size){ _show_buffers(&Buffer_list_head, dev, size) ; _show_buffers(&g_free_buffers, dev, size) ;}static void insert_into_hash_queue (struct buffer_head * bh){ int index = bh->b_blocknr % NR_HASH_QUEUES; if (bh->b_hash_prev || bh->b_hash_next) die ("insert_into_hash_queue: hash queue corrupted"); if (g_a_hash_queues[index]) { g_a_hash_queues[index]->b_hash_prev = bh; bh->b_hash_next = g_a_hash_queues[index]; } g_a_hash_queues[index] = bh;}static void remove_from_hash_queue (struct buffer_head * bh){ if (bh->b_hash_next == 0 && bh->b_hash_prev == 0 && bh != g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES]) /* (b_dev == -1) ? */ return; if (bh == g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES]) { if (bh->b_hash_prev != 0) die ("remove_from_hash_queue: hash queue corrupted"); g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES] = bh->b_hash_next; } if (bh->b_hash_next) bh->b_hash_next->b_hash_prev = bh->b_hash_prev; if (bh->b_hash_prev) bh->b_hash_prev->b_hash_next = bh->b_hash_next; bh->b_hash_prev = bh->b_hash_next = 0;}static void put_buffer_list_end (struct buffer_head **list, struct buffer_head * bh){ struct buffer_head * last = 0; if (bh->b_prev || bh->b_next) die ("put_buffer_list_end: buffer list corrupted"); if (*list == 0) { bh->b_next = bh; bh->b_prev = bh; *list = bh; } else { last = (*list)->b_prev; bh->b_next = last->b_next; bh->b_prev = last; last->b_next->b_prev = bh; last->b_next = bh; }}static void remove_from_buffer_list (struct buffer_head **list, struct buffer_head * bh){ if (bh == bh->b_next) { *list = 0; } else { bh->b_prev->b_next = bh->b_next; bh->b_next->b_prev = bh->b_prev; if (bh == *list) *list = bh->b_next; } bh->b_next = bh->b_prev = 0;}static void put_buffer_list_head (struct buffer_head **list, struct buffer_head * bh){ put_buffer_list_end (list, bh); *list = bh;}/*#include <sys/mman.h>static size_t estimate_memory_amount (void){ size_t len = 1; size_t max = 0; void * addr; while (len > 0) { addr = mmap (0, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) { if (errno != ENOMEM) die ("mmap failed: %s\n", strerror(errno)); break; } if (mlock (addr, len) != 0) { if (errno == EPERM) die ("No permission to run mlock"); break; } munlock (addr, len); munmap (addr, len); max = len; len *= 2; } // * If we've looped, we don't want to return 0, we want to return the // * last successful len before we looped. In the event that mmap/mlock // * failed for len = 1, max will still be 0, so we don't get an invalid // * result return max;}*/#define GROW_BUFFERS__NEW_BUFERS_PER_CALL 10/* creates number of new buffers and insert them into head of buffer list */static int grow_buffers (int size){ int i; struct buffer_head * bh, * tmp; /* get memory for array of buffer heads */ bh = (struct buffer_head *)getmem (GROW_BUFFERS__NEW_BUFERS_PER_CALL * sizeof (struct buffer_head) + sizeof (struct buffer_head *)); if (g_buffer_heads == 0) g_buffer_heads = bh; else { /* link new array to the end of array list */ tmp = g_buffer_heads; while (*(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL) != 0) tmp = *(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL); *(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL) = bh; } for (i = 0; i < GROW_BUFFERS__NEW_BUFERS_PER_CALL; i ++) { tmp = bh + i; memset (tmp, 0, sizeof (struct buffer_head)); tmp->b_data = getmem (size); if (tmp->b_data == 0) die ("grow_buffers: no memory for new buffer data"); tmp->b_dev = -1; tmp->b_size = size; put_buffer_list_head (&g_free_buffers, tmp); } buffers_memory += GROW_BUFFERS__NEW_BUFERS_PER_CALL * size; g_nr_buffers += GROW_BUFFERS__NEW_BUFERS_PER_CALL; return GROW_BUFFERS__NEW_BUFERS_PER_CALL;}struct buffer_head *find_buffer(int dev, unsigned long block, unsigned long size){ struct buffer_head * next; next = g_a_hash_queues[block % NR_HASH_QUEUES]; for (;;) { struct buffer_head *tmp = next; if (!next) break; next = tmp->b_hash_next; if (tmp->b_blocknr != block || tmp->b_size != size || tmp->b_dev != dev) continue; next = tmp; break; } return next;}static struct buffer_head * get_free_buffer (struct buffer_head **list, unsigned long size){ struct buffer_head * next; next = *list; if (!next) return 0; for (;;) { if (!next) die ("get_free_buffer: buffer list is corrupted"); if (next->b_count == 0 && buffer_clean (next) && next->b_size == size) { remove_from_hash_queue (next); remove_from_buffer_list (list, next); return next; } next = next->b_next; if (next == *list) break; } return 0;}/* to_write == 0 when all blocks have to be flushed. Otherwise - write only buffers with b_count == 0 */static int sync_buffers (struct buffer_head **list, int dev, int to_write) { struct buffer_head * next; int written = 0;restart: next = *list; if (!next) return 0; for (;;) { if (!next) die ("sync_buffers: buffer list is corrupted"); if (next->b_dev == dev && buffer_dirty (next) && buffer_uptodate (next)) { if ((to_write == 0 || next->b_count == 0) && !buffer_do_not_flush (next)) { bwrite (next); } } /* if this buffer is reusable, put it onto the end of the free list */ if (next->b_count == 0 && buffer_clean(next)) { remove_from_hash_queue (next); remove_from_buffer_list (list, next); put_buffer_list_end (&g_free_buffers, next); written++ ; if (written == to_write) return written; goto restart; } if (to_write && written >= to_write) return written; next = next->b_next; if (next == *list) break; } return written;}void flush_buffers (int dev){ if (dev == -1) die ("flush_buffers: device is not specified"); sync_buffers (&Buffer_list_head, dev, 0/*all*/); buffer_soft_limit = BUFFER_SOFT_LIMIT;}struct buffer_head * getblk (int dev, unsigned long block, int size){ struct buffer_head * bh; bh = find_buffer (dev, block, size); if (bh) { /* move the buffer to the end of list */ /*checkmem (bh->b_data, bh->b_size);*/ remove_from_buffer_list (&Buffer_list_head, bh); put_buffer_list_end (&Buffer_list_head, bh); bh->b_count ++; buffer_hits++ ; return bh; } buffer_misses++ ; bh = get_free_buffer (&g_free_buffers, size); if (bh == NULL) { if (buffers_memory >= buffer_soft_limit) { if (sync_buffers (&Buffer_list_head, dev, 32) == 0) { grow_buffers(size); buffer_soft_limit = buffers_memory + GROW_BUFFERS__NEW_BUFERS_PER_CALL * size; } } else { if (grow_buffers(size) == 0) sync_buffers (&Buffer_list_head, dev, 32); } bh = get_free_buffer (&g_free_buffers, size); if (bh == NULL) { show_buffers (dev, size); die ("getblk: no free buffers after grow_buffers " "and refill (%d)", g_nr_buffers); } } bh->b_count = 1; bh->b_dev = dev; bh->b_size = size; bh->b_blocknr = block; bh->b_end_io = NULL ; memset (bh->b_data, 0, size); misc_clear_bit(BH_Dirty, &bh->b_state); misc_clear_bit(BH_Uptodate, &bh->b_state); put_buffer_list_end (&Buffer_list_head, bh); insert_into_hash_queue (bh); /*checkmem (bh->b_data, bh->b_size);*/ return bh;}void brelse (struct buffer_head * bh){ if (bh == 0) return; if (bh->b_count == 0) die ("brelse: can not free a free buffer %lu", bh->b_blocknr); /*checkmem (bh->b_data, get_mem_size (bh->b_data));*/ bh->b_count --;}void bforget (struct buffer_head * bh){ if (bh) { bh->b_state = 0; brelse (bh); remove_from_hash_queue (bh); remove_from_buffer_list(&Buffer_list_head, bh); put_buffer_list_head(&Buffer_list_head, bh); }}/* Returns 0 on success; 1 - end of file; 0 - OK. */static int f_read(struct buffer_head * bh){ unsigned long long offset; ssize_t bytes; buffer_reads++ ; offset = (unsigned long long)bh->b_size * bh->b_blocknr; if (lseek (bh->b_dev, offset, SEEK_SET) < 0) return -1; bytes = read (bh->b_dev, bh->b_data, bh->b_size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -