/* * try_to_free() checks if all the buffers on this particular page * are unused, and free's the page if so. */ static int try_to_free(struct buffer_head * bh) { unsigned long page; struct buffer_head * tmp, * p; tmp = bh; do { if (!tmp) return 0; if (tmp->b_count || tmp->b_dirt || tmp->b_lock) return 0; tmp = tmp->b_this_page; } while (tmp != bh); page = (unsigned long) bh->b_data; page &= 0xfffff000; tmp = bh; do { p = tmp; tmp = tmp->b_this_page; nr_buffers--; remove_from_queues(p); put_unused_buffer_head(p); } while (tmp != bh); free_page(page); return 1; }
/* * try_to_free() checks if all the buffers on this particular page * are unused, and free's the page if so. */ static int try_to_free(struct buffer_head * bh, struct buffer_head ** bhp) { unsigned long page; struct buffer_head * tmp, * p; *bhp = bh; page = (unsigned long) bh->b_data; page &= PAGE_MASK; tmp = bh; do { if (!tmp) return 0; if (tmp->b_count || tmp->b_dirt || tmp->b_lock || tmp->b_wait) return 0; tmp = tmp->b_this_page; } while (tmp != bh); tmp = bh; do { p = tmp; tmp = tmp->b_this_page; nr_buffers--; if (p == *bhp) *bhp = p->b_prev_free; remove_from_queues(p); put_unused_buffer_head(p); } while (tmp != bh); buffermem -= PAGE_SIZE; free_page(page); return !mem_map[MAP_NR(page)]; }
/* * Create the appropriate buffers when given a page for data area and * the size of each buffer.. Use the bh->b_this_page linked list to * follow the buffers created. Return NULL if unable to create more * buffers. */ static struct buffer_head * create_buffers(unsigned long page, unsigned long size) { struct buffer_head *bh, *head; unsigned long offset; head = NULL; offset = PAGE_SIZE; while ((offset -= size) < PAGE_SIZE) { bh = get_unused_buffer_head(); if (!bh) goto no_grow; bh->b_this_page = head; head = bh; bh->b_data = (char *) (page+offset); bh->b_size = size; } return head; /* * In case anything failed, we just free everything we got. */ no_grow: bh = head; while (bh) { head = bh; bh = bh->b_this_page; put_unused_buffer_head(head); } return NULL; }
/* * Try to increase the number of buffers available: the size argument * is used to determine what kind of buffers we want. Currently only * 1024-byte buffers are supported by the rest of the system, but I * think this will change eventually. */ void grow_buffers(int size) { unsigned long page; int i; struct buffer_head *bh, *tmp; if ((size & 511) || (size > 4096)) { printk("grow_buffers: size = %d\n",size); return; } page = get_free_page(GFP_BUFFER); if (!page) return; tmp = NULL; i = 0; for (i = 0 ; i+size <= 4096 ; i += size) { bh = get_unused_buffer_head(); if (!bh) goto no_grow; bh->b_this_page = tmp; tmp = bh; bh->b_data = (char * ) (page+i); bh->b_size = size; } tmp = bh; while (1) { if (free_list) { tmp->b_next_free = free_list; tmp->b_prev_free = free_list->b_prev_free; free_list->b_prev_free->b_next_free = tmp; free_list->b_prev_free = tmp; } else { tmp->b_prev_free = tmp; tmp->b_next_free = tmp; } free_list = tmp; ++nr_buffers; if (tmp->b_this_page) tmp = tmp->b_this_page; else break; } tmp->b_this_page = bh; return; /* * In case anything failed, we just free everything we got. */ no_grow: bh = tmp; while (bh) { tmp = bh; bh = bh->b_this_page; put_unused_buffer_head(tmp); } free_page(page); }
static unsigned long try_to_load_aligned(unsigned long address, dev_t dev, int b[], int size) { struct buffer_head * bh, * tmp, * arr[8]; unsigned long offset; int * p; int block; bh = create_buffers(address, size); if (!bh) return 0; /* do any of the buffers already exist? punt if so.. */ p = b; for (offset = 0 ; offset < PAGE_SIZE ; offset += size) { block = *(p++); if (!block) goto not_aligned; if (find_buffer(dev, block, size)) goto not_aligned; } tmp = bh; p = b; block = 0; while (1) { arr[block++] = bh; bh->b_count = 1; bh->b_dirt = 0; bh->b_uptodate = 0; bh->b_dev = dev; bh->b_blocknr = *(p++); nr_buffers++; insert_into_queues(bh); if (bh->b_this_page) bh = bh->b_this_page; else break; } buffermem += PAGE_SIZE; bh->b_this_page = tmp; mem_map[MAP_NR(address)]++; read_buffers(arr,block); while (block-- > 0) brelse(arr[block]); ++current->maj_flt; return address; not_aligned: while ((tmp = bh) != NULL) { bh = bh->b_this_page; put_unused_buffer_head(tmp); } return 0; }
static void get_more_buffer_heads(void) { unsigned long page; struct buffer_head * bh; if (unused_list) return; page = get_free_page(GFP_KERNEL); if (!page) return; bh = (struct buffer_head *) page; while ((unsigned long) (bh+1) <= page+4096) { put_unused_buffer_head(bh); bh++; nr_buffer_heads++; } }