xref: /OK3568_Linux_fs/kernel/fs/nfs/blocklayout/extent_tree.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2014-2016 Christoph Hellwig.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/vmalloc.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "blocklayout.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #define NFSDBG_FACILITY		NFSDBG_PNFS_LD
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun static inline struct pnfs_block_extent *
ext_node(struct rb_node * node)13*4882a593Smuzhiyun ext_node(struct rb_node *node)
14*4882a593Smuzhiyun {
15*4882a593Smuzhiyun 	return rb_entry(node, struct pnfs_block_extent, be_node);
16*4882a593Smuzhiyun }
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun static struct pnfs_block_extent *
ext_tree_first(struct rb_root * root)19*4882a593Smuzhiyun ext_tree_first(struct rb_root *root)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	struct rb_node *node = rb_first(root);
22*4882a593Smuzhiyun 	return node ? ext_node(node) : NULL;
23*4882a593Smuzhiyun }
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun static struct pnfs_block_extent *
ext_tree_prev(struct pnfs_block_extent * be)26*4882a593Smuzhiyun ext_tree_prev(struct pnfs_block_extent *be)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	struct rb_node *node = rb_prev(&be->be_node);
29*4882a593Smuzhiyun 	return node ? ext_node(node) : NULL;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun static struct pnfs_block_extent *
ext_tree_next(struct pnfs_block_extent * be)33*4882a593Smuzhiyun ext_tree_next(struct pnfs_block_extent *be)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	struct rb_node *node = rb_next(&be->be_node);
36*4882a593Smuzhiyun 	return node ? ext_node(node) : NULL;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun static inline sector_t
ext_f_end(struct pnfs_block_extent * be)40*4882a593Smuzhiyun ext_f_end(struct pnfs_block_extent *be)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	return be->be_f_offset + be->be_length;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun static struct pnfs_block_extent *
__ext_tree_search(struct rb_root * root,sector_t start)46*4882a593Smuzhiyun __ext_tree_search(struct rb_root *root, sector_t start)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	struct rb_node *node = root->rb_node;
49*4882a593Smuzhiyun 	struct pnfs_block_extent *be = NULL;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	while (node) {
52*4882a593Smuzhiyun 		be = ext_node(node);
53*4882a593Smuzhiyun 		if (start < be->be_f_offset)
54*4882a593Smuzhiyun 			node = node->rb_left;
55*4882a593Smuzhiyun 		else if (start >= ext_f_end(be))
56*4882a593Smuzhiyun 			node = node->rb_right;
57*4882a593Smuzhiyun 		else
58*4882a593Smuzhiyun 			return be;
59*4882a593Smuzhiyun 	}
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	if (be) {
62*4882a593Smuzhiyun 		if (start < be->be_f_offset)
63*4882a593Smuzhiyun 			return be;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 		if (start >= ext_f_end(be))
66*4882a593Smuzhiyun 			return ext_tree_next(be);
67*4882a593Smuzhiyun 	}
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	return NULL;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun static bool
ext_can_merge(struct pnfs_block_extent * be1,struct pnfs_block_extent * be2)73*4882a593Smuzhiyun ext_can_merge(struct pnfs_block_extent *be1, struct pnfs_block_extent *be2)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	if (be1->be_state != be2->be_state)
76*4882a593Smuzhiyun 		return false;
77*4882a593Smuzhiyun 	if (be1->be_device != be2->be_device)
78*4882a593Smuzhiyun 		return false;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	if (be1->be_f_offset + be1->be_length != be2->be_f_offset)
81*4882a593Smuzhiyun 		return false;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	if (be1->be_state != PNFS_BLOCK_NONE_DATA &&
84*4882a593Smuzhiyun 	    (be1->be_v_offset + be1->be_length != be2->be_v_offset))
85*4882a593Smuzhiyun 		return false;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (be1->be_state == PNFS_BLOCK_INVALID_DATA &&
88*4882a593Smuzhiyun 	    be1->be_tag != be2->be_tag)
89*4882a593Smuzhiyun 		return false;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return true;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun static struct pnfs_block_extent *
ext_try_to_merge_left(struct rb_root * root,struct pnfs_block_extent * be)95*4882a593Smuzhiyun ext_try_to_merge_left(struct rb_root *root, struct pnfs_block_extent *be)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	struct pnfs_block_extent *left = ext_tree_prev(be);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	if (left && ext_can_merge(left, be)) {
100*4882a593Smuzhiyun 		left->be_length += be->be_length;
101*4882a593Smuzhiyun 		rb_erase(&be->be_node, root);
102*4882a593Smuzhiyun 		nfs4_put_deviceid_node(be->be_device);
103*4882a593Smuzhiyun 		kfree(be);
104*4882a593Smuzhiyun 		return left;
105*4882a593Smuzhiyun 	}
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	return be;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun static struct pnfs_block_extent *
ext_try_to_merge_right(struct rb_root * root,struct pnfs_block_extent * be)111*4882a593Smuzhiyun ext_try_to_merge_right(struct rb_root *root, struct pnfs_block_extent *be)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	struct pnfs_block_extent *right = ext_tree_next(be);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if (right && ext_can_merge(be, right)) {
116*4882a593Smuzhiyun 		be->be_length += right->be_length;
117*4882a593Smuzhiyun 		rb_erase(&right->be_node, root);
118*4882a593Smuzhiyun 		nfs4_put_deviceid_node(right->be_device);
119*4882a593Smuzhiyun 		kfree(right);
120*4882a593Smuzhiyun 	}
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return be;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
__ext_put_deviceids(struct list_head * head)125*4882a593Smuzhiyun static void __ext_put_deviceids(struct list_head *head)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct pnfs_block_extent *be, *tmp;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	list_for_each_entry_safe(be, tmp, head, be_list) {
130*4882a593Smuzhiyun 		nfs4_put_deviceid_node(be->be_device);
131*4882a593Smuzhiyun 		kfree(be);
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun static void
__ext_tree_insert(struct rb_root * root,struct pnfs_block_extent * new,bool merge_ok)136*4882a593Smuzhiyun __ext_tree_insert(struct rb_root *root,
137*4882a593Smuzhiyun 		struct pnfs_block_extent *new, bool merge_ok)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	struct rb_node **p = &root->rb_node, *parent = NULL;
140*4882a593Smuzhiyun 	struct pnfs_block_extent *be;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	while (*p) {
143*4882a593Smuzhiyun 		parent = *p;
144*4882a593Smuzhiyun 		be = ext_node(parent);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 		if (new->be_f_offset < be->be_f_offset) {
147*4882a593Smuzhiyun 			if (merge_ok && ext_can_merge(new, be)) {
148*4882a593Smuzhiyun 				be->be_f_offset = new->be_f_offset;
149*4882a593Smuzhiyun 				if (be->be_state != PNFS_BLOCK_NONE_DATA)
150*4882a593Smuzhiyun 					be->be_v_offset = new->be_v_offset;
151*4882a593Smuzhiyun 				be->be_length += new->be_length;
152*4882a593Smuzhiyun 				be = ext_try_to_merge_left(root, be);
153*4882a593Smuzhiyun 				goto free_new;
154*4882a593Smuzhiyun 			}
155*4882a593Smuzhiyun 			p = &(*p)->rb_left;
156*4882a593Smuzhiyun 		} else if (new->be_f_offset >= ext_f_end(be)) {
157*4882a593Smuzhiyun 			if (merge_ok && ext_can_merge(be, new)) {
158*4882a593Smuzhiyun 				be->be_length += new->be_length;
159*4882a593Smuzhiyun 				be = ext_try_to_merge_right(root, be);
160*4882a593Smuzhiyun 				goto free_new;
161*4882a593Smuzhiyun 			}
162*4882a593Smuzhiyun 			p = &(*p)->rb_right;
163*4882a593Smuzhiyun 		} else {
164*4882a593Smuzhiyun 			BUG();
165*4882a593Smuzhiyun 		}
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	rb_link_node(&new->be_node, parent, p);
169*4882a593Smuzhiyun 	rb_insert_color(&new->be_node, root);
170*4882a593Smuzhiyun 	return;
171*4882a593Smuzhiyun free_new:
172*4882a593Smuzhiyun 	nfs4_put_deviceid_node(new->be_device);
173*4882a593Smuzhiyun 	kfree(new);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun static int
__ext_tree_remove(struct rb_root * root,sector_t start,sector_t end,struct list_head * tmp)177*4882a593Smuzhiyun __ext_tree_remove(struct rb_root *root,
178*4882a593Smuzhiyun 		sector_t start, sector_t end, struct list_head *tmp)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	struct pnfs_block_extent *be;
181*4882a593Smuzhiyun 	sector_t len1 = 0, len2 = 0;
182*4882a593Smuzhiyun 	sector_t orig_v_offset;
183*4882a593Smuzhiyun 	sector_t orig_len;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	be = __ext_tree_search(root, start);
186*4882a593Smuzhiyun 	if (!be)
187*4882a593Smuzhiyun 		return 0;
188*4882a593Smuzhiyun 	if (be->be_f_offset >= end)
189*4882a593Smuzhiyun 		return 0;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	orig_v_offset = be->be_v_offset;
192*4882a593Smuzhiyun 	orig_len = be->be_length;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	if (start > be->be_f_offset)
195*4882a593Smuzhiyun 		len1 = start - be->be_f_offset;
196*4882a593Smuzhiyun 	if (ext_f_end(be) > end)
197*4882a593Smuzhiyun 		len2 = ext_f_end(be) - end;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (len2 > 0) {
200*4882a593Smuzhiyun 		if (len1 > 0) {
201*4882a593Smuzhiyun 			struct pnfs_block_extent *new;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 			new = kzalloc(sizeof(*new), GFP_ATOMIC);
204*4882a593Smuzhiyun 			if (!new)
205*4882a593Smuzhiyun 				return -ENOMEM;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 			be->be_length = len1;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 			new->be_f_offset = end;
210*4882a593Smuzhiyun 			if (be->be_state != PNFS_BLOCK_NONE_DATA) {
211*4882a593Smuzhiyun 				new->be_v_offset =
212*4882a593Smuzhiyun 					orig_v_offset + orig_len - len2;
213*4882a593Smuzhiyun 			}
214*4882a593Smuzhiyun 			new->be_length = len2;
215*4882a593Smuzhiyun 			new->be_state = be->be_state;
216*4882a593Smuzhiyun 			new->be_tag = be->be_tag;
217*4882a593Smuzhiyun 			new->be_device = nfs4_get_deviceid(be->be_device);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 			__ext_tree_insert(root, new, true);
220*4882a593Smuzhiyun 		} else {
221*4882a593Smuzhiyun 			be->be_f_offset = end;
222*4882a593Smuzhiyun 			if (be->be_state != PNFS_BLOCK_NONE_DATA) {
223*4882a593Smuzhiyun 				be->be_v_offset =
224*4882a593Smuzhiyun 					orig_v_offset + orig_len - len2;
225*4882a593Smuzhiyun 			}
226*4882a593Smuzhiyun 			be->be_length = len2;
227*4882a593Smuzhiyun 		}
228*4882a593Smuzhiyun 	} else {
229*4882a593Smuzhiyun 		if (len1 > 0) {
230*4882a593Smuzhiyun 			be->be_length = len1;
231*4882a593Smuzhiyun 			be = ext_tree_next(be);
232*4882a593Smuzhiyun 		}
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 		while (be && ext_f_end(be) <= end) {
235*4882a593Smuzhiyun 			struct pnfs_block_extent *next = ext_tree_next(be);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 			rb_erase(&be->be_node, root);
238*4882a593Smuzhiyun 			list_add_tail(&be->be_list, tmp);
239*4882a593Smuzhiyun 			be = next;
240*4882a593Smuzhiyun 		}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 		if (be && be->be_f_offset < end) {
243*4882a593Smuzhiyun 			len1 = ext_f_end(be) - end;
244*4882a593Smuzhiyun 			be->be_f_offset = end;
245*4882a593Smuzhiyun 			if (be->be_state != PNFS_BLOCK_NONE_DATA)
246*4882a593Smuzhiyun 				be->be_v_offset += be->be_length - len1;
247*4882a593Smuzhiyun 			be->be_length = len1;
248*4882a593Smuzhiyun 		}
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	return 0;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun int
ext_tree_insert(struct pnfs_block_layout * bl,struct pnfs_block_extent * new)255*4882a593Smuzhiyun ext_tree_insert(struct pnfs_block_layout *bl, struct pnfs_block_extent *new)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	struct pnfs_block_extent *be;
258*4882a593Smuzhiyun 	struct rb_root *root;
259*4882a593Smuzhiyun 	int err = 0;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	switch (new->be_state) {
262*4882a593Smuzhiyun 	case PNFS_BLOCK_READWRITE_DATA:
263*4882a593Smuzhiyun 	case PNFS_BLOCK_INVALID_DATA:
264*4882a593Smuzhiyun 		root = &bl->bl_ext_rw;
265*4882a593Smuzhiyun 		break;
266*4882a593Smuzhiyun 	case PNFS_BLOCK_READ_DATA:
267*4882a593Smuzhiyun 	case PNFS_BLOCK_NONE_DATA:
268*4882a593Smuzhiyun 		root = &bl->bl_ext_ro;
269*4882a593Smuzhiyun 		break;
270*4882a593Smuzhiyun 	default:
271*4882a593Smuzhiyun 		dprintk("invalid extent type\n");
272*4882a593Smuzhiyun 		return -EINVAL;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	spin_lock(&bl->bl_ext_lock);
276*4882a593Smuzhiyun retry:
277*4882a593Smuzhiyun 	be = __ext_tree_search(root, new->be_f_offset);
278*4882a593Smuzhiyun 	if (!be || be->be_f_offset >= ext_f_end(new)) {
279*4882a593Smuzhiyun 		__ext_tree_insert(root, new, true);
280*4882a593Smuzhiyun 	} else if (new->be_f_offset >= be->be_f_offset) {
281*4882a593Smuzhiyun 		if (ext_f_end(new) <= ext_f_end(be)) {
282*4882a593Smuzhiyun 			nfs4_put_deviceid_node(new->be_device);
283*4882a593Smuzhiyun 			kfree(new);
284*4882a593Smuzhiyun 		} else {
285*4882a593Smuzhiyun 			sector_t new_len = ext_f_end(new) - ext_f_end(be);
286*4882a593Smuzhiyun 			sector_t diff = new->be_length - new_len;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 			new->be_f_offset += diff;
289*4882a593Smuzhiyun 			new->be_v_offset += diff;
290*4882a593Smuzhiyun 			new->be_length = new_len;
291*4882a593Smuzhiyun 			goto retry;
292*4882a593Smuzhiyun 		}
293*4882a593Smuzhiyun 	} else if (ext_f_end(new) <= ext_f_end(be)) {
294*4882a593Smuzhiyun 		new->be_length = be->be_f_offset - new->be_f_offset;
295*4882a593Smuzhiyun 		__ext_tree_insert(root, new, true);
296*4882a593Smuzhiyun 	} else {
297*4882a593Smuzhiyun 		struct pnfs_block_extent *split;
298*4882a593Smuzhiyun 		sector_t new_len = ext_f_end(new) - ext_f_end(be);
299*4882a593Smuzhiyun 		sector_t diff = new->be_length - new_len;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 		split = kmemdup(new, sizeof(*new), GFP_ATOMIC);
302*4882a593Smuzhiyun 		if (!split) {
303*4882a593Smuzhiyun 			err = -EINVAL;
304*4882a593Smuzhiyun 			goto out;
305*4882a593Smuzhiyun 		}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 		split->be_length = be->be_f_offset - split->be_f_offset;
308*4882a593Smuzhiyun 		split->be_device = nfs4_get_deviceid(new->be_device);
309*4882a593Smuzhiyun 		__ext_tree_insert(root, split, true);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 		new->be_f_offset += diff;
312*4882a593Smuzhiyun 		new->be_v_offset += diff;
313*4882a593Smuzhiyun 		new->be_length = new_len;
314*4882a593Smuzhiyun 		goto retry;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun out:
317*4882a593Smuzhiyun 	spin_unlock(&bl->bl_ext_lock);
318*4882a593Smuzhiyun 	return err;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun static bool
__ext_tree_lookup(struct rb_root * root,sector_t isect,struct pnfs_block_extent * ret)322*4882a593Smuzhiyun __ext_tree_lookup(struct rb_root *root, sector_t isect,
323*4882a593Smuzhiyun 		struct pnfs_block_extent *ret)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct rb_node *node;
326*4882a593Smuzhiyun 	struct pnfs_block_extent *be;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	node = root->rb_node;
329*4882a593Smuzhiyun 	while (node) {
330*4882a593Smuzhiyun 		be = ext_node(node);
331*4882a593Smuzhiyun 		if (isect < be->be_f_offset)
332*4882a593Smuzhiyun 			node = node->rb_left;
333*4882a593Smuzhiyun 		else if (isect >= ext_f_end(be))
334*4882a593Smuzhiyun 			node = node->rb_right;
335*4882a593Smuzhiyun 		else {
336*4882a593Smuzhiyun 			*ret = *be;
337*4882a593Smuzhiyun 			return true;
338*4882a593Smuzhiyun 		}
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	return false;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun bool
ext_tree_lookup(struct pnfs_block_layout * bl,sector_t isect,struct pnfs_block_extent * ret,bool rw)345*4882a593Smuzhiyun ext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect,
346*4882a593Smuzhiyun 	    struct pnfs_block_extent *ret, bool rw)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	bool found = false;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	spin_lock(&bl->bl_ext_lock);
351*4882a593Smuzhiyun 	if (!rw)
352*4882a593Smuzhiyun 		found = __ext_tree_lookup(&bl->bl_ext_ro, isect, ret);
353*4882a593Smuzhiyun 	if (!found)
354*4882a593Smuzhiyun 		found = __ext_tree_lookup(&bl->bl_ext_rw, isect, ret);
355*4882a593Smuzhiyun 	spin_unlock(&bl->bl_ext_lock);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	return found;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
ext_tree_remove(struct pnfs_block_layout * bl,bool rw,sector_t start,sector_t end)360*4882a593Smuzhiyun int ext_tree_remove(struct pnfs_block_layout *bl, bool rw,
361*4882a593Smuzhiyun 		sector_t start, sector_t end)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	int err, err2;
364*4882a593Smuzhiyun 	LIST_HEAD(tmp);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	spin_lock(&bl->bl_ext_lock);
367*4882a593Smuzhiyun 	err = __ext_tree_remove(&bl->bl_ext_ro, start, end, &tmp);
368*4882a593Smuzhiyun 	if (rw) {
369*4882a593Smuzhiyun 		err2 = __ext_tree_remove(&bl->bl_ext_rw, start, end, &tmp);
370*4882a593Smuzhiyun 		if (!err)
371*4882a593Smuzhiyun 			err = err2;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 	spin_unlock(&bl->bl_ext_lock);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	__ext_put_deviceids(&tmp);
376*4882a593Smuzhiyun 	return err;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun static int
ext_tree_split(struct rb_root * root,struct pnfs_block_extent * be,sector_t split)380*4882a593Smuzhiyun ext_tree_split(struct rb_root *root, struct pnfs_block_extent *be,
381*4882a593Smuzhiyun 		sector_t split)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	struct pnfs_block_extent *new;
384*4882a593Smuzhiyun 	sector_t orig_len = be->be_length;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	new = kzalloc(sizeof(*new), GFP_ATOMIC);
387*4882a593Smuzhiyun 	if (!new)
388*4882a593Smuzhiyun 		return -ENOMEM;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	be->be_length = split - be->be_f_offset;
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	new->be_f_offset = split;
393*4882a593Smuzhiyun 	if (be->be_state != PNFS_BLOCK_NONE_DATA)
394*4882a593Smuzhiyun 		new->be_v_offset = be->be_v_offset + be->be_length;
395*4882a593Smuzhiyun 	new->be_length = orig_len - be->be_length;
396*4882a593Smuzhiyun 	new->be_state = be->be_state;
397*4882a593Smuzhiyun 	new->be_tag = be->be_tag;
398*4882a593Smuzhiyun 	new->be_device = nfs4_get_deviceid(be->be_device);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	__ext_tree_insert(root, new, false);
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun int
ext_tree_mark_written(struct pnfs_block_layout * bl,sector_t start,sector_t len,u64 lwb)405*4882a593Smuzhiyun ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start,
406*4882a593Smuzhiyun 		sector_t len, u64 lwb)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	struct rb_root *root = &bl->bl_ext_rw;
409*4882a593Smuzhiyun 	sector_t end = start + len;
410*4882a593Smuzhiyun 	struct pnfs_block_extent *be;
411*4882a593Smuzhiyun 	int err = 0;
412*4882a593Smuzhiyun 	LIST_HEAD(tmp);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	spin_lock(&bl->bl_ext_lock);
415*4882a593Smuzhiyun 	/*
416*4882a593Smuzhiyun 	 * First remove all COW extents or holes from written to range.
417*4882a593Smuzhiyun 	 */
418*4882a593Smuzhiyun 	err = __ext_tree_remove(&bl->bl_ext_ro, start, end, &tmp);
419*4882a593Smuzhiyun 	if (err)
420*4882a593Smuzhiyun 		goto out;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	/*
423*4882a593Smuzhiyun 	 * Then mark all invalid extents in the range as written to.
424*4882a593Smuzhiyun 	 */
425*4882a593Smuzhiyun 	for (be = __ext_tree_search(root, start); be; be = ext_tree_next(be)) {
426*4882a593Smuzhiyun 		if (be->be_f_offset >= end)
427*4882a593Smuzhiyun 			break;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 		if (be->be_state != PNFS_BLOCK_INVALID_DATA || be->be_tag)
430*4882a593Smuzhiyun 			continue;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 		if (be->be_f_offset < start) {
433*4882a593Smuzhiyun 			struct pnfs_block_extent *left = ext_tree_prev(be);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 			if (left && ext_can_merge(left, be)) {
436*4882a593Smuzhiyun 				sector_t diff = start - be->be_f_offset;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 				left->be_length += diff;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 				be->be_f_offset += diff;
441*4882a593Smuzhiyun 				be->be_v_offset += diff;
442*4882a593Smuzhiyun 				be->be_length -= diff;
443*4882a593Smuzhiyun 			} else {
444*4882a593Smuzhiyun 				err = ext_tree_split(root, be, start);
445*4882a593Smuzhiyun 				if (err)
446*4882a593Smuzhiyun 					goto out;
447*4882a593Smuzhiyun 			}
448*4882a593Smuzhiyun 		}
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 		if (ext_f_end(be) > end) {
451*4882a593Smuzhiyun 			struct pnfs_block_extent *right = ext_tree_next(be);
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 			if (right && ext_can_merge(be, right)) {
454*4882a593Smuzhiyun 				sector_t diff = end - be->be_f_offset;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 				be->be_length -= diff;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 				right->be_f_offset -= diff;
459*4882a593Smuzhiyun 				right->be_v_offset -= diff;
460*4882a593Smuzhiyun 				right->be_length += diff;
461*4882a593Smuzhiyun 			} else {
462*4882a593Smuzhiyun 				err = ext_tree_split(root, be, end);
463*4882a593Smuzhiyun 				if (err)
464*4882a593Smuzhiyun 					goto out;
465*4882a593Smuzhiyun 			}
466*4882a593Smuzhiyun 		}
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 		if (be->be_f_offset >= start && ext_f_end(be) <= end) {
469*4882a593Smuzhiyun 			be->be_tag = EXTENT_WRITTEN;
470*4882a593Smuzhiyun 			be = ext_try_to_merge_left(root, be);
471*4882a593Smuzhiyun 			be = ext_try_to_merge_right(root, be);
472*4882a593Smuzhiyun 		}
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun out:
475*4882a593Smuzhiyun 	if (bl->bl_lwb < lwb)
476*4882a593Smuzhiyun 		bl->bl_lwb = lwb;
477*4882a593Smuzhiyun 	spin_unlock(&bl->bl_ext_lock);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	__ext_put_deviceids(&tmp);
480*4882a593Smuzhiyun 	return err;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
ext_tree_layoutupdate_size(struct pnfs_block_layout * bl,size_t count)483*4882a593Smuzhiyun static size_t ext_tree_layoutupdate_size(struct pnfs_block_layout *bl, size_t count)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	if (bl->bl_scsi_layout)
486*4882a593Smuzhiyun 		return sizeof(__be32) + PNFS_SCSI_RANGE_SIZE * count;
487*4882a593Smuzhiyun 	else
488*4882a593Smuzhiyun 		return sizeof(__be32) + PNFS_BLOCK_EXTENT_SIZE * count;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
ext_tree_free_commitdata(struct nfs4_layoutcommit_args * arg,size_t buffer_size)491*4882a593Smuzhiyun static void ext_tree_free_commitdata(struct nfs4_layoutcommit_args *arg,
492*4882a593Smuzhiyun 		size_t buffer_size)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun 	if (arg->layoutupdate_pages != &arg->layoutupdate_page) {
495*4882a593Smuzhiyun 		int nr_pages = DIV_ROUND_UP(buffer_size, PAGE_SIZE), i;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 		for (i = 0; i < nr_pages; i++)
498*4882a593Smuzhiyun 			put_page(arg->layoutupdate_pages[i]);
499*4882a593Smuzhiyun 		vfree(arg->start_p);
500*4882a593Smuzhiyun 		kfree(arg->layoutupdate_pages);
501*4882a593Smuzhiyun 	} else {
502*4882a593Smuzhiyun 		put_page(arg->layoutupdate_page);
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
encode_block_extent(struct pnfs_block_extent * be,__be32 * p)506*4882a593Smuzhiyun static __be32 *encode_block_extent(struct pnfs_block_extent *be, __be32 *p)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	p = xdr_encode_opaque_fixed(p, be->be_device->deviceid.data,
509*4882a593Smuzhiyun 			NFS4_DEVICEID4_SIZE);
510*4882a593Smuzhiyun 	p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
511*4882a593Smuzhiyun 	p = xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
512*4882a593Smuzhiyun 	p = xdr_encode_hyper(p, 0LL);
513*4882a593Smuzhiyun 	*p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
514*4882a593Smuzhiyun 	return p;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun 
encode_scsi_range(struct pnfs_block_extent * be,__be32 * p)517*4882a593Smuzhiyun static __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun 	p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
520*4882a593Smuzhiyun 	return xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun 
ext_tree_encode_commit(struct pnfs_block_layout * bl,__be32 * p,size_t buffer_size,size_t * count,__u64 * lastbyte)523*4882a593Smuzhiyun static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
524*4882a593Smuzhiyun 		size_t buffer_size, size_t *count, __u64 *lastbyte)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	struct pnfs_block_extent *be;
527*4882a593Smuzhiyun 	int ret = 0;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	spin_lock(&bl->bl_ext_lock);
530*4882a593Smuzhiyun 	for (be = ext_tree_first(&bl->bl_ext_rw); be; be = ext_tree_next(be)) {
531*4882a593Smuzhiyun 		if (be->be_state != PNFS_BLOCK_INVALID_DATA ||
532*4882a593Smuzhiyun 		    be->be_tag != EXTENT_WRITTEN)
533*4882a593Smuzhiyun 			continue;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 		(*count)++;
536*4882a593Smuzhiyun 		if (ext_tree_layoutupdate_size(bl, *count) > buffer_size) {
537*4882a593Smuzhiyun 			/* keep counting.. */
538*4882a593Smuzhiyun 			ret = -ENOSPC;
539*4882a593Smuzhiyun 			continue;
540*4882a593Smuzhiyun 		}
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 		if (bl->bl_scsi_layout)
543*4882a593Smuzhiyun 			p = encode_scsi_range(be, p);
544*4882a593Smuzhiyun 		else
545*4882a593Smuzhiyun 			p = encode_block_extent(be, p);
546*4882a593Smuzhiyun 		be->be_tag = EXTENT_COMMITTING;
547*4882a593Smuzhiyun 	}
548*4882a593Smuzhiyun 	*lastbyte = bl->bl_lwb - 1;
549*4882a593Smuzhiyun 	bl->bl_lwb = 0;
550*4882a593Smuzhiyun 	spin_unlock(&bl->bl_ext_lock);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	return ret;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun int
ext_tree_prepare_commit(struct nfs4_layoutcommit_args * arg)556*4882a593Smuzhiyun ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	struct pnfs_block_layout *bl = BLK_LO2EXT(NFS_I(arg->inode)->layout);
559*4882a593Smuzhiyun 	size_t count = 0, buffer_size = PAGE_SIZE;
560*4882a593Smuzhiyun 	__be32 *start_p;
561*4882a593Smuzhiyun 	int ret;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	dprintk("%s enter\n", __func__);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	arg->layoutupdate_page = alloc_page(GFP_NOFS);
566*4882a593Smuzhiyun 	if (!arg->layoutupdate_page)
567*4882a593Smuzhiyun 		return -ENOMEM;
568*4882a593Smuzhiyun 	start_p = page_address(arg->layoutupdate_page);
569*4882a593Smuzhiyun 	arg->layoutupdate_pages = &arg->layoutupdate_page;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun retry:
572*4882a593Smuzhiyun 	ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size, &count, &arg->lastbytewritten);
573*4882a593Smuzhiyun 	if (unlikely(ret)) {
574*4882a593Smuzhiyun 		ext_tree_free_commitdata(arg, buffer_size);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 		buffer_size = ext_tree_layoutupdate_size(bl, count);
577*4882a593Smuzhiyun 		count = 0;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 		arg->layoutupdate_pages =
580*4882a593Smuzhiyun 			kcalloc(DIV_ROUND_UP(buffer_size, PAGE_SIZE),
581*4882a593Smuzhiyun 				sizeof(struct page *), GFP_NOFS);
582*4882a593Smuzhiyun 		if (!arg->layoutupdate_pages)
583*4882a593Smuzhiyun 			return -ENOMEM;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 		start_p = __vmalloc(buffer_size, GFP_NOFS);
586*4882a593Smuzhiyun 		if (!start_p) {
587*4882a593Smuzhiyun 			kfree(arg->layoutupdate_pages);
588*4882a593Smuzhiyun 			return -ENOMEM;
589*4882a593Smuzhiyun 		}
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 		goto retry;
592*4882a593Smuzhiyun 	}
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	*start_p = cpu_to_be32(count);
595*4882a593Smuzhiyun 	arg->layoutupdate_len = ext_tree_layoutupdate_size(bl, count);
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	if (unlikely(arg->layoutupdate_pages != &arg->layoutupdate_page)) {
598*4882a593Smuzhiyun 		void *p = start_p, *end = p + arg->layoutupdate_len;
599*4882a593Smuzhiyun 		struct page *page = NULL;
600*4882a593Smuzhiyun 		int i = 0;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 		arg->start_p = start_p;
603*4882a593Smuzhiyun 		for ( ; p < end; p += PAGE_SIZE) {
604*4882a593Smuzhiyun 			page = vmalloc_to_page(p);
605*4882a593Smuzhiyun 			arg->layoutupdate_pages[i++] = page;
606*4882a593Smuzhiyun 			get_page(page);
607*4882a593Smuzhiyun 		}
608*4882a593Smuzhiyun 	}
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	dprintk("%s found %zu ranges\n", __func__, count);
611*4882a593Smuzhiyun 	return 0;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun void
ext_tree_mark_committed(struct nfs4_layoutcommit_args * arg,int status)615*4882a593Smuzhiyun ext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	struct pnfs_block_layout *bl = BLK_LO2EXT(NFS_I(arg->inode)->layout);
618*4882a593Smuzhiyun 	struct rb_root *root = &bl->bl_ext_rw;
619*4882a593Smuzhiyun 	struct pnfs_block_extent *be;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	dprintk("%s status %d\n", __func__, status);
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	ext_tree_free_commitdata(arg, arg->layoutupdate_len);
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	spin_lock(&bl->bl_ext_lock);
626*4882a593Smuzhiyun 	for (be = ext_tree_first(root); be; be = ext_tree_next(be)) {
627*4882a593Smuzhiyun 		if (be->be_state != PNFS_BLOCK_INVALID_DATA ||
628*4882a593Smuzhiyun 		    be->be_tag != EXTENT_COMMITTING)
629*4882a593Smuzhiyun 			continue;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 		if (status) {
632*4882a593Smuzhiyun 			/*
633*4882a593Smuzhiyun 			 * Mark as written and try again.
634*4882a593Smuzhiyun 			 *
635*4882a593Smuzhiyun 			 * XXX: some real error handling here wouldn't hurt..
636*4882a593Smuzhiyun 			 */
637*4882a593Smuzhiyun 			be->be_tag = EXTENT_WRITTEN;
638*4882a593Smuzhiyun 		} else {
639*4882a593Smuzhiyun 			be->be_state = PNFS_BLOCK_READWRITE_DATA;
640*4882a593Smuzhiyun 			be->be_tag = 0;
641*4882a593Smuzhiyun 		}
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 		be = ext_try_to_merge_left(root, be);
644*4882a593Smuzhiyun 		be = ext_try_to_merge_right(root, be);
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun 	spin_unlock(&bl->bl_ext_lock);
647*4882a593Smuzhiyun }
648