1. 03 7月, 2018 10 次提交
  2. 20 6月, 2018 1 次提交
  3. 13 6月, 2018 2 次提交
    • K
      treewide: Use array_size() in vzalloc() · fad953ce
      Kees Cook 提交于
      The vzalloc() function has no 2-factor argument form, so multiplication
      factors need to be wrapped in array_size(). This patch replaces cases of:
      
              vzalloc(a * b)
      
      with:
              vzalloc(array_size(a, b))
      
      as well as handling cases of:
      
              vzalloc(a * b * c)
      
      with:
      
              vzalloc(array3_size(a, b, c))
      
      This does, however, attempt to ignore constant size factors like:
      
              vzalloc(4 * 1024)
      
      though any constants defined via macros get caught up in the conversion.
      
      Any factors with a sizeof() of "unsigned char", "char", and "u8" were
      dropped, since they're redundant.
      
      The Coccinelle script used for this was:
      
      // Fix redundant parens around sizeof().
      @@
      type TYPE;
      expression THING, E;
      @@
      
      (
        vzalloc(
      -	(sizeof(TYPE)) * E
      +	sizeof(TYPE) * E
        , ...)
      |
        vzalloc(
      -	(sizeof(THING)) * E
      +	sizeof(THING) * E
        , ...)
      )
      
      // Drop single-byte sizes and redundant parens.
      @@
      expression COUNT;
      typedef u8;
      typedef __u8;
      @@
      
      (
        vzalloc(
      -	sizeof(u8) * (COUNT)
      +	COUNT
        , ...)
      |
        vzalloc(
      -	sizeof(__u8) * (COUNT)
      +	COUNT
        , ...)
      |
        vzalloc(
      -	sizeof(char) * (COUNT)
      +	COUNT
        , ...)
      |
        vzalloc(
      -	sizeof(unsigned char) * (COUNT)
      +	COUNT
        , ...)
      |
        vzalloc(
      -	sizeof(u8) * COUNT
      +	COUNT
        , ...)
      |
        vzalloc(
      -	sizeof(__u8) * COUNT
      +	COUNT
        , ...)
      |
        vzalloc(
      -	sizeof(char) * COUNT
      +	COUNT
        , ...)
      |
        vzalloc(
      -	sizeof(unsigned char) * COUNT
      +	COUNT
        , ...)
      )
      
      // 2-factor product with sizeof(type/expression) and identifier or constant.
      @@
      type TYPE;
      expression THING;
      identifier COUNT_ID;
      constant COUNT_CONST;
      @@
      
      (
        vzalloc(
      -	sizeof(TYPE) * (COUNT_ID)
      +	array_size(COUNT_ID, sizeof(TYPE))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE) * COUNT_ID
      +	array_size(COUNT_ID, sizeof(TYPE))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE) * (COUNT_CONST)
      +	array_size(COUNT_CONST, sizeof(TYPE))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE) * COUNT_CONST
      +	array_size(COUNT_CONST, sizeof(TYPE))
        , ...)
      |
        vzalloc(
      -	sizeof(THING) * (COUNT_ID)
      +	array_size(COUNT_ID, sizeof(THING))
        , ...)
      |
        vzalloc(
      -	sizeof(THING) * COUNT_ID
      +	array_size(COUNT_ID, sizeof(THING))
        , ...)
      |
        vzalloc(
      -	sizeof(THING) * (COUNT_CONST)
      +	array_size(COUNT_CONST, sizeof(THING))
        , ...)
      |
        vzalloc(
      -	sizeof(THING) * COUNT_CONST
      +	array_size(COUNT_CONST, sizeof(THING))
        , ...)
      )
      
      // 2-factor product, only identifiers.
      @@
      identifier SIZE, COUNT;
      @@
      
        vzalloc(
      -	SIZE * COUNT
      +	array_size(COUNT, SIZE)
        , ...)
      
      // 3-factor product with 1 sizeof(type) or sizeof(expression), with
      // redundant parens removed.
      @@
      expression THING;
      identifier STRIDE, COUNT;
      type TYPE;
      @@
      
      (
        vzalloc(
      -	sizeof(TYPE) * (COUNT) * (STRIDE)
      +	array3_size(COUNT, STRIDE, sizeof(TYPE))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE) * (COUNT) * STRIDE
      +	array3_size(COUNT, STRIDE, sizeof(TYPE))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE) * COUNT * (STRIDE)
      +	array3_size(COUNT, STRIDE, sizeof(TYPE))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE) * COUNT * STRIDE
      +	array3_size(COUNT, STRIDE, sizeof(TYPE))
        , ...)
      |
        vzalloc(
      -	sizeof(THING) * (COUNT) * (STRIDE)
      +	array3_size(COUNT, STRIDE, sizeof(THING))
        , ...)
      |
        vzalloc(
      -	sizeof(THING) * (COUNT) * STRIDE
      +	array3_size(COUNT, STRIDE, sizeof(THING))
        , ...)
      |
        vzalloc(
      -	sizeof(THING) * COUNT * (STRIDE)
      +	array3_size(COUNT, STRIDE, sizeof(THING))
        , ...)
      |
        vzalloc(
      -	sizeof(THING) * COUNT * STRIDE
      +	array3_size(COUNT, STRIDE, sizeof(THING))
        , ...)
      )
      
      // 3-factor product with 2 sizeof(variable), with redundant parens removed.
      @@
      expression THING1, THING2;
      identifier COUNT;
      type TYPE1, TYPE2;
      @@
      
      (
        vzalloc(
      -	sizeof(TYPE1) * sizeof(TYPE2) * COUNT
      +	array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE1) * sizeof(THING2) * (COUNT)
      +	array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
        , ...)
      |
        vzalloc(
      -	sizeof(THING1) * sizeof(THING2) * COUNT
      +	array3_size(COUNT, sizeof(THING1), sizeof(THING2))
        , ...)
      |
        vzalloc(
      -	sizeof(THING1) * sizeof(THING2) * (COUNT)
      +	array3_size(COUNT, sizeof(THING1), sizeof(THING2))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE1) * sizeof(THING2) * COUNT
      +	array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
        , ...)
      |
        vzalloc(
      -	sizeof(TYPE1) * sizeof(THING2) * (COUNT)
      +	array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
        , ...)
      )
      
      // 3-factor product, only identifiers, with redundant parens removed.
      @@
      identifier STRIDE, SIZE, COUNT;
      @@
      
      (
        vzalloc(
      -	(COUNT) * STRIDE * SIZE
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        vzalloc(
      -	COUNT * (STRIDE) * SIZE
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        vzalloc(
      -	COUNT * STRIDE * (SIZE)
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        vzalloc(
      -	(COUNT) * (STRIDE) * SIZE
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        vzalloc(
      -	COUNT * (STRIDE) * (SIZE)
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        vzalloc(
      -	(COUNT) * STRIDE * (SIZE)
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        vzalloc(
      -	(COUNT) * (STRIDE) * (SIZE)
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        vzalloc(
      -	COUNT * STRIDE * SIZE
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      )
      
      // Any remaining multi-factor products, first at least 3-factor products
      // when they're not all constants...
      @@
      expression E1, E2, E3;
      constant C1, C2, C3;
      @@
      
      (
        vzalloc(C1 * C2 * C3, ...)
      |
        vzalloc(
      -	E1 * E2 * E3
      +	array3_size(E1, E2, E3)
        , ...)
      )
      
      // And then all remaining 2 factors products when they're not all constants.
      @@
      expression E1, E2;
      constant C1, C2;
      @@
      
      (
        vzalloc(C1 * C2, ...)
      |
        vzalloc(
      -	E1 * E2
      +	array_size(E1, E2)
        , ...)
      )
      Signed-off-by: NKees Cook <keescook@chromium.org>
      fad953ce
    • K
      treewide: kzalloc() -> kcalloc() · 6396bb22
      Kees Cook 提交于
      The kzalloc() function has a 2-factor argument form, kcalloc(). This
      patch replaces cases of:
      
              kzalloc(a * b, gfp)
      
      with:
              kcalloc(a * b, gfp)
      
      as well as handling cases of:
      
              kzalloc(a * b * c, gfp)
      
      with:
      
              kzalloc(array3_size(a, b, c), gfp)
      
      as it's slightly less ugly than:
      
              kzalloc_array(array_size(a, b), c, gfp)
      
      This does, however, attempt to ignore constant size factors like:
      
              kzalloc(4 * 1024, gfp)
      
      though any constants defined via macros get caught up in the conversion.
      
      Any factors with a sizeof() of "unsigned char", "char", and "u8" were
      dropped, since they're redundant.
      
      The Coccinelle script used for this was:
      
      // Fix redundant parens around sizeof().
      @@
      type TYPE;
      expression THING, E;
      @@
      
      (
        kzalloc(
      -	(sizeof(TYPE)) * E
      +	sizeof(TYPE) * E
        , ...)
      |
        kzalloc(
      -	(sizeof(THING)) * E
      +	sizeof(THING) * E
        , ...)
      )
      
      // Drop single-byte sizes and redundant parens.
      @@
      expression COUNT;
      typedef u8;
      typedef __u8;
      @@
      
      (
        kzalloc(
      -	sizeof(u8) * (COUNT)
      +	COUNT
        , ...)
      |
        kzalloc(
      -	sizeof(__u8) * (COUNT)
      +	COUNT
        , ...)
      |
        kzalloc(
      -	sizeof(char) * (COUNT)
      +	COUNT
        , ...)
      |
        kzalloc(
      -	sizeof(unsigned char) * (COUNT)
      +	COUNT
        , ...)
      |
        kzalloc(
      -	sizeof(u8) * COUNT
      +	COUNT
        , ...)
      |
        kzalloc(
      -	sizeof(__u8) * COUNT
      +	COUNT
        , ...)
      |
        kzalloc(
      -	sizeof(char) * COUNT
      +	COUNT
        , ...)
      |
        kzalloc(
      -	sizeof(unsigned char) * COUNT
      +	COUNT
        , ...)
      )
      
      // 2-factor product with sizeof(type/expression) and identifier or constant.
      @@
      type TYPE;
      expression THING;
      identifier COUNT_ID;
      constant COUNT_CONST;
      @@
      
      (
      - kzalloc
      + kcalloc
        (
      -	sizeof(TYPE) * (COUNT_ID)
      +	COUNT_ID, sizeof(TYPE)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(TYPE) * COUNT_ID
      +	COUNT_ID, sizeof(TYPE)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(TYPE) * (COUNT_CONST)
      +	COUNT_CONST, sizeof(TYPE)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(TYPE) * COUNT_CONST
      +	COUNT_CONST, sizeof(TYPE)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(THING) * (COUNT_ID)
      +	COUNT_ID, sizeof(THING)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(THING) * COUNT_ID
      +	COUNT_ID, sizeof(THING)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(THING) * (COUNT_CONST)
      +	COUNT_CONST, sizeof(THING)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(THING) * COUNT_CONST
      +	COUNT_CONST, sizeof(THING)
        , ...)
      )
      
      // 2-factor product, only identifiers.
      @@
      identifier SIZE, COUNT;
      @@
      
      - kzalloc
      + kcalloc
        (
      -	SIZE * COUNT
      +	COUNT, SIZE
        , ...)
      
      // 3-factor product with 1 sizeof(type) or sizeof(expression), with
      // redundant parens removed.
      @@
      expression THING;
      identifier STRIDE, COUNT;
      type TYPE;
      @@
      
      (
        kzalloc(
      -	sizeof(TYPE) * (COUNT) * (STRIDE)
      +	array3_size(COUNT, STRIDE, sizeof(TYPE))
        , ...)
      |
        kzalloc(
      -	sizeof(TYPE) * (COUNT) * STRIDE
      +	array3_size(COUNT, STRIDE, sizeof(TYPE))
        , ...)
      |
        kzalloc(
      -	sizeof(TYPE) * COUNT * (STRIDE)
      +	array3_size(COUNT, STRIDE, sizeof(TYPE))
        , ...)
      |
        kzalloc(
      -	sizeof(TYPE) * COUNT * STRIDE
      +	array3_size(COUNT, STRIDE, sizeof(TYPE))
        , ...)
      |
        kzalloc(
      -	sizeof(THING) * (COUNT) * (STRIDE)
      +	array3_size(COUNT, STRIDE, sizeof(THING))
        , ...)
      |
        kzalloc(
      -	sizeof(THING) * (COUNT) * STRIDE
      +	array3_size(COUNT, STRIDE, sizeof(THING))
        , ...)
      |
        kzalloc(
      -	sizeof(THING) * COUNT * (STRIDE)
      +	array3_size(COUNT, STRIDE, sizeof(THING))
        , ...)
      |
        kzalloc(
      -	sizeof(THING) * COUNT * STRIDE
      +	array3_size(COUNT, STRIDE, sizeof(THING))
        , ...)
      )
      
      // 3-factor product with 2 sizeof(variable), with redundant parens removed.
      @@
      expression THING1, THING2;
      identifier COUNT;
      type TYPE1, TYPE2;
      @@
      
      (
        kzalloc(
      -	sizeof(TYPE1) * sizeof(TYPE2) * COUNT
      +	array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
        , ...)
      |
        kzalloc(
      -	sizeof(TYPE1) * sizeof(THING2) * (COUNT)
      +	array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
        , ...)
      |
        kzalloc(
      -	sizeof(THING1) * sizeof(THING2) * COUNT
      +	array3_size(COUNT, sizeof(THING1), sizeof(THING2))
        , ...)
      |
        kzalloc(
      -	sizeof(THING1) * sizeof(THING2) * (COUNT)
      +	array3_size(COUNT, sizeof(THING1), sizeof(THING2))
        , ...)
      |
        kzalloc(
      -	sizeof(TYPE1) * sizeof(THING2) * COUNT
      +	array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
        , ...)
      |
        kzalloc(
      -	sizeof(TYPE1) * sizeof(THING2) * (COUNT)
      +	array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
        , ...)
      )
      
      // 3-factor product, only identifiers, with redundant parens removed.
      @@
      identifier STRIDE, SIZE, COUNT;
      @@
      
      (
        kzalloc(
      -	(COUNT) * STRIDE * SIZE
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        kzalloc(
      -	COUNT * (STRIDE) * SIZE
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        kzalloc(
      -	COUNT * STRIDE * (SIZE)
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        kzalloc(
      -	(COUNT) * (STRIDE) * SIZE
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        kzalloc(
      -	COUNT * (STRIDE) * (SIZE)
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        kzalloc(
      -	(COUNT) * STRIDE * (SIZE)
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        kzalloc(
      -	(COUNT) * (STRIDE) * (SIZE)
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      |
        kzalloc(
      -	COUNT * STRIDE * SIZE
      +	array3_size(COUNT, STRIDE, SIZE)
        , ...)
      )
      
      // Any remaining multi-factor products, first at least 3-factor products,
      // when they're not all constants...
      @@
      expression E1, E2, E3;
      constant C1, C2, C3;
      @@
      
      (
        kzalloc(C1 * C2 * C3, ...)
      |
        kzalloc(
      -	(E1) * E2 * E3
      +	array3_size(E1, E2, E3)
        , ...)
      |
        kzalloc(
      -	(E1) * (E2) * E3
      +	array3_size(E1, E2, E3)
        , ...)
      |
        kzalloc(
      -	(E1) * (E2) * (E3)
      +	array3_size(E1, E2, E3)
        , ...)
      |
        kzalloc(
      -	E1 * E2 * E3
      +	array3_size(E1, E2, E3)
        , ...)
      )
      
      // And then all remaining 2 factors products when they're not all constants,
      // keeping sizeof() as the second factor argument.
      @@
      expression THING, E1, E2;
      type TYPE;
      constant C1, C2, C3;
      @@
      
      (
        kzalloc(sizeof(THING) * C2, ...)
      |
        kzalloc(sizeof(TYPE) * C2, ...)
      |
        kzalloc(C1 * C2 * C3, ...)
      |
        kzalloc(C1 * C2, ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(TYPE) * (E2)
      +	E2, sizeof(TYPE)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(TYPE) * E2
      +	E2, sizeof(TYPE)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(THING) * (E2)
      +	E2, sizeof(THING)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	sizeof(THING) * E2
      +	E2, sizeof(THING)
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	(E1) * E2
      +	E1, E2
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	(E1) * (E2)
      +	E1, E2
        , ...)
      |
      - kzalloc
      + kcalloc
        (
      -	E1 * E2
      +	E1, E2
        , ...)
      )
      Signed-off-by: NKees Cook <keescook@chromium.org>
      6396bb22
  4. 29 5月, 2018 1 次提交
  5. 19 5月, 2018 1 次提交
  6. 21 4月, 2018 2 次提交
    • R
      scsi: target: target_core_transport.c: enable+fix kernel-doc · 9ad97b8b
      Randy Dunlap 提交于
      For exported functions that already have near-kernel-doc notation,
      fix them to begin with "/**" and make a few corrections so that they
      don't have any kernel-doc warnings.
      Signed-off-by: NRandy Dunlap <rdunlap@infradead.org>
      To: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
      Cc: linux-scsi@vger.kernel.org
      Cc: target-devel@vger.kernel.org
      Cc: linux-doc@vger.kernel.org
      Cc: "James E.J. Bottomley" <jejb@linux.vnet.ibm.com>
      Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
      Cc: Jonathan Corbet <corbet@lwn.net>
      Signed-off-by: NMartin K. Petersen <martin.petersen@oracle.com>
      9ad97b8b
    • R
      scsi: target: target_core_transport.c: fix kernel-doc warnings · 1e74aff1
      Randy Dunlap 提交于
      Correct a function parameter's name to eliminate kernel-doc warnings
      in drivers/target/target_core_transport.c.
      
      Fixes these kernel-doc warnings: (tested by adding these files to a new
      target.rst documentation file)
      
      ../drivers/target/target_core_transport.c:1671: warning: No description found for parameter 'fabric_tmr_ptr'
      ../drivers/target/target_core_transport.c:1671: warning: Excess function parameter 'fabric_context' description in 'target_submit_tmr'
      Signed-off-by: NRandy Dunlap <rdunlap@infradead.org>
      To: "Nicholas A. Bellinger" <nab@linux-iscsi.org>
      Cc: linux-scsi@vger.kernel.org
      Cc: target-devel@vger.kernel.org
      Cc: linux-doc@vger.kernel.org
      Cc: "James E.J. Bottomley" <jejb@linux.vnet.ibm.com>
      Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
      Cc: Jonathan Corbet <corbet@lwn.net>
      Signed-off-by: NMartin K. Petersen <martin.petersen@oracle.com>
      1e74aff1
  7. 20 1月, 2018 1 次提交
    • B
      lib/scatterlist: Fix chaining support in sgl_alloc_order() · 8c7a8d1c
      Bart Van Assche 提交于
      This patch avoids that workloads with large block sizes (megabytes)
      can trigger the following call stack with the ib_srpt driver (that
      driver is the only driver that chains scatterlists allocated by
      sgl_alloc_order()):
      
      BUG: Bad page state in process kworker/0:1H  pfn:2423a78
      page:fffffb03d08e9e00 count:-3 mapcount:0 mapping:          (null) index:0x0
      flags: 0x57ffffc0000000()
      raw: 0057ffffc0000000 0000000000000000 0000000000000000 fffffffdffffffff
      raw: dead000000000100 dead000000000200 0000000000000000 0000000000000000
      page dumped because: nonzero _count
      CPU: 0 PID: 733 Comm: kworker/0:1H Tainted: G          I      4.15.0-rc7.bart+ #1
      Hardware name: HP ProLiant DL380 G7, BIOS P67 08/16/2015
      Workqueue: ib-comp-wq ib_cq_poll_work [ib_core]
      Call Trace:
       dump_stack+0x5c/0x83
       bad_page+0xf5/0x10f
       get_page_from_freelist+0xa46/0x11b0
       __alloc_pages_nodemask+0x103/0x290
       sgl_alloc_order+0x101/0x180
       target_alloc_sgl+0x2c/0x40 [target_core_mod]
       srpt_alloc_rw_ctxs+0x173/0x2d0 [ib_srpt]
       srpt_handle_new_iu+0x61e/0x7f0 [ib_srpt]
       __ib_process_cq+0x55/0xa0 [ib_core]
       ib_cq_poll_work+0x1b/0x60 [ib_core]
       process_one_work+0x141/0x340
       worker_thread+0x47/0x3e0
       kthread+0xf5/0x130
       ret_from_fork+0x1f/0x30
      
      Fixes: e80a0af4 ("lib/scatterlist: Introduce sgl_alloc() and sgl_free()")
      Reported-by: NLaurence Oberman <loberman@redhat.com>
      Tested-by: NLaurence Oberman <loberman@redhat.com>
      Signed-off-by: NBart Van Assche <bart.vanassche@wdc.com>
      Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
      Cc: Laurence Oberman <loberman@redhat.com>
      Signed-off-by: NJens Axboe <axboe@kernel.dk>
      8c7a8d1c
  8. 13 1月, 2018 1 次提交
  9. 07 1月, 2018 1 次提交
  10. 08 11月, 2017 4 次提交
    • N
      target: Avoid early CMD_T_PRE_EXECUTE failures during ABORT_TASK · 1c21a480
      Nicholas Bellinger 提交于
      This patch fixes bug where early se_cmd exceptions that occur
      before backend execution can result in use-after-free if/when
      a subsequent ABORT_TASK occurs for the same tag.
      
      Since an early se_cmd exception will have had se_cmd added to
      se_session->sess_cmd_list via target_get_sess_cmd(), it will
      not have CMD_T_COMPLETE set by the usual target_complete_cmd()
      backend completion path.
      
      This causes a subsequent ABORT_TASK + __target_check_io_state()
      to signal ABORT_TASK should proceed.  As core_tmr_abort_task()
      executes, it will bring the outstanding se_cmd->cmd_kref count
      down to zero releasing se_cmd, after se_cmd has already been
      queued with error status into fabric driver response path code.
      
      To address this bug, introduce a CMD_T_PRE_EXECUTE bit that is
      set at target_get_sess_cmd() time, and cleared immediately before
      backend driver dispatch in target_execute_cmd() once CMD_T_ACTIVE
      is set.
      
      Then, check CMD_T_PRE_EXECUTE within __target_check_io_state() to
      determine when an early exception has occured, and avoid aborting
      this se_cmd since it will have already been queued into fabric
      driver response path code.
      Reported-by: NDonald White <dew@datera.io>
      Cc: Donald White <dew@datera.io>
      Cc: Mike Christie <mchristi@redhat.com>
      Cc: Hannes Reinecke <hare@suse.com>
      Cc: stable@vger.kernel.org # 3.14+
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      1c21a480
    • N
      target: Fix quiese during transport_write_pending_qf endless loop · 9574a497
      Nicholas Bellinger 提交于
      This patch fixes a potential end-less loop during QUEUE_FULL,
      where cmd->se_tfo->write_pending() callback fails repeatedly
      but __transport_wait_for_tasks() has already been invoked to
      quiese the outstanding se_cmd descriptor.
      
      To address this bug, this patch adds a CMD_T_STOP|CMD_T_ABORTED
      check within transport_write_pending_qf() and invokes the
      existing se_cmd->t_transport_stop_comp to signal quiese
      completion back to __transport_wait_for_tasks().
      
      Cc: Mike Christie <mchristi@redhat.com>
      Cc: Hannes Reinecke <hare@suse.com>
      Cc: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
      Cc: Michael Cyr <mikecyr@linux.vnet.ibm.com>
      Cc: Potnuri Bharat Teja <bharat@chelsio.com>
      Cc: Sagi Grimberg <sagi@grimberg.me>
      Cc: stable@vger.kernel.org # 4.11+
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      9574a497
    • N
      target: Fix caw_sem leak in transport_generic_request_failure · fd2f928b
      Nicholas Bellinger 提交于
      With the recent addition of transport_check_aborted_status() within
      transport_generic_request_failure() to avoid sending a SCSI status
      exception after CMD_T_ABORTED w/ TAS=1 has occured, it introduced
      a COMPARE_AND_WRITE early failure regression.
      
      Namely when COMPARE_AND_WRITE fails and se_device->caw_sem has
      been taken by sbc_compare_and_write(), if the new check for
      transport_check_aborted_status() returns true and exits,
      cmd->transport_complete_callback() -> compare_and_write_post()
      is skipped never releasing se_device->caw_sem.
      
      This regression was originally introduced by:
      
        commit e3b88ee9
        Author: Bart Van Assche <bart.vanassche@sandisk.com>
        Date:   Tue Feb 14 16:25:45 2017 -0800
      
            target: Fix handling of aborted failed commands
      
      To address this bug, move the transport_check_aborted_status()
      call after transport_complete_task_attr() and
      cmd->transport_complete_callback().
      
      Cc: Mike Christie <mchristi@redhat.com>
      Cc: Hannes Reinecke <hare@suse.com>
      Cc: Bart Van Assche <bart.vanassche@sandisk.com>
      Cc: stable@vger.kernel.org # 4.11+
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      fd2f928b
    • N
      target: Fix QUEUE_FULL + SCSI task attribute handling · 1c79df1f
      Nicholas Bellinger 提交于
      This patch fixes a bug during QUEUE_FULL where transport_complete_qf()
      calls transport_complete_task_attr() after it's already been invoked
      by target_complete_ok_work() or transport_generic_request_failure()
      during initial completion, preceeding QUEUE_FULL.
      
      This will result in se_device->simple_cmds, se_device->dev_cur_ordered_id
      and/or se_device->dev_ordered_sync being updated multiple times for
      a single se_cmd.
      
      To address this bug, clear SCF_TASK_ATTR_SET after the first call
      to transport_complete_task_attr(), and avoid updating SCSI task
      attribute related counters for any subsequent calls.
      
      Also, when a se_cmd is deferred due to ordered tags and executed
      via target_restart_delayed_cmds(), set CMD_T_SENT before execution
      matching what target_execute_cmd() does.
      
      Cc: Michael Cyr <mikecyr@linux.vnet.ibm.com>
      Cc: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
      Cc: Mike Christie <mchristi@redhat.com>
      Cc: Hannes Reinecke <hare@suse.com>
      Cc: stable@vger.kernel.org # 4.1+
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      1c79df1f
  11. 05 11月, 2017 4 次提交
  12. 10 8月, 2017 1 次提交
    • N
      target: Fix node_acl demo-mode + uncached dynamic shutdown regression · 6f48655f
      Nicholas Bellinger 提交于
      This patch fixes a generate_node_acls = 1 + cache_dynamic_acls = 0
      regression, that was introduced by
      
        commit 01d4d673
        Author: Nicholas Bellinger <nab@linux-iscsi.org>
        Date:   Wed Dec 7 12:55:54 2016 -0800
      
      which originally had the proper list_del_init() usage, but was
      dropped during list review as it was thought unnecessary by HCH.
      
      However, list_del_init() usage is required during the special
      generate_node_acls = 1 + cache_dynamic_acls = 0 case when
      transport_free_session() does a list_del(&se_nacl->acl_list),
      followed by target_complete_nacl() doing the same thing.
      
      This was manifesting as a general protection fault as reported
      by Justin:
      
      kernel: general protection fault: 0000 [#1] SMP
      kernel: Modules linked in:
      kernel: CPU: 0 PID: 11047 Comm: iscsi_ttx Not tainted 4.13.0-rc2.x86_64.1+ #20
      kernel: Hardware name: Intel Corporation S5500BC/S5500BC, BIOS S5500.86B.01.00.0064.050520141428 05/05/2014
      kernel: task: ffff88026939e800 task.stack: ffffc90007884000
      kernel: RIP: 0010:target_put_nacl+0x49/0xb0
      kernel: RSP: 0018:ffffc90007887d70 EFLAGS: 00010246
      kernel: RAX: dead000000000200 RBX: ffff8802556ca000 RCX: 0000000000000000
      kernel: RDX: dead000000000100 RSI: 0000000000000246 RDI: ffff8802556ce028
      kernel: RBP: ffffc90007887d88 R08: 0000000000000001 R09: 0000000000000000
      kernel: R10: ffffc90007887df8 R11: ffffea0009986900 R12: ffff8802556ce020
      kernel: R13: ffff8802556ce028 R14: ffff8802556ce028 R15: ffffffff88d85540
      kernel: FS:  0000000000000000(0000) GS:ffff88027fc00000(0000) knlGS:0000000000000000
      kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
      kernel: CR2: 00007fffe36f5f94 CR3: 0000000009209000 CR4: 00000000003406f0
      kernel: DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
      kernel: DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
      kernel: Call Trace:
      kernel:  transport_free_session+0x67/0x140
      kernel:  transport_deregister_session+0x7a/0xc0
      kernel:  iscsit_close_session+0x92/0x210
      kernel:  iscsit_close_connection+0x5f9/0x840
      kernel:  iscsit_take_action_for_connection_exit+0xfe/0x110
      kernel:  iscsi_target_tx_thread+0x140/0x1e0
      kernel:  ? wait_woken+0x90/0x90
      kernel:  kthread+0x124/0x160
      kernel:  ? iscsit_thread_get_cpumask+0x90/0x90
      kernel:  ? kthread_create_on_node+0x40/0x40
      kernel:  ret_from_fork+0x22/0x30
      kernel: Code: 00 48 89 fb 4c 8b a7 48 01 00 00 74 68 4d 8d 6c 24 08 4c
      89 ef e8 e8 28 43 00 48 8b 93 20 04 00 00 48 8b 83 28 04 00 00 4c 89
      ef <48> 89 42 08 48 89 10 48 b8 00 01 00 00 00 00 ad de 48 89 83 20
      kernel: RIP: target_put_nacl+0x49/0xb0 RSP: ffffc90007887d70
      kernel: ---[ end trace f12821adbfd46fed ]---
      
      To address this, go ahead and use proper list_del_list() for all
      cases of se_nacl->acl_list deletion.
      Reported-by: NJustin Maggard <jmaggard01@gmail.com>
      Tested-by: NJustin Maggard <jmaggard01@gmail.com>
      Cc: Justin Maggard <jmaggard01@gmail.com>
      Cc: stable@vger.kernel.org # 4.1+
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      6f48655f
  13. 13 7月, 2017 1 次提交
    • M
      mm, tree wide: replace __GFP_REPEAT by __GFP_RETRY_MAYFAIL with more useful semantic · dcda9b04
      Michal Hocko 提交于
      __GFP_REPEAT was designed to allow retry-but-eventually-fail semantic to
      the page allocator.  This has been true but only for allocations
      requests larger than PAGE_ALLOC_COSTLY_ORDER.  It has been always
      ignored for smaller sizes.  This is a bit unfortunate because there is
      no way to express the same semantic for those requests and they are
      considered too important to fail so they might end up looping in the
      page allocator for ever, similarly to GFP_NOFAIL requests.
      
      Now that the whole tree has been cleaned up and accidental or misled
      usage of __GFP_REPEAT flag has been removed for !costly requests we can
      give the original flag a better name and more importantly a more useful
      semantic.  Let's rename it to __GFP_RETRY_MAYFAIL which tells the user
      that the allocator would try really hard but there is no promise of a
      success.  This will work independent of the order and overrides the
      default allocator behavior.  Page allocator users have several levels of
      guarantee vs.  cost options (take GFP_KERNEL as an example)
      
       - GFP_KERNEL & ~__GFP_RECLAIM - optimistic allocation without _any_
         attempt to free memory at all. The most light weight mode which even
         doesn't kick the background reclaim. Should be used carefully because
         it might deplete the memory and the next user might hit the more
         aggressive reclaim
      
       - GFP_KERNEL & ~__GFP_DIRECT_RECLAIM (or GFP_NOWAIT)- optimistic
         allocation without any attempt to free memory from the current
         context but can wake kswapd to reclaim memory if the zone is below
         the low watermark. Can be used from either atomic contexts or when
         the request is a performance optimization and there is another
         fallback for a slow path.
      
       - (GFP_KERNEL|__GFP_HIGH) & ~__GFP_DIRECT_RECLAIM (aka GFP_ATOMIC) -
         non sleeping allocation with an expensive fallback so it can access
         some portion of memory reserves. Usually used from interrupt/bh
         context with an expensive slow path fallback.
      
       - GFP_KERNEL - both background and direct reclaim are allowed and the
         _default_ page allocator behavior is used. That means that !costly
         allocation requests are basically nofail but there is no guarantee of
         that behavior so failures have to be checked properly by callers
         (e.g. OOM killer victim is allowed to fail currently).
      
       - GFP_KERNEL | __GFP_NORETRY - overrides the default allocator behavior
         and all allocation requests fail early rather than cause disruptive
         reclaim (one round of reclaim in this implementation). The OOM killer
         is not invoked.
      
       - GFP_KERNEL | __GFP_RETRY_MAYFAIL - overrides the default allocator
         behavior and all allocation requests try really hard. The request
         will fail if the reclaim cannot make any progress. The OOM killer
         won't be triggered.
      
       - GFP_KERNEL | __GFP_NOFAIL - overrides the default allocator behavior
         and all allocation requests will loop endlessly until they succeed.
         This might be really dangerous especially for larger orders.
      
      Existing users of __GFP_REPEAT are changed to __GFP_RETRY_MAYFAIL
      because they already had their semantic.  No new users are added.
      __alloc_pages_slowpath is changed to bail out for __GFP_RETRY_MAYFAIL if
      there is no progress and we have already passed the OOM point.
      
      This means that all the reclaim opportunities have been exhausted except
      the most disruptive one (the OOM killer) and a user defined fallback
      behavior is more sensible than keep retrying in the page allocator.
      
      [akpm@linux-foundation.org: fix arch/sparc/kernel/mdesc.c]
      [mhocko@suse.com: semantic fix]
        Link: http://lkml.kernel.org/r/20170626123847.GM11534@dhcp22.suse.cz
      [mhocko@kernel.org: address other thing spotted by Vlastimil]
        Link: http://lkml.kernel.org/r/20170626124233.GN11534@dhcp22.suse.cz
      Link: http://lkml.kernel.org/r/20170623085345.11304-3-mhocko@kernel.orgSigned-off-by: NMichal Hocko <mhocko@suse.com>
      Acked-by: NVlastimil Babka <vbabka@suse.cz>
      Cc: Alex Belits <alex.belits@cavium.com>
      Cc: Chris Wilson <chris@chris-wilson.co.uk>
      Cc: Christoph Hellwig <hch@infradead.org>
      Cc: Darrick J. Wong <darrick.wong@oracle.com>
      Cc: David Daney <david.daney@cavium.com>
      Cc: Johannes Weiner <hannes@cmpxchg.org>
      Cc: Mel Gorman <mgorman@suse.de>
      Cc: NeilBrown <neilb@suse.com>
      Cc: Ralf Baechle <ralf@linux-mips.org>
      Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      dcda9b04
  14. 07 7月, 2017 9 次提交
    • M
      target: fix SAM_STAT_BUSY/TASK_SET_FULL handling · 402242c9
      Mike Christie 提交于
      If the scsi status was not SAM_STAT_GOOD or there was no transport
      sense, we would ignore the scsi status and do a generic not ready
      LUN communication failure check condition failure.
      
      The problem is that LUN COMM failure is treated as a hard error
      sometimes and will cause apps to get IO errors instead of the OS's SCSI
      layer retrying. For example, the tcmu daemon will return SAM_STAT_QUEUE_FULL
      when memory runs low and can still make progress but wants the initiator to
      reduce the work load. Windows will fail this error directly the app
      instead of retrying.
      
      This patch is based on Nick's "target/iblock: Use -EAGAIN/-ENOMEM to
      propigate SAM BUSY/TASK_SET_FULL" patch here:
      
      http://comments.gmane.org/gmane.linux.scsi.target.devel/11301
      
      but instead of only setting SAM_STAT_GOOD, SAM_STAT_TASK_SET_FULL
      and SAM_STAT_BUSY as success, it sets all non check condition status
      as success so they are passed back to the initiator, so passthrough
      type backends can return all SCSI status codes. Since only passthrough
      uses this, I was not sure if we wanted to add checks for non-passthrough
      and specific codes.
      Signed-off-by: NMike Christie <mchristi@redhat.com>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      402242c9
    • M
      target: remove transport_complete · 1a444175
      Mike Christie 提交于
      transport_complete is no longer used, so drop the code.
      Signed-off-by: NMike Christie <mchristi@redhat.com>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      1a444175
    • M
      target: add helper to copy sense to se_cmd buffer · c6d66aba
      Mike Christie 提交于
      This adds a helper to copy sense from backend module buffer to
      the se_cmd's sense buffer.
      Signed-off-by: NMike Christie <mchristi@redhat.com>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      c6d66aba
    • M
      target: do not require a transport_complete for SCF_TRANSPORT_TASK_SENSE · 9fe36984
      Mike Christie 提交于
      tcmu needs to pass raw sense to target_complete_cmd, but a a
      transport_complete callout is akward to implement for it.
      
      This moves the check for SCF_TRANSPORT_TASK_SENSE so any backend
      can pass sense.
      Signed-off-by: NMike Christie <mchristi@redhat.com>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      9fe36984
    • J
      target: Fix COMPARE_AND_WRITE caw_sem leak during se_cmd quiesce · 1d6ef276
      Jiang Yi 提交于
      This patch addresses a COMPARE_AND_WRITE se_device->caw_sem leak,
      that would be triggered during normal se_cmd shutdown or abort
      via __transport_wait_for_tasks().
      
      This would occur because target_complete_cmd() would catch this
      early and do complete_all(&cmd->t_transport_stop_comp), but since
      target_complete_ok_work() or target_complete_failure_work() are
      never called to invoke se_cmd->transport_complete_callback(),
      the COMPARE_AND_WRITE specific callbacks never release caw_sem.
      
      To address this special case, go ahead and release caw_sem
      directly from target_complete_cmd().
      
      (Remove '&& success' from check, to release caw_sem regardless
       of scsi_status - nab)
      Signed-off-by: NJiang Yi <jiangyilism@gmail.com>
      Cc: <stable@vger.kernel.org> # 3.14+
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      1d6ef276
    • B
      target: Introduce a function that shows the command state · c00e6220
      Bart Van Assche 提交于
      Introduce target_show_cmd() and use it where appropriate. If
      transport_wait_for_tasks() takes too long, make it show the
      state of the command it is waiting for.
      
      (Add missing brackets around multi-line conditions - nab)
      Signed-off-by: NBart Van Assche <bart.vanassche@sandisk.com>
      Cc: Hannes Reinecke <hare@suse.com>
      Cc: Christoph Hellwig <hch@lst.de>
      Cc: Andy Grover <agrover@redhat.com>
      Cc: David Disseldorp <ddiss@suse.de>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      c00e6220
    • B
      target: Fix transport_init_se_cmd() · f2b72d6a
      Bart Van Assche 提交于
      Avoid that aborting a command before it has been submitted onto
      a workqueue triggers the following warning:
      
      INFO: trying to register non-static key.
      the code is fine but needs lockdep annotation.
      turning off the locking correctness validator.
      CPU: 3 PID: 46 Comm: kworker/u8:1 Not tainted 4.12.0-rc2-dbg+ #1
      Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014
      Workqueue: tmr-iblock target_tmr_work [target_core_mod]
      Call Trace:
       dump_stack+0x86/0xcf
       register_lock_class+0xe8/0x570
       __lock_acquire+0xa1/0x11d0
       lock_acquire+0x59/0x80
       flush_work+0x42/0x2b0
       __cancel_work_timer+0x10c/0x180
       cancel_work_sync+0xb/0x10
       core_tmr_lun_reset+0x352/0x740 [target_core_mod]
       target_tmr_work+0xd6/0x130 [target_core_mod]
       process_one_work+0x1ca/0x3f0
       worker_thread+0x49/0x3b0
       kthread+0x109/0x140
       ret_from_fork+0x31/0x40
      Signed-off-by: NBart Van Assche <bart.vanassche@sandisk.com>
      Cc: Christoph Hellwig <hch@lst.de>
      Cc: Hannes Reinecke <hare@suse.com>
      Cc: David Disseldorp <ddiss@suse.de>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      f2b72d6a
    • N
      target: Add TARGET_SCF_LOOKUP_LUN_FROM_TAG support for ABORT_TASK · 5465e7d3
      Nicholas Bellinger 提交于
      This patch introduces support in target_submit_tmr() for locating a
      unpacked_lun from an existing se_cmd->tag during ABORT_TASK.
      
      When TARGET_SCF_LOOKUP_LUN_FROM_TAG is set, target_submit_tmr()
      will do the extra lookup via target_lookup_lun_from_tag() and
      subsequently invoke transport_lookup_tmr_lun() so a proper
      percpu se_lun->lun_ref is taken before workqueue dispatch into
      se_device->tmr_wq happens.
      
      Aside from the extra target_lookup_lun_from_tag(), the existing
      code-path remains unchanged.
      Reviewed-by: NHimanshu Madhani <himanshu.madhani@cavium.com>
      Reviewed-by: NQuinn Tran <quinn.tran@cavium.com>
      Cc: Mike Christie <mchristi@redhat.com>
      Cc: Hannes Reinecke <hare@suse.com>
      Cc: Christoph Hellwig <hch@lst.de>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      5465e7d3
    • N
      target: Add support for TMR percpu reference counting · eeb64d23
      Nicholas Bellinger 提交于
      This patch introduces TMR percpu reference counting using
      se_lun->lun_ref in transport_lookup_tmr_lun(), following
      how existing non TMR per se_lun reference counting works
      within transport_lookup_cmd_lun().
      
      It also adds explicit transport_lun_remove_cmd() calls to
      drop the reference in the three tmr related locations that
      invoke transport_cmd_check_stop_to_fabric();
      
         - target_tmr_work() during normal ->queue_tm_rsp()
         - target_complete_tmr_failure() during error ->queue_tm_rsp()
         - transport_generic_handle_tmr() during early failure
      
      Also, note the exception paths in transport_generic_free_cmd()
      and transport_cmd_finish_abort() already check SCF_SE_LUN_CMD,
      and will invoke transport_lun_remove_cmd() when necessary.
      Reviewed-by: NHimanshu Madhani <himanshu.madhani@cavium.com>
      Reviewed-by: NQuinn Tran <quinn.tran@cavium.com>
      Cc: Mike Christie <mchristi@redhat.com>
      Cc: Hannes Reinecke <hare@suse.com>
      Cc: Christoph Hellwig <hch@lst.de>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      eeb64d23
  15. 09 6月, 2017 1 次提交
    • N
      target: Fix kref->refcount underflow in transport_cmd_finish_abort · 73d4e580
      Nicholas Bellinger 提交于
      This patch fixes a se_cmd->cmd_kref underflow during CMD_T_ABORTED
      when a fabric driver drops it's second reference from below the
      target_core_tmr.c based callers of transport_cmd_finish_abort().
      
      Recently with the conversion of kref to refcount_t, this bug was
      manifesting itself as:
      
      [705519.601034] refcount_t: underflow; use-after-free.
      [705519.604034] INFO: NMI handler (kgdb_nmi_handler) took too long to run: 20116.512 msecs
      [705539.719111] ------------[ cut here ]------------
      [705539.719117] WARNING: CPU: 3 PID: 26510 at lib/refcount.c:184 refcount_sub_and_test+0x33/0x51
      
      Since the original kref atomic_t based kref_put() didn't check for
      underflow and only invoked the final callback when zero was reached,
      this bug did not manifest in practice since all se_cmd memory is
      using preallocated tags.
      
      To address this, go ahead and propigate the existing return from
      transport_put_cmd() up via transport_cmd_finish_abort(), and
      change transport_cmd_finish_abort() + core_tmr_handle_tas_abort()
      callers to only do their local target_put_sess_cmd() if necessary.
      Reported-by: NBart Van Assche <bart.vanassche@sandisk.com>
      Tested-by: NBart Van Assche <bart.vanassche@sandisk.com>
      Cc: Mike Christie <mchristi@redhat.com>
      Cc: Hannes Reinecke <hare@suse.de>
      Cc: Christoph Hellwig <hch@lst.de>
      Cc: Himanshu Madhani <himanshu.madhani@qlogic.com>
      Cc: Sagi Grimberg <sagig@mellanox.com>
      Cc: stable@vger.kernel.org # 3.14+
      Tested-by: NGary Guo <ghg@datera.io>
      Tested-by: NChu Yuan Lin <cyl@datera.io>
      Signed-off-by: NNicholas Bellinger <nab@linux-iscsi.org>
      73d4e580