/** * nilfs_readpages() - implement readpages() method of nilfs_aops {} * address_space_operations. * @file - file struct of the file to be read * @mapping - address_space struct used for reading multiple pages * @pages - the pages to be read * @nr_pages - number of pages to be read */ static int nilfs_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { return mpage_readpages(mapping, pages, nr_pages, nilfs_get_block); } static int nilfs_writepages(struct address_space *mapping, struct writeback_control *wbc) { struct inode *inode = mapping->host; int err = 0; #if NEED_WB_SYNC_NONE_CHECK_FOR_DO_SYNC_MAPPING_RANGE if (wbc->sync_mode == WB_SYNC_ALL || (wbc->sync_mode == WB_SYNC_NONE && !current_is_pdflush())) #else if (wbc->sync_mode == WB_SYNC_ALL) #endif err = nilfs_construct_dsync_segment(inode->i_sb, inode, wbc->range_start, wbc->range_end); return err; } static int nilfs_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; int err; page_debug(3, "called (page=%p, index=%lu, wbc nonblocking %d, " "wbc for_reclaim %d)\n", page, page->index, wbc->nonblocking, wbc->for_reclaim); redirty_page_for_writepage(wbc, page); unlock_page(page); if (wbc->sync_mode == WB_SYNC_ALL) { err = nilfs_construct_segment(inode->i_sb); if (unlikely(err)) return err; } else if (wbc->for_reclaim) nilfs_flush_segment(inode->i_sb, inode->i_ino); return 0; } static int nilfs_set_page_dirty(struct page *page) { int ret = __set_page_dirty_buffers(page); page_debug(3, "called (page=%p)\n", page); if (ret) { struct inode *inode = page->mapping->host; struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb); unsigned nr_dirty = 1 << (PAGE_SHIFT - inode->i_blkbits); nilfs_set_file_dirty(sbi, inode, nr_dirty); } page_debug(3, "done (ret=%d, page=%p)\n", ret, page); return ret; } #if HAVE_WRITE_BEGIN_WRITE_END static int nilfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { struct inode *inode = mapping->host; int err = nilfs_transaction_begin(inode->i_sb, NULL, 1); if (unlikely(err)) return err; *pagep = NULL; err = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, nilfs_get_block); if (unlikely(err)) nilfs_transaction_abort(inode->i_sb); return err; } static int nilfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) { struct inode *inode = mapping->host; unsigned start = pos & (PAGE_CACHE_SIZE - 1); unsigned nr_dirty; int err; nr_dirty = nilfs_page_count_clean_buffers(page, start, start + copied); copied = generic_write_end(file, mapping, pos, len, copied, page, fsdata); nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty); err = nilfs_transaction_commit(inode->i_sb); return err ? : copied; } #else /* HAVE_WRITE_BEGIN_WRITE_END */ static int nilfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { struct address_space *mapping = page->mapping; pgoff_t offset = page->index; struct inode *inode = mapping->host; int err; unlock_page(page); err = nilfs_transaction_begin(inode->i_sb, NULL, 1); lock_page(page); if (unlikely(page->mapping != mapping || page->index != offset)) { unlock_page(page); if (likely(!err)) nilfs_transaction_abort(inode->i_sb); return AOP_TRUNCATED_PAGE; } if (unlikely(err)) return err; err = block_prepare_write(page, from, to, nilfs_get_block); if (unlikely(err)) nilfs_transaction_abort(inode->i_sb); return err; }
/* * This is called from ocfs2_write_zero_page() which has handled it's * own cluster locking and has ensured allocation exists for those * blocks to be written. */ int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page, unsigned from, unsigned to) { int ret; ret = block_prepare_write(page, from, to, ocfs2_get_block); return ret; }
/* * This is called from ocfs2_write_zero_page() which has handled it's * own cluster locking and has ensured allocation exists for those * blocks to be written. */ int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page, unsigned from, unsigned to) { int ret; down_read(&OCFS2_I(inode)->ip_alloc_sem); ret = block_prepare_write(page, from, to, ocfs2_get_block); up_read(&OCFS2_I(inode)->ip_alloc_sem); return ret; }
/* * Try to make the page cache and handle ready for the inline data case. * We can call this function in 2 cases: * 1. The inode is created and the first write exceeds inline size. We can * clear the inode state safely. * 2. The inode has inline data, then we need to read the data, make it * update and dirty so that ext4_da_writepages can handle it. We don't * need to start the journal since the file's metatdata isn't changed now. */ static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping, struct inode *inode, unsigned flags, void **fsdata) { int ret = 0, inline_size; struct page *page; page = grab_cache_page_write_begin(mapping, 0, flags); if (!page) return -ENOMEM; down_read(&EXT4_I(inode)->xattr_sem); if (!ext4_has_inline_data(inode)) { ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); goto out; } inline_size = ext4_get_inline_size(inode); if (!PageUptodate(page)) { ret = ext4_read_inline_page(inode, page); if (ret < 0) goto out; } ret = block_prepare_write(page, 0, inline_size, ext4_da_get_block_prep); if (ret) { ext4_truncate_failed_write(inode); goto out; } SetPageDirty(page); SetPageUptodate(page); ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); *fsdata = (void *)CONVERT_INLINE_DATA; out: up_read(&EXT4_I(inode)->xattr_sem); if (page) { unlock_page(page); page_cache_release(page); } return ret; }
static int gfs2_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { struct gfs2_inode *ip = GFS2_I(mapping->host); struct gfs2_sbd *sdp = GFS2_SB(mapping->host); unsigned int data_blocks, ind_blocks, rblocks; int alloc_required; int error = 0; struct gfs2_alloc *al; pgoff_t index = pos >> PAGE_CACHE_SHIFT; unsigned from = pos & (PAGE_CACHE_SIZE - 1); unsigned to = from + len; struct page *page; gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME, &ip->i_gh); error = gfs2_glock_nq_atime(&ip->i_gh); if (unlikely(error)) goto out_uninit; gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks); error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); if (error) goto out_unlock; if (alloc_required) { al = gfs2_alloc_get(ip); if (!al) { error = -ENOMEM; goto out_unlock; } error = gfs2_quota_lock_check(ip); if (error) goto out_alloc_put; al->al_requested = data_blocks + ind_blocks; error = gfs2_inplace_reserve(ip); if (error) goto out_qunlock; } rblocks = RES_DINODE + ind_blocks; if (gfs2_is_jdata(ip)) rblocks += data_blocks ? data_blocks : 1; if (ind_blocks || data_blocks) rblocks += RES_STATFS + RES_QUOTA; error = gfs2_trans_begin(sdp, rblocks, PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); if (error) goto out_trans_fail; error = -ENOMEM; page = grab_cache_page_write_begin(mapping, index, flags); *pagep = page; if (unlikely(!page)) goto out_endtrans; if (gfs2_is_stuffed(ip)) { error = 0; if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { error = gfs2_unstuff_dinode(ip, page); if (error == 0) goto prepare_write; } else if (!PageUptodate(page)) { error = stuffed_readpage(ip, page); } goto out; } prepare_write: error = block_prepare_write(page, from, to, gfs2_block_map); out: if (error == 0) return 0; page_cache_release(page); if (pos + len > ip->i_inode.i_size) vmtruncate(&ip->i_inode, ip->i_inode.i_size); out_endtrans: gfs2_trans_end(sdp); out_trans_fail: if (alloc_required) { gfs2_inplace_release(ip); out_qunlock: gfs2_quota_unlock(ip); out_alloc_put: gfs2_alloc_put(ip); } out_unlock: gfs2_glock_dq(&ip->i_gh); out_uninit: gfs2_holder_uninit(&ip->i_gh); return error; }
static int gfs2_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { struct gfs2_inode *ip = GFS2_I(page->mapping->host); struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); unsigned int data_blocks, ind_blocks, rblocks; int alloc_required; int error = 0; loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + from; loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; struct gfs2_alloc *al; unsigned int write_len = to - from; gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh); error = gfs2_glock_nq_atime(&ip->i_gh); if (unlikely(error)) { if (error == GLR_TRYFAILED) { unlock_page(page); error = AOP_TRUNCATED_PAGE; yield(); } goto out_uninit; } gfs2_write_calc_reserv(ip, write_len, &data_blocks, &ind_blocks); error = gfs2_write_alloc_required(ip, pos, write_len, &alloc_required); if (error) goto out_unlock; ip->i_alloc.al_requested = 0; if (alloc_required) { al = gfs2_alloc_get(ip); error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) goto out_alloc_put; error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); if (error) goto out_qunlock; al->al_requested = data_blocks + ind_blocks; error = gfs2_inplace_reserve(ip); if (error) goto out_qunlock; } rblocks = RES_DINODE + ind_blocks; if (gfs2_is_jdata(ip)) rblocks += data_blocks ? data_blocks : 1; if (ind_blocks || data_blocks) rblocks += RES_STATFS + RES_QUOTA; error = gfs2_trans_begin(sdp, rblocks, 0); if (error) goto out; if (gfs2_is_stuffed(ip)) { if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { error = gfs2_unstuff_dinode(ip, page); if (error == 0) goto prepare_write; } else if (!PageUptodate(page)) error = stuffed_readpage(ip, page); goto out; } prepare_write: error = block_prepare_write(page, from, to, gfs2_get_block); out: if (error) { gfs2_trans_end(sdp); if (alloc_required) { gfs2_inplace_release(ip); out_qunlock: gfs2_quota_unlock(ip); out_alloc_put: gfs2_alloc_put(ip); } out_unlock: gfs2_glock_dq_m(1, &ip->i_gh); out_uninit: gfs2_holder_uninit(&ip->i_gh); } return error; }
static int blkdev_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { return block_prepare_write(page, from, to, blkdev_get_block); }
static int gfs2_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { struct gfs2_inode *ip = GFS2_I(mapping->host); struct gfs2_sbd *sdp = GFS2_SB(mapping->host); struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); unsigned int data_blocks = 0, ind_blocks = 0, rblocks; int alloc_required; int error = 0; struct gfs2_alloc *al; pgoff_t index = pos >> PAGE_CACHE_SHIFT; unsigned from = pos & (PAGE_CACHE_SIZE - 1); unsigned to = from + len; struct page *page; gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); error = gfs2_glock_nq(&ip->i_gh); if (unlikely(error)) goto out_uninit; if (&ip->i_inode == sdp->sd_rindex) { error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, &m_ip->i_gh); if (unlikely(error)) { gfs2_glock_dq(&ip->i_gh); goto out_uninit; } } error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); if (error) goto out_unlock; if (alloc_required || gfs2_is_jdata(ip)) gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks); if (alloc_required) { al = gfs2_alloc_get(ip); if (!al) { error = -ENOMEM; goto out_unlock; } error = gfs2_quota_lock_check(ip); if (error) goto out_alloc_put; al->al_requested = data_blocks + ind_blocks; error = gfs2_inplace_reserve(ip); if (error) goto out_qunlock; } rblocks = RES_DINODE + ind_blocks; if (gfs2_is_jdata(ip)) rblocks += data_blocks ? data_blocks : 1; if (ind_blocks || data_blocks) rblocks += RES_STATFS + RES_QUOTA; if (&ip->i_inode == sdp->sd_rindex) rblocks += 2 * RES_STATFS; error = gfs2_trans_begin(sdp, rblocks, PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); if (error) goto out_trans_fail; error = -ENOMEM; flags |= AOP_FLAG_NOFS; page = grab_cache_page_write_begin(mapping, index, flags); *pagep = page; if (unlikely(!page)) goto out_endtrans; if (gfs2_is_stuffed(ip)) { error = 0; if (pos + len > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) { error = gfs2_unstuff_dinode(ip, page); if (error == 0) goto prepare_write; } else if (!PageUptodate(page)) { error = stuffed_readpage(ip, page); } goto out; } prepare_write: error = block_prepare_write(page, from, to, gfs2_block_map); out: if (error == 0) return 0; page_cache_release(page); /* * XXX(hch): the call below should probably be replaced with * a call to the gfs2-specific truncate blocks helper to actually * release disk blocks.. */ if (pos + len > ip->i_inode.i_size) simple_setsize(&ip->i_inode, ip->i_inode.i_size); out_endtrans: gfs2_trans_end(sdp); out_trans_fail: if (alloc_required) { gfs2_inplace_release(ip); out_qunlock: gfs2_quota_unlock(ip); out_alloc_put: gfs2_alloc_put(ip); } out_unlock: if (&ip->i_inode == sdp->sd_rindex) { gfs2_glock_dq(&m_ip->i_gh); gfs2_holder_uninit(&m_ip->i_gh); } gfs2_glock_dq(&ip->i_gh); out_uninit: gfs2_holder_uninit(&ip->i_gh); return error; }
static int ext4_convert_inline_data_to_extent(struct address_space *mapping, struct inode *inode, unsigned flags) { int ret, needed_blocks; handle_t *handle = NULL; int retries = 0, sem_held = 0; struct page *page = NULL; unsigned from, to; struct ext4_iloc iloc; if (!ext4_has_inline_data(inode)) { /* * clear the flag so that no new write * will trap here again. */ ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); return 0; } needed_blocks = ext4_writepage_trans_blocks(inode); ret = ext4_get_inode_loc(inode, &iloc); if (ret) return ret; retry: handle = ext4_journal_start(inode, needed_blocks); if (IS_ERR(handle)) { ret = PTR_ERR(handle); handle = NULL; goto out; } /* We cannot recurse into the filesystem as the transaction is already * started */ flags |= AOP_FLAG_NOFS; page = grab_cache_page_write_begin(mapping, 0, flags); if (!page) { ret = -ENOMEM; goto out; } down_write(&EXT4_I(inode)->xattr_sem); sem_held = 1; /* If some one has already done this for us, just exit. */ if (!ext4_has_inline_data(inode)) { ret = 0; goto out; } from = 0; to = ext4_get_inline_size(inode); if (!PageUptodate(page)) { ret = ext4_read_inline_page(inode, page); if (ret < 0) goto out; } ret = ext4_destroy_inline_data_nolock(handle, inode); if (ret) goto out; ret = block_prepare_write(page, from & (PAGE_CACHE_SIZE - 1), to, ext4_get_block); if (!ret && ext4_should_journal_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, do_journal_get_write_access); } if (ret) { unlock_page(page); page_cache_release(page); ext4_orphan_add(handle, inode); up_write(&EXT4_I(inode)->xattr_sem); sem_held = 0; ext4_journal_stop(handle); handle = NULL; ext4_truncate_failed_write(inode); /* * If truncate failed early the inode might * still be on the orphan list; we need to * make sure the inode is removed from the * orphan list in that case. */ if (inode->i_nlink) ext4_orphan_del(NULL, inode); } if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; block_commit_write(page, from, to); out: if (page) { unlock_page(page); page_cache_release(page); } if (sem_held) up_write(&EXT4_I(inode)->xattr_sem); if (handle) ext4_journal_stop(handle); brelse(iloc.bh); return ret; }
int ux_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { return block_prepare_write(page, from, to, ux_get_block); }