1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5  */
6 #include "xfs.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_log_format.h"
11 #include "xfs_trans_resv.h"
12 #include "xfs_mount.h"
13 #include "xfs_defer.h"
14 #include "xfs_trans.h"
15 #include "xfs_trans_priv.h"
16 #include "xfs_bmap_item.h"
17 #include "xfs_alloc.h"
18 #include "xfs_bmap.h"
19 #include "xfs_inode.h"
20 
21 /*
22  * This routine is called to allocate a "bmap update done"
23  * log item.
24  */
25 struct xfs_bud_log_item *
xfs_trans_get_bud(struct xfs_trans * tp,struct xfs_bui_log_item * buip)26 xfs_trans_get_bud(
27 	struct xfs_trans		*tp,
28 	struct xfs_bui_log_item		*buip)
29 {
30 	struct xfs_bud_log_item		*budp;
31 
32 	budp = xfs_bud_init(tp->t_mountp, buip);
33 	xfs_trans_add_item(tp, &budp->bud_item);
34 	return budp;
35 }
36 
37 /*
38  * Finish an bmap update and log it to the BUD. Note that the
39  * transaction is marked dirty regardless of whether the bmap update
40  * succeeds or fails to support the BUI/BUD lifecycle rules.
41  */
42 int
xfs_trans_log_finish_bmap_update(struct xfs_trans * tp,struct xfs_bud_log_item * budp,enum xfs_bmap_intent_type type,struct xfs_inode * ip,int whichfork,xfs_fileoff_t startoff,xfs_fsblock_t startblock,xfs_filblks_t * blockcount,xfs_exntst_t state)43 xfs_trans_log_finish_bmap_update(
44 	struct xfs_trans		*tp,
45 	struct xfs_bud_log_item		*budp,
46 	enum xfs_bmap_intent_type	type,
47 	struct xfs_inode		*ip,
48 	int				whichfork,
49 	xfs_fileoff_t			startoff,
50 	xfs_fsblock_t			startblock,
51 	xfs_filblks_t			*blockcount,
52 	xfs_exntst_t			state)
53 {
54 	int				error;
55 
56 	error = xfs_bmap_finish_one(tp, ip, type, whichfork, startoff,
57 			startblock, blockcount, state);
58 
59 	/*
60 	 * Mark the transaction dirty, even on error. This ensures the
61 	 * transaction is aborted, which:
62 	 *
63 	 * 1.) releases the BUI and frees the BUD
64 	 * 2.) shuts down the filesystem
65 	 */
66 	tp->t_flags |= XFS_TRANS_DIRTY;
67 	set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags);
68 
69 	return error;
70 }
71 
72 /* Sort bmap intents by inode. */
73 static int
xfs_bmap_update_diff_items(void * priv,struct list_head * a,struct list_head * b)74 xfs_bmap_update_diff_items(
75 	void				*priv,
76 	struct list_head		*a,
77 	struct list_head		*b)
78 {
79 	struct xfs_bmap_intent		*ba;
80 	struct xfs_bmap_intent		*bb;
81 
82 	ba = container_of(a, struct xfs_bmap_intent, bi_list);
83 	bb = container_of(b, struct xfs_bmap_intent, bi_list);
84 	return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
85 }
86 
87 /* Get an BUI. */
88 STATIC void *
xfs_bmap_update_create_intent(struct xfs_trans * tp,unsigned int count)89 xfs_bmap_update_create_intent(
90 	struct xfs_trans		*tp,
91 	unsigned int			count)
92 {
93 	struct xfs_bui_log_item		*buip;
94 
95 	ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS);
96 	ASSERT(tp != NULL);
97 
98 	buip = xfs_bui_init(tp->t_mountp);
99 	ASSERT(buip != NULL);
100 
101 	/*
102 	 * Get a log_item_desc to point at the new item.
103 	 */
104 	xfs_trans_add_item(tp, &buip->bui_item);
105 	return buip;
106 }
107 
108 /* Set the map extent flags for this mapping. */
109 static void
xfs_trans_set_bmap_flags(struct xfs_map_extent * bmap,enum xfs_bmap_intent_type type,int whichfork,xfs_exntst_t state)110 xfs_trans_set_bmap_flags(
111 	struct xfs_map_extent		*bmap,
112 	enum xfs_bmap_intent_type	type,
113 	int				whichfork,
114 	xfs_exntst_t			state)
115 {
116 	bmap->me_flags = 0;
117 	switch (type) {
118 	case XFS_BMAP_MAP:
119 	case XFS_BMAP_UNMAP:
120 		bmap->me_flags = type;
121 		break;
122 	default:
123 		ASSERT(0);
124 	}
125 	if (state == XFS_EXT_UNWRITTEN)
126 		bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN;
127 	if (whichfork == XFS_ATTR_FORK)
128 		bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK;
129 }
130 
131 /* Log bmap updates in the intent item. */
132 STATIC void
xfs_bmap_update_log_item(struct xfs_trans * tp,void * intent,struct list_head * item)133 xfs_bmap_update_log_item(
134 	struct xfs_trans		*tp,
135 	void				*intent,
136 	struct list_head		*item)
137 {
138 	struct xfs_bui_log_item		*buip = intent;
139 	struct xfs_bmap_intent		*bmap;
140 	uint				next_extent;
141 	struct xfs_map_extent		*map;
142 
143 	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
144 
145 	tp->t_flags |= XFS_TRANS_DIRTY;
146 	set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags);
147 
148 	/*
149 	 * atomic_inc_return gives us the value after the increment;
150 	 * we want to use it as an array index so we need to subtract 1 from
151 	 * it.
152 	 */
153 	next_extent = atomic_inc_return(&buip->bui_next_extent) - 1;
154 	ASSERT(next_extent < buip->bui_format.bui_nextents);
155 	map = &buip->bui_format.bui_extents[next_extent];
156 	map->me_owner = bmap->bi_owner->i_ino;
157 	map->me_startblock = bmap->bi_bmap.br_startblock;
158 	map->me_startoff = bmap->bi_bmap.br_startoff;
159 	map->me_len = bmap->bi_bmap.br_blockcount;
160 	xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork,
161 			bmap->bi_bmap.br_state);
162 }
163 
164 /* Get an BUD so we can process all the deferred rmap updates. */
165 STATIC void *
xfs_bmap_update_create_done(struct xfs_trans * tp,void * intent,unsigned int count)166 xfs_bmap_update_create_done(
167 	struct xfs_trans		*tp,
168 	void				*intent,
169 	unsigned int			count)
170 {
171 	return xfs_trans_get_bud(tp, intent);
172 }
173 
174 /* Process a deferred rmap update. */
175 STATIC int
xfs_bmap_update_finish_item(struct xfs_trans * tp,struct list_head * item,void * done_item,void ** state)176 xfs_bmap_update_finish_item(
177 	struct xfs_trans		*tp,
178 	struct list_head		*item,
179 	void				*done_item,
180 	void				**state)
181 {
182 	struct xfs_bmap_intent		*bmap;
183 	xfs_filblks_t			count;
184 	int				error;
185 
186 	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
187 	count = bmap->bi_bmap.br_blockcount;
188 	error = xfs_trans_log_finish_bmap_update(tp, done_item,
189 			bmap->bi_type,
190 			bmap->bi_owner, bmap->bi_whichfork,
191 			bmap->bi_bmap.br_startoff,
192 			bmap->bi_bmap.br_startblock,
193 			&count,
194 			bmap->bi_bmap.br_state);
195 	if (!error && count > 0) {
196 		ASSERT(bmap->bi_type == XFS_BMAP_UNMAP);
197 		bmap->bi_bmap.br_blockcount = count;
198 		return -EAGAIN;
199 	}
200 	kmem_free(bmap);
201 	return error;
202 }
203 
204 /* Abort all pending BUIs. */
205 STATIC void
xfs_bmap_update_abort_intent(void * intent)206 xfs_bmap_update_abort_intent(
207 	void				*intent)
208 {
209 	xfs_bui_release(intent);
210 }
211 
212 /* Cancel a deferred rmap update. */
213 STATIC void
xfs_bmap_update_cancel_item(struct list_head * item)214 xfs_bmap_update_cancel_item(
215 	struct list_head		*item)
216 {
217 	struct xfs_bmap_intent		*bmap;
218 
219 	bmap = container_of(item, struct xfs_bmap_intent, bi_list);
220 	kmem_free(bmap);
221 }
222 
223 static const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
224 	.type		= XFS_DEFER_OPS_TYPE_BMAP,
225 	.max_items	= XFS_BUI_MAX_FAST_EXTENTS,
226 	.diff_items	= xfs_bmap_update_diff_items,
227 	.create_intent	= xfs_bmap_update_create_intent,
228 	.abort_intent	= xfs_bmap_update_abort_intent,
229 	.log_item	= xfs_bmap_update_log_item,
230 	.create_done	= xfs_bmap_update_create_done,
231 	.finish_item	= xfs_bmap_update_finish_item,
232 	.cancel_item	= xfs_bmap_update_cancel_item,
233 };
234 
235 /* Register the deferred op type. */
236 void
xfs_bmap_update_init_defer_op(void)237 xfs_bmap_update_init_defer_op(void)
238 {
239 	xfs_defer_init_op_type(&xfs_bmap_update_defer_type);
240 }
241