xref: /linux/fs/xfs/libxfs/xfs_group.c (revision c771600c6af14749609b49565ffb4cac2959710d)
1e9c4d8bfSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
2e9c4d8bfSChristoph Hellwig /*
3e9c4d8bfSChristoph Hellwig  * Copyright (c) 2018 Red Hat, Inc.
4e9c4d8bfSChristoph Hellwig  */
5e9c4d8bfSChristoph Hellwig 
6e9c4d8bfSChristoph Hellwig #include "xfs.h"
7e9c4d8bfSChristoph Hellwig #include "xfs_shared.h"
8e9c4d8bfSChristoph Hellwig #include "xfs_format.h"
9e9c4d8bfSChristoph Hellwig #include "xfs_trans_resv.h"
10e9c4d8bfSChristoph Hellwig #include "xfs_mount.h"
11e9c4d8bfSChristoph Hellwig #include "xfs_error.h"
12e9c4d8bfSChristoph Hellwig #include "xfs_trace.h"
13adbc76aaSChristoph Hellwig #include "xfs_extent_busy.h"
14e9c4d8bfSChristoph Hellwig #include "xfs_group.h"
15e9c4d8bfSChristoph Hellwig 
16e9c4d8bfSChristoph Hellwig /*
17e9c4d8bfSChristoph Hellwig  * Groups can have passive and active references.
18e9c4d8bfSChristoph Hellwig  *
19e9c4d8bfSChristoph Hellwig  * For passive references the code freeing a group is responsible for cleaning
20e9c4d8bfSChristoph Hellwig  * up objects that hold the passive references (e.g. cached buffers).
21e9c4d8bfSChristoph Hellwig  * Routines manipulating passive references are xfs_group_get, xfs_group_hold
22e9c4d8bfSChristoph Hellwig  * and xfs_group_put.
23e9c4d8bfSChristoph Hellwig  *
24e9c4d8bfSChristoph Hellwig  * Active references are for short term access to the group for walking trees or
25e9c4d8bfSChristoph Hellwig  * accessing state. If a group is being shrunk or offlined, the lookup will fail
26e9c4d8bfSChristoph Hellwig  * to find that group and return NULL instead.
27e9c4d8bfSChristoph Hellwig  * Routines manipulating active references are xfs_group_grab and
28e9c4d8bfSChristoph Hellwig  * xfs_group_rele.
29e9c4d8bfSChristoph Hellwig  */
30e9c4d8bfSChristoph Hellwig 
31e9c4d8bfSChristoph Hellwig struct xfs_group *
32e9c4d8bfSChristoph Hellwig xfs_group_get(
33e9c4d8bfSChristoph Hellwig 	struct xfs_mount	*mp,
34e9c4d8bfSChristoph Hellwig 	uint32_t		index,
35e9c4d8bfSChristoph Hellwig 	enum xfs_group_type	type)
36e9c4d8bfSChristoph Hellwig {
37e9c4d8bfSChristoph Hellwig 	struct xfs_group	*xg;
38e9c4d8bfSChristoph Hellwig 
39e9c4d8bfSChristoph Hellwig 	rcu_read_lock();
40e9c4d8bfSChristoph Hellwig 	xg = xa_load(&mp->m_groups[type].xa, index);
41e9c4d8bfSChristoph Hellwig 	if (xg) {
42e9c4d8bfSChristoph Hellwig 		trace_xfs_group_get(xg, _RET_IP_);
43e9c4d8bfSChristoph Hellwig 		ASSERT(atomic_read(&xg->xg_ref) >= 0);
44e9c4d8bfSChristoph Hellwig 		atomic_inc(&xg->xg_ref);
45e9c4d8bfSChristoph Hellwig 	}
46e9c4d8bfSChristoph Hellwig 	rcu_read_unlock();
47e9c4d8bfSChristoph Hellwig 	return xg;
48e9c4d8bfSChristoph Hellwig }
49e9c4d8bfSChristoph Hellwig 
50e9c4d8bfSChristoph Hellwig struct xfs_group *
51e9c4d8bfSChristoph Hellwig xfs_group_hold(
52e9c4d8bfSChristoph Hellwig 	struct xfs_group	*xg)
53e9c4d8bfSChristoph Hellwig {
54e9c4d8bfSChristoph Hellwig 	ASSERT(atomic_read(&xg->xg_ref) > 0 ||
55e9c4d8bfSChristoph Hellwig 	       atomic_read(&xg->xg_active_ref) > 0);
56e9c4d8bfSChristoph Hellwig 
57e9c4d8bfSChristoph Hellwig 	trace_xfs_group_hold(xg, _RET_IP_);
58e9c4d8bfSChristoph Hellwig 	atomic_inc(&xg->xg_ref);
59e9c4d8bfSChristoph Hellwig 	return xg;
60e9c4d8bfSChristoph Hellwig }
61e9c4d8bfSChristoph Hellwig 
62e9c4d8bfSChristoph Hellwig void
63e9c4d8bfSChristoph Hellwig xfs_group_put(
64e9c4d8bfSChristoph Hellwig 	struct xfs_group	*xg)
65e9c4d8bfSChristoph Hellwig {
66e9c4d8bfSChristoph Hellwig 	trace_xfs_group_put(xg, _RET_IP_);
67e9c4d8bfSChristoph Hellwig 
68e9c4d8bfSChristoph Hellwig 	ASSERT(atomic_read(&xg->xg_ref) > 0);
69e9c4d8bfSChristoph Hellwig 	atomic_dec(&xg->xg_ref);
70e9c4d8bfSChristoph Hellwig }
71e9c4d8bfSChristoph Hellwig 
72e9c4d8bfSChristoph Hellwig struct xfs_group *
73e9c4d8bfSChristoph Hellwig xfs_group_grab(
74e9c4d8bfSChristoph Hellwig 	struct xfs_mount	*mp,
75e9c4d8bfSChristoph Hellwig 	uint32_t		index,
76e9c4d8bfSChristoph Hellwig 	enum xfs_group_type	type)
77e9c4d8bfSChristoph Hellwig {
78e9c4d8bfSChristoph Hellwig 	struct xfs_group	*xg;
79e9c4d8bfSChristoph Hellwig 
80e9c4d8bfSChristoph Hellwig 	rcu_read_lock();
81e9c4d8bfSChristoph Hellwig 	xg = xa_load(&mp->m_groups[type].xa, index);
82e9c4d8bfSChristoph Hellwig 	if (xg) {
83e9c4d8bfSChristoph Hellwig 		trace_xfs_group_grab(xg, _RET_IP_);
84e9c4d8bfSChristoph Hellwig 		if (!atomic_inc_not_zero(&xg->xg_active_ref))
85e9c4d8bfSChristoph Hellwig 			xg = NULL;
86e9c4d8bfSChristoph Hellwig 	}
87e9c4d8bfSChristoph Hellwig 	rcu_read_unlock();
88e9c4d8bfSChristoph Hellwig 	return xg;
89e9c4d8bfSChristoph Hellwig }
90e9c4d8bfSChristoph Hellwig 
91e9c4d8bfSChristoph Hellwig /*
9281992877SChristoph Hellwig  * Iterate to the next group.  To start the iteration at @start_index, a %NULL
9381992877SChristoph Hellwig  * @xg is passed, else the previous group returned from this function.  The
9481992877SChristoph Hellwig  * caller should break out of the loop when this returns %NULL.  If the caller
9581992877SChristoph Hellwig  * wants to break out of a loop that did not finish it needs to release the
9681992877SChristoph Hellwig  * active reference to @xg using xfs_group_rele() itself.
9781992877SChristoph Hellwig  */
9881992877SChristoph Hellwig struct xfs_group *
9981992877SChristoph Hellwig xfs_group_next_range(
10081992877SChristoph Hellwig 	struct xfs_mount	*mp,
10181992877SChristoph Hellwig 	struct xfs_group	*xg,
10281992877SChristoph Hellwig 	uint32_t		start_index,
10381992877SChristoph Hellwig 	uint32_t		end_index,
10481992877SChristoph Hellwig 	enum xfs_group_type	type)
10581992877SChristoph Hellwig {
10681992877SChristoph Hellwig 	uint32_t		index = start_index;
10781992877SChristoph Hellwig 
10881992877SChristoph Hellwig 	if (xg) {
10981992877SChristoph Hellwig 		index = xg->xg_gno + 1;
11081992877SChristoph Hellwig 		xfs_group_rele(xg);
11181992877SChristoph Hellwig 	}
11281992877SChristoph Hellwig 	if (index > end_index)
11381992877SChristoph Hellwig 		return NULL;
11481992877SChristoph Hellwig 	return xfs_group_grab(mp, index, type);
11581992877SChristoph Hellwig }
11681992877SChristoph Hellwig 
11781992877SChristoph Hellwig /*
118e9c4d8bfSChristoph Hellwig  * Find the next group after @xg, or the first group if @xg is NULL.
119e9c4d8bfSChristoph Hellwig  */
120e9c4d8bfSChristoph Hellwig struct xfs_group *
121e9c4d8bfSChristoph Hellwig xfs_group_grab_next_mark(
122e9c4d8bfSChristoph Hellwig 	struct xfs_mount	*mp,
123e9c4d8bfSChristoph Hellwig 	struct xfs_group	*xg,
124e9c4d8bfSChristoph Hellwig 	xa_mark_t		mark,
125e9c4d8bfSChristoph Hellwig 	enum xfs_group_type	type)
126e9c4d8bfSChristoph Hellwig {
127e9c4d8bfSChristoph Hellwig 	unsigned long		index = 0;
128e9c4d8bfSChristoph Hellwig 
129e9c4d8bfSChristoph Hellwig 	if (xg) {
130e9c4d8bfSChristoph Hellwig 		index = xg->xg_gno + 1;
131e9c4d8bfSChristoph Hellwig 		xfs_group_rele(xg);
132e9c4d8bfSChristoph Hellwig 	}
133e9c4d8bfSChristoph Hellwig 
134e9c4d8bfSChristoph Hellwig 	rcu_read_lock();
135e9c4d8bfSChristoph Hellwig 	xg = xa_find(&mp->m_groups[type].xa, &index, ULONG_MAX, mark);
136e9c4d8bfSChristoph Hellwig 	if (xg) {
137e9c4d8bfSChristoph Hellwig 		trace_xfs_group_grab_next_tag(xg, _RET_IP_);
138e9c4d8bfSChristoph Hellwig 		if (!atomic_inc_not_zero(&xg->xg_active_ref))
139e9c4d8bfSChristoph Hellwig 			xg = NULL;
140e9c4d8bfSChristoph Hellwig 	}
141e9c4d8bfSChristoph Hellwig 	rcu_read_unlock();
142e9c4d8bfSChristoph Hellwig 	return xg;
143e9c4d8bfSChristoph Hellwig }
144e9c4d8bfSChristoph Hellwig 
145e9c4d8bfSChristoph Hellwig void
146e9c4d8bfSChristoph Hellwig xfs_group_rele(
147e9c4d8bfSChristoph Hellwig 	struct xfs_group	*xg)
148e9c4d8bfSChristoph Hellwig {
149e9c4d8bfSChristoph Hellwig 	trace_xfs_group_rele(xg, _RET_IP_);
150e9c4d8bfSChristoph Hellwig 	atomic_dec(&xg->xg_active_ref);
151e9c4d8bfSChristoph Hellwig }
152e9c4d8bfSChristoph Hellwig 
153e9c4d8bfSChristoph Hellwig void
154e9c4d8bfSChristoph Hellwig xfs_group_free(
155e9c4d8bfSChristoph Hellwig 	struct xfs_mount	*mp,
156e9c4d8bfSChristoph Hellwig 	uint32_t		index,
157e9c4d8bfSChristoph Hellwig 	enum xfs_group_type	type,
158e9c4d8bfSChristoph Hellwig 	void			(*uninit)(struct xfs_group *xg))
159e9c4d8bfSChristoph Hellwig {
160e9c4d8bfSChristoph Hellwig 	struct xfs_group	*xg = xa_erase(&mp->m_groups[type].xa, index);
161e9c4d8bfSChristoph Hellwig 
162e9c4d8bfSChristoph Hellwig 	XFS_IS_CORRUPT(mp, atomic_read(&xg->xg_ref) != 0);
163e9c4d8bfSChristoph Hellwig 
16434cf3a6fSChristoph Hellwig 	xfs_defer_drain_free(&xg->xg_intents_drain);
165adbc76aaSChristoph Hellwig #ifdef __KERNEL__
166adbc76aaSChristoph Hellwig 	kfree(xg->xg_busy_extents);
167adbc76aaSChristoph Hellwig #endif
16834cf3a6fSChristoph Hellwig 
169e9c4d8bfSChristoph Hellwig 	if (uninit)
170e9c4d8bfSChristoph Hellwig 		uninit(xg);
171e9c4d8bfSChristoph Hellwig 
172e9c4d8bfSChristoph Hellwig 	/* drop the mount's active reference */
173e9c4d8bfSChristoph Hellwig 	xfs_group_rele(xg);
174e9c4d8bfSChristoph Hellwig 	XFS_IS_CORRUPT(mp, atomic_read(&xg->xg_active_ref) != 0);
175e9c4d8bfSChristoph Hellwig 	kfree_rcu_mightsleep(xg);
176e9c4d8bfSChristoph Hellwig }
177e9c4d8bfSChristoph Hellwig 
178e9c4d8bfSChristoph Hellwig int
179e9c4d8bfSChristoph Hellwig xfs_group_insert(
180e9c4d8bfSChristoph Hellwig 	struct xfs_mount	*mp,
181e9c4d8bfSChristoph Hellwig 	struct xfs_group	*xg,
182e9c4d8bfSChristoph Hellwig 	uint32_t		index,
183e9c4d8bfSChristoph Hellwig 	enum xfs_group_type	type)
184e9c4d8bfSChristoph Hellwig {
185e9c4d8bfSChristoph Hellwig 	int			error;
186e9c4d8bfSChristoph Hellwig 
187e9c4d8bfSChristoph Hellwig 	xg->xg_mount = mp;
188e9c4d8bfSChristoph Hellwig 	xg->xg_gno = index;
189e9c4d8bfSChristoph Hellwig 	xg->xg_type = type;
190e9c4d8bfSChristoph Hellwig 
1915c8483ceSChristoph Hellwig #ifdef __KERNEL__
192adbc76aaSChristoph Hellwig 	xg->xg_busy_extents = xfs_extent_busy_alloc();
193adbc76aaSChristoph Hellwig 	if (!xg->xg_busy_extents)
194adbc76aaSChristoph Hellwig 		return -ENOMEM;
1955c8483ceSChristoph Hellwig 	spin_lock_init(&xg->xg_state_lock);
196eb4a84a3SChristoph Hellwig 	xfs_hooks_init(&xg->xg_rmap_update_hooks);
1975c8483ceSChristoph Hellwig #endif
19834cf3a6fSChristoph Hellwig 	xfs_defer_drain_init(&xg->xg_intents_drain);
1995c8483ceSChristoph Hellwig 
200e9c4d8bfSChristoph Hellwig 	/* Active ref owned by mount indicates group is online. */
201e9c4d8bfSChristoph Hellwig 	atomic_set(&xg->xg_active_ref, 1);
202e9c4d8bfSChristoph Hellwig 
203e9c4d8bfSChristoph Hellwig 	error = xa_insert(&mp->m_groups[type].xa, index, xg, GFP_KERNEL);
204e9c4d8bfSChristoph Hellwig 	if (error) {
205e9c4d8bfSChristoph Hellwig 		WARN_ON_ONCE(error == -EBUSY);
206adbc76aaSChristoph Hellwig 		goto out_drain;
207e9c4d8bfSChristoph Hellwig 	}
208e9c4d8bfSChristoph Hellwig 
209e9c4d8bfSChristoph Hellwig 	return 0;
210adbc76aaSChristoph Hellwig out_drain:
211adbc76aaSChristoph Hellwig 	xfs_defer_drain_free(&xg->xg_intents_drain);
212adbc76aaSChristoph Hellwig #ifdef __KERNEL__
213adbc76aaSChristoph Hellwig 	kfree(xg->xg_busy_extents);
214adbc76aaSChristoph Hellwig #endif
215adbc76aaSChristoph Hellwig 	return error;
216e9c4d8bfSChristoph Hellwig }
217*759cc198SChristoph Hellwig 
218*759cc198SChristoph Hellwig struct xfs_group *
219*759cc198SChristoph Hellwig xfs_group_get_by_fsb(
220*759cc198SChristoph Hellwig 	struct xfs_mount	*mp,
221*759cc198SChristoph Hellwig 	xfs_fsblock_t		fsbno,
222*759cc198SChristoph Hellwig 	enum xfs_group_type	type)
223*759cc198SChristoph Hellwig {
224*759cc198SChristoph Hellwig 	return xfs_group_get(mp, xfs_fsb_to_gno(mp, fsbno, type), type);
225*759cc198SChristoph Hellwig }
226