xfs: enable the xfs_defer mechanism to process rmaps to update
[linux-2.6-block.git] / fs / xfs / xfs_trans_rmap.c
1 /*
2  * Copyright (C) 2016 Oracle.  All Rights Reserved.
3  *
4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it would be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write the Free Software Foundation,
18  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 #include "xfs.h"
21 #include "xfs_fs.h"
22 #include "xfs_shared.h"
23 #include "xfs_format.h"
24 #include "xfs_log_format.h"
25 #include "xfs_trans_resv.h"
26 #include "xfs_mount.h"
27 #include "xfs_defer.h"
28 #include "xfs_trans.h"
29 #include "xfs_trans_priv.h"
30 #include "xfs_rmap_item.h"
31 #include "xfs_alloc.h"
32 #include "xfs_rmap.h"
33
34 /*
35  * This routine is called to allocate an "rmap update intent"
36  * log item that will hold nextents worth of extents.  The
37  * caller must use all nextents extents, because we are not
38  * flexible about this at all.
39  */
40 STATIC struct xfs_rui_log_item *
41 xfs_trans_get_rui(
42         struct xfs_trans                *tp,
43         uint                            nextents)
44 {
45         struct xfs_rui_log_item         *ruip;
46
47         ASSERT(tp != NULL);
48         ASSERT(nextents > 0);
49
50         ruip = xfs_rui_init(tp->t_mountp, nextents);
51         ASSERT(ruip != NULL);
52
53         /*
54          * Get a log_item_desc to point at the new item.
55          */
56         xfs_trans_add_item(tp, &ruip->rui_item);
57         return ruip;
58 }
59
60 /* Set the map extent flags for this reverse mapping. */
61 static void
62 xfs_trans_set_rmap_flags(
63         struct xfs_map_extent           *rmap,
64         enum xfs_rmap_intent_type       type,
65         int                             whichfork,
66         xfs_exntst_t                    state)
67 {
68         rmap->me_flags = 0;
69         if (state == XFS_EXT_UNWRITTEN)
70                 rmap->me_flags |= XFS_RMAP_EXTENT_UNWRITTEN;
71         if (whichfork == XFS_ATTR_FORK)
72                 rmap->me_flags |= XFS_RMAP_EXTENT_ATTR_FORK;
73         switch (type) {
74         case XFS_RMAP_MAP:
75                 rmap->me_flags |= XFS_RMAP_EXTENT_MAP;
76                 break;
77         case XFS_RMAP_UNMAP:
78                 rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP;
79                 break;
80         case XFS_RMAP_CONVERT:
81                 rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT;
82                 break;
83         case XFS_RMAP_ALLOC:
84                 rmap->me_flags |= XFS_RMAP_EXTENT_ALLOC;
85                 break;
86         case XFS_RMAP_FREE:
87                 rmap->me_flags |= XFS_RMAP_EXTENT_FREE;
88                 break;
89         default:
90                 ASSERT(0);
91         }
92 }
93
94 /*
95  * This routine is called to indicate that the described reverse
96  * mapping is to be logged as needing to be updated.  It should be
97  * called once for each mapping.
98  */
99 STATIC void
100 xfs_trans_log_start_rmap_update(
101         struct xfs_trans                *tp,
102         struct xfs_rui_log_item         *ruip,
103         enum xfs_rmap_intent_type       type,
104         __uint64_t                      owner,
105         int                             whichfork,
106         xfs_fileoff_t                   startoff,
107         xfs_fsblock_t                   startblock,
108         xfs_filblks_t                   blockcount,
109         xfs_exntst_t                    state)
110 {
111         uint                            next_extent;
112         struct xfs_map_extent           *rmap;
113
114         tp->t_flags |= XFS_TRANS_DIRTY;
115         ruip->rui_item.li_desc->lid_flags |= XFS_LID_DIRTY;
116
117         /*
118          * atomic_inc_return gives us the value after the increment;
119          * we want to use it as an array index so we need to subtract 1 from
120          * it.
121          */
122         next_extent = atomic_inc_return(&ruip->rui_next_extent) - 1;
123         ASSERT(next_extent < ruip->rui_format.rui_nextents);
124         rmap = &(ruip->rui_format.rui_extents[next_extent]);
125         rmap->me_owner = owner;
126         rmap->me_startblock = startblock;
127         rmap->me_startoff = startoff;
128         rmap->me_len = blockcount;
129         xfs_trans_set_rmap_flags(rmap, type, whichfork, state);
130 }
131
132 /*
133  * This routine is called to allocate an "rmap update done"
134  * log item that will hold nextents worth of extents.  The
135  * caller must use all nextents extents, because we are not
136  * flexible about this at all.
137  */
138 struct xfs_rud_log_item *
139 xfs_trans_get_rud(
140         struct xfs_trans                *tp,
141         struct xfs_rui_log_item         *ruip,
142         uint                            nextents)
143 {
144         struct xfs_rud_log_item         *rudp;
145
146         ASSERT(tp != NULL);
147         ASSERT(nextents > 0);
148
149         rudp = xfs_rud_init(tp->t_mountp, ruip, nextents);
150         ASSERT(rudp != NULL);
151
152         /*
153          * Get a log_item_desc to point at the new item.
154          */
155         xfs_trans_add_item(tp, &rudp->rud_item);
156         return rudp;
157 }
158
159 /*
160  * Finish an rmap update and log it to the RUD. Note that the transaction is
161  * marked dirty regardless of whether the rmap update succeeds or fails to
162  * support the RUI/RUD lifecycle rules.
163  */
164 int
165 xfs_trans_log_finish_rmap_update(
166         struct xfs_trans                *tp,
167         struct xfs_rud_log_item         *rudp,
168         enum xfs_rmap_intent_type       type,
169         __uint64_t                      owner,
170         int                             whichfork,
171         xfs_fileoff_t                   startoff,
172         xfs_fsblock_t                   startblock,
173         xfs_filblks_t                   blockcount,
174         xfs_exntst_t                    state)
175 {
176         uint                            next_extent;
177         struct xfs_map_extent           *rmap;
178         int                             error;
179
180         /* XXX: actually finish the rmap update here */
181         error = -EFSCORRUPTED;
182
183         /*
184          * Mark the transaction dirty, even on error. This ensures the
185          * transaction is aborted, which:
186          *
187          * 1.) releases the RUI and frees the RUD
188          * 2.) shuts down the filesystem
189          */
190         tp->t_flags |= XFS_TRANS_DIRTY;
191         rudp->rud_item.li_desc->lid_flags |= XFS_LID_DIRTY;
192
193         next_extent = rudp->rud_next_extent;
194         ASSERT(next_extent < rudp->rud_format.rud_nextents);
195         rmap = &(rudp->rud_format.rud_extents[next_extent]);
196         rmap->me_owner = owner;
197         rmap->me_startblock = startblock;
198         rmap->me_startoff = startoff;
199         rmap->me_len = blockcount;
200         xfs_trans_set_rmap_flags(rmap, type, whichfork, state);
201         rudp->rud_next_extent++;
202
203         return error;
204 }
205
206 /* Sort rmap intents by AG. */
207 static int
208 xfs_rmap_update_diff_items(
209         void                            *priv,
210         struct list_head                *a,
211         struct list_head                *b)
212 {
213         struct xfs_mount                *mp = priv;
214         struct xfs_rmap_intent          *ra;
215         struct xfs_rmap_intent          *rb;
216
217         ra = container_of(a, struct xfs_rmap_intent, ri_list);
218         rb = container_of(b, struct xfs_rmap_intent, ri_list);
219         return  XFS_FSB_TO_AGNO(mp, ra->ri_bmap.br_startblock) -
220                 XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock);
221 }
222
223 /* Get an RUI. */
224 STATIC void *
225 xfs_rmap_update_create_intent(
226         struct xfs_trans                *tp,
227         unsigned int                    count)
228 {
229         return xfs_trans_get_rui(tp, count);
230 }
231
232 /* Log rmap updates in the intent item. */
233 STATIC void
234 xfs_rmap_update_log_item(
235         struct xfs_trans                *tp,
236         void                            *intent,
237         struct list_head                *item)
238 {
239         struct xfs_rmap_intent          *rmap;
240
241         rmap = container_of(item, struct xfs_rmap_intent, ri_list);
242         xfs_trans_log_start_rmap_update(tp, intent, rmap->ri_type,
243                         rmap->ri_owner, rmap->ri_whichfork,
244                         rmap->ri_bmap.br_startoff,
245                         rmap->ri_bmap.br_startblock,
246                         rmap->ri_bmap.br_blockcount,
247                         rmap->ri_bmap.br_state);
248 }
249
250 /* Get an RUD so we can process all the deferred rmap updates. */
251 STATIC void *
252 xfs_rmap_update_create_done(
253         struct xfs_trans                *tp,
254         void                            *intent,
255         unsigned int                    count)
256 {
257         return xfs_trans_get_rud(tp, intent, count);
258 }
259
260 /* Process a deferred rmap update. */
261 STATIC int
262 xfs_rmap_update_finish_item(
263         struct xfs_trans                *tp,
264         struct xfs_defer_ops            *dop,
265         struct list_head                *item,
266         void                            *done_item,
267         void                            **state)
268 {
269         struct xfs_rmap_intent          *rmap;
270         int                             error;
271
272         rmap = container_of(item, struct xfs_rmap_intent, ri_list);
273         error = xfs_trans_log_finish_rmap_update(tp, done_item,
274                         rmap->ri_type,
275                         rmap->ri_owner, rmap->ri_whichfork,
276                         rmap->ri_bmap.br_startoff,
277                         rmap->ri_bmap.br_startblock,
278                         rmap->ri_bmap.br_blockcount,
279                         rmap->ri_bmap.br_state);
280         kmem_free(rmap);
281         return error;
282 }
283
284 /* Clean up after processing deferred rmaps. */
285 STATIC void
286 xfs_rmap_update_finish_cleanup(
287         struct xfs_trans        *tp,
288         void                    *state,
289         int                     error)
290 {
291 }
292
293 /* Abort all pending RUIs. */
294 STATIC void
295 xfs_rmap_update_abort_intent(
296         void                            *intent)
297 {
298         xfs_rui_release(intent);
299 }
300
301 /* Cancel a deferred rmap update. */
302 STATIC void
303 xfs_rmap_update_cancel_item(
304         struct list_head                *item)
305 {
306         struct xfs_rmap_intent          *rmap;
307
308         rmap = container_of(item, struct xfs_rmap_intent, ri_list);
309         kmem_free(rmap);
310 }
311
312 static const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
313         .type           = XFS_DEFER_OPS_TYPE_RMAP,
314         .max_items      = XFS_RUI_MAX_FAST_EXTENTS,
315         .diff_items     = xfs_rmap_update_diff_items,
316         .create_intent  = xfs_rmap_update_create_intent,
317         .abort_intent   = xfs_rmap_update_abort_intent,
318         .log_item       = xfs_rmap_update_log_item,
319         .create_done    = xfs_rmap_update_create_done,
320         .finish_item    = xfs_rmap_update_finish_item,
321         .finish_cleanup = xfs_rmap_update_finish_cleanup,
322         .cancel_item    = xfs_rmap_update_cancel_item,
323 };
324
325 /* Register the deferred op type. */
326 void
327 xfs_rmap_update_init_defer_op(void)
328 {
329         xfs_defer_init_op_type(&xfs_rmap_update_defer_type);
330 }