Commit dc4fa29f authored by Mike Snitzer's avatar Mike Snitzer
Browse files

dm io tracker: factor out IO tracker



Allow other code to use dm_io_tracker.

Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent b6e58b54
Loading
Loading
Loading
Loading
+6 −76
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include "dm-bio-prison-v2.h"
#include "dm-bio-record.h"
#include "dm-cache-metadata.h"
#include "dm-io-tracker.h"

#include <linux/dm-io.h>
#include <linux/dm-kcopyd.h>
@@ -39,77 +40,6 @@ DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(cache_copy_throttle,

/*----------------------------------------------------------------*/

struct io_tracker {
	spinlock_t lock;

	/*
	 * Sectors of in-flight IO.
	 */
	sector_t in_flight;

	/*
	 * The time, in jiffies, when this device became idle (if it is
	 * indeed idle).
	 */
	unsigned long idle_time;
	unsigned long last_update_time;
};

static void iot_init(struct io_tracker *iot)
{
	spin_lock_init(&iot->lock);
	iot->in_flight = 0ul;
	iot->idle_time = 0ul;
	iot->last_update_time = jiffies;
}

static bool __iot_idle_for(struct io_tracker *iot, unsigned long jifs)
{
	if (iot->in_flight)
		return false;

	return time_after(jiffies, iot->idle_time + jifs);
}

static bool iot_idle_for(struct io_tracker *iot, unsigned long jifs)
{
	bool r;

	spin_lock_irq(&iot->lock);
	r = __iot_idle_for(iot, jifs);
	spin_unlock_irq(&iot->lock);

	return r;
}

static void iot_io_begin(struct io_tracker *iot, sector_t len)
{
	spin_lock_irq(&iot->lock);
	iot->in_flight += len;
	spin_unlock_irq(&iot->lock);
}

static void __iot_io_end(struct io_tracker *iot, sector_t len)
{
	if (!len)
		return;

	iot->in_flight -= len;
	if (!iot->in_flight)
		iot->idle_time = jiffies;
}

static void iot_io_end(struct io_tracker *iot, sector_t len)
{
	unsigned long flags;

	spin_lock_irqsave(&iot->lock, flags);
	__iot_io_end(iot, len);
	spin_unlock_irqrestore(&iot->lock, flags);
}

/*----------------------------------------------------------------*/

/*
 * Represents a chunk of future work.  'input' allows continuations to pass
 * values between themselves, typically error values.
@@ -470,7 +400,7 @@ struct cache {
	struct batcher committer;
	struct work_struct commit_ws;

	struct io_tracker tracker;
	struct dm_io_tracker tracker;

	mempool_t migration_pool;

@@ -866,7 +796,7 @@ static void accounted_begin(struct cache *cache, struct bio *bio)
	if (accountable_bio(cache, bio)) {
		pb = get_per_bio_data(bio);
		pb->len = bio_sectors(bio);
		iot_io_begin(&cache->tracker, pb->len);
		dm_iot_io_begin(&cache->tracker, pb->len);
	}
}

@@ -874,7 +804,7 @@ static void accounted_complete(struct cache *cache, struct bio *bio)
{
	struct per_bio_data *pb = get_per_bio_data(bio);

	iot_io_end(&cache->tracker, pb->len);
	dm_iot_io_end(&cache->tracker, pb->len);
}

static void accounted_request(struct cache *cache, struct bio *bio)
@@ -1642,7 +1572,7 @@ enum busy {

static enum busy spare_migration_bandwidth(struct cache *cache)
{
	bool idle = iot_idle_for(&cache->tracker, HZ);
	bool idle = dm_iot_idle_for(&cache->tracker, HZ);
	sector_t current_volume = (atomic_read(&cache->nr_io_migrations) + 1) *
		cache->sectors_per_block;

@@ -2603,7 +2533,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)

	batcher_init(&cache->committer, commit_op, cache,
		     issue_op, cache, cache->wq);
	iot_init(&cache->tracker);
	dm_iot_init(&cache->tracker);

	init_rwsem(&cache->background_work_lock);
	prevent_background_work(cache);
+69 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 Red Hat, Inc. All rights reserved.
 *
 * This file is released under the GPL.
 */

#ifndef DM_IO_TRACKER_H
#define DM_IO_TRACKER_H

#include <linux/jiffies.h>

struct dm_io_tracker {
	spinlock_t lock;

	/*
	 * Sectors of in-flight IO.
	 */
	sector_t in_flight;

	/*
	 * The time, in jiffies, when this device became idle
	 * (if it is indeed idle).
	 */
	unsigned long idle_time;
	unsigned long last_update_time;
};

static inline void dm_iot_init(struct dm_io_tracker *iot)
{
	spin_lock_init(&iot->lock);
	iot->in_flight = 0ul;
	iot->idle_time = 0ul;
	iot->last_update_time = jiffies;
}

static inline bool dm_iot_idle_for(struct dm_io_tracker *iot, unsigned long j)
{
	bool r = false;

	spin_lock_irq(&iot->lock);
	if (!iot->in_flight)
		r = time_after(jiffies, iot->idle_time + j);
	spin_unlock_irq(&iot->lock);

	return r;
}

static inline void dm_iot_io_begin(struct dm_io_tracker *iot, sector_t len)
{
	spin_lock_irq(&iot->lock);
	iot->in_flight += len;
	spin_unlock_irq(&iot->lock);
}

static inline void dm_iot_io_end(struct dm_io_tracker *iot, sector_t len)
{
	unsigned long flags;

	if (!len)
		return;

	spin_lock_irqsave(&iot->lock, flags);
	iot->in_flight -= len;
	if (!iot->in_flight)
		iot->idle_time = jiffies;
	spin_unlock_irqrestore(&iot->lock, flags);
}

#endif