aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs/file.c
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2014-04-28 05:12:36 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2014-05-06 21:21:57 -0400
commit7f7670fe9fe47e7e56db658eb8831febe47627f2 (patch)
tree17c349d23d99166cbf91753703a240b97c64cb1c /fs/f2fs/file.c
parentfe369bc8ba205537864cb86ba08b390ad20201c4 (diff)
f2fs: consider fallocated space for SEEK_DATA
If an amount of data are allocated though fallocate and user writes a couple of data among the space, f2fs should return the data offset made by user when SEEK_DATA is requested. For example, (N: NEW_ADDR by fallocate, X: NEW_ADDR by user) 1) fallocate 0 ~ 10MB f -> N N N N N N N N N N N N ... N 2) write 4KB at 5MB offset f -> N N N N N X N N N N N N ... N 3) SEEK_DATA from 0 should return 5MB offset So, this patch adds a routine to search the first dirty page to handle that. Then, the SEEK_DATA flow skips NEW_ADDR offsets until any dirty page is found. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs/file.c')
-rw-r--r--fs/f2fs/file.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 31128571e284..b9f4fbf5c07e 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -19,6 +19,7 @@
19#include <linux/compat.h> 19#include <linux/compat.h>
20#include <linux/uaccess.h> 20#include <linux/uaccess.h>
21#include <linux/mount.h> 21#include <linux/mount.h>
22#include <linux/pagevec.h>
22 23
23#include "f2fs.h" 24#include "f2fs.h"
24#include "node.h" 25#include "node.h"
@@ -194,13 +195,48 @@ out:
194 return ret; 195 return ret;
195} 196}
196 197
198static pgoff_t __get_first_dirty_index(struct address_space *mapping,
199 pgoff_t pgofs, int whence)
200{
201 struct pagevec pvec;
202 int nr_pages;
203
204 if (whence != SEEK_DATA)
205 return 0;
206
207 /* find first dirty page index */
208 pagevec_init(&pvec, 0);
209 nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs, PAGECACHE_TAG_DIRTY, 1);
210 pgofs = nr_pages ? pvec.pages[0]->index: LONG_MAX;
211 pagevec_release(&pvec);
212 return pgofs;
213}
214
215static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
216 int whence)
217{
218 switch (whence) {
219 case SEEK_DATA:
220 if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
221 (blkaddr != NEW_ADDR && blkaddr != NULL_ADDR))
222 return true;
223 break;
224 case SEEK_HOLE:
225 if (blkaddr == NULL_ADDR)
226 return true;
227 break;
228 }
229 return false;
230}
231
197static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence) 232static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
198{ 233{
199 struct inode *inode = file->f_mapping->host; 234 struct inode *inode = file->f_mapping->host;
200 loff_t maxbytes = inode->i_sb->s_maxbytes; 235 loff_t maxbytes = inode->i_sb->s_maxbytes;
201 struct dnode_of_data dn; 236 struct dnode_of_data dn;
202 pgoff_t pgofs, end_offset; 237 pgoff_t pgofs, end_offset, dirty;
203 loff_t data_ofs = offset, isize; 238 loff_t data_ofs = offset;
239 loff_t isize;
204 int err = 0; 240 int err = 0;
205 241
206 mutex_lock(&inode->i_mutex); 242 mutex_lock(&inode->i_mutex);
@@ -218,6 +254,8 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
218 254
219 pgofs = (pgoff_t)(offset >> PAGE_CACHE_SHIFT); 255 pgofs = (pgoff_t)(offset >> PAGE_CACHE_SHIFT);
220 256
257 dirty = __get_first_dirty_index(inode->i_mapping, pgofs, whence);
258
221 for (; data_ofs < isize; data_ofs = pgofs << PAGE_CACHE_SHIFT) { 259 for (; data_ofs < isize; data_ofs = pgofs << PAGE_CACHE_SHIFT) {
222 set_new_dnode(&dn, inode, NULL, NULL, 0); 260 set_new_dnode(&dn, inode, NULL, NULL, 0);
223 err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA); 261 err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE_RA);
@@ -244,8 +282,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
244 block_t blkaddr; 282 block_t blkaddr;
245 blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node); 283 blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
246 284
247 if ((whence == SEEK_DATA && blkaddr != NULL_ADDR) || 285 if (__found_offset(blkaddr, dirty, pgofs, whence)) {
248 (whence == SEEK_HOLE && blkaddr == NULL_ADDR)) {
249 f2fs_put_dnode(&dn); 286 f2fs_put_dnode(&dn);
250 goto found; 287 goto found;
251 } 288 }