GNU Linux-libre 4.9.309-gnu1
[releases.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 /* Set the map extent flags for this reverse mapping. */
35 static void
36 xfs_trans_set_rmap_flags(
37         struct xfs_map_extent           *rmap,
38         enum xfs_rmap_intent_type       type,
39         int                             whichfork,
40         xfs_exntst_t                    state)
41 {
42         rmap->me_flags = 0;
43         if (state == XFS_EXT_UNWRITTEN)
44                 rmap->me_flags |= XFS_RMAP_EXTENT_UNWRITTEN;
45         if (whichfork == XFS_ATTR_FORK)
46                 rmap->me_flags |= XFS_RMAP_EXTENT_ATTR_FORK;
47         switch (type) {
48         case XFS_RMAP_MAP:
49                 rmap->me_flags |= XFS_RMAP_EXTENT_MAP;
50                 break;
51         case XFS_RMAP_MAP_SHARED:
52                 rmap->me_flags |= XFS_RMAP_EXTENT_MAP_SHARED;
53                 break;
54         case XFS_RMAP_UNMAP:
55                 rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP;
56                 break;
57         case XFS_RMAP_UNMAP_SHARED:
58                 rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP_SHARED;
59                 break;
60         case XFS_RMAP_CONVERT:
61                 rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT;
62                 break;
63         case XFS_RMAP_CONVERT_SHARED:
64                 rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT_SHARED;
65                 break;
66         case XFS_RMAP_ALLOC:
67                 rmap->me_flags |= XFS_RMAP_EXTENT_ALLOC;
68                 break;
69         case XFS_RMAP_FREE:
70                 rmap->me_flags |= XFS_RMAP_EXTENT_FREE;
71                 break;
72         default:
73                 ASSERT(0);
74         }
75 }
76
77 struct xfs_rud_log_item *
78 xfs_trans_get_rud(
79         struct xfs_trans                *tp,
80         struct xfs_rui_log_item         *ruip)
81 {
82         struct xfs_rud_log_item         *rudp;
83
84         rudp = xfs_rud_init(tp->t_mountp, ruip);
85         xfs_trans_add_item(tp, &rudp->rud_item);
86         return rudp;
87 }
88
89 /*
90  * Finish an rmap update and log it to the RUD. Note that the transaction is
91  * marked dirty regardless of whether the rmap update succeeds or fails to
92  * support the RUI/RUD lifecycle rules.
93  */
94 int
95 xfs_trans_log_finish_rmap_update(
96         struct xfs_trans                *tp,
97         struct xfs_rud_log_item         *rudp,
98         enum xfs_rmap_intent_type       type,
99         __uint64_t                      owner,
100         int                             whichfork,
101         xfs_fileoff_t                   startoff,
102         xfs_fsblock_t                   startblock,
103         xfs_filblks_t                   blockcount,
104         xfs_exntst_t                    state,
105         struct xfs_btree_cur            **pcur)
106 {
107         int                             error;
108
109         error = xfs_rmap_finish_one(tp, type, owner, whichfork, startoff,
110                         startblock, blockcount, state, pcur);
111
112         /*
113          * Mark the transaction dirty, even on error. This ensures the
114          * transaction is aborted, which:
115          *
116          * 1.) releases the RUI and frees the RUD
117          * 2.) shuts down the filesystem
118          */
119         tp->t_flags |= XFS_TRANS_DIRTY;
120         rudp->rud_item.li_desc->lid_flags |= XFS_LID_DIRTY;
121
122         return error;
123 }
124
125 /* Sort rmap intents by AG. */
126 static int
127 xfs_rmap_update_diff_items(
128         void                            *priv,
129         struct list_head                *a,
130         struct list_head                *b)
131 {
132         struct xfs_mount                *mp = priv;
133         struct xfs_rmap_intent          *ra;
134         struct xfs_rmap_intent          *rb;
135
136         ra = container_of(a, struct xfs_rmap_intent, ri_list);
137         rb = container_of(b, struct xfs_rmap_intent, ri_list);
138         return  XFS_FSB_TO_AGNO(mp, ra->ri_bmap.br_startblock) -
139                 XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock);
140 }
141
142 /* Get an RUI. */
143 STATIC void *
144 xfs_rmap_update_create_intent(
145         struct xfs_trans                *tp,
146         unsigned int                    count)
147 {
148         struct xfs_rui_log_item         *ruip;
149
150         ASSERT(tp != NULL);
151         ASSERT(count > 0);
152
153         ruip = xfs_rui_init(tp->t_mountp, count);
154         ASSERT(ruip != NULL);
155
156         /*
157          * Get a log_item_desc to point at the new item.
158          */
159         xfs_trans_add_item(tp, &ruip->rui_item);
160         return ruip;
161 }
162
163 /* Log rmap updates in the intent item. */
164 STATIC void
165 xfs_rmap_update_log_item(
166         struct xfs_trans                *tp,
167         void                            *intent,
168         struct list_head                *item)
169 {
170         struct xfs_rui_log_item         *ruip = intent;
171         struct xfs_rmap_intent          *rmap;
172         uint                            next_extent;
173         struct xfs_map_extent           *map;
174
175         rmap = container_of(item, struct xfs_rmap_intent, ri_list);
176
177         tp->t_flags |= XFS_TRANS_DIRTY;
178         ruip->rui_item.li_desc->lid_flags |= XFS_LID_DIRTY;
179
180         /*
181          * atomic_inc_return gives us the value after the increment;
182          * we want to use it as an array index so we need to subtract 1 from
183          * it.
184          */
185         next_extent = atomic_inc_return(&ruip->rui_next_extent) - 1;
186         ASSERT(next_extent < ruip->rui_format.rui_nextents);
187         map = &ruip->rui_format.rui_extents[next_extent];
188         map->me_owner = rmap->ri_owner;
189         map->me_startblock = rmap->ri_bmap.br_startblock;
190         map->me_startoff = rmap->ri_bmap.br_startoff;
191         map->me_len = rmap->ri_bmap.br_blockcount;
192         xfs_trans_set_rmap_flags(map, rmap->ri_type, rmap->ri_whichfork,
193                         rmap->ri_bmap.br_state);
194 }
195
196 /* Get an RUD so we can process all the deferred rmap updates. */
197 STATIC void *
198 xfs_rmap_update_create_done(
199         struct xfs_trans                *tp,
200         void                            *intent,
201         unsigned int                    count)
202 {
203         return xfs_trans_get_rud(tp, intent);
204 }
205
206 /* Process a deferred rmap update. */
207 STATIC int
208 xfs_rmap_update_finish_item(
209         struct xfs_trans                *tp,
210         struct xfs_defer_ops            *dop,
211         struct list_head                *item,
212         void                            *done_item,
213         void                            **state)
214 {
215         struct xfs_rmap_intent          *rmap;
216         int                             error;
217
218         rmap = container_of(item, struct xfs_rmap_intent, ri_list);
219         error = xfs_trans_log_finish_rmap_update(tp, done_item,
220                         rmap->ri_type,
221                         rmap->ri_owner, rmap->ri_whichfork,
222                         rmap->ri_bmap.br_startoff,
223                         rmap->ri_bmap.br_startblock,
224                         rmap->ri_bmap.br_blockcount,
225                         rmap->ri_bmap.br_state,
226                         (struct xfs_btree_cur **)state);
227         kmem_free(rmap);
228         return error;
229 }
230
231 /* Clean up after processing deferred rmaps. */
232 STATIC void
233 xfs_rmap_update_finish_cleanup(
234         struct xfs_trans        *tp,
235         void                    *state,
236         int                     error)
237 {
238         struct xfs_btree_cur    *rcur = state;
239
240         xfs_rmap_finish_one_cleanup(tp, rcur, error);
241 }
242
243 /* Abort all pending RUIs. */
244 STATIC void
245 xfs_rmap_update_abort_intent(
246         void                            *intent)
247 {
248         xfs_rui_release(intent);
249 }
250
251 /* Cancel a deferred rmap update. */
252 STATIC void
253 xfs_rmap_update_cancel_item(
254         struct list_head                *item)
255 {
256         struct xfs_rmap_intent          *rmap;
257
258         rmap = container_of(item, struct xfs_rmap_intent, ri_list);
259         kmem_free(rmap);
260 }
261
262 static const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
263         .type           = XFS_DEFER_OPS_TYPE_RMAP,
264         .max_items      = XFS_RUI_MAX_FAST_EXTENTS,
265         .diff_items     = xfs_rmap_update_diff_items,
266         .create_intent  = xfs_rmap_update_create_intent,
267         .abort_intent   = xfs_rmap_update_abort_intent,
268         .log_item       = xfs_rmap_update_log_item,
269         .create_done    = xfs_rmap_update_create_done,
270         .finish_item    = xfs_rmap_update_finish_item,
271         .finish_cleanup = xfs_rmap_update_finish_cleanup,
272         .cancel_item    = xfs_rmap_update_cancel_item,
273 };
274
275 /* Register the deferred op type. */
276 void
277 xfs_rmap_update_init_defer_op(void)
278 {
279         xfs_defer_init_op_type(&xfs_rmap_update_defer_type);
280 }