|
@@ -1770,9 +1770,12 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
|
|
add_pending_csums(trans, inode, ordered_extent->file_offset,
|
|
add_pending_csums(trans, inode, ordered_extent->file_offset,
|
|
&ordered_extent->list);
|
|
&ordered_extent->list);
|
|
|
|
|
|
- btrfs_ordered_update_i_size(inode, 0, ordered_extent);
|
|
|
|
- ret = btrfs_update_inode(trans, root, inode);
|
|
|
|
- BUG_ON(ret);
|
|
|
|
|
|
+ ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
|
|
|
|
+ if (!ret) {
|
|
|
|
+ ret = btrfs_update_inode(trans, root, inode);
|
|
|
|
+ BUG_ON(ret);
|
|
|
|
+ }
|
|
|
|
+ ret = 0;
|
|
out:
|
|
out:
|
|
if (nolock) {
|
|
if (nolock) {
|
|
if (trans)
|
|
if (trans)
|
|
@@ -2590,6 +2593,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
|
|
struct btrfs_inode_item *item,
|
|
struct btrfs_inode_item *item,
|
|
struct inode *inode)
|
|
struct inode *inode)
|
|
{
|
|
{
|
|
|
|
+ if (!leaf->map_token)
|
|
|
|
+ map_private_extent_buffer(leaf, (unsigned long)item,
|
|
|
|
+ sizeof(struct btrfs_inode_item),
|
|
|
|
+ &leaf->map_token, &leaf->kaddr,
|
|
|
|
+ &leaf->map_start, &leaf->map_len,
|
|
|
|
+ KM_USER1);
|
|
|
|
+
|
|
btrfs_set_inode_uid(leaf, item, inode->i_uid);
|
|
btrfs_set_inode_uid(leaf, item, inode->i_uid);
|
|
btrfs_set_inode_gid(leaf, item, inode->i_gid);
|
|
btrfs_set_inode_gid(leaf, item, inode->i_gid);
|
|
btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size);
|
|
btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size);
|
|
@@ -2618,6 +2628,11 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
|
|
btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
|
|
btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
|
|
btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
|
|
btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
|
|
btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group);
|
|
btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group);
|
|
|
|
+
|
|
|
|
+ if (leaf->map_token) {
|
|
|
|
+ unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
|
|
|
|
+ leaf->map_token = NULL;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -4207,10 +4222,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
|
struct btrfs_key found_key;
|
|
struct btrfs_key found_key;
|
|
struct btrfs_path *path;
|
|
struct btrfs_path *path;
|
|
int ret;
|
|
int ret;
|
|
- u32 nritems;
|
|
|
|
struct extent_buffer *leaf;
|
|
struct extent_buffer *leaf;
|
|
int slot;
|
|
int slot;
|
|
- int advance;
|
|
|
|
unsigned char d_type;
|
|
unsigned char d_type;
|
|
int over = 0;
|
|
int over = 0;
|
|
u32 di_cur;
|
|
u32 di_cur;
|
|
@@ -4253,27 +4266,19 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto err;
|
|
goto err;
|
|
- advance = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
while (1) {
|
|
leaf = path->nodes[0];
|
|
leaf = path->nodes[0];
|
|
- nritems = btrfs_header_nritems(leaf);
|
|
|
|
slot = path->slots[0];
|
|
slot = path->slots[0];
|
|
- if (advance || slot >= nritems) {
|
|
|
|
- if (slot >= nritems - 1) {
|
|
|
|
- ret = btrfs_next_leaf(root, path);
|
|
|
|
- if (ret)
|
|
|
|
- break;
|
|
|
|
- leaf = path->nodes[0];
|
|
|
|
- nritems = btrfs_header_nritems(leaf);
|
|
|
|
- slot = path->slots[0];
|
|
|
|
- } else {
|
|
|
|
- slot++;
|
|
|
|
- path->slots[0]++;
|
|
|
|
- }
|
|
|
|
|
|
+ if (slot >= btrfs_header_nritems(leaf)) {
|
|
|
|
+ ret = btrfs_next_leaf(root, path);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto err;
|
|
|
|
+ else if (ret > 0)
|
|
|
|
+ break;
|
|
|
|
+ continue;
|
|
}
|
|
}
|
|
|
|
|
|
- advance = 1;
|
|
|
|
item = btrfs_item_nr(leaf, slot);
|
|
item = btrfs_item_nr(leaf, slot);
|
|
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
|
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
|
|
|
|
|
@@ -4282,7 +4287,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,
|
|
if (btrfs_key_type(&found_key) != key_type)
|
|
if (btrfs_key_type(&found_key) != key_type)
|
|
break;
|
|
break;
|
|
if (found_key.offset < filp->f_pos)
|
|
if (found_key.offset < filp->f_pos)
|
|
- continue;
|
|
|
|
|
|
+ goto next;
|
|
|
|
|
|
filp->f_pos = found_key.offset;
|
|
filp->f_pos = found_key.offset;
|
|
|
|
|
|
@@ -4335,6 +4340,8 @@ skip:
|
|
di_cur += di_len;
|
|
di_cur += di_len;
|
|
di = (struct btrfs_dir_item *)((char *)di + di_len);
|
|
di = (struct btrfs_dir_item *)((char *)di + di_len);
|
|
}
|
|
}
|
|
|
|
+next:
|
|
|
|
+ path->slots[0]++;
|
|
}
|
|
}
|
|
|
|
|
|
/* Reached end of directory/root. Bump pos past the last item. */
|
|
/* Reached end of directory/root. Bump pos past the last item. */
|
|
@@ -4527,14 +4534,17 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
|
BUG_ON(!path);
|
|
BUG_ON(!path);
|
|
|
|
|
|
inode = new_inode(root->fs_info->sb);
|
|
inode = new_inode(root->fs_info->sb);
|
|
- if (!inode)
|
|
|
|
|
|
+ if (!inode) {
|
|
|
|
+ btrfs_free_path(path);
|
|
return ERR_PTR(-ENOMEM);
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
+ }
|
|
|
|
|
|
if (dir) {
|
|
if (dir) {
|
|
trace_btrfs_inode_request(dir);
|
|
trace_btrfs_inode_request(dir);
|
|
|
|
|
|
ret = btrfs_set_inode_index(dir, index);
|
|
ret = btrfs_set_inode_index(dir, index);
|
|
if (ret) {
|
|
if (ret) {
|
|
|
|
+ btrfs_free_path(path);
|
|
iput(inode);
|
|
iput(inode);
|
|
return ERR_PTR(ret);
|
|
return ERR_PTR(ret);
|
|
}
|
|
}
|
|
@@ -4834,9 +4844,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|
if (inode->i_nlink == ~0U)
|
|
if (inode->i_nlink == ~0U)
|
|
return -EMLINK;
|
|
return -EMLINK;
|
|
|
|
|
|
- btrfs_inc_nlink(inode);
|
|
|
|
- inode->i_ctime = CURRENT_TIME;
|
|
|
|
-
|
|
|
|
err = btrfs_set_inode_index(dir, &index);
|
|
err = btrfs_set_inode_index(dir, &index);
|
|
if (err)
|
|
if (err)
|
|
goto fail;
|
|
goto fail;
|
|
@@ -4852,6 +4859,9 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ btrfs_inc_nlink(inode);
|
|
|
|
+ inode->i_ctime = CURRENT_TIME;
|
|
|
|
+
|
|
btrfs_set_trans_block_group(trans, dir);
|
|
btrfs_set_trans_block_group(trans, dir);
|
|
ihold(inode);
|
|
ihold(inode);
|
|
|
|
|
|
@@ -5221,7 +5231,7 @@ again:
|
|
btrfs_mark_buffer_dirty(leaf);
|
|
btrfs_mark_buffer_dirty(leaf);
|
|
}
|
|
}
|
|
set_extent_uptodate(io_tree, em->start,
|
|
set_extent_uptodate(io_tree, em->start,
|
|
- extent_map_end(em) - 1, GFP_NOFS);
|
|
|
|
|
|
+ extent_map_end(em) - 1, NULL, GFP_NOFS);
|
|
goto insert;
|
|
goto insert;
|
|
} else {
|
|
} else {
|
|
printk(KERN_ERR "btrfs unknown found_type %d\n", found_type);
|
|
printk(KERN_ERR "btrfs unknown found_type %d\n", found_type);
|
|
@@ -5428,17 +5438,30 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
|
|
static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
|
|
|
|
+ struct extent_map *em,
|
|
u64 start, u64 len)
|
|
u64 start, u64 len)
|
|
{
|
|
{
|
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
|
struct btrfs_trans_handle *trans;
|
|
struct btrfs_trans_handle *trans;
|
|
- struct extent_map *em;
|
|
|
|
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
|
|
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
|
|
struct btrfs_key ins;
|
|
struct btrfs_key ins;
|
|
u64 alloc_hint;
|
|
u64 alloc_hint;
|
|
int ret;
|
|
int ret;
|
|
|
|
+ bool insert = false;
|
|
|
|
|
|
- btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Ok if the extent map we looked up is a hole and is for the exact
|
|
|
|
+ * range we want, there is no reason to allocate a new one, however if
|
|
|
|
+ * it is not right then we need to free this one and drop the cache for
|
|
|
|
+ * our range.
|
|
|
|
+ */
|
|
|
|
+ if (em->block_start != EXTENT_MAP_HOLE || em->start != start ||
|
|
|
|
+ em->len != len) {
|
|
|
|
+ free_extent_map(em);
|
|
|
|
+ em = NULL;
|
|
|
|
+ insert = true;
|
|
|
|
+ btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
|
|
|
|
+ }
|
|
|
|
|
|
trans = btrfs_join_transaction(root, 0);
|
|
trans = btrfs_join_transaction(root, 0);
|
|
if (IS_ERR(trans))
|
|
if (IS_ERR(trans))
|
|
@@ -5454,10 +5477,12 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- em = alloc_extent_map(GFP_NOFS);
|
|
|
|
if (!em) {
|
|
if (!em) {
|
|
- em = ERR_PTR(-ENOMEM);
|
|
|
|
- goto out;
|
|
|
|
|
|
+ em = alloc_extent_map(GFP_NOFS);
|
|
|
|
+ if (!em) {
|
|
|
|
+ em = ERR_PTR(-ENOMEM);
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
em->start = start;
|
|
em->start = start;
|
|
@@ -5467,9 +5492,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
|
|
em->block_start = ins.objectid;
|
|
em->block_start = ins.objectid;
|
|
em->block_len = ins.offset;
|
|
em->block_len = ins.offset;
|
|
em->bdev = root->fs_info->fs_devices->latest_bdev;
|
|
em->bdev = root->fs_info->fs_devices->latest_bdev;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We need to do this because if we're using the original em we searched
|
|
|
|
+ * for, we could have EXTENT_FLAG_VACANCY set, and we don't want that.
|
|
|
|
+ */
|
|
|
|
+ em->flags = 0;
|
|
set_bit(EXTENT_FLAG_PINNED, &em->flags);
|
|
set_bit(EXTENT_FLAG_PINNED, &em->flags);
|
|
|
|
|
|
- while (1) {
|
|
|
|
|
|
+ while (insert) {
|
|
write_lock(&em_tree->lock);
|
|
write_lock(&em_tree->lock);
|
|
ret = add_extent_mapping(em_tree, em);
|
|
ret = add_extent_mapping(em_tree, em);
|
|
write_unlock(&em_tree->lock);
|
|
write_unlock(&em_tree->lock);
|
|
@@ -5687,8 +5718,7 @@ must_cow:
|
|
* it above
|
|
* it above
|
|
*/
|
|
*/
|
|
len = bh_result->b_size;
|
|
len = bh_result->b_size;
|
|
- free_extent_map(em);
|
|
|
|
- em = btrfs_new_extent_direct(inode, start, len);
|
|
|
|
|
|
+ em = btrfs_new_extent_direct(inode, em, start, len);
|
|
if (IS_ERR(em))
|
|
if (IS_ERR(em))
|
|
return PTR_ERR(em);
|
|
return PTR_ERR(em);
|
|
len = min(len, em->len - (start - em->start));
|
|
len = min(len, em->len - (start - em->start));
|
|
@@ -5851,8 +5881,10 @@ again:
|
|
}
|
|
}
|
|
|
|
|
|
add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
|
|
add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
|
|
- btrfs_ordered_update_i_size(inode, 0, ordered);
|
|
|
|
- btrfs_update_inode(trans, root, inode);
|
|
|
|
|
|
+ ret = btrfs_ordered_update_i_size(inode, 0, ordered);
|
|
|
|
+ if (!ret)
|
|
|
|
+ btrfs_update_inode(trans, root, inode);
|
|
|
|
+ ret = 0;
|
|
out_unlock:
|
|
out_unlock:
|
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset,
|
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset,
|
|
ordered->file_offset + ordered->len - 1,
|
|
ordered->file_offset + ordered->len - 1,
|
|
@@ -5938,7 +5970,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
|
|
|
|
|
|
static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
|
|
static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
|
|
int rw, u64 file_offset, int skip_sum,
|
|
int rw, u64 file_offset, int skip_sum,
|
|
- u32 *csums)
|
|
|
|
|
|
+ u32 *csums, int async_submit)
|
|
{
|
|
{
|
|
int write = rw & REQ_WRITE;
|
|
int write = rw & REQ_WRITE;
|
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
|
@@ -5949,13 +5981,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
|
|
if (ret)
|
|
if (ret)
|
|
goto err;
|
|
goto err;
|
|
|
|
|
|
- if (write && !skip_sum) {
|
|
|
|
|
|
+ if (skip_sum)
|
|
|
|
+ goto map;
|
|
|
|
+
|
|
|
|
+ if (write && async_submit) {
|
|
ret = btrfs_wq_submit_bio(root->fs_info,
|
|
ret = btrfs_wq_submit_bio(root->fs_info,
|
|
inode, rw, bio, 0, 0,
|
|
inode, rw, bio, 0, 0,
|
|
file_offset,
|
|
file_offset,
|
|
__btrfs_submit_bio_start_direct_io,
|
|
__btrfs_submit_bio_start_direct_io,
|
|
__btrfs_submit_bio_done);
|
|
__btrfs_submit_bio_done);
|
|
goto err;
|
|
goto err;
|
|
|
|
+ } else if (write) {
|
|
|
|
+ /*
|
|
|
|
+ * If we aren't doing async submit, calculate the csum of the
|
|
|
|
+ * bio now.
|
|
|
|
+ */
|
|
|
|
+ ret = btrfs_csum_one_bio(root, inode, bio, file_offset, 1);
|
|
|
|
+ if (ret)
|
|
|
|
+ goto err;
|
|
} else if (!skip_sum) {
|
|
} else if (!skip_sum) {
|
|
ret = btrfs_lookup_bio_sums_dio(root, inode, bio,
|
|
ret = btrfs_lookup_bio_sums_dio(root, inode, bio,
|
|
file_offset, csums);
|
|
file_offset, csums);
|
|
@@ -5963,7 +6006,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
|
|
goto err;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = btrfs_map_bio(root, rw, bio, 0, 1);
|
|
|
|
|
|
+map:
|
|
|
|
+ ret = btrfs_map_bio(root, rw, bio, 0, async_submit);
|
|
err:
|
|
err:
|
|
bio_put(bio);
|
|
bio_put(bio);
|
|
return ret;
|
|
return ret;
|
|
@@ -5985,15 +6029,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|
int nr_pages = 0;
|
|
int nr_pages = 0;
|
|
u32 *csums = dip->csums;
|
|
u32 *csums = dip->csums;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
+ int async_submit = 0;
|
|
int write = rw & REQ_WRITE;
|
|
int write = rw & REQ_WRITE;
|
|
|
|
|
|
- bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
|
|
|
|
- if (!bio)
|
|
|
|
- return -ENOMEM;
|
|
|
|
- bio->bi_private = dip;
|
|
|
|
- bio->bi_end_io = btrfs_end_dio_bio;
|
|
|
|
- atomic_inc(&dip->pending_bios);
|
|
|
|
-
|
|
|
|
map_length = orig_bio->bi_size;
|
|
map_length = orig_bio->bi_size;
|
|
ret = btrfs_map_block(map_tree, READ, start_sector << 9,
|
|
ret = btrfs_map_block(map_tree, READ, start_sector << 9,
|
|
&map_length, NULL, 0);
|
|
&map_length, NULL, 0);
|
|
@@ -6002,6 +6040,19 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|
return -EIO;
|
|
return -EIO;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (map_length >= orig_bio->bi_size) {
|
|
|
|
+ bio = orig_bio;
|
|
|
|
+ goto submit;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ async_submit = 1;
|
|
|
|
+ bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
|
|
|
|
+ if (!bio)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ bio->bi_private = dip;
|
|
|
|
+ bio->bi_end_io = btrfs_end_dio_bio;
|
|
|
|
+ atomic_inc(&dip->pending_bios);
|
|
|
|
+
|
|
while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
|
|
while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
|
|
if (unlikely(map_length < submit_len + bvec->bv_len ||
|
|
if (unlikely(map_length < submit_len + bvec->bv_len ||
|
|
bio_add_page(bio, bvec->bv_page, bvec->bv_len,
|
|
bio_add_page(bio, bvec->bv_page, bvec->bv_len,
|
|
@@ -6015,7 +6066,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|
atomic_inc(&dip->pending_bios);
|
|
atomic_inc(&dip->pending_bios);
|
|
ret = __btrfs_submit_dio_bio(bio, inode, rw,
|
|
ret = __btrfs_submit_dio_bio(bio, inode, rw,
|
|
file_offset, skip_sum,
|
|
file_offset, skip_sum,
|
|
- csums);
|
|
|
|
|
|
+ csums, async_submit);
|
|
if (ret) {
|
|
if (ret) {
|
|
bio_put(bio);
|
|
bio_put(bio);
|
|
atomic_dec(&dip->pending_bios);
|
|
atomic_dec(&dip->pending_bios);
|
|
@@ -6052,8 +6103,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+submit:
|
|
ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum,
|
|
ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum,
|
|
- csums);
|
|
|
|
|
|
+ csums, async_submit);
|
|
if (!ret)
|
|
if (!ret)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
@@ -6148,6 +6200,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io
|
|
unsigned long nr_segs)
|
|
unsigned long nr_segs)
|
|
{
|
|
{
|
|
int seg;
|
|
int seg;
|
|
|
|
+ int i;
|
|
size_t size;
|
|
size_t size;
|
|
unsigned long addr;
|
|
unsigned long addr;
|
|
unsigned blocksize_mask = root->sectorsize - 1;
|
|
unsigned blocksize_mask = root->sectorsize - 1;
|
|
@@ -6162,8 +6215,22 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io
|
|
addr = (unsigned long)iov[seg].iov_base;
|
|
addr = (unsigned long)iov[seg].iov_base;
|
|
size = iov[seg].iov_len;
|
|
size = iov[seg].iov_len;
|
|
end += size;
|
|
end += size;
|
|
- if ((addr & blocksize_mask) || (size & blocksize_mask))
|
|
|
|
|
|
+ if ((addr & blocksize_mask) || (size & blocksize_mask))
|
|
goto out;
|
|
goto out;
|
|
|
|
+
|
|
|
|
+ /* If this is a write we don't need to check anymore */
|
|
|
|
+ if (rw & WRITE)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Check to make sure we don't have duplicate iov_base's in this
|
|
|
|
+ * iovec, if so return EINVAL, otherwise we'll get csum errors
|
|
|
|
+ * when reading back.
|
|
|
|
+ */
|
|
|
|
+ for (i = seg + 1; i < nr_segs; i++) {
|
|
|
|
+ if (iov[seg].iov_base == iov[i].iov_base)
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
retval = 0;
|
|
retval = 0;
|
|
out:
|
|
out:
|