Commit 886a3911 authored by Al Viro's avatar Al Viro

new primitive: iov_iter_alignment()

returns the value aligned as badly as the worst remaining segment
in iov_iter is.  Use instead of open-coded equivalents.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 26978b8b
...@@ -391,11 +391,8 @@ static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb, ...@@ -391,11 +391,8 @@ static ssize_t ll_direct_IO_26(int rw, struct kiocb *iocb,
MAX_DIO_SIZE >> PAGE_CACHE_SHIFT); MAX_DIO_SIZE >> PAGE_CACHE_SHIFT);
/* Check that all user buffers are aligned as well */ /* Check that all user buffers are aligned as well */
for (seg = 0; seg < iter->nr_segs; seg++) { if (iov_iter_alignment(iter) & ~CFS_PAGE_MASK)
if (((unsigned long)iter->iov[seg].iov_base & ~CFS_PAGE_MASK) ||
(iter->iov[seg].iov_len & ~CFS_PAGE_MASK))
return -EINVAL; return -EINVAL;
}
env = cl_env_get(&refcheck); env = cl_env_get(&refcheck);
LASSERT(!IS_ERR(env)); LASSERT(!IS_ERR(env));
......
...@@ -1112,19 +1112,18 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, ...@@ -1112,19 +1112,18 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
dio_submit_t submit_io, int flags) dio_submit_t submit_io, int flags)
{ {
int seg; int seg;
size_t size;
unsigned long addr;
unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits); unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits);
unsigned blkbits = i_blkbits; unsigned blkbits = i_blkbits;
unsigned blocksize_mask = (1 << blkbits) - 1; unsigned blocksize_mask = (1 << blkbits) - 1;
ssize_t retval = -EINVAL; ssize_t retval = -EINVAL;
loff_t end = offset; loff_t end = offset + iov_iter_count(iter);
struct dio *dio; struct dio *dio;
struct dio_submit sdio = { 0, }; struct dio_submit sdio = { 0, };
unsigned long user_addr; unsigned long user_addr;
size_t bytes; size_t bytes;
struct buffer_head map_bh = { 0, }; struct buffer_head map_bh = { 0, };
struct blk_plug plug; struct blk_plug plug;
unsigned long align = offset | iov_iter_alignment(iter);
if (rw & WRITE) if (rw & WRITE)
rw = WRITE_ODIRECT; rw = WRITE_ODIRECT;
...@@ -1134,32 +1133,16 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, ...@@ -1134,32 +1133,16 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
* the early prefetch in the caller enough time. * the early prefetch in the caller enough time.
*/ */
if (offset & blocksize_mask) { if (align & blocksize_mask) {
if (bdev) if (bdev)
blkbits = blksize_bits(bdev_logical_block_size(bdev)); blkbits = blksize_bits(bdev_logical_block_size(bdev));
blocksize_mask = (1 << blkbits) - 1; blocksize_mask = (1 << blkbits) - 1;
if (offset & blocksize_mask) if (align & blocksize_mask)
goto out; goto out;
} }
/* Check the memory alignment. Blocks cannot straddle pages */
for (seg = 0; seg < iter->nr_segs; seg++) {
addr = (unsigned long)iter->iov[seg].iov_base;
size = iter->iov[seg].iov_len;
end += size;
if (unlikely((addr & blocksize_mask) ||
(size & blocksize_mask))) {
if (bdev)
blkbits = blksize_bits(
bdev_logical_block_size(bdev));
blocksize_mask = (1 << blkbits) - 1;
if ((addr & blocksize_mask) || (size & blocksize_mask))
goto out;
}
}
/* watch out for a 0 len io from a tricksy fs */ /* watch out for a 0 len io from a tricksy fs */
if (rw == READ && end == offset) if (rw == READ && !iov_iter_count(iter))
return 0; return 0;
dio = kmem_cache_alloc(dio_cache, GFP_KERNEL); dio = kmem_cache_alloc(dio_cache, GFP_KERNEL);
......
...@@ -67,6 +67,7 @@ int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes); ...@@ -67,6 +67,7 @@ int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
size_t iov_iter_single_seg_count(const struct iov_iter *i); size_t iov_iter_single_seg_count(const struct iov_iter *i);
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i); struct iov_iter *i);
unsigned long iov_iter_alignment(const struct iov_iter *i);
static inline void iov_iter_init(struct iov_iter *i, static inline void iov_iter_init(struct iov_iter *i,
const struct iovec *iov, unsigned long nr_segs, const struct iovec *iov, unsigned long nr_segs,
...@@ -88,4 +89,5 @@ static inline size_t iov_iter_count(struct iov_iter *i) ...@@ -88,4 +89,5 @@ static inline size_t iov_iter_count(struct iov_iter *i)
int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len); int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len);
#endif #endif
...@@ -195,3 +195,28 @@ size_t iov_iter_single_seg_count(const struct iov_iter *i) ...@@ -195,3 +195,28 @@ size_t iov_iter_single_seg_count(const struct iov_iter *i)
return min(i->count, iov->iov_len - i->iov_offset); return min(i->count, iov->iov_len - i->iov_offset);
} }
EXPORT_SYMBOL(iov_iter_single_seg_count); EXPORT_SYMBOL(iov_iter_single_seg_count);
unsigned long iov_iter_alignment(const struct iov_iter *i)
{
const struct iovec *iov = i->iov;
unsigned long res;
size_t size = i->count;
size_t n;
if (!size)
return 0;
res = (unsigned long)iov->iov_base + i->iov_offset;
n = iov->iov_len - i->iov_offset;
if (n >= size)
return res | size;
size -= n;
res |= n;
while (size > (++iov)->iov_len) {
res |= (unsigned long)iov->iov_base | iov->iov_len;
size -= iov->iov_len;
}
res |= (unsigned long)iov->iov_base | size;
return res;
}
EXPORT_SYMBOL(iov_iter_alignment);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment