/* * Modify inode page cache in such way: * have - blocks with b_blocknr equal to oldb...oldb+count-1 * get - blocks with b_blocknr equal to newb...newb+count-1 * also we suppose that oldb...oldb+count-1 blocks * situated at the end of file. * * We can come here from ufs_writepage or ufs_prepare_write, * locked_page is argument of these functions, so we already lock it. */ static void ufs_change_blocknr(struct inode *inode, sector_t beg, unsigned int count, sector_t oldb, sector_t newb, struct page *locked_page) { const unsigned blks_per_page = 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits); const unsigned mask = blks_per_page - 1; struct address_space * const mapping = inode->i_mapping; pgoff_t index, cur_index, last_index; unsigned pos, j, lblock; sector_t end, i; struct page *page; struct buffer_head *head, *bh; UFSD("ENTER, ino %lu, count %u, oldb %llu, newb %llu\n", inode->i_ino, count, (unsigned long long)oldb, (unsigned long long)newb); BUG_ON(!locked_page); BUG_ON(!PageLocked(locked_page)); cur_index = locked_page->index; end = count + beg; last_index = end >> (PAGE_CACHE_SHIFT - inode->i_blkbits); for (i = beg; i < end; i = (i | mask) + 1) { index = i >> (PAGE_CACHE_SHIFT - inode->i_blkbits); if (likely(cur_index != index)) { page = ufs_get_locked_page(mapping, index); if (!page)/* it was truncated */ continue; if (IS_ERR(page)) {/* or EIO */ ufs_error(inode->i_sb, __func__, "read of page %llu failed\n", (unsigned long long)index); continue; } } else page = locked_page; head = page_buffers(page); bh = head; pos = i & mask; for (j = 0; j < pos; ++j) bh = bh->b_this_page; if (unlikely(index == last_index)) lblock = end & mask; else lblock = blks_per_page; do { if (j >= lblock) break; pos = (i - beg) + j; if (!buffer_mapped(bh)) map_bh(bh, inode->i_sb, oldb + pos); if (!buffer_uptodate(bh)) { ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { ufs_error(inode->i_sb, __func__, "read of block failed\n"); break; } } UFSD(" change from %llu to %llu, pos %u\n", (unsigned long long)(pos + oldb), (unsigned long long)(pos + newb), pos); bh->b_blocknr = newb + pos; unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); mark_buffer_dirty(bh); ++j; bh = bh->b_this_page; } while (bh != head); if (likely(cur_index != index)) ufs_put_locked_page(page); } UFSD("EXIT\n"); }
/* * Modify inode page cache in such way: * have - blocks with b_blocknr equal to oldb...oldb+count-1 * get - blocks with b_blocknr equal to newb...newb+count-1 * also we suppose that oldb...oldb+count-1 blocks * situated at the end of file. * * We can come here from ufs_writepage or ufs_prepare_write, * locked_page is argument of these functions, so we already lock it. */ static void ufs_change_blocknr(struct inode *inode, unsigned int beg, unsigned int count, unsigned int oldb, unsigned int newb, struct page *locked_page) { const unsigned mask = (1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1; struct address_space * const mapping = inode->i_mapping; pgoff_t index, cur_index; unsigned end, pos, j; struct page *page; struct buffer_head *head, *bh; UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n", inode->i_ino, count, oldb, newb); BUG_ON(!locked_page); BUG_ON(!PageLocked(locked_page)); cur_index = locked_page->index; for (end = count + beg; beg < end; beg = (beg | mask) + 1) { index = beg >> (PAGE_CACHE_SHIFT - inode->i_blkbits); if (likely(cur_index != index)) { page = ufs_get_locked_page(mapping, index); if (!page || IS_ERR(page)) /* it was truncated or EIO */ continue; } else page = locked_page; head = page_buffers(page); bh = head; pos = beg & mask; for (j = 0; j < pos; ++j) bh = bh->b_this_page; j = 0; do { if (buffer_mapped(bh)) { pos = bh->b_blocknr - oldb; if (pos < count) { UFSD(" change from %llu to %llu\n", (unsigned long long)pos + oldb, (unsigned long long)pos + newb); bh->b_blocknr = newb + pos; unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); mark_buffer_dirty(bh); ++j; } } bh = bh->b_this_page; } while (bh != head); if (j) set_page_dirty(page); if (likely(cur_index != index)) ufs_put_locked_page(page); } UFSD("EXIT\n"); }