/*
 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/mm_types.h>
#include <linux/swapfile.h>
#include <linux/swap.h>

#define SWAP_RATIO_GROUP_START (SWAP_FLAG_PRIO_MASK - 9) /* 32758 */
#define SWAP_RATIO_GROUP_END (SWAP_FLAG_PRIO_MASK) /* 32767 */
#define SWAP_FAST_WRITES (SWAPFILE_CLUSTER * (SWAP_CLUSTER_MAX / 8))
#define SWAP_SLOW_WRITES SWAPFILE_CLUSTER

/*
 * The fast/slow swap write ratio.
 * 100 indicates that all writes should
 * go to fast swap device.
 */
int sysctl_swap_ratio = 100;

/* Enable the swap ratio feature */
int sysctl_swap_ratio_enable;

static bool is_same_group(struct swap_info_struct *a,
		struct swap_info_struct *b)
{
	if (!sysctl_swap_ratio_enable)
		return false;

	if (!is_swap_ratio_group(a->prio))
		return false;

	if (a->prio == b->prio)
		return true;

	return false;
}

/* Caller must hold swap_avail_lock */
static int calculate_write_pending(struct swap_info_struct *si,
			struct swap_info_struct *n)
{
	int ratio = sysctl_swap_ratio;

	if ((ratio < 0) || (ratio > 100))
		return -EINVAL;

	if (WARN_ON(!(si->flags & SWP_FAST)))
		return -ENODEV;

	if ((n->flags & SWP_FAST) || !is_same_group(si, n))
		return -ENODEV;

	si->max_writes = ratio ? SWAP_FAST_WRITES : 0;
	n->max_writes  = ratio ? (SWAP_FAST_WRITES * 100) /
			ratio - SWAP_FAST_WRITES : SWAP_SLOW_WRITES;

	si->write_pending = si->max_writes;
	n->write_pending = n->max_writes;

	return 0;
}

static int swap_ratio_slow(struct swap_info_struct **si)
{
	struct swap_info_struct *n = NULL;
	int ret = 0;

	spin_lock(&(*si)->lock);
	spin_lock(&swap_avail_lock);
	if (&(*si)->avail_list == plist_last(&swap_avail_head)) {
		/* just to make skip work */
		n = *si;
		ret = -ENODEV;
		goto skip;
	}
	n = plist_next_entry(&(*si)->avail_list,
			struct swap_info_struct,
			avail_list);
	if (n == *si) {
		/* No other swap device */
		ret = -ENODEV;
		goto skip;
	}

	spin_unlock(&swap_avail_lock);
	spin_lock(&n->lock);
	spin_lock(&swap_avail_lock);

	if ((*si)->flags & SWP_FAST) {
		if ((*si)->write_pending) {
			(*si)->write_pending--;
			goto exit;
		} else {
			if ((n->flags & SWP_FAST) || !is_same_group(*si, n)) {
				/* Should never happen */
				ret = -ENODEV;
			} else if (n->write_pending) {
				/*
				 * Requeue fast device, since there are pending
				 * writes for slow device.
				 */
				plist_requeue(&(*si)->avail_list,
					&swap_avail_head);
				n->write_pending--;
				spin_unlock(&(*si)->lock);
				*si = n;
				goto skip;
			} else {
				if (0 > calculate_write_pending(*si, n)) {
					ret = -ENODEV;
					goto exit;
				}
				/* Restart from fast device */
				(*si)->write_pending--;
			}
		}
	} else {
		if (!(n->flags & SWP_FAST) || !is_same_group(*si, n)) {
			/* Should never happen */
			ret = -ENODEV;
		} else if (n->write_pending) {
			/*
			 * Pending writes for fast device.
			 * We reach here when slow device is swapped on first,
			 * before fast device.
			 */
			/* requeue slow device to the end */
			plist_requeue(&(*si)->avail_list, &swap_avail_head);
			n->write_pending--;
			spin_unlock(&(*si)->lock);
			*si = n;
			goto skip;
		} else {
			if ((*si)->write_pending) {
				(*si)->write_pending--;
			} else {
				if (0 > calculate_write_pending(n, *si)) {
					ret = -ENODEV;
					goto exit;
				}
				n->write_pending--;
				plist_requeue(&(*si)->avail_list,
					&swap_avail_head);
				spin_unlock(&(*si)->lock);
				*si = n;
				goto skip;
			}
		}
	}
exit:
	spin_unlock(&(*si)->lock);
skip:
	spin_unlock(&swap_avail_lock);
	/* n and si would have got interchanged */
	spin_unlock(&n->lock);
	return ret;
}

bool is_swap_ratio_group(int prio)
{
	return ((prio >= SWAP_RATIO_GROUP_START) &&
		(prio <= SWAP_RATIO_GROUP_END)) ? true : false;
}

void setup_swap_ratio(struct swap_info_struct *p, int prio)
{
	/* Used only if sysctl_swap_ratio_enable is set */
	if (is_swap_ratio_group(prio)) {
		if (p->flags & SWP_FAST)
			p->write_pending = SWAP_FAST_WRITES;
		else
			p->write_pending = SWAP_SLOW_WRITES;
		p->max_writes =  p->write_pending;
	}
}

int swap_ratio(struct swap_info_struct **si)
{
	if (!sysctl_swap_ratio_enable)
		return -ENODEV;

	if (is_swap_ratio_group((*si)->prio))
		return swap_ratio_slow(si);
	else
		return -ENODEV;
}
