X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Fbuffer.c;h=62cfd17dc5fee6c87a1dbaabe5e01299e89dc5ad;hb=9fddaca2293d768eb21ea115e5eedec7f1c13c1c;hp=b9bb7ad6897b90456332813bc15615741171c9c8;hpb=e7de369050534025b33aab1033358bf47a577e4d;p=linux-2.6 diff --git a/fs/buffer.c b/fs/buffer.c index b9bb7ad689..62cfd17dc5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1022,12 +1022,13 @@ try_again: bh->b_state = 0; atomic_set(&bh->b_count, 0); + bh->b_private = NULL; bh->b_size = size; /* Link the buffer to its page */ set_bh_page(bh, page, offset); - bh->b_end_io = NULL; + init_buffer(bh, NULL, NULL); } return head; /* @@ -1165,7 +1166,7 @@ failed: * some of those buffers may be aliases of filesystem data. * grow_dev_page() will go BUG() if this happens. */ -static inline int +static int grow_buffers(struct block_device *bdev, sector_t block, int size) { struct page *page; @@ -1391,7 +1392,7 @@ static void bh_lru_install(struct buffer_head *bh) /* * Look up the bh in this cpu's LRU. If it's there, move it to the head. */ -static inline struct buffer_head * +static struct buffer_head * lookup_bh_lru(struct block_device *bdev, sector_t block, int size) { struct buffer_head *ret = NULL; @@ -1541,7 +1542,7 @@ EXPORT_SYMBOL(set_bh_page); /* * Called when truncating a buffer on a page completely. */ -static inline void discard_buffer(struct buffer_head * bh) +static void discard_buffer(struct buffer_head * bh) { lock_buffer(bh); clear_buffer_dirty(bh); @@ -2866,22 +2867,22 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) else if (test_set_buffer_locked(bh)) continue; - get_bh(bh); if (rw == WRITE || rw == SWRITE) { if (test_clear_buffer_dirty(bh)) { bh->b_end_io = end_buffer_write_sync; + get_bh(bh); submit_bh(WRITE, bh); continue; } } else { if (!buffer_uptodate(bh)) { bh->b_end_io = end_buffer_read_sync; + get_bh(bh); submit_bh(rw, bh); continue; } } unlock_buffer(bh); - put_bh(bh); } } @@ -3049,6 +3050,66 @@ asmlinkage long sys_bdflush(int func, long data) return 0; } +/* + * Migration function for pages with buffers. This function can only be used + * if the underlying filesystem guarantees that no other references to "page" + * exist. + */ +#ifdef CONFIG_MIGRATION +int buffer_migrate_page(struct page *newpage, struct page *page) +{ + struct address_space *mapping = page->mapping; + struct buffer_head *bh, *head; + + if (!mapping) + return -EAGAIN; + + if (!page_has_buffers(page)) + return migrate_page(newpage, page); + + head = page_buffers(page); + + if (migrate_page_remove_references(newpage, page, 3)) + return -EAGAIN; + + bh = head; + do { + get_bh(bh); + lock_buffer(bh); + bh = bh->b_this_page; + + } while (bh != head); + + ClearPagePrivate(page); + set_page_private(newpage, page_private(page)); + set_page_private(page, 0); + put_page(page); + get_page(newpage); + + bh = head; + do { + set_bh_page(bh, newpage, bh_offset(bh)); + bh = bh->b_this_page; + + } while (bh != head); + + SetPagePrivate(newpage); + + migrate_page_copy(newpage, page); + + bh = head; + do { + unlock_buffer(bh); + put_bh(bh); + bh = bh->b_this_page; + + } while (bh != head); + + return 0; +} +EXPORT_SYMBOL(buffer_migrate_page); +#endif + /* * Buffer-head allocation */