struct page *node_page = dn->node_page;
unsigned int ofs_in_node = dn->ofs_in_node;
- f2fs_wait_on_page_writeback(node_page, NODE, false);
+ f2fs_wait_on_page_writeback(node_page, NODE);
rn = F2FS_NODE(node_page);
bool need_put = dn->inode_page ? false : true;
int err;
+ /* if inode_page exists, index should be zero */
+ f2fs_bug_on(!need_put && index);
+
err = get_dnode_of_data(dn, index, ALLOC_NODE);
if (err)
return err;
+
if (dn->data_blkaddr == NULL_ADDR)
err = reserve_new_block(dn);
-
- if (need_put)
+ if (err || need_put)
f2fs_put_dnode(dn);
return err;
}
*
* Also, caller should grab and release a rwsem by calling f2fs_lock_op() and
* f2fs_unlock_op().
- * Note that, npage is set only by make_empty_dir.
+ * Note that, ipage is set only by make_empty_dir.
*/
struct page *get_new_data_page(struct inode *inode,
- struct page *npage, pgoff_t index, bool new_i_size)
+ struct page *ipage, pgoff_t index, bool new_i_size)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct address_space *mapping = inode->i_mapping;
struct dnode_of_data dn;
int err;
- set_new_dnode(&dn, inode, npage, npage, 0);
+ set_new_dnode(&dn, inode, ipage, NULL, 0);
err = f2fs_reserve_block(&dn, index);
if (err)
return ERR_PTR(err);
repeat:
page = grab_cache_page(mapping, index);
- if (!page)
- return ERR_PTR(-ENOMEM);
+ if (!page) {
+ err = -ENOMEM;
+ goto put_err;
+ }
if (PageUptodate(page))
return page;
err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr,
READ_SYNC);
if (err)
- return ERR_PTR(err);
+ goto put_err;
+
lock_page(page);
if (unlikely(!PageUptodate(page))) {
f2fs_put_page(page, 1);
- return ERR_PTR(-EIO);
+ err = -EIO;
+ goto put_err;
}
if (unlikely(page->mapping != mapping)) {
f2fs_put_page(page, 1);
mark_inode_dirty_sync(inode);
}
return page;
+
+put_err:
+ f2fs_put_dnode(&dn);
+ return ERR_PTR(err);
}
static int __allocate_data_block(struct dnode_of_data *dn)
static int f2fs_read_data_page(struct file *file, struct page *page)
{
- return mpage_readpage(page, get_data_block);
+ struct inode *inode = page->mapping->host;
+ int ret;
+
+ /* If the file has inline data, try to read it directlly */
+ if (f2fs_has_inline_data(inode))
+ ret = f2fs_read_inline_data(inode, page);
+ else
+ ret = mpage_readpage(page, get_data_block);
+
+ return ret;
}
static int f2fs_read_data_pages(struct file *file,
struct address_space *mapping,
struct list_head *pages, unsigned nr_pages)
{
+ struct inode *inode = file->f_mapping->host;
+
+ /* If the file has inline data, skip readpages */
+ if (f2fs_has_inline_data(inode))
+ return 0;
+
return mpage_readpages(mapping, pages, nr_pages, get_data_block);
}
loff_t i_size = i_size_read(inode);
const pgoff_t end_index = ((unsigned long long) i_size)
>> PAGE_CACHE_SHIFT;
- unsigned offset;
+ unsigned offset = 0;
bool need_balance_fs = false;
int err = 0;
struct f2fs_io_info fio = {
err = do_write_data_page(page, &fio);
} else {
f2fs_lock_op(sbi);
- err = do_write_data_page(page, &fio);
+
+ if (f2fs_has_inline_data(inode) || f2fs_may_inline(inode)) {
+ err = f2fs_write_inline_data(inode, page, offset);
+ f2fs_unlock_op(sbi);
+ goto out;
+ } else {
+ err = do_write_data_page(page, &fio);
+ }
+
f2fs_unlock_op(sbi);
need_balance_fs = true;
}
else if (err)
goto redirty_out;
- if (wbc->for_reclaim)
+ if (wbc->for_reclaim) {
f2fs_submit_merged_bio(sbi, DATA, WRITE);
+ need_balance_fs = false;
+ }
clear_cold_data(page);
out:
f2fs_balance_fs(sbi);
repeat:
+ err = f2fs_convert_inline_data(inode, pos + len);
+ if (err)
+ return err;
+
page = grab_cache_page_write_begin(mapping, index, flags);
if (!page)
return -ENOMEM;
*pagep = page;
+ if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA)
+ goto inline_data;
+
f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = f2fs_reserve_block(&dn, index);
f2fs_put_page(page, 1);
return err;
}
-
+inline_data:
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
return 0;
if (dn.data_blkaddr == NEW_ADDR) {
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
} else {
- err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr,
+ if (f2fs_has_inline_data(inode))
+ err = f2fs_read_inline_data(inode, page);
+ else
+ err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr,
READ_SYNC);
if (err)
return err;
return copied;
}
+static int check_direct_IO(struct inode *inode, int rw,
+ const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+{
+ unsigned blocksize_mask = inode->i_sb->s_blocksize - 1;
+ int i;
+
+ if (rw == READ)
+ return 0;
+
+ if (offset & blocksize_mask)
+ return -EINVAL;
+
+ for (i = 0; i < nr_segs; i++)
+ if (iov[i].iov_len & blocksize_mask)
+ return -EINVAL;
+ return 0;
+}
+
static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
const struct iovec *iov, loff_t offset, unsigned long nr_segs)
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
+
+ /* Let buffer I/O handle the inline data case. */
+ if (f2fs_has_inline_data(inode))
+ return 0;
+
+ if (check_direct_IO(inode, rw, iov, offset, nr_segs))
+ return 0;
+
return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
get_data_block);
}