Linux-libre 4.19.116-gnu
[librecmc/linux-libre.git] / fs / xfs / xfs_trans_bmap.c
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 *
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
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
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 *
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
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
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 *
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
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
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
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
237 xfs_bmap_update_init_defer_op(void)
238 {
239         xfs_defer_init_op_type(&xfs_bmap_update_defer_type);
240 }