summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2022-07-19 21:02:54 -0600
committerJens Axboe <axboe@kernel.dk>2022-07-19 21:02:54 -0600
commit1e89db9bd676df24bded8da2053fe24ccfb4587a (patch)
treeadf8ec7eea28238884879a336beb23fae76aed4c /lib
parentca85855bdcae8f84f1512e88b4c75009ea17ea2f (diff)
parentbf14fad19ffbb3d37a1bb1324f966973e7d4a7b6 (diff)
Merge branch 'for-5.20/block' into for-5.20/drivers-post
* for-5.20/block: (162 commits) mmc: fix disk/queue leak in case of adding disk failure ublk_drv: fix an IS_ERR() vs NULL check ublk: remove UBLK_IO_F_INTEGRITY ublk_drv: remove unneeded semicolon ublk_drv: fix missing error return code in ublk_add_dev() ublk_drv: fix build warning with -Wmaybe-uninitialized and one sparse warning blktrace: Fix the blk_fill_rwbs() kernel-doc header fs/buffer: Fix the ll_rw_block() kernel-doc header fs/zonefs: Use the enum req_op type for tracing request operations fs/xfs: Use the enum req_op and blk_opf_t types PM: Use the enum req_op and blk_opf_t types fs/ocfs2: Use the enum req_op and blk_opf_t types fs/ntfs3: Use enum req_op where appropriate fs/nilfs2: Use the enum req_op and blk_opf_t types fs/nfs: Use enum req_op where appropriate fs/jbd2: Fix the documentation of the jbd2_write_superblock() callers fs/iomap: Use the new blk_opf_t type fs/hfsplus: Use the enum req_op and blk_opf_t types fs/gfs2: Use the enum req_op and blk_opf_t types fs/f2fs: Use the enum req_op and blk_opf_t types ...
Diffstat (limited to 'lib')
-rw-r--r--lib/iov_iter.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 0b64695ab632..507e732ef7cf 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -1268,6 +1268,98 @@ void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count)
}
EXPORT_SYMBOL(iov_iter_discard);
+static bool iov_iter_aligned_iovec(const struct iov_iter *i, unsigned addr_mask,
+ unsigned len_mask)
+{
+ size_t size = i->count;
+ size_t skip = i->iov_offset;
+ unsigned k;
+
+ for (k = 0; k < i->nr_segs; k++, skip = 0) {
+ size_t len = i->iov[k].iov_len - skip;
+
+ if (len > size)
+ len = size;
+ if (len & len_mask)
+ return false;
+ if ((unsigned long)(i->iov[k].iov_base + skip) & addr_mask)
+ return false;
+
+ size -= len;
+ if (!size)
+ break;
+ }
+ return true;
+}
+
+static bool iov_iter_aligned_bvec(const struct iov_iter *i, unsigned addr_mask,
+ unsigned len_mask)
+{
+ size_t size = i->count;
+ unsigned skip = i->iov_offset;
+ unsigned k;
+
+ for (k = 0; k < i->nr_segs; k++, skip = 0) {
+ size_t len = i->bvec[k].bv_len - skip;
+
+ if (len > size)
+ len = size;
+ if (len & len_mask)
+ return false;
+ if ((unsigned long)(i->bvec[k].bv_offset + skip) & addr_mask)
+ return false;
+
+ size -= len;
+ if (!size)
+ break;
+ }
+ return true;
+}
+
+/**
+ * iov_iter_is_aligned() - Check if the addresses and lengths of each segments
+ * are aligned to the parameters.
+ *
+ * @i: &struct iov_iter to restore
+ * @addr_mask: bit mask to check against the iov element's addresses
+ * @len_mask: bit mask to check against the iov element's lengths
+ *
+ * Return: false if any addresses or lengths intersect with the provided masks
+ */
+bool iov_iter_is_aligned(const struct iov_iter *i, unsigned addr_mask,
+ unsigned len_mask)
+{
+ if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i)))
+ return iov_iter_aligned_iovec(i, addr_mask, len_mask);
+
+ if (iov_iter_is_bvec(i))
+ return iov_iter_aligned_bvec(i, addr_mask, len_mask);
+
+ if (iov_iter_is_pipe(i)) {
+ unsigned int p_mask = i->pipe->ring_size - 1;
+ size_t size = i->count;
+
+ if (size & len_mask)
+ return false;
+ if (size && allocated(&i->pipe->bufs[i->head & p_mask])) {
+ if (i->iov_offset & addr_mask)
+ return false;
+ }
+
+ return true;
+ }
+
+ if (iov_iter_is_xarray(i)) {
+ if (i->count & len_mask)
+ return false;
+ if ((i->xarray_start + i->iov_offset) & addr_mask)
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(iov_iter_is_aligned);
+
static unsigned long iov_iter_alignment_iovec(const struct iov_iter *i)
{
unsigned long res = 0;