Re: [PATCH 1/5] md/raid1: fix potential data inconsistency issue with write behind device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 6/18/19 10:39 PM, Song Liu wrote:
On Tue, Jun 18, 2019 at 1:35 AM Guoqing Jiang <gqjiang@xxxxxxxx> wrote:



On 6/18/19 11:41 AM, Guoqing Jiang wrote:

+static int check_and_add_wb(struct md_rdev *rdev, sector_t lo,
sector_t hi)
+{
+       struct wb_info *wi;
+       unsigned long flags;
+       int ret = 0;
+       struct mddev *mddev = rdev->mddev;
+
+       wi = mempool_alloc(mddev->wb_info_pool, GFP_NOIO);
+
+       spin_lock_irqsave(&rdev->wb_list_lock, flags);
+       list_for_each_entry(wi, &rdev->wb_list, list) {
This doesn't look right. We should allocate wi from mempool after
the list_for_each_entry(), right?

Good catch, I will use an temp variable in the iteration since
mempool_alloc
could sleep.

After a second thought, I think it should be fine since wi is either
reused to record the sector range or freed after the iteration.

Could you elaborate your concern? Thanks.

First, we allocated wb_info and stored the ptr to wi. Then we use
same wi in list_for_each_entry(), where the original value of wi is
overwritten:

#define list_for_each_entry(pos, head, member)                          \
         for (pos = list_first_entry(head, typeof(*pos), member);        \
              &pos->member != (head);                                    \
              pos = list_next_entry(pos, member))

So we are leaking the original wi from mempool_alloc, right?

Yes, you are right, thanks for the details.

And we probably over writing one element on wb_list.

Will change it to:

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 93dff41c4ff9..f1ea17b14b6e 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -85,7 +85,7 @@ static void lower_barrier(struct r1conf *conf, sector_t sector_nr);

static int check_and_add_wb(struct md_rdev *rdev, sector_t lo, sector_t hi)
 {
-       struct wb_info *wi;
+       struct wb_info *wi, *temp_wi;
        unsigned long flags;
        int ret = 0;
        struct mddev *mddev = rdev->mddev;
@@ -93,9 +93,9 @@ static int check_and_add_wb(struct md_rdev *rdev, sector_t lo, sector_t hi)
        wi = mempool_alloc(mddev->wb_info_pool, GFP_NOIO);

        spin_lock_irqsave(&rdev->wb_list_lock, flags);
-       list_for_each_entry(wi, &rdev->wb_list, list) {
+       list_for_each_entry(temp_wi, &rdev->wb_list, list) {
                /* collision happened */
-               if (hi > wi->lo && lo < wi->hi) {
+               if (hi > temp_wi->lo && lo < temp_wi->hi) {
                        ret = -EBUSY;
                        break;
                }


BRs,
Guoqing



[Index of Archives]     [Linux RAID Wiki]     [ATA RAID]     [Linux SCSI Target Infrastructure]     [Linux Block]     [Linux IDE]     [Linux SCSI]     [Linux Hams]     [Device Mapper]     [Device Mapper Cryptographics]     [Kernel]     [Linux Admin]     [Linux Net]     [GFS]     [RPM]     [git]     [Yosemite Forum]


  Powered by Linux