block: add a proper block layer data direction encoding
authorChristoph Hellwig <hch@lst.de>
Thu, 20 Oct 2016 13:12:15 +0000 (15:12 +0200)
committerJens Axboe <axboe@fb.com>
Fri, 28 Oct 2016 14:48:54 +0000 (08:48 -0600)
Currently the block layer op_is_write, bio_data_dir and rq_data_dir
helper treat every operation that is not a READ as a data out operation.
This worked surprisingly long, but the new REQ_OP_ZONE_REPORT operation
actually adds a second operation that reads data from the device.
Surprisingly nothing critical relied on this direction, but this might
be a good opportunity to properly fix this issue up.

We take a little inspiration and use the least significant bit of the
operation number to encode the data direction, which just requires us
to renumber the operations to fix this scheme.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Shaun Tancheff <shaun.tancheff@seagate.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
include/linux/blk_types.h
include/linux/fs.h

index dca972d6754865a2eef137c01c2cbf20e6e92181..3fa62cabe8d219854a6c988749a0008bce8e32b6 100644 (file)
@@ -131,20 +131,37 @@ struct bio {
 /*
  * Operations and flags common to the bio and request structures.
  * We use 8 bits for encoding the operation, and the remaining 24 for flags.
+ *
+ * The least significant bit of the operation number indicates the data
+ * transfer direction:
+ *
+ *   - if the least significant bit is set transfers are TO the device
+ *   - if the least significant bit is not set transfers are FROM the device
+ *
+ * If a operation does not transfer data the least significant bit has no
+ * meaning.
  */
 #define REQ_OP_BITS    8
 #define REQ_OP_MASK    ((1 << REQ_OP_BITS) - 1)
 #define REQ_FLAG_BITS  24
 
 enum req_opf {
-       REQ_OP_READ,
-       REQ_OP_WRITE,
-       REQ_OP_DISCARD,         /* request to discard sectors */
-       REQ_OP_SECURE_ERASE,    /* request to securely erase sectors */
-       REQ_OP_WRITE_SAME,      /* write same block many times */
-       REQ_OP_FLUSH,           /* request for cache flush */
-       REQ_OP_ZONE_REPORT,     /* Get zone information */
-       REQ_OP_ZONE_RESET,      /* Reset a zone write pointer */
+       /* read sectors from the device */
+       REQ_OP_READ             = 0,
+       /* write sectors to the device */
+       REQ_OP_WRITE            = 1,
+       /* flush the volatile write cache */
+       REQ_OP_FLUSH            = 2,
+       /* discard sectors */
+       REQ_OP_DISCARD          = 3,
+       /* get zone information */
+       REQ_OP_ZONE_REPORT      = 4,
+       /* securely erase sectors */
+       REQ_OP_SECURE_ERASE     = 5,
+       /* seset a zone write pointer */
+       REQ_OP_ZONE_RESET       = 6,
+       /* write the same sector many times */
+       REQ_OP_WRITE_SAME       = 7,
 
        REQ_OP_LAST,
 };
@@ -194,6 +211,11 @@ enum req_flag_bits {
 #define bio_set_op_attrs(bio, op, op_flags) \
        ((bio)->bi_opf |= (op | op_flags))
 
+static inline bool op_is_write(unsigned int op)
+{
+       return (op & 1);
+}
+
 static inline bool op_is_sync(unsigned int op)
 {
        return (op & REQ_OP_MASK) == REQ_OP_READ || (op & REQ_SYNC);
index 16d2b6e874d679597478e653f3ef23974e0c33de..e3e878f12b2522d57f383fb999301f6569943ea9 100644 (file)
@@ -2499,11 +2499,6 @@ extern void make_bad_inode(struct inode *);
 extern bool is_bad_inode(struct inode *);
 
 #ifdef CONFIG_BLOCK
-static inline bool op_is_write(unsigned int op)
-{
-       return op == REQ_OP_READ ? false : true;
-}
-
 /*
  * return data direction, READ or WRITE
  */