18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2014-2016 Christoph Hellwig.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "blocklayout.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define NFSDBG_FACILITY		NFSDBG_PNFS_LD
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic inline struct pnfs_block_extent *
138c2ecf20Sopenharmony_ciext_node(struct rb_node *node)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	return rb_entry(node, struct pnfs_block_extent, be_node);
168c2ecf20Sopenharmony_ci}
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic struct pnfs_block_extent *
198c2ecf20Sopenharmony_ciext_tree_first(struct rb_root *root)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct rb_node *node = rb_first(root);
228c2ecf20Sopenharmony_ci	return node ? ext_node(node) : NULL;
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic struct pnfs_block_extent *
268c2ecf20Sopenharmony_ciext_tree_prev(struct pnfs_block_extent *be)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	struct rb_node *node = rb_prev(&be->be_node);
298c2ecf20Sopenharmony_ci	return node ? ext_node(node) : NULL;
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic struct pnfs_block_extent *
338c2ecf20Sopenharmony_ciext_tree_next(struct pnfs_block_extent *be)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct rb_node *node = rb_next(&be->be_node);
368c2ecf20Sopenharmony_ci	return node ? ext_node(node) : NULL;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic inline sector_t
408c2ecf20Sopenharmony_ciext_f_end(struct pnfs_block_extent *be)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	return be->be_f_offset + be->be_length;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic struct pnfs_block_extent *
468c2ecf20Sopenharmony_ci__ext_tree_search(struct rb_root *root, sector_t start)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct rb_node *node = root->rb_node;
498c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be = NULL;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	while (node) {
528c2ecf20Sopenharmony_ci		be = ext_node(node);
538c2ecf20Sopenharmony_ci		if (start < be->be_f_offset)
548c2ecf20Sopenharmony_ci			node = node->rb_left;
558c2ecf20Sopenharmony_ci		else if (start >= ext_f_end(be))
568c2ecf20Sopenharmony_ci			node = node->rb_right;
578c2ecf20Sopenharmony_ci		else
588c2ecf20Sopenharmony_ci			return be;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (be) {
628c2ecf20Sopenharmony_ci		if (start < be->be_f_offset)
638c2ecf20Sopenharmony_ci			return be;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		if (start >= ext_f_end(be))
668c2ecf20Sopenharmony_ci			return ext_tree_next(be);
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	return NULL;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic bool
738c2ecf20Sopenharmony_ciext_can_merge(struct pnfs_block_extent *be1, struct pnfs_block_extent *be2)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	if (be1->be_state != be2->be_state)
768c2ecf20Sopenharmony_ci		return false;
778c2ecf20Sopenharmony_ci	if (be1->be_device != be2->be_device)
788c2ecf20Sopenharmony_ci		return false;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (be1->be_f_offset + be1->be_length != be2->be_f_offset)
818c2ecf20Sopenharmony_ci		return false;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (be1->be_state != PNFS_BLOCK_NONE_DATA &&
848c2ecf20Sopenharmony_ci	    (be1->be_v_offset + be1->be_length != be2->be_v_offset))
858c2ecf20Sopenharmony_ci		return false;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (be1->be_state == PNFS_BLOCK_INVALID_DATA &&
888c2ecf20Sopenharmony_ci	    be1->be_tag != be2->be_tag)
898c2ecf20Sopenharmony_ci		return false;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return true;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic struct pnfs_block_extent *
958c2ecf20Sopenharmony_ciext_try_to_merge_left(struct rb_root *root, struct pnfs_block_extent *be)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct pnfs_block_extent *left = ext_tree_prev(be);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (left && ext_can_merge(left, be)) {
1008c2ecf20Sopenharmony_ci		left->be_length += be->be_length;
1018c2ecf20Sopenharmony_ci		rb_erase(&be->be_node, root);
1028c2ecf20Sopenharmony_ci		nfs4_put_deviceid_node(be->be_device);
1038c2ecf20Sopenharmony_ci		kfree(be);
1048c2ecf20Sopenharmony_ci		return left;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return be;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic struct pnfs_block_extent *
1118c2ecf20Sopenharmony_ciext_try_to_merge_right(struct rb_root *root, struct pnfs_block_extent *be)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct pnfs_block_extent *right = ext_tree_next(be);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (right && ext_can_merge(be, right)) {
1168c2ecf20Sopenharmony_ci		be->be_length += right->be_length;
1178c2ecf20Sopenharmony_ci		rb_erase(&right->be_node, root);
1188c2ecf20Sopenharmony_ci		nfs4_put_deviceid_node(right->be_device);
1198c2ecf20Sopenharmony_ci		kfree(right);
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	return be;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic void __ext_put_deviceids(struct list_head *head)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be, *tmp;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	list_for_each_entry_safe(be, tmp, head, be_list) {
1308c2ecf20Sopenharmony_ci		nfs4_put_deviceid_node(be->be_device);
1318c2ecf20Sopenharmony_ci		kfree(be);
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic void
1368c2ecf20Sopenharmony_ci__ext_tree_insert(struct rb_root *root,
1378c2ecf20Sopenharmony_ci		struct pnfs_block_extent *new, bool merge_ok)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_node, *parent = NULL;
1408c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	while (*p) {
1438c2ecf20Sopenharmony_ci		parent = *p;
1448c2ecf20Sopenharmony_ci		be = ext_node(parent);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci		if (new->be_f_offset < be->be_f_offset) {
1478c2ecf20Sopenharmony_ci			if (merge_ok && ext_can_merge(new, be)) {
1488c2ecf20Sopenharmony_ci				be->be_f_offset = new->be_f_offset;
1498c2ecf20Sopenharmony_ci				if (be->be_state != PNFS_BLOCK_NONE_DATA)
1508c2ecf20Sopenharmony_ci					be->be_v_offset = new->be_v_offset;
1518c2ecf20Sopenharmony_ci				be->be_length += new->be_length;
1528c2ecf20Sopenharmony_ci				be = ext_try_to_merge_left(root, be);
1538c2ecf20Sopenharmony_ci				goto free_new;
1548c2ecf20Sopenharmony_ci			}
1558c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
1568c2ecf20Sopenharmony_ci		} else if (new->be_f_offset >= ext_f_end(be)) {
1578c2ecf20Sopenharmony_ci			if (merge_ok && ext_can_merge(be, new)) {
1588c2ecf20Sopenharmony_ci				be->be_length += new->be_length;
1598c2ecf20Sopenharmony_ci				be = ext_try_to_merge_right(root, be);
1608c2ecf20Sopenharmony_ci				goto free_new;
1618c2ecf20Sopenharmony_ci			}
1628c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
1638c2ecf20Sopenharmony_ci		} else {
1648c2ecf20Sopenharmony_ci			BUG();
1658c2ecf20Sopenharmony_ci		}
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	rb_link_node(&new->be_node, parent, p);
1698c2ecf20Sopenharmony_ci	rb_insert_color(&new->be_node, root);
1708c2ecf20Sopenharmony_ci	return;
1718c2ecf20Sopenharmony_cifree_new:
1728c2ecf20Sopenharmony_ci	nfs4_put_deviceid_node(new->be_device);
1738c2ecf20Sopenharmony_ci	kfree(new);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int
1778c2ecf20Sopenharmony_ci__ext_tree_remove(struct rb_root *root,
1788c2ecf20Sopenharmony_ci		sector_t start, sector_t end, struct list_head *tmp)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be;
1818c2ecf20Sopenharmony_ci	sector_t len1 = 0, len2 = 0;
1828c2ecf20Sopenharmony_ci	sector_t orig_v_offset;
1838c2ecf20Sopenharmony_ci	sector_t orig_len;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	be = __ext_tree_search(root, start);
1868c2ecf20Sopenharmony_ci	if (!be)
1878c2ecf20Sopenharmony_ci		return 0;
1888c2ecf20Sopenharmony_ci	if (be->be_f_offset >= end)
1898c2ecf20Sopenharmony_ci		return 0;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	orig_v_offset = be->be_v_offset;
1928c2ecf20Sopenharmony_ci	orig_len = be->be_length;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (start > be->be_f_offset)
1958c2ecf20Sopenharmony_ci		len1 = start - be->be_f_offset;
1968c2ecf20Sopenharmony_ci	if (ext_f_end(be) > end)
1978c2ecf20Sopenharmony_ci		len2 = ext_f_end(be) - end;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (len2 > 0) {
2008c2ecf20Sopenharmony_ci		if (len1 > 0) {
2018c2ecf20Sopenharmony_ci			struct pnfs_block_extent *new;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci			new = kzalloc(sizeof(*new), GFP_ATOMIC);
2048c2ecf20Sopenharmony_ci			if (!new)
2058c2ecf20Sopenharmony_ci				return -ENOMEM;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci			be->be_length = len1;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci			new->be_f_offset = end;
2108c2ecf20Sopenharmony_ci			if (be->be_state != PNFS_BLOCK_NONE_DATA) {
2118c2ecf20Sopenharmony_ci				new->be_v_offset =
2128c2ecf20Sopenharmony_ci					orig_v_offset + orig_len - len2;
2138c2ecf20Sopenharmony_ci			}
2148c2ecf20Sopenharmony_ci			new->be_length = len2;
2158c2ecf20Sopenharmony_ci			new->be_state = be->be_state;
2168c2ecf20Sopenharmony_ci			new->be_tag = be->be_tag;
2178c2ecf20Sopenharmony_ci			new->be_device = nfs4_get_deviceid(be->be_device);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci			__ext_tree_insert(root, new, true);
2208c2ecf20Sopenharmony_ci		} else {
2218c2ecf20Sopenharmony_ci			be->be_f_offset = end;
2228c2ecf20Sopenharmony_ci			if (be->be_state != PNFS_BLOCK_NONE_DATA) {
2238c2ecf20Sopenharmony_ci				be->be_v_offset =
2248c2ecf20Sopenharmony_ci					orig_v_offset + orig_len - len2;
2258c2ecf20Sopenharmony_ci			}
2268c2ecf20Sopenharmony_ci			be->be_length = len2;
2278c2ecf20Sopenharmony_ci		}
2288c2ecf20Sopenharmony_ci	} else {
2298c2ecf20Sopenharmony_ci		if (len1 > 0) {
2308c2ecf20Sopenharmony_ci			be->be_length = len1;
2318c2ecf20Sopenharmony_ci			be = ext_tree_next(be);
2328c2ecf20Sopenharmony_ci		}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		while (be && ext_f_end(be) <= end) {
2358c2ecf20Sopenharmony_ci			struct pnfs_block_extent *next = ext_tree_next(be);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci			rb_erase(&be->be_node, root);
2388c2ecf20Sopenharmony_ci			list_add_tail(&be->be_list, tmp);
2398c2ecf20Sopenharmony_ci			be = next;
2408c2ecf20Sopenharmony_ci		}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		if (be && be->be_f_offset < end) {
2438c2ecf20Sopenharmony_ci			len1 = ext_f_end(be) - end;
2448c2ecf20Sopenharmony_ci			be->be_f_offset = end;
2458c2ecf20Sopenharmony_ci			if (be->be_state != PNFS_BLOCK_NONE_DATA)
2468c2ecf20Sopenharmony_ci				be->be_v_offset += be->be_length - len1;
2478c2ecf20Sopenharmony_ci			be->be_length = len1;
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ciint
2558c2ecf20Sopenharmony_ciext_tree_insert(struct pnfs_block_layout *bl, struct pnfs_block_extent *new)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be;
2588c2ecf20Sopenharmony_ci	struct rb_root *root;
2598c2ecf20Sopenharmony_ci	int err = 0;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	switch (new->be_state) {
2628c2ecf20Sopenharmony_ci	case PNFS_BLOCK_READWRITE_DATA:
2638c2ecf20Sopenharmony_ci	case PNFS_BLOCK_INVALID_DATA:
2648c2ecf20Sopenharmony_ci		root = &bl->bl_ext_rw;
2658c2ecf20Sopenharmony_ci		break;
2668c2ecf20Sopenharmony_ci	case PNFS_BLOCK_READ_DATA:
2678c2ecf20Sopenharmony_ci	case PNFS_BLOCK_NONE_DATA:
2688c2ecf20Sopenharmony_ci		root = &bl->bl_ext_ro;
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci	default:
2718c2ecf20Sopenharmony_ci		dprintk("invalid extent type\n");
2728c2ecf20Sopenharmony_ci		return -EINVAL;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	spin_lock(&bl->bl_ext_lock);
2768c2ecf20Sopenharmony_ciretry:
2778c2ecf20Sopenharmony_ci	be = __ext_tree_search(root, new->be_f_offset);
2788c2ecf20Sopenharmony_ci	if (!be || be->be_f_offset >= ext_f_end(new)) {
2798c2ecf20Sopenharmony_ci		__ext_tree_insert(root, new, true);
2808c2ecf20Sopenharmony_ci	} else if (new->be_f_offset >= be->be_f_offset) {
2818c2ecf20Sopenharmony_ci		if (ext_f_end(new) <= ext_f_end(be)) {
2828c2ecf20Sopenharmony_ci			nfs4_put_deviceid_node(new->be_device);
2838c2ecf20Sopenharmony_ci			kfree(new);
2848c2ecf20Sopenharmony_ci		} else {
2858c2ecf20Sopenharmony_ci			sector_t new_len = ext_f_end(new) - ext_f_end(be);
2868c2ecf20Sopenharmony_ci			sector_t diff = new->be_length - new_len;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci			new->be_f_offset += diff;
2898c2ecf20Sopenharmony_ci			new->be_v_offset += diff;
2908c2ecf20Sopenharmony_ci			new->be_length = new_len;
2918c2ecf20Sopenharmony_ci			goto retry;
2928c2ecf20Sopenharmony_ci		}
2938c2ecf20Sopenharmony_ci	} else if (ext_f_end(new) <= ext_f_end(be)) {
2948c2ecf20Sopenharmony_ci		new->be_length = be->be_f_offset - new->be_f_offset;
2958c2ecf20Sopenharmony_ci		__ext_tree_insert(root, new, true);
2968c2ecf20Sopenharmony_ci	} else {
2978c2ecf20Sopenharmony_ci		struct pnfs_block_extent *split;
2988c2ecf20Sopenharmony_ci		sector_t new_len = ext_f_end(new) - ext_f_end(be);
2998c2ecf20Sopenharmony_ci		sector_t diff = new->be_length - new_len;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		split = kmemdup(new, sizeof(*new), GFP_ATOMIC);
3028c2ecf20Sopenharmony_ci		if (!split) {
3038c2ecf20Sopenharmony_ci			err = -EINVAL;
3048c2ecf20Sopenharmony_ci			goto out;
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		split->be_length = be->be_f_offset - split->be_f_offset;
3088c2ecf20Sopenharmony_ci		split->be_device = nfs4_get_deviceid(new->be_device);
3098c2ecf20Sopenharmony_ci		__ext_tree_insert(root, split, true);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci		new->be_f_offset += diff;
3128c2ecf20Sopenharmony_ci		new->be_v_offset += diff;
3138c2ecf20Sopenharmony_ci		new->be_length = new_len;
3148c2ecf20Sopenharmony_ci		goto retry;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ciout:
3178c2ecf20Sopenharmony_ci	spin_unlock(&bl->bl_ext_lock);
3188c2ecf20Sopenharmony_ci	return err;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic bool
3228c2ecf20Sopenharmony_ci__ext_tree_lookup(struct rb_root *root, sector_t isect,
3238c2ecf20Sopenharmony_ci		struct pnfs_block_extent *ret)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct rb_node *node;
3268c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	node = root->rb_node;
3298c2ecf20Sopenharmony_ci	while (node) {
3308c2ecf20Sopenharmony_ci		be = ext_node(node);
3318c2ecf20Sopenharmony_ci		if (isect < be->be_f_offset)
3328c2ecf20Sopenharmony_ci			node = node->rb_left;
3338c2ecf20Sopenharmony_ci		else if (isect >= ext_f_end(be))
3348c2ecf20Sopenharmony_ci			node = node->rb_right;
3358c2ecf20Sopenharmony_ci		else {
3368c2ecf20Sopenharmony_ci			*ret = *be;
3378c2ecf20Sopenharmony_ci			return true;
3388c2ecf20Sopenharmony_ci		}
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return false;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cibool
3458c2ecf20Sopenharmony_ciext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect,
3468c2ecf20Sopenharmony_ci	    struct pnfs_block_extent *ret, bool rw)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	bool found = false;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	spin_lock(&bl->bl_ext_lock);
3518c2ecf20Sopenharmony_ci	if (!rw)
3528c2ecf20Sopenharmony_ci		found = __ext_tree_lookup(&bl->bl_ext_ro, isect, ret);
3538c2ecf20Sopenharmony_ci	if (!found)
3548c2ecf20Sopenharmony_ci		found = __ext_tree_lookup(&bl->bl_ext_rw, isect, ret);
3558c2ecf20Sopenharmony_ci	spin_unlock(&bl->bl_ext_lock);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	return found;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ciint ext_tree_remove(struct pnfs_block_layout *bl, bool rw,
3618c2ecf20Sopenharmony_ci		sector_t start, sector_t end)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	int err, err2;
3648c2ecf20Sopenharmony_ci	LIST_HEAD(tmp);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	spin_lock(&bl->bl_ext_lock);
3678c2ecf20Sopenharmony_ci	err = __ext_tree_remove(&bl->bl_ext_ro, start, end, &tmp);
3688c2ecf20Sopenharmony_ci	if (rw) {
3698c2ecf20Sopenharmony_ci		err2 = __ext_tree_remove(&bl->bl_ext_rw, start, end, &tmp);
3708c2ecf20Sopenharmony_ci		if (!err)
3718c2ecf20Sopenharmony_ci			err = err2;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci	spin_unlock(&bl->bl_ext_lock);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	__ext_put_deviceids(&tmp);
3768c2ecf20Sopenharmony_ci	return err;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int
3808c2ecf20Sopenharmony_ciext_tree_split(struct rb_root *root, struct pnfs_block_extent *be,
3818c2ecf20Sopenharmony_ci		sector_t split)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct pnfs_block_extent *new;
3848c2ecf20Sopenharmony_ci	sector_t orig_len = be->be_length;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	new = kzalloc(sizeof(*new), GFP_ATOMIC);
3878c2ecf20Sopenharmony_ci	if (!new)
3888c2ecf20Sopenharmony_ci		return -ENOMEM;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	be->be_length = split - be->be_f_offset;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	new->be_f_offset = split;
3938c2ecf20Sopenharmony_ci	if (be->be_state != PNFS_BLOCK_NONE_DATA)
3948c2ecf20Sopenharmony_ci		new->be_v_offset = be->be_v_offset + be->be_length;
3958c2ecf20Sopenharmony_ci	new->be_length = orig_len - be->be_length;
3968c2ecf20Sopenharmony_ci	new->be_state = be->be_state;
3978c2ecf20Sopenharmony_ci	new->be_tag = be->be_tag;
3988c2ecf20Sopenharmony_ci	new->be_device = nfs4_get_deviceid(be->be_device);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	__ext_tree_insert(root, new, false);
4018c2ecf20Sopenharmony_ci	return 0;
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ciint
4058c2ecf20Sopenharmony_ciext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start,
4068c2ecf20Sopenharmony_ci		sector_t len, u64 lwb)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	struct rb_root *root = &bl->bl_ext_rw;
4098c2ecf20Sopenharmony_ci	sector_t end = start + len;
4108c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be;
4118c2ecf20Sopenharmony_ci	int err = 0;
4128c2ecf20Sopenharmony_ci	LIST_HEAD(tmp);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	spin_lock(&bl->bl_ext_lock);
4158c2ecf20Sopenharmony_ci	/*
4168c2ecf20Sopenharmony_ci	 * First remove all COW extents or holes from written to range.
4178c2ecf20Sopenharmony_ci	 */
4188c2ecf20Sopenharmony_ci	err = __ext_tree_remove(&bl->bl_ext_ro, start, end, &tmp);
4198c2ecf20Sopenharmony_ci	if (err)
4208c2ecf20Sopenharmony_ci		goto out;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	/*
4238c2ecf20Sopenharmony_ci	 * Then mark all invalid extents in the range as written to.
4248c2ecf20Sopenharmony_ci	 */
4258c2ecf20Sopenharmony_ci	for (be = __ext_tree_search(root, start); be; be = ext_tree_next(be)) {
4268c2ecf20Sopenharmony_ci		if (be->be_f_offset >= end)
4278c2ecf20Sopenharmony_ci			break;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		if (be->be_state != PNFS_BLOCK_INVALID_DATA || be->be_tag)
4308c2ecf20Sopenharmony_ci			continue;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci		if (be->be_f_offset < start) {
4338c2ecf20Sopenharmony_ci			struct pnfs_block_extent *left = ext_tree_prev(be);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci			if (left && ext_can_merge(left, be)) {
4368c2ecf20Sopenharmony_ci				sector_t diff = start - be->be_f_offset;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci				left->be_length += diff;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci				be->be_f_offset += diff;
4418c2ecf20Sopenharmony_ci				be->be_v_offset += diff;
4428c2ecf20Sopenharmony_ci				be->be_length -= diff;
4438c2ecf20Sopenharmony_ci			} else {
4448c2ecf20Sopenharmony_ci				err = ext_tree_split(root, be, start);
4458c2ecf20Sopenharmony_ci				if (err)
4468c2ecf20Sopenharmony_ci					goto out;
4478c2ecf20Sopenharmony_ci			}
4488c2ecf20Sopenharmony_ci		}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		if (ext_f_end(be) > end) {
4518c2ecf20Sopenharmony_ci			struct pnfs_block_extent *right = ext_tree_next(be);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci			if (right && ext_can_merge(be, right)) {
4548c2ecf20Sopenharmony_ci				sector_t diff = end - be->be_f_offset;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci				be->be_length -= diff;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci				right->be_f_offset -= diff;
4598c2ecf20Sopenharmony_ci				right->be_v_offset -= diff;
4608c2ecf20Sopenharmony_ci				right->be_length += diff;
4618c2ecf20Sopenharmony_ci			} else {
4628c2ecf20Sopenharmony_ci				err = ext_tree_split(root, be, end);
4638c2ecf20Sopenharmony_ci				if (err)
4648c2ecf20Sopenharmony_ci					goto out;
4658c2ecf20Sopenharmony_ci			}
4668c2ecf20Sopenharmony_ci		}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		if (be->be_f_offset >= start && ext_f_end(be) <= end) {
4698c2ecf20Sopenharmony_ci			be->be_tag = EXTENT_WRITTEN;
4708c2ecf20Sopenharmony_ci			be = ext_try_to_merge_left(root, be);
4718c2ecf20Sopenharmony_ci			be = ext_try_to_merge_right(root, be);
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ciout:
4758c2ecf20Sopenharmony_ci	if (bl->bl_lwb < lwb)
4768c2ecf20Sopenharmony_ci		bl->bl_lwb = lwb;
4778c2ecf20Sopenharmony_ci	spin_unlock(&bl->bl_ext_lock);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	__ext_put_deviceids(&tmp);
4808c2ecf20Sopenharmony_ci	return err;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic size_t ext_tree_layoutupdate_size(struct pnfs_block_layout *bl, size_t count)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	if (bl->bl_scsi_layout)
4868c2ecf20Sopenharmony_ci		return sizeof(__be32) + PNFS_SCSI_RANGE_SIZE * count;
4878c2ecf20Sopenharmony_ci	else
4888c2ecf20Sopenharmony_ci		return sizeof(__be32) + PNFS_BLOCK_EXTENT_SIZE * count;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic void ext_tree_free_commitdata(struct nfs4_layoutcommit_args *arg,
4928c2ecf20Sopenharmony_ci		size_t buffer_size)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	if (arg->layoutupdate_pages != &arg->layoutupdate_page) {
4958c2ecf20Sopenharmony_ci		int nr_pages = DIV_ROUND_UP(buffer_size, PAGE_SIZE), i;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci		for (i = 0; i < nr_pages; i++)
4988c2ecf20Sopenharmony_ci			put_page(arg->layoutupdate_pages[i]);
4998c2ecf20Sopenharmony_ci		vfree(arg->start_p);
5008c2ecf20Sopenharmony_ci		kfree(arg->layoutupdate_pages);
5018c2ecf20Sopenharmony_ci	} else {
5028c2ecf20Sopenharmony_ci		put_page(arg->layoutupdate_page);
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic __be32 *encode_block_extent(struct pnfs_block_extent *be, __be32 *p)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	p = xdr_encode_opaque_fixed(p, be->be_device->deviceid.data,
5098c2ecf20Sopenharmony_ci			NFS4_DEVICEID4_SIZE);
5108c2ecf20Sopenharmony_ci	p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
5118c2ecf20Sopenharmony_ci	p = xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
5128c2ecf20Sopenharmony_ci	p = xdr_encode_hyper(p, 0LL);
5138c2ecf20Sopenharmony_ci	*p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
5148c2ecf20Sopenharmony_ci	return p;
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_cistatic __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
5208c2ecf20Sopenharmony_ci	return xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
5248c2ecf20Sopenharmony_ci		size_t buffer_size, size_t *count, __u64 *lastbyte)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be;
5278c2ecf20Sopenharmony_ci	int ret = 0;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	spin_lock(&bl->bl_ext_lock);
5308c2ecf20Sopenharmony_ci	for (be = ext_tree_first(&bl->bl_ext_rw); be; be = ext_tree_next(be)) {
5318c2ecf20Sopenharmony_ci		if (be->be_state != PNFS_BLOCK_INVALID_DATA ||
5328c2ecf20Sopenharmony_ci		    be->be_tag != EXTENT_WRITTEN)
5338c2ecf20Sopenharmony_ci			continue;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		(*count)++;
5368c2ecf20Sopenharmony_ci		if (ext_tree_layoutupdate_size(bl, *count) > buffer_size) {
5378c2ecf20Sopenharmony_ci			/* keep counting.. */
5388c2ecf20Sopenharmony_ci			ret = -ENOSPC;
5398c2ecf20Sopenharmony_ci			continue;
5408c2ecf20Sopenharmony_ci		}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci		if (bl->bl_scsi_layout)
5438c2ecf20Sopenharmony_ci			p = encode_scsi_range(be, p);
5448c2ecf20Sopenharmony_ci		else
5458c2ecf20Sopenharmony_ci			p = encode_block_extent(be, p);
5468c2ecf20Sopenharmony_ci		be->be_tag = EXTENT_COMMITTING;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci	*lastbyte = bl->bl_lwb - 1;
5498c2ecf20Sopenharmony_ci	bl->bl_lwb = 0;
5508c2ecf20Sopenharmony_ci	spin_unlock(&bl->bl_ext_lock);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return ret;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ciint
5568c2ecf20Sopenharmony_ciext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct pnfs_block_layout *bl = BLK_LO2EXT(NFS_I(arg->inode)->layout);
5598c2ecf20Sopenharmony_ci	size_t count = 0, buffer_size = PAGE_SIZE;
5608c2ecf20Sopenharmony_ci	__be32 *start_p;
5618c2ecf20Sopenharmony_ci	int ret;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	dprintk("%s enter\n", __func__);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	arg->layoutupdate_page = alloc_page(GFP_NOFS);
5668c2ecf20Sopenharmony_ci	if (!arg->layoutupdate_page)
5678c2ecf20Sopenharmony_ci		return -ENOMEM;
5688c2ecf20Sopenharmony_ci	start_p = page_address(arg->layoutupdate_page);
5698c2ecf20Sopenharmony_ci	arg->layoutupdate_pages = &arg->layoutupdate_page;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ciretry:
5728c2ecf20Sopenharmony_ci	ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size, &count, &arg->lastbytewritten);
5738c2ecf20Sopenharmony_ci	if (unlikely(ret)) {
5748c2ecf20Sopenharmony_ci		ext_tree_free_commitdata(arg, buffer_size);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		buffer_size = ext_tree_layoutupdate_size(bl, count);
5778c2ecf20Sopenharmony_ci		count = 0;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		arg->layoutupdate_pages =
5808c2ecf20Sopenharmony_ci			kcalloc(DIV_ROUND_UP(buffer_size, PAGE_SIZE),
5818c2ecf20Sopenharmony_ci				sizeof(struct page *), GFP_NOFS);
5828c2ecf20Sopenharmony_ci		if (!arg->layoutupdate_pages)
5838c2ecf20Sopenharmony_ci			return -ENOMEM;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		start_p = __vmalloc(buffer_size, GFP_NOFS);
5868c2ecf20Sopenharmony_ci		if (!start_p) {
5878c2ecf20Sopenharmony_ci			kfree(arg->layoutupdate_pages);
5888c2ecf20Sopenharmony_ci			return -ENOMEM;
5898c2ecf20Sopenharmony_ci		}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci		goto retry;
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	*start_p = cpu_to_be32(count);
5958c2ecf20Sopenharmony_ci	arg->layoutupdate_len = ext_tree_layoutupdate_size(bl, count);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	if (unlikely(arg->layoutupdate_pages != &arg->layoutupdate_page)) {
5988c2ecf20Sopenharmony_ci		void *p = start_p, *end = p + arg->layoutupdate_len;
5998c2ecf20Sopenharmony_ci		struct page *page = NULL;
6008c2ecf20Sopenharmony_ci		int i = 0;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		arg->start_p = start_p;
6038c2ecf20Sopenharmony_ci		for ( ; p < end; p += PAGE_SIZE) {
6048c2ecf20Sopenharmony_ci			page = vmalloc_to_page(p);
6058c2ecf20Sopenharmony_ci			arg->layoutupdate_pages[i++] = page;
6068c2ecf20Sopenharmony_ci			get_page(page);
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	dprintk("%s found %zu ranges\n", __func__, count);
6118c2ecf20Sopenharmony_ci	return 0;
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_civoid
6158c2ecf20Sopenharmony_ciext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	struct pnfs_block_layout *bl = BLK_LO2EXT(NFS_I(arg->inode)->layout);
6188c2ecf20Sopenharmony_ci	struct rb_root *root = &bl->bl_ext_rw;
6198c2ecf20Sopenharmony_ci	struct pnfs_block_extent *be;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	dprintk("%s status %d\n", __func__, status);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	ext_tree_free_commitdata(arg, arg->layoutupdate_len);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	spin_lock(&bl->bl_ext_lock);
6268c2ecf20Sopenharmony_ci	for (be = ext_tree_first(root); be; be = ext_tree_next(be)) {
6278c2ecf20Sopenharmony_ci		if (be->be_state != PNFS_BLOCK_INVALID_DATA ||
6288c2ecf20Sopenharmony_ci		    be->be_tag != EXTENT_COMMITTING)
6298c2ecf20Sopenharmony_ci			continue;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci		if (status) {
6328c2ecf20Sopenharmony_ci			/*
6338c2ecf20Sopenharmony_ci			 * Mark as written and try again.
6348c2ecf20Sopenharmony_ci			 *
6358c2ecf20Sopenharmony_ci			 * XXX: some real error handling here wouldn't hurt..
6368c2ecf20Sopenharmony_ci			 */
6378c2ecf20Sopenharmony_ci			be->be_tag = EXTENT_WRITTEN;
6388c2ecf20Sopenharmony_ci		} else {
6398c2ecf20Sopenharmony_ci			be->be_state = PNFS_BLOCK_READWRITE_DATA;
6408c2ecf20Sopenharmony_ci			be->be_tag = 0;
6418c2ecf20Sopenharmony_ci		}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		be = ext_try_to_merge_left(root, be);
6448c2ecf20Sopenharmony_ci		be = ext_try_to_merge_right(root, be);
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci	spin_unlock(&bl->bl_ext_lock);
6478c2ecf20Sopenharmony_ci}
648