]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - include/linux/bvec.h
kernel/watchdog: split up config options
[mirror_ubuntu-bionic-kernel.git] / include / linux / bvec.h
index 89b65b82d98f5c5e77c34f967e856dcc6028dabe..ec8a4d7af6bda55586bc0b0221b3dcfe6e5ab487 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/kernel.h>
 #include <linux/bug.h>
+#include <linux/errno.h>
 
 /*
  * was unsigned short, but we might as well be ready for > 64kB I/O pages
@@ -39,6 +40,8 @@ struct bvec_iter {
 
        unsigned int            bi_idx;         /* current index into bvl_vec */
 
+       unsigned int            bi_done;        /* number of bytes completed */
+
        unsigned int            bi_bvec_done;   /* number of bytes completed in
                                                   current bvec */
 };
@@ -66,12 +69,14 @@ struct bvec_iter {
        .bv_offset      = bvec_iter_offset((bvec), (iter)),     \
 })
 
-static inline void bvec_iter_advance(const struct bio_vec *bv,
-                                    struct bvec_iter *iter,
-                                    unsigned bytes)
+static inline bool bvec_iter_advance(const struct bio_vec *bv,
+               struct bvec_iter *iter, unsigned bytes)
 {
-       WARN_ONCE(bytes > iter->bi_size,
-                 "Attempted to advance past end of bvec iter\n");
+       if (WARN_ONCE(bytes > iter->bi_size,
+                    "Attempted to advance past end of bvec iter\n")) {
+               iter->bi_size = 0;
+               return false;
+       }
 
        while (bytes) {
                unsigned iter_len = bvec_iter_len(bv, *iter);
@@ -80,12 +85,38 @@ static inline void bvec_iter_advance(const struct bio_vec *bv,
                bytes -= len;
                iter->bi_size -= len;
                iter->bi_bvec_done += len;
+               iter->bi_done += len;
 
                if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) {
                        iter->bi_bvec_done = 0;
                        iter->bi_idx++;
                }
        }
+       return true;
+}
+
+static inline bool bvec_iter_rewind(const struct bio_vec *bv,
+                                    struct bvec_iter *iter,
+                                    unsigned int bytes)
+{
+       while (bytes) {
+               unsigned len = min(bytes, iter->bi_bvec_done);
+
+               if (iter->bi_bvec_done == 0) {
+                       if (WARN_ONCE(iter->bi_idx == 0,
+                                     "Attempted to rewind iter beyond "
+                                     "bvec's boundaries\n")) {
+                               return false;
+                       }
+                       iter->bi_idx--;
+                       iter->bi_bvec_done = __bvec_iter_bvec(bv, *iter)->bv_len;
+                       continue;
+               }
+               bytes -= len;
+               iter->bi_size += len;
+               iter->bi_bvec_done -= len;
+       }
+       return true;
 }
 
 #define for_each_bvec(bvl, bio_vec, iter, start)                       \