Hello,

It seems that this commit is applied two times. Furthermore, as
indicated in the commit message, dm_internal_suspend_fast and
dm_internal_resume_fast need to be replaced by dm_internal_suspend and
dm_internal_resume instead in kernel 3.18.
Doing this trival replacements solves the compiles error.

Sincerely yours,

François Valenduc

Le 16/04/15 19:10, Sasha Levin a écrit :
> From: Mikulas Patocka <[email protected]>
> 
> [ Upstream commit 09ee96b21456883e108c3b00597bb37ec512151b
> b735fede8d957d9d255e9c5cf3964cfa59799637 ]
> 
> The "dm snapshot: suspend origin when doing exception handover" commit
> fixed a exception store handover bug associated with pending exceptions
> to the "snapshot-origin" target.
> 
> However, a similar problem exists in snapshot merging.  When snapshot
> merging is in progress, we use the target "snapshot-merge" instead of
> "snapshot-origin".  Consequently, during exception store handover, we
> must find the snapshot-merge target and suspend its associated
> mapped_device.
> 
> To avoid lockdep warnings, the target must be suspended and resumed
> without holding _origins_lock.
> 
> Introduce a dm_hold() function that grabs a reference on a
> mapped_device, but unlike dm_get(), it doesn't crash if the device has
> the DMF_FREEING flag set, it returns an error in this case.
> 
> In snapshot_resume() we grab the reference to the origin device using
> dm_hold() while holding _origins_lock (_origins_lock guarantees that the
> device won't disappear).  Then we release _origins_lock, suspend the
> device and grab _origins_lock again.
> 
> NOTE to stable@ people:
> When backporting to kernels 3.18 and older, use dm_internal_suspend and
> dm_internal_resume instead of dm_internal_suspend_fast and
> dm_internal_resume_fast.
> 
> Signed-off-by: Mikulas Patocka <[email protected]>
> Signed-off-by: Mike Snitzer <[email protected]>
> Cc: [email protected]
> 
> dm snapshot: suspend origin when doing exception handover
> 
> [ Upstream commit 09ee96b21456883e108c3b00597bb37ec512151b
> b735fede8d957d9d255e9c5cf3964cfa59799637 ]
> 
> In the function snapshot_resume we perform exception store handover.  If
> there is another active snapshot target, the exception store is moved
> from this target to the target that is being resumed.
> 
> The problem is that if there is some pending exception, it will point to
> an incorrect exception store after that handover, causing a crash due to
> dm-snap-persistent.c:get_exception()'s BUG_ON.
> 
> This bug can be triggered by repeatedly changing snapshot permissions
> with "lvchange -p r" and "lvchange -p rw" while there are writes on the
> associated origin device.
> 
> To fix this bug, we must suspend the origin device when doing the
> exception store handover to make sure that there are no pending
> exceptions:
> - introduce _origin_hash that keeps track of dm_origin structures.
> - introduce functions __lookup_dm_origin, __insert_dm_origin and
>   __remove_dm_origin that manipulate the origin hash.
> - modify snapshot_resume so that it calls dm_internal_suspend_fast() and
>   dm_internal_resume_fast() on the origin device.
> 
> NOTE to stable@ people:
> 
> When backporting to kernels 3.12-3.18, use dm_internal_suspend and
> dm_internal_resume instead of dm_internal_suspend_fast and
> dm_internal_resume_fast.
> 
> When backporting to kernels older than 3.12, you need to pick functions
> dm_internal_suspend and dm_internal_resume from the commit
> fd2ed4d252701d3bbed4cd3e3d267ad469bb832a.
> 
> Signed-off-by: Mikulas Patocka <[email protected]>
> Signed-off-by: Mike Snitzer <[email protected]>
> Cc: [email protected]
> Signed-off-by: Sasha Levin <[email protected]>
> ---
>  drivers/md/dm-snap.c | 93 
> +++++++++++++++++++++++++++++++++++++++++++++++-----
>  drivers/md/dm.c      |  2 ++
>  2 files changed, 86 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
> index 8b204ae2..c2bf822 100644
> --- a/drivers/md/dm-snap.c
> +++ b/drivers/md/dm-snap.c
> @@ -20,6 +20,8 @@
>  #include <linux/log2.h>
>  #include <linux/dm-kcopyd.h>
>  
> +#include "dm.h"
> +
>  #include "dm-exception-store.h"
>  
>  #define DM_MSG_PREFIX "snapshots"
> @@ -291,12 +293,23 @@ struct origin {
>  };
>  
>  /*
> + * This structure is allocated for each origin target
> + */
> +struct dm_origin {
> +     struct dm_dev *dev;
> +     struct dm_target *ti;
> +     unsigned split_boundary;
> +     struct list_head hash_list;
> +};
> +
> +/*
>   * Size of the hash table for origin volumes. If we make this
>   * the size of the minors list then it should be nearly perfect
>   */
>  #define ORIGIN_HASH_SIZE 256
>  #define ORIGIN_MASK      0xFF
>  static struct list_head *_origins;
> +static struct list_head *_dm_origins;
>  static struct rw_semaphore _origins_lock;
>  
>  static DECLARE_WAIT_QUEUE_HEAD(_pending_exceptions_done);
> @@ -310,12 +323,22 @@ static int init_origin_hash(void)
>       _origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
>                          GFP_KERNEL);
>       if (!_origins) {
> -             DMERR("unable to allocate memory");
> +             DMERR("unable to allocate memory for _origins");
>               return -ENOMEM;
>       }
> -
>       for (i = 0; i < ORIGIN_HASH_SIZE; i++)
>               INIT_LIST_HEAD(_origins + i);
> +
> +     _dm_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
> +                           GFP_KERNEL);
> +     if (!_dm_origins) {
> +             DMERR("unable to allocate memory for _dm_origins");
> +             kfree(_origins);
> +             return -ENOMEM;
> +     }
> +     for (i = 0; i < ORIGIN_HASH_SIZE; i++)
> +             INIT_LIST_HEAD(_dm_origins + i);
> +
>       init_rwsem(&_origins_lock);
>  
>       return 0;
> @@ -324,6 +347,7 @@ static int init_origin_hash(void)
>  static void exit_origin_hash(void)
>  {
>       kfree(_origins);
> +     kfree(_dm_origins);
>  }
>  
>  static unsigned origin_hash(struct block_device *bdev)
> @@ -350,6 +374,30 @@ static void __insert_origin(struct origin *o)
>       list_add_tail(&o->hash_list, sl);
>  }
>  
> +static struct dm_origin *__lookup_dm_origin(struct block_device *origin)
> +{
> +     struct list_head *ol;
> +     struct dm_origin *o;
> +
> +     ol = &_dm_origins[origin_hash(origin)];
> +     list_for_each_entry (o, ol, hash_list)
> +             if (bdev_equal(o->dev->bdev, origin))
> +                     return o;
> +
> +     return NULL;
> +}
> +
> +static void __insert_dm_origin(struct dm_origin *o)
> +{
> +     struct list_head *sl = &_dm_origins[origin_hash(o->dev->bdev)];
> +     list_add_tail(&o->hash_list, sl);
> +}
> +
> +static void __remove_dm_origin(struct dm_origin *o)
> +{
> +     list_del(&o->hash_list);
> +}
> +
>  /*
>   * _origins_lock must be held when calling this function.
>   * Returns number of snapshots registered using the supplied cow device, 
> plus:
> @@ -1841,8 +1889,20 @@ static void snapshot_resume(struct dm_target *ti)
>  {
>       struct dm_snapshot *s = ti->private;
>       struct dm_snapshot *snap_src = NULL, *snap_dest = NULL;
> +     struct dm_origin *o;
> +     struct mapped_device *origin_md = NULL;
>  
>       down_read(&_origins_lock);
> +
> +     o = __lookup_dm_origin(s->origin->bdev);
> +     if (o)
> +             origin_md = dm_table_get_md(o->ti->table);
> +     if (origin_md == dm_table_get_md(ti->table))
> +             origin_md = NULL;
> +
> +     if (origin_md)
> +             dm_internal_suspend_fast(origin_md);
> +
>       (void) __find_snapshots_sharing_cow(s, &snap_src, &snap_dest, NULL);
>       if (snap_src && snap_dest) {
>               down_write(&snap_src->lock);
> @@ -1851,6 +1911,10 @@ static void snapshot_resume(struct dm_target *ti)
>               up_write(&snap_dest->lock);
>               up_write(&snap_src->lock);
>       }
> +
> +     if (origin_md)
> +             dm_internal_resume_fast(origin_md);
> +
>       up_read(&_origins_lock);
>  
>       /* Now we have correct chunk size, reregister */
> @@ -2133,11 +2197,6 @@ static int origin_write_extent(struct dm_snapshot 
> *merging_snap,
>   * Origin: maps a linear range of a device, with hooks for snapshotting.
>   */
>  
> -struct dm_origin {
> -     struct dm_dev *dev;
> -     unsigned split_boundary;
> -};
> -
>  /*
>   * Construct an origin mapping: <dev_path>
>   * The context for an origin is merely a 'struct dm_dev *'
> @@ -2166,6 +2225,7 @@ static int origin_ctr(struct dm_target *ti, unsigned 
> int argc, char **argv)
>               goto bad_open;
>       }
>  
> +     o->ti = ti;
>       ti->private = o;
>       ti->num_flush_bios = 1;
>  
> @@ -2180,6 +2240,7 @@ bad_alloc:
>  static void origin_dtr(struct dm_target *ti)
>  {
>       struct dm_origin *o = ti->private;
> +
>       dm_put_device(ti, o->dev);
>       kfree(o);
>  }
> @@ -2216,6 +2277,19 @@ static void origin_resume(struct dm_target *ti)
>       struct dm_origin *o = ti->private;
>  
>       o->split_boundary = get_origin_minimum_chunksize(o->dev->bdev);
> +
> +     down_write(&_origins_lock);
> +     __insert_dm_origin(o);
> +     up_write(&_origins_lock);
> +}
> +
> +static void origin_postsuspend(struct dm_target *ti)
> +{
> +     struct dm_origin *o = ti->private;
> +
> +     down_write(&_origins_lock);
> +     __remove_dm_origin(o);
> +     up_write(&_origins_lock);
>  }
>  
>  static void origin_status(struct dm_target *ti, status_type_t type,
> @@ -2258,12 +2332,13 @@ static int origin_iterate_devices(struct dm_target 
> *ti,
>  
>  static struct target_type origin_target = {
>       .name    = "snapshot-origin",
> -     .version = {1, 8, 1},
> +     .version = {1, 9, 0},
>       .module  = THIS_MODULE,
>       .ctr     = origin_ctr,
>       .dtr     = origin_dtr,
>       .map     = origin_map,
>       .resume  = origin_resume,
> +     .postsuspend = origin_postsuspend,
>       .status  = origin_status,
>       .merge   = origin_merge,
>       .iterate_devices = origin_iterate_devices,
> @@ -2271,7 +2346,7 @@ static struct target_type origin_target = {
>  
>  static struct target_type snapshot_target = {
>       .name    = "snapshot",
> -     .version = {1, 12, 0},
> +     .version = {1, 13, 0},
>       .module  = THIS_MODULE,
>       .ctr     = snapshot_ctr,
>       .dtr     = snapshot_dtr,
> diff --git a/drivers/md/dm.c b/drivers/md/dm.c
> index f743f47..83aa36f 100644
> --- a/drivers/md/dm.c
> +++ b/drivers/md/dm.c
> @@ -2887,6 +2887,7 @@ void dm_internal_suspend(struct mapped_device *md)
>       flush_workqueue(md->wq);
>       dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
>  }
> +EXPORT_SYMBOL_GPL(dm_internal_suspend_fast);
>  
>  void dm_internal_resume(struct mapped_device *md)
>  {
> @@ -2898,6 +2899,7 @@ void dm_internal_resume(struct mapped_device *md)
>  done:
>       mutex_unlock(&md->suspend_lock);
>  }
> +EXPORT_SYMBOL_GPL(dm_internal_resume_fast);
>  
>  /*-----------------------------------------------------------------
>   * Event notification.
> 

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to