diff options
Diffstat (limited to 'fs/ocfs2/aops.c')
-rw-r--r-- | fs/ocfs2/aops.c | 80 |
1 files changed, 76 insertions, 4 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 8416e383197c..fef0186a91cd 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -206,9 +206,70 @@ bail: | |||
206 | return err; | 206 | return err; |
207 | } | 207 | } |
208 | 208 | ||
209 | static int ocfs2_read_inline_data(struct inode *inode, struct page *page, | ||
210 | struct buffer_head *di_bh) | ||
211 | { | ||
212 | void *kaddr; | ||
213 | unsigned int size; | ||
214 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | ||
215 | |||
216 | if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) { | ||
217 | ocfs2_error(inode->i_sb, "Inode %llu lost inline data flag", | ||
218 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | ||
219 | return -EROFS; | ||
220 | } | ||
221 | |||
222 | size = i_size_read(inode); | ||
223 | |||
224 | if (size > PAGE_CACHE_SIZE || | ||
225 | size > ocfs2_max_inline_data(inode->i_sb)) { | ||
226 | ocfs2_error(inode->i_sb, | ||
227 | "Inode %llu has with inline data has bad size: %u", | ||
228 | (unsigned long long)OCFS2_I(inode)->ip_blkno, size); | ||
229 | return -EROFS; | ||
230 | } | ||
231 | |||
232 | kaddr = kmap_atomic(page, KM_USER0); | ||
233 | if (size) | ||
234 | memcpy(kaddr, di->id2.i_data.id_data, size); | ||
235 | /* Clear the remaining part of the page */ | ||
236 | memset(kaddr + size, 0, PAGE_CACHE_SIZE - size); | ||
237 | flush_dcache_page(page); | ||
238 | kunmap_atomic(kaddr, KM_USER0); | ||
239 | |||
240 | SetPageUptodate(page); | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int ocfs2_readpage_inline(struct inode *inode, struct page *page) | ||
246 | { | ||
247 | int ret; | ||
248 | struct buffer_head *di_bh = NULL; | ||
249 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
250 | |||
251 | BUG_ON(!PageLocked(page)); | ||
252 | BUG_ON(!OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); | ||
253 | |||
254 | ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh, | ||
255 | OCFS2_BH_CACHED, inode); | ||
256 | if (ret) { | ||
257 | mlog_errno(ret); | ||
258 | goto out; | ||
259 | } | ||
260 | |||
261 | ret = ocfs2_read_inline_data(inode, page, di_bh); | ||
262 | out: | ||
263 | unlock_page(page); | ||
264 | |||
265 | brelse(di_bh); | ||
266 | return ret; | ||
267 | } | ||
268 | |||
209 | static int ocfs2_readpage(struct file *file, struct page *page) | 269 | static int ocfs2_readpage(struct file *file, struct page *page) |
210 | { | 270 | { |
211 | struct inode *inode = page->mapping->host; | 271 | struct inode *inode = page->mapping->host; |
272 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
212 | loff_t start = (loff_t)page->index << PAGE_CACHE_SHIFT; | 273 | loff_t start = (loff_t)page->index << PAGE_CACHE_SHIFT; |
213 | int ret, unlock = 1; | 274 | int ret, unlock = 1; |
214 | 275 | ||
@@ -222,7 +283,7 @@ static int ocfs2_readpage(struct file *file, struct page *page) | |||
222 | goto out; | 283 | goto out; |
223 | } | 284 | } |
224 | 285 | ||
225 | if (down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem) == 0) { | 286 | if (down_read_trylock(&oi->ip_alloc_sem) == 0) { |
226 | ret = AOP_TRUNCATED_PAGE; | 287 | ret = AOP_TRUNCATED_PAGE; |
227 | goto out_meta_unlock; | 288 | goto out_meta_unlock; |
228 | } | 289 | } |
@@ -252,7 +313,10 @@ static int ocfs2_readpage(struct file *file, struct page *page) | |||
252 | goto out_alloc; | 313 | goto out_alloc; |
253 | } | 314 | } |
254 | 315 | ||
255 | ret = block_read_full_page(page, ocfs2_get_block); | 316 | if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) |
317 | ret = ocfs2_readpage_inline(inode, page); | ||
318 | else | ||
319 | ret = block_read_full_page(page, ocfs2_get_block); | ||
256 | unlock = 0; | 320 | unlock = 0; |
257 | 321 | ||
258 | ocfs2_data_unlock(inode, 0); | 322 | ocfs2_data_unlock(inode, 0); |
@@ -397,7 +461,9 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) | |||
397 | down_read(&OCFS2_I(inode)->ip_alloc_sem); | 461 | down_read(&OCFS2_I(inode)->ip_alloc_sem); |
398 | } | 462 | } |
399 | 463 | ||
400 | err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, NULL); | 464 | if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)) |
465 | err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, | ||
466 | NULL); | ||
401 | 467 | ||
402 | if (!INODE_JOURNAL(inode)) { | 468 | if (!INODE_JOURNAL(inode)) { |
403 | up_read(&OCFS2_I(inode)->ip_alloc_sem); | 469 | up_read(&OCFS2_I(inode)->ip_alloc_sem); |
@@ -411,7 +477,6 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) | |||
411 | goto bail; | 477 | goto bail; |
412 | } | 478 | } |
413 | 479 | ||
414 | |||
415 | bail: | 480 | bail: |
416 | status = err ? 0 : p_blkno; | 481 | status = err ? 0 : p_blkno; |
417 | 482 | ||
@@ -566,6 +631,13 @@ static ssize_t ocfs2_direct_IO(int rw, | |||
566 | 631 | ||
567 | mlog_entry_void(); | 632 | mlog_entry_void(); |
568 | 633 | ||
634 | /* | ||
635 | * Fallback to buffered I/O if we see an inode without | ||
636 | * extents. | ||
637 | */ | ||
638 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) | ||
639 | return 0; | ||
640 | |||
569 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { | 641 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { |
570 | /* | 642 | /* |
571 | * We get PR data locks even for O_DIRECT. This | 643 | * We get PR data locks even for O_DIRECT. This |