aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-10 10:23:21 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:01 -0400
commit16432985920f3c45af82da214e2498f3e2f9066b (patch)
treece05f57eefb1a6f5952c53205ec8a07e93d03b3c /fs/btrfs
parent85d824c4a407ba8dbd897f4e05bbe21bf24cc071 (diff)
Btrfs: Add O_DIRECT read and write (writes == buffered + cache flush)
This adds basic O_DIRECT read and write support. In the write case, we just do a normal buffered write followed by a cache flush. O_DIRECT + O_SYNC are required to trigger metadata syncs. In the read case, there is a basic btrfs_get_block call for use by the generic O_DIRECT code. This does honor multi-volume mapping rules but it skips all checksumming. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/file.c11
-rw-r--r--fs/btrfs/inode.c66
2 files changed, 75 insertions, 2 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 5fa450452f9b..5b9386452218 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -796,8 +796,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
796 PAGE_CACHE_SIZE / (sizeof(struct page *))); 796 PAGE_CACHE_SIZE / (sizeof(struct page *)));
797 pinned[0] = NULL; 797 pinned[0] = NULL;
798 pinned[1] = NULL; 798 pinned[1] = NULL;
799 if (file->f_flags & O_DIRECT)
800 return -EINVAL;
801 799
802 pos = *ppos; 800 pos = *ppos;
803 start_pos = pos; 801 start_pos = pos;
@@ -909,6 +907,15 @@ out_nolock:
909 start_pos, num_written); 907 start_pos, num_written);
910 if (err < 0) 908 if (err < 0)
911 num_written = err; 909 num_written = err;
910 } else if (num_written > 0 && (file->f_flags & O_DIRECT)) {
911 do_sync_mapping_range(inode->i_mapping, start_pos,
912 start_pos + num_written - 1,
913 SYNC_FILE_RANGE_WRITE |
914 SYNC_FILE_RANGE_WAIT_AFTER);
915
916 invalidate_mapping_pages(inode->i_mapping,
917 start_pos >> PAGE_CACHE_SHIFT,
918 (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT);
912 } 919 }
913 current->backing_dev_info = NULL; 920 current->backing_dev_info = NULL;
914 return num_written ? num_written : err; 921 return num_written ? num_written : err;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 48f1d1b96450..32e778fb014e 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2265,6 +2265,70 @@ out:
2265 return em; 2265 return em;
2266} 2266}
2267 2267
2268static int btrfs_get_block(struct inode *inode, sector_t iblock,
2269 struct buffer_head *bh_result, int create)
2270{
2271 struct extent_map *em;
2272 u64 start = (u64)iblock << inode->i_blkbits;
2273 struct btrfs_multi_bio *multi = NULL;
2274 struct btrfs_root *root = BTRFS_I(inode)->root;
2275 u64 len;
2276 u64 logical;
2277 u64 map_length;
2278 int ret = 0;
2279
2280 em = btrfs_get_extent(inode, NULL, 0, start, bh_result->b_size, 0);
2281
2282 if (!em || IS_ERR(em))
2283 goto out;
2284
2285 if (em->start > start || em->start + em->len <= start)
2286 goto out;
2287
2288 if (em->block_start == EXTENT_MAP_INLINE) {
2289 ret = -EINVAL;
2290 goto out;
2291 }
2292
2293 if (em->block_start == EXTENT_MAP_HOLE ||
2294 em->block_start == EXTENT_MAP_DELALLOC) {
2295 goto out;
2296 }
2297
2298 len = em->start + em->len - start;
2299 len = min_t(u64, len, INT_LIMIT(typeof(bh_result->b_size)));
2300
2301 logical = start - em->start;
2302 logical = em->block_start + logical;
2303
2304 map_length = len;
2305 ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
2306 logical, &map_length, &multi, 0);
2307 BUG_ON(ret);
2308 bh_result->b_blocknr = multi->stripes[0].physical >> inode->i_blkbits;
2309 bh_result->b_size = min(map_length, len);
2310 bh_result->b_bdev = multi->stripes[0].dev->bdev;
2311 set_buffer_mapped(bh_result);
2312 kfree(multi);
2313out:
2314 free_extent_map(em);
2315 return ret;
2316}
2317
2318static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
2319 const struct iovec *iov, loff_t offset,
2320 unsigned long nr_segs)
2321{
2322 struct file *file = iocb->ki_filp;
2323 struct inode *inode = file->f_mapping->host;
2324
2325 if (rw == WRITE)
2326 return -EINVAL;
2327
2328 return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
2329 offset, nr_segs, btrfs_get_block, NULL);
2330}
2331
2268static sector_t btrfs_bmap(struct address_space *mapping, sector_t iblock) 2332static sector_t btrfs_bmap(struct address_space *mapping, sector_t iblock)
2269{ 2333{
2270 return extent_bmap(mapping, iblock, btrfs_get_extent); 2334 return extent_bmap(mapping, iblock, btrfs_get_extent);
@@ -3136,6 +3200,7 @@ out_fail:
3136 btrfs_throttle(root); 3200 btrfs_throttle(root);
3137 return err; 3201 return err;
3138} 3202}
3203
3139static int btrfs_permission(struct inode *inode, int mask, 3204static int btrfs_permission(struct inode *inode, int mask,
3140 struct nameidata *nd) 3205 struct nameidata *nd)
3141{ 3206{
@@ -3193,6 +3258,7 @@ static struct address_space_operations btrfs_aops = {
3193 .readpages = btrfs_readpages, 3258 .readpages = btrfs_readpages,
3194 .sync_page = block_sync_page, 3259 .sync_page = block_sync_page,
3195 .bmap = btrfs_bmap, 3260 .bmap = btrfs_bmap,
3261 .direct_IO = btrfs_direct_IO,
3196 .invalidatepage = btrfs_invalidatepage, 3262 .invalidatepage = btrfs_invalidatepage,
3197 .releasepage = btrfs_releasepage, 3263 .releasepage = btrfs_releasepage,
3198 .set_page_dirty = __set_page_dirty_nobuffers, 3264 .set_page_dirty = __set_page_dirty_nobuffers,