static int ufs_alloc_lastblock(struct inode *inode) { int err = 0; struct address_space *mapping = inode->i_mapping; struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; unsigned lastfrag, i, end; struct page *lastpage; struct buffer_head *bh; lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift; if (!lastfrag) goto out; lastfrag--; lastpage = ufs_get_locked_page(mapping, lastfrag >> (PAGE_CACHE_SHIFT - inode->i_blkbits)); if (IS_ERR(lastpage)) { err = -EIO; goto out; } end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1); bh = page_buffers(lastpage); for (i = 0; i < end; ++i) bh = bh->b_this_page; err = ufs_getfrag_block(inode, lastfrag, bh, 1); if (unlikely(err)) goto out_unlock; if (buffer_new(bh)) { clear_buffer_new(bh); unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); /* * we do not zeroize fragment, because of * if it maped to hole, it already contains zeroes */ set_buffer_uptodate(bh); mark_buffer_dirty(bh); set_page_dirty(lastpage); } out_unlock: ufs_put_locked_page(lastpage); out: return err; }
static int io_submit_add_bh(struct ext4_io_submit *io, struct ext4_io_page *io_page, struct inode *inode, struct writeback_control *wbc, struct buffer_head *bh) { ext4_io_end_t *io_end; int ret; if (buffer_new(bh)) { clear_buffer_new(bh); unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); } if (!buffer_mapped(bh) || buffer_delay(bh)) { if (!buffer_mapped(bh)) clear_buffer_dirty(bh); if (io->io_bio) ext4_io_submit(io); return 0; } if (io->io_bio && bh->b_blocknr != io->io_next_block) { submit_and_retry: ext4_io_submit(io); } if (io->io_bio == NULL) { ret = io_submit_init(io, inode, wbc, bh); if (ret) return ret; } io_end = io->io_end; if ((io_end->num_io_pages >= MAX_IO_PAGES) && (io_end->pages[io_end->num_io_pages-1] != io_page)) goto submit_and_retry; if (buffer_uninit(bh) && !(io_end->flag & EXT4_IO_END_UNWRITTEN)) { io_end->flag |= EXT4_IO_END_UNWRITTEN; atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten); } io->io_end->size += bh->b_size; io->io_next_block++; ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh)); if (ret != bh->b_size) goto submit_and_retry; if ((io_end->num_io_pages == 0) || (io_end->pages[io_end->num_io_pages-1] != io_page)) { io_end->pages[io_end->num_io_pages++] = io_page; atomic_inc(&io_page->p_count); } return 0; }
static int __mpage_writepage(struct page *page, struct writeback_control *wbc, void *data) { struct mpage_data *mpd = data; struct bio *bio = mpd->bio; struct address_space *mapping = page->mapping; struct inode *inode = page->mapping->host; const unsigned blkbits = inode->i_blkbits; unsigned long end_index; const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits; sector_t last_block; sector_t block_in_file; sector_t blocks[MAX_BUF_PER_PAGE]; unsigned page_block; unsigned first_unmapped = blocks_per_page; struct block_device *bdev = NULL; int boundary = 0; sector_t boundary_block = 0; struct block_device *boundary_bdev = NULL; int length; struct buffer_head map_bh; loff_t i_size = i_size_read(inode); int ret = 0; int wr = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE); if (page_has_buffers(page)) { struct buffer_head *head = page_buffers(page); struct buffer_head *bh = head; /* If they're all mapped and dirty, do it */ page_block = 0; do { BUG_ON(buffer_locked(bh)); if (!buffer_mapped(bh)) { /* * unmapped dirty buffers are created by * __set_page_dirty_buffers -> mmapped data */ if (buffer_dirty(bh)) goto confused; if (first_unmapped == blocks_per_page) first_unmapped = page_block; continue; } if (first_unmapped != blocks_per_page) goto confused; /* hole -> non-hole */ if (!buffer_dirty(bh) || !buffer_uptodate(bh)) goto confused; if (page_block) { if (bh->b_blocknr != blocks[page_block-1] + 1) goto confused; } blocks[page_block++] = bh->b_blocknr; boundary = buffer_boundary(bh); if (boundary) { boundary_block = bh->b_blocknr; boundary_bdev = bh->b_bdev; } bdev = bh->b_bdev; } while ((bh = bh->b_this_page) != head); if (first_unmapped) goto page_is_mapped; /* * Page has buffers, but they are all unmapped. The page was * created by pagein or read over a hole which was handled by * block_read_full_page(). If this address_space is also * using mpage_readpages then this can rarely happen. */ goto confused; } /* * The page has no buffers: map it to disk */ BUG_ON(!PageUptodate(page)); block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits); last_block = (i_size - 1) >> blkbits; map_bh.b_page = page; for (page_block = 0; page_block < blocks_per_page; ) { map_bh.b_state = 0; map_bh.b_size = 1 << blkbits; if (mpd->get_block(inode, block_in_file, &map_bh, 1)) goto confused; if (buffer_new(&map_bh)) unmap_underlying_metadata(map_bh.b_bdev, map_bh.b_blocknr); if (buffer_boundary(&map_bh)) { boundary_block = map_bh.b_blocknr; boundary_bdev = map_bh.b_bdev; } if (page_block) { if (map_bh.b_blocknr != blocks[page_block-1] + 1) goto confused; } blocks[page_block++] = map_bh.b_blocknr; boundary = buffer_boundary(&map_bh); bdev = map_bh.b_bdev; if (block_in_file == last_block) break; block_in_file++; } BUG_ON(page_block == 0); first_unmapped = page_block; page_is_mapped: end_index = i_size >> PAGE_CACHE_SHIFT; if (page->index >= end_index) { /* * The page straddles i_size. It must be zeroed out on each * and every writepage invocation because it may be mmapped. * "A file is mapped in multiples of the page size. For a file * that is not a multiple of the page size, the remaining memory * is zeroed when mapped, and writes to that region are not * written out to the file." */ unsigned offset = i_size & (PAGE_CACHE_SIZE - 1); if (page->index > end_index || !offset) goto confused; zero_user_segment(page, offset, PAGE_CACHE_SIZE); } /* * This page will go to BIO. Do we need to send this BIO off first? */ if (bio && mpd->last_block_in_bio != blocks[0] - 1) bio = mpage_bio_submit(wr, bio); alloc_new: if (bio == NULL) { if (first_unmapped == blocks_per_page) { if (!bdev_write_page(bdev, blocks[0] << (blkbits - 9), page, wbc)) { clean_buffers(page, first_unmapped); goto out; } } bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), BIO_MAX_PAGES, GFP_NOFS|__GFP_HIGH); if (bio == NULL) goto confused; wbc_init_bio(wbc, bio); } /* * Must try to add the page before marking the buffer clean or * the confused fail path above (OOM) will be very confused when * it finds all bh marked clean (i.e. it will not write anything) */ wbc_account_io(wbc, page, PAGE_SIZE); length = first_unmapped << blkbits; if (bio_add_page(bio, page, length, 0) < length) { bio = mpage_bio_submit(wr, bio); goto alloc_new; } clean_buffers(page, first_unmapped); BUG_ON(PageWriteback(page)); set_page_writeback(page); unlock_page(page); if (boundary || (first_unmapped != blocks_per_page)) { bio = mpage_bio_submit(wr, bio); if (boundary_block) { write_boundary_block(boundary_bdev, boundary_block, 1 << blkbits); } } else { mpd->last_block_in_bio = blocks[blocks_per_page - 1]; } goto out; confused: if (bio) bio = mpage_bio_submit(wr, bio); if (mpd->use_writepage) { ret = mapping->a_ops->writepage(page, wbc); } else { ret = -EAGAIN; goto out; } /* * The caller has a ref on the inode, so *mapping is stable */ mapping_set_error(mapping, ret); out: mpd->bio = bio; return ret; }
/* * 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"); }
static int ufs_alloc_lastblock(struct inode *inode) { int err = 0; struct super_block *sb = inode->i_sb; struct address_space *mapping = inode->i_mapping; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; unsigned i, end; sector_t lastfrag; struct page *lastpage; struct buffer_head *bh; u64 phys64; lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift; if (!lastfrag) goto out; lastfrag--; lastpage = ufs_get_locked_page(mapping, lastfrag >> (PAGE_CACHE_SHIFT - inode->i_blkbits)); if (IS_ERR(lastpage)) { err = -EIO; goto out; } end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1); bh = page_buffers(lastpage); for (i = 0; i < end; ++i) bh = bh->b_this_page; err = ufs_getfrag_block(inode, lastfrag, bh, 1); if (unlikely(err)) goto out_unlock; if (buffer_new(bh)) { clear_buffer_new(bh); unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); /* * we do not zeroize fragment, because of * if it maped to hole, it already contains zeroes */ set_buffer_uptodate(bh); mark_buffer_dirty(bh); set_page_dirty(lastpage); } if (lastfrag >= UFS_IND_FRAGMENT) { end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1; phys64 = bh->b_blocknr + 1; for (i = 0; i < end; ++i) { bh = sb_getblk(sb, i + phys64); lock_buffer(bh); memset(bh->b_data, 0, sb->s_blocksize); set_buffer_uptodate(bh); mark_buffer_dirty(bh); unlock_buffer(bh); sync_dirty_buffer(bh); brelse(bh); } } out_unlock: ufs_put_locked_page(lastpage); out: return err; }
/* * 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"); }